Coverage Report

Created: 2026-10-14 09:33

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