1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <dbase/DIndex.hxx>
21 #include <dbase/DIndexColumns.hxx>
22 #include <dbase/DTable.hxx>
23 #include <dbase/DIndexIter.hxx>
24 #include <osl/file.hxx>
25 #include <sal/log.hxx>
26 #include <tools/config.hxx>
27 #include <connectivity/CommonTools.hxx>
28 #include <com/sun/star/sdbc/XResultSet.hpp>
29 #include <com/sun/star/sdbc/XRow.hpp>
30 #include <unotools/ucbhelper.hxx>
31 #include <comphelper/servicehelper.hxx>
32 #include <comphelper/types.hxx>
33 #include <cppuhelper/typeprovider.hxx>
34 #include <connectivity/dbexception.hxx>
35 #include <dbase/DResultSet.hxx>
36 #include <strings.hrc>
37 #include <unotools/sharedunocomponent.hxx>
38 
39 using namespace ::comphelper;
40 
41 using namespace connectivity;
42 using namespace utl;
43 using namespace ::cppu;
44 using namespace connectivity::file;
45 using namespace connectivity::sdbcx;
46 using namespace connectivity::dbase;
47 using namespace com::sun::star::sdbc;
48 using namespace com::sun::star::sdbcx;
49 using namespace com::sun::star::uno;
50 using namespace com::sun::star::beans;
51 using namespace com::sun::star::lang;
52 
53 IMPLEMENT_SERVICE_INFO(ODbaseIndex,"com.sun.star.sdbcx.driver.dbase.Index","com.sun.star.sdbcx.Index");
54 
ODbaseIndex(ODbaseTable * _pTable)55 ODbaseIndex::ODbaseIndex(ODbaseTable* _pTable)
56     : OIndex(true/*_pTable->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers()*/)
57     , m_nCurNode(NODE_NOTFOUND)
58     , m_nPageCount(0)
59     , m_nRootPage(0)
60     , m_pTable(_pTable)
61     , m_bUseCollector(false)
62 {
63     construct();
64 }
65 
ODbaseIndex(ODbaseTable * _pTable,const NDXHeader & _rHeader,const OUString & _rName)66 ODbaseIndex::ODbaseIndex(   ODbaseTable* _pTable,
67                             const NDXHeader& _rHeader,
68                             const OUString& _rName)
69     : OIndex(_rName, OUString(), _rHeader.db_unique, false, false, true)
70     , m_aHeader(_rHeader)
71     , m_nCurNode(NODE_NOTFOUND)
72     , m_nPageCount(0)
73     , m_nRootPage(0)
74     , m_pTable(_pTable)
75     , m_bUseCollector(false)
76 {
77     construct();
78 }
79 
~ODbaseIndex()80 ODbaseIndex::~ODbaseIndex()
81 {
82     closeImpl();
83 }
84 
refreshColumns()85 void ODbaseIndex::refreshColumns()
86 {
87     ::osl::MutexGuard aGuard( m_aMutex );
88 
89     ::std::vector< OUString> aVector;
90     if(!isNew())
91     {
92         OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
93         OSL_ENSURE(m_aHeader.db_name[0] != '\0',"Invalid name for the column!");
94         aVector.push_back(OUString::createFromAscii(m_aHeader.db_name));
95     }
96 
97     if(m_pColumns)
98         m_pColumns->reFill(aVector);
99     else
100         m_pColumns.reset(new ODbaseIndexColumns(this,m_aMutex,aVector));
101 }
102 
getUnoTunnelId()103 Sequence< sal_Int8 > ODbaseIndex::getUnoTunnelId()
104 {
105     static ::cppu::OImplementationId implId;
106 
107     return implId.getImplementationId();
108 }
109 
110 // XUnoTunnel
111 
getSomething(const Sequence<sal_Int8> & rId)112 sal_Int64 ODbaseIndex::getSomething( const Sequence< sal_Int8 > & rId )
113 {
114     return (isUnoTunnelId<ODbaseIndex>(rId))
115                 ? reinterpret_cast< sal_Int64 >( this )
116                 : ODbaseIndex_BASE::getSomething(rId);
117 }
118 
getRoot()119 ONDXPagePtr const & ODbaseIndex::getRoot()
120 {
121     openIndexFile();
122     if (!m_aRoot.Is())
123     {
124         m_nRootPage = m_aHeader.db_rootpage;
125         m_nPageCount = m_aHeader.db_pagecount;
126         m_aRoot = CreatePage(m_nRootPage,nullptr,true);
127     }
128     return m_aRoot;
129 }
130 
openIndexFile()131 void ODbaseIndex::openIndexFile()
132 {
133     if(m_pFileStream)
134         return;
135 
136     OUString sFile = getCompletePath();
137     if(UCBContentHelper::Exists(sFile))
138     {
139         m_pFileStream = OFileTable::createStream_simpleError(sFile, StreamMode::READWRITE | StreamMode::NOCREATE | StreamMode::SHARE_DENYWRITE);
140         if (!m_pFileStream)
141             m_pFileStream = OFileTable::createStream_simpleError(sFile, StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYNONE);
142         if(m_pFileStream)
143         {
144             m_pFileStream->SetEndian(SvStreamEndian::LITTLE);
145             m_pFileStream->SetBufferSize(DINDEX_PAGE_SIZE);
146             (*m_pFileStream) >> *this;
147         }
148     }
149     if(!m_pFileStream)
150     {
151         const OUString sError( m_pTable->getConnection()->getResources().getResourceStringWithSubstitution(
152             STR_COULD_NOT_LOAD_FILE,
153             "$filename$", sFile
154          ) );
155         ::dbtools::throwGenericSQLException( sError, *this );
156     }
157 }
158 
createIterator()159 std::unique_ptr<OIndexIterator> ODbaseIndex::createIterator()
160 {
161     openIndexFile();
162     return std::make_unique<OIndexIterator>(this);
163 }
164 
ConvertToKey(ONDXKey * rKey,sal_uInt32 nRec,const ORowSetValue & rValue)165 bool ODbaseIndex::ConvertToKey(ONDXKey* rKey, sal_uInt32 nRec, const ORowSetValue& rValue)
166 {
167     OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
168     // Search a specific value in Index
169     // If the Index is unique, the key doesn't matter
170     try
171     {
172         if (m_aHeader.db_keytype == 0)
173         {
174             *rKey = ONDXKey(rValue.getString(), nRec );
175         }
176         else
177         {
178             if (rValue.isNull())
179                 *rKey = ONDXKey(rValue.getDouble(), DataType::DOUBLE, nRec );
180             else
181                 *rKey = ONDXKey(rValue.getDouble(), nRec );
182         }
183     }
184     catch (Exception&)
185     {
186         OSL_ASSERT(false);
187         return false;
188     }
189     return true;
190 }
191 
192 
Find(sal_uInt32 nRec,const ORowSetValue & rValue)193 bool ODbaseIndex::Find(sal_uInt32 nRec, const ORowSetValue& rValue)
194 {
195     openIndexFile();
196     OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
197     // Search a specific value in Index
198     // If the Index is unique, the key doesn't matter
199     ONDXKey aKey;
200     return ConvertToKey(&aKey, nRec, rValue) && getRoot()->Find(aKey);
201 }
202 
203 
Insert(sal_uInt32 nRec,const ORowSetValue & rValue)204 bool ODbaseIndex::Insert(sal_uInt32 nRec, const ORowSetValue& rValue)
205 {
206     openIndexFile();
207     OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
208     ONDXKey aKey;
209 
210     // Does the value already exist
211     // Use Find() always to determine the actual leaf
212     if (!ConvertToKey(&aKey, nRec, rValue) || (getRoot()->Find(aKey) && isUnique()))
213         return false;
214 
215     ONDXNode aNewNode(aKey);
216 
217     // insert in the current leaf
218     if (!m_aCurLeaf.Is())
219         return false;
220 
221     bool bResult = m_aCurLeaf->Insert(aNewNode);
222     Release(bResult);
223 
224     return bResult;
225 }
226 
227 
Update(sal_uInt32 nRec,const ORowSetValue & rOldValue,const ORowSetValue & rNewValue)228 bool ODbaseIndex::Update(sal_uInt32 nRec, const ORowSetValue& rOldValue,
229                          const ORowSetValue& rNewValue)
230 {
231     openIndexFile();
232     OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
233     ONDXKey aKey;
234     if (!ConvertToKey(&aKey, nRec, rNewValue) || (isUnique() && getRoot()->Find(aKey)))
235         return false;
236     else
237         return Delete(nRec, rOldValue) && Insert(nRec,rNewValue);
238 }
239 
240 
Delete(sal_uInt32 nRec,const ORowSetValue & rValue)241 bool ODbaseIndex::Delete(sal_uInt32 nRec, const ORowSetValue& rValue)
242 {
243     openIndexFile();
244     OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
245     // Does the value already exist
246     // Always use Find() to determine the actual leaf
247     ONDXKey aKey;
248     if (!ConvertToKey(&aKey, nRec, rValue) || !getRoot()->Find(aKey))
249         return false;
250 
251     // insert in the current leaf
252     if (!m_aCurLeaf.Is())
253         return false;
254 #if OSL_DEBUG_LEVEL > 1
255     m_aRoot->PrintPage();
256 #endif
257 
258     m_aCurLeaf->Delete(m_nCurNode);
259     return true;
260 }
261 
Collect(ONDXPage * pPage)262 void ODbaseIndex::Collect(ONDXPage* pPage)
263 {
264     if (pPage)
265         m_aCollector.push_back(pPage);
266 }
267 
Release(bool bSave)268 void ODbaseIndex::Release(bool bSave)
269 {
270     // Release the Index-resources
271     m_bUseCollector = false;
272 
273     if (m_aCurLeaf.Is())
274     {
275         m_aCurLeaf->Release(bSave);
276         m_aCurLeaf.Clear();
277     }
278 
279     // Release the root
280     if (m_aRoot.Is())
281     {
282         m_aRoot->Release(bSave);
283         m_aRoot.Clear();
284     }
285     // Release all references, before the FileStream will be closed
286     for (auto& i : m_aCollector)
287         i->QueryDelete();
288 
289     m_aCollector.clear();
290 
291     // Header modified?
292     if (bSave && (m_aHeader.db_rootpage != m_nRootPage ||
293         m_aHeader.db_pagecount != m_nPageCount))
294     {
295         m_aHeader.db_rootpage = m_nRootPage;
296         m_aHeader.db_pagecount = m_nPageCount;
297         WriteODbaseIndex( *m_pFileStream, *this );
298     }
299     m_nRootPage = m_nPageCount = 0;
300     m_nCurNode = NODE_NOTFOUND;
301 
302     closeImpl();
303 }
304 
closeImpl()305 void ODbaseIndex::closeImpl()
306 {
307     m_pFileStream.reset();
308 }
309 
CreatePage(sal_uInt32 nPagePos,ONDXPage * pParent,bool bLoad)310 ONDXPage* ODbaseIndex::CreatePage(sal_uInt32 nPagePos, ONDXPage* pParent, bool bLoad)
311 {
312     OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
313 
314     ONDXPage* pPage;
315     if ( !m_aCollector.empty() )
316     {
317         pPage = *(m_aCollector.rbegin());
318         m_aCollector.pop_back();
319         pPage->SetPagePos(nPagePos);
320         pPage->SetParent(pParent);
321     }
322     else
323         pPage = new ONDXPage(*this, nPagePos, pParent);
324 
325     if (bLoad)
326         (*m_pFileStream) >> *pPage;
327 
328     return pPage;
329 }
330 
ReadHeader(SvStream & rStream,ODbaseIndex::NDXHeader & rHeader)331 void connectivity::dbase::ReadHeader(
332         SvStream & rStream, ODbaseIndex::NDXHeader & rHeader)
333 {
334 #if !defined(NDEBUG)
335     sal_uInt64 const nOldPos(rStream.Tell());
336 #endif
337     rStream.ReadUInt32(rHeader.db_rootpage);
338     rStream.ReadUInt32(rHeader.db_pagecount);
339     rStream.ReadBytes(&rHeader.db_free, 4);
340     rStream.ReadUInt16(rHeader.db_keylen);
341     rStream.ReadUInt16(rHeader.db_maxkeys);
342     rStream.ReadUInt16(rHeader.db_keytype);
343     rStream.ReadUInt16(rHeader.db_keyrec);
344     rStream.ReadBytes(&rHeader.db_free1, 3);
345     rStream.ReadUChar(rHeader.db_unique);
346     rStream.ReadBytes(&rHeader.db_name, 488);
347     assert(rStream.GetError() || rStream.Tell() == nOldPos + DINDEX_PAGE_SIZE);
348 }
349 
operator >>(SvStream & rStream,ODbaseIndex & rIndex)350 SvStream& connectivity::dbase::operator >> (SvStream &rStream, ODbaseIndex& rIndex)
351 {
352     rStream.Seek(0);
353     ReadHeader(rStream, rIndex.m_aHeader);
354 
355     rIndex.m_nRootPage = rIndex.m_aHeader.db_rootpage;
356     rIndex.m_nPageCount = rIndex.m_aHeader.db_pagecount;
357     return rStream;
358 }
359 
WriteODbaseIndex(SvStream & rStream,ODbaseIndex & rIndex)360 SvStream& connectivity::dbase::WriteODbaseIndex(SvStream &rStream, ODbaseIndex& rIndex)
361 {
362     rStream.Seek(0);
363     rStream.WriteUInt32(rIndex.m_aHeader.db_rootpage);
364     rStream.WriteUInt32(rIndex.m_aHeader.db_pagecount);
365     rStream.WriteBytes(&rIndex.m_aHeader.db_free, 4);
366     rStream.WriteUInt16(rIndex.m_aHeader.db_keylen);
367     rStream.WriteUInt16(rIndex.m_aHeader.db_maxkeys);
368     rStream.WriteUInt16(rIndex.m_aHeader.db_keytype);
369     rStream.WriteUInt16(rIndex.m_aHeader.db_keyrec);
370     rStream.WriteBytes(&rIndex.m_aHeader.db_free1, 3);
371     rStream.WriteUChar(rIndex.m_aHeader.db_unique);
372     rStream.WriteBytes(&rIndex.m_aHeader.db_name, 488);
373     assert(rStream.GetError() || rStream.Tell() == DINDEX_PAGE_SIZE);
374     SAL_WARN_IF(rStream.GetError(), "connectivity.dbase", "write error");
375     return rStream;
376 }
377 
getCompletePath() const378 OUString ODbaseIndex::getCompletePath() const
379 {
380     OUString sDir = m_pTable->getConnection()->getURL() +
381         OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DELIMITER) +
382         m_Name + ".ndx";
383     return sDir;
384 }
385 
createINFEntry()386 void ODbaseIndex::createINFEntry()
387 {
388     // synchronize inf-file
389     const OUString sEntry(m_Name + ".ndx");
390 
391     OUString sCfgFile(m_pTable->getConnection()->getURL() +
392                       OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DELIMITER) +
393                       m_pTable->getName() +
394                       ".inf");
395 
396     OUString sPhysicalPath;
397     osl::FileBase::getSystemPathFromFileURL(sCfgFile, sPhysicalPath);
398 
399     Config aInfFile(sPhysicalPath);
400     aInfFile.SetGroup(dBASE_III_GROUP);
401 
402     sal_uInt16 nSuffix = aInfFile.GetKeyCount();
403     OString aNewEntry,aKeyName;
404     bool bCase = isCaseSensitive();
405     while (aNewEntry.isEmpty())
406     {
407         aNewEntry = OString("NDX");
408         aNewEntry += OString::number(++nSuffix);
409         for (sal_uInt16 i = 0; i < aInfFile.GetKeyCount(); i++)
410         {
411             aKeyName = aInfFile.GetKeyName(i);
412             if (bCase ? aKeyName == aNewEntry : aKeyName.equalsIgnoreAsciiCase(aNewEntry))
413             {
414                 aNewEntry.clear();
415                 break;
416             }
417         }
418     }
419     aInfFile.WriteKey(aNewEntry, OUStringToOString(sEntry, m_pTable->getConnection()->getTextEncoding()));
420 }
421 
DropImpl()422 void ODbaseIndex::DropImpl()
423 {
424     closeImpl();
425 
426     OUString sPath = getCompletePath();
427     if(UCBContentHelper::Exists(sPath))
428     {
429         if(!UCBContentHelper::Kill(sPath))
430             m_pTable->getConnection()->throwGenericSQLException(STR_COULD_NOT_DELETE_INDEX,*m_pTable);
431     }
432 
433     // synchronize inf-file
434     OUString sCfgFile = m_pTable->getConnection()->getURL() +
435         OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DELIMITER) +
436         m_pTable->getName() + ".inf";
437 
438     OUString sPhysicalPath;
439     OSL_VERIFY( osl::FileBase::getSystemPathFromFileURL(sCfgFile, sPhysicalPath)
440                     == osl::FileBase::E_None );
441 
442     Config aInfFile(sPhysicalPath);
443     aInfFile.SetGroup(dBASE_III_GROUP);
444     sal_uInt16 nKeyCnt = aInfFile.GetKeyCount();
445     OString aKeyName;
446     OUString sEntry = m_Name + ".ndx";
447 
448     // delete entries from the inf file
449     for (sal_uInt16 nKey = 0; nKey < nKeyCnt; nKey++)
450     {
451         // References the Key to an Index-file?
452         aKeyName = aInfFile.GetKeyName( nKey );
453         if (aKeyName.startsWith("NDX"))
454         {
455             if(sEntry == OStringToOUString(aInfFile.ReadKey(aKeyName),m_pTable->getConnection()->getTextEncoding()))
456             {
457                 aInfFile.DeleteKey(aKeyName);
458                 break;
459             }
460         }
461     }
462 }
463 
impl_killFileAndthrowError_throw(const char * pErrorId,const OUString & _sFile)464 void ODbaseIndex::impl_killFileAndthrowError_throw(const char* pErrorId, const OUString& _sFile)
465 {
466     closeImpl();
467     if(UCBContentHelper::Exists(_sFile))
468         UCBContentHelper::Kill(_sFile);
469     m_pTable->getConnection()->throwGenericSQLException(pErrorId, *this);
470 }
471 
CreateImpl()472 void ODbaseIndex::CreateImpl()
473 {
474     // Create the Index
475     const OUString sFile = getCompletePath();
476     if(UCBContentHelper::Exists(sFile))
477     {
478         const OUString sError( m_pTable->getConnection()->getResources().getResourceStringWithSubstitution(
479             STR_COULD_NOT_CREATE_INDEX_NAME,
480             "$filename$", sFile
481          ) );
482         ::dbtools::throwGenericSQLException( sError, *this );
483     }
484     // Index comprises only one column
485     if (m_pColumns->getCount() > 1)
486         m_pTable->getConnection()->throwGenericSQLException(STR_ONL_ONE_COLUMN_PER_INDEX,*this);
487 
488     Reference<XFastPropertySet> xCol(m_pColumns->getByIndex(0),UNO_QUERY);
489 
490     // Is the column already indexed?
491     if ( !xCol.is() )
492         ::dbtools::throwFunctionSequenceException(*this);
493 
494     // create the index file
495     m_pFileStream = OFileTable::createStream_simpleError(sFile,StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE | StreamMode::TRUNC);
496     if (!m_pFileStream)
497     {
498         const OUString sError( m_pTable->getConnection()->getResources().getResourceStringWithSubstitution(
499             STR_COULD_NOT_LOAD_FILE,
500             "$filename$", sFile
501          ) );
502         ::dbtools::throwGenericSQLException( sError, *this );
503     }
504 
505     m_pFileStream->SetEndian(SvStreamEndian::LITTLE);
506     m_pFileStream->SetBufferSize(DINDEX_PAGE_SIZE);
507 
508     // firstly the result must be sorted
509     utl::SharedUNOComponent<XStatement> xStmt;
510     utl::SharedUNOComponent<XResultSet> xSet;
511     OUString aName;
512     try
513     {
514         xStmt.set( m_pTable->getConnection()->createStatement(), UNO_SET_THROW);
515 
516         aName = getString(xCol->getFastPropertyValue(PROPERTY_ID_NAME));
517 
518         const OUString aQuote(m_pTable->getConnection()->getMetaData()->getIdentifierQuoteString());
519         OUString aStatement( "SELECT " + aQuote + aName + aQuote +" FROM " + aQuote + m_pTable->getName() + aQuote + " ORDER BY " + aQuote + aName + aQuote);
520 
521         xSet.set( xStmt->executeQuery(aStatement),UNO_SET_THROW );
522     }
523     catch(const Exception& )
524     {
525         impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX,sFile);
526     }
527     if (!xSet.is())
528     {
529         impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX,sFile);
530     }
531 
532     // Set the header info
533     memset(&m_aHeader,0,sizeof(m_aHeader));
534     sal_Int32 nType = 0;
535     ::rtl::Reference<OSQLColumns> aCols = m_pTable->getTableColumns();
536     const Reference< XPropertySet > xTableCol(*find(aCols->begin(),aCols->end(),aName,::comphelper::UStringMixEqual(isCaseSensitive())));
537 
538     xTableCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType;
539 
540     m_aHeader.db_keytype = (nType == DataType::VARCHAR || nType == DataType::CHAR) ? 0 : 1;
541     m_aHeader.db_keylen  = (m_aHeader.db_keytype) ? 8 : static_cast<sal_uInt16>(getINT32(xTableCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))));
542     m_aHeader.db_keylen = (( m_aHeader.db_keylen - 1) / 4 + 1) * 4;
543     m_aHeader.db_maxkeys = (DINDEX_PAGE_SIZE - 4) / (8 + m_aHeader.db_keylen);
544     if ( m_aHeader.db_maxkeys < 3 )
545     {
546         impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX_KEYSIZE,sFile);
547     }
548 
549     m_pFileStream->SetStreamSize(DINDEX_PAGE_SIZE);
550 
551     OString aCol(OUStringToOString(aName, m_pTable->getConnection()->getTextEncoding()));
552     strncpy(m_aHeader.db_name, aCol.getStr(), std::min<size_t>(sizeof(m_aHeader.db_name), aCol.getLength()));
553     m_aHeader.db_unique  = m_IsUnique ? 1: 0;
554     m_aHeader.db_keyrec  = m_aHeader.db_keylen + 8;
555 
556     // modifications of the header are detected by differences between
557     // the HeaderInfo and nRootPage or nPageCount respectively
558     m_nRootPage = 1;
559     m_nPageCount = 2;
560 
561     m_aCurLeaf = m_aRoot = CreatePage(m_nRootPage);
562     m_aRoot->SetModified(true);
563 
564     m_bUseCollector = true;
565 
566     sal_Int32 nRowsLeft = 0;
567     Reference<XRow> xRow(xSet,UNO_QUERY);
568 
569     if(xSet->last())
570     {
571         Reference< XUnoTunnel> xTunnel(xSet, UNO_QUERY_THROW);
572         ODbaseResultSet* pDbaseRes = reinterpret_cast< ODbaseResultSet* >( xTunnel->getSomething(ODbaseResultSet::getUnoTunnelId()) );
573         assert(pDbaseRes); //"No dbase resultset found? What's going on here!
574         nRowsLeft = xSet->getRow();
575 
576         xSet->beforeFirst();
577         ORowSetValue atmpValue;
578         ONDXKey aKey(atmpValue, nType, 0);
579         ONDXKey aInsertKey(atmpValue, nType, 0);
580         // Create the index structure
581         while (xSet->next())
582         {
583             ORowSetValue aValue(m_aHeader.db_keytype ? ORowSetValue(xRow->getDouble(1)) : ORowSetValue(xRow->getString(1)));
584             // checking for duplicate entries
585             if (m_IsUnique && m_nCurNode != NODE_NOTFOUND)
586             {
587                 aKey.setValue(aValue);
588                 if (aKey == (*m_aCurLeaf)[m_nCurNode].GetKey())
589                 {
590                     impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX_NOT_UNIQUE,sFile);
591                 }
592             }
593             aInsertKey.setValue(aValue);
594             aInsertKey.setRecord(pDbaseRes->getCurrentFilePos());
595 
596             ONDXNode aNewNode(aInsertKey);
597             if (!m_aCurLeaf->Insert(aNewNode, --nRowsLeft))
598                 break;
599         }
600     }
601 
602     if(nRowsLeft)
603     {
604         impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX,sFile);
605     }
606     Release();
607     createINFEntry();
608 }
609 
610 
611 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
612