1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_connectivity.hxx"
26 #include "dbase/DIndex.hxx"
27 #include "dbase/DIndexColumns.hxx"
28 #include <com/sun/star/lang/DisposedException.hpp>
29 #include "connectivity/sdbcx/VColumn.hxx"
30 #include <comphelper/sequence.hxx>
31 #include "dbase/DTable.hxx"
32 #include "dbase/DIndexIter.hxx"
33 #include <tools/config.hxx>
34 #include "connectivity/CommonTools.hxx"
35 #include <com/sun/star/sdbc/XResultSetMetaData.hpp>
36 #include <com/sun/star/sdbc/XResultSet.hpp>
37 #include <com/sun/star/sdbcx/XRowLocate.hpp>
38 #include <com/sun/star/sdbc/XRow.hpp>
39 #include <comphelper/extract.hxx>
40 #include <unotools/localfilehelper.hxx>
41 #include <unotools/ucbhelper.hxx>
42 #include <comphelper/types.hxx>
43 #include <connectivity/dbexception.hxx>
44 #include "dbase/DResultSet.hxx"
45 #include "diagnose_ex.h"
46 #include <comphelper/types.hxx>
47 #include "resource/dbase_res.hrc"
48 #include <unotools/sharedunocomponent.hxx>
49
50 using namespace ::comphelper;
51 // -------------------------------------------------------------------------
52 using namespace connectivity;
53 using namespace utl;
54 using namespace ::cppu;
55 using namespace connectivity::file;
56 using namespace connectivity::sdbcx;
57 using namespace connectivity::dbase;
58 using namespace com::sun::star::sdbc;
59 using namespace com::sun::star::sdbcx;
60 using namespace com::sun::star::uno;
61 using namespace com::sun::star::beans;
62 using namespace com::sun::star::lang;
63
64 IMPLEMENT_SERVICE_INFO(ODbaseIndex,"com.sun.star.sdbcx.driver.dbase.Index","com.sun.star.sdbcx.Index");
65 // -------------------------------------------------------------------------
ODbaseIndex(ODbaseTable * _pTable)66 ODbaseIndex::ODbaseIndex(ODbaseTable* _pTable) : OIndex(sal_True/*_pTable->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers()*/)
67 ,m_pFileStream(NULL)
68 ,m_nCurNode(NODE_NOTFOUND)
69 ,m_pTable(_pTable)
70 {
71 m_aHeader.db_pagecount = m_aHeader.db_rootpage = m_aHeader.db_keytype = m_aHeader.db_maxkeys = m_aHeader.db_keylen = 0;
72 m_aHeader.db_name[0] = '\0';
73 construct();
74 }
75 // -------------------------------------------------------------------------
ODbaseIndex(ODbaseTable * _pTable,const NDXHeader & _rHeader,const::rtl::OUString & _rName)76 ODbaseIndex::ODbaseIndex( ODbaseTable* _pTable,
77 const NDXHeader& _rHeader,
78 const ::rtl::OUString& _rName)
79 :OIndex(_rName,::rtl::OUString(),_rHeader.db_unique,sal_False,sal_False,sal_True) // _pTable->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers()
80 ,m_pFileStream(NULL)
81 ,m_aHeader(_rHeader)
82 ,m_nCurNode(NODE_NOTFOUND)
83 ,m_pTable(_pTable)
84 {
85 construct();
86 }
87 // -----------------------------------------------------------------------------
~ODbaseIndex()88 ODbaseIndex::~ODbaseIndex()
89 {
90 closeImpl();
91 }
92 // -------------------------------------------------------------------------
refreshColumns()93 void ODbaseIndex::refreshColumns()
94 {
95 ::osl::MutexGuard aGuard( m_aMutex );
96
97 TStringVector aVector;
98 if(!isNew())
99 {
100 OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
101 OSL_ENSURE(m_aHeader.db_name[0] != '\0',"Invalid name for the column!");
102 aVector.push_back(::rtl::OUString::createFromAscii(m_aHeader.db_name));
103 }
104
105 if(m_pColumns)
106 m_pColumns->reFill(aVector);
107 else
108 m_pColumns = new ODbaseIndexColumns(this,m_aMutex,aVector);
109 }
110 //--------------------------------------------------------------------------
getUnoTunnelImplementationId()111 Sequence< sal_Int8 > ODbaseIndex::getUnoTunnelImplementationId()
112 {
113 static ::cppu::OImplementationId * pId = 0;
114 if (! pId)
115 {
116 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
117 if (! pId)
118 {
119 static ::cppu::OImplementationId aId;
120 pId = &aId;
121 }
122 }
123 return pId->getImplementationId();
124 }
125
126 // XUnoTunnel
127 //------------------------------------------------------------------
getSomething(const Sequence<sal_Int8> & rId)128 sal_Int64 ODbaseIndex::getSomething( const Sequence< sal_Int8 > & rId ) throw (RuntimeException)
129 {
130 return (rId.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(), rId.getConstArray(), 16 ) )
131 ? reinterpret_cast< sal_Int64 >( this )
132 : ODbaseIndex_BASE::getSomething(rId);
133 }
134 //------------------------------------------------------------------
getRoot()135 ONDXPagePtr ODbaseIndex::getRoot()
136 {
137 openIndexFile();
138 if (!m_aRoot.Is())
139 {
140 m_nRootPage = m_aHeader.db_rootpage;
141 m_nPageCount = m_aHeader.db_pagecount;
142 m_aRoot = CreatePage(m_nRootPage,NULL,sal_True);
143 }
144 return m_aRoot;
145 }
146 //------------------------------------------------------------------
openIndexFile()147 sal_Bool ODbaseIndex::openIndexFile()
148 {
149 if(!m_pFileStream)
150 {
151 ::rtl::OUString sFile = getCompletePath();
152 if(UCBContentHelper::Exists(sFile))
153 {
154 m_pFileStream = OFileTable::createStream_simpleError(sFile, STREAM_READWRITE | STREAM_NOCREATE | STREAM_SHARE_DENYWRITE);
155 if (!m_pFileStream)
156 m_pFileStream = OFileTable::createStream_simpleError(sFile,STREAM_READ | STREAM_NOCREATE | STREAM_SHARE_DENYNONE);
157 if(m_pFileStream)
158 {
159 m_pFileStream->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN);
160 m_pFileStream->SetBufferSize(PAGE_SIZE);
161 (*m_pFileStream) >> *this;
162 }
163 }
164 if(!m_pFileStream)
165 {
166 const ::rtl::OUString sError( m_pTable->getConnection()->getResources().getResourceStringWithSubstitution(
167 STR_COULD_NOT_LOAD_FILE,
168 "$filename$", sFile
169 ) );
170 ::dbtools::throwGenericSQLException( sError, *this );
171 }
172 }
173
174 return m_pFileStream != NULL;
175 }
176 //------------------------------------------------------------------
createIterator(OBoolOperator * pOp,const OOperand * pOperand)177 OIndexIterator* ODbaseIndex::createIterator(OBoolOperator* pOp,
178 const OOperand* pOperand)
179 {
180 openIndexFile();
181 return new OIndexIterator(this, pOp, pOperand);
182 }
183 //------------------------------------------------------------------
ConvertToKey(ONDXKey * rKey,sal_uInt32 nRec,const ORowSetValue & rValue)184 sal_Bool ODbaseIndex::ConvertToKey(ONDXKey* rKey, sal_uInt32 nRec, const ORowSetValue& rValue)
185 {
186 OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
187 // Sucht ein bestimmten Wert im Index
188 // Wenn der Index Unique ist, interssiert der Key nicht, sonst ja
189 try
190 {
191 if (m_aHeader.db_keytype == 0)
192 {
193 *rKey = ONDXKey(rValue.getString(), nRec );
194 }
195 else
196 {
197 if (rValue.isNull())
198 *rKey = ONDXKey(rValue.getDouble(), DataType::DOUBLE, nRec );
199 else
200 *rKey = ONDXKey(rValue.getDouble(), nRec );
201 }
202 }
203 catch (Exception&)
204 {
205 OSL_ASSERT(0);
206 return sal_False;
207 }
208 return sal_True;
209 }
210
211 //------------------------------------------------------------------
Find(sal_uInt32 nRec,const ORowSetValue & rValue)212 sal_Bool ODbaseIndex::Find(sal_uInt32 nRec, const ORowSetValue& rValue)
213 {
214 openIndexFile();
215 OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
216 // Sucht ein bestimmten Wert im Index
217 // Wenn der Index Unique ist, interssiert der Key nicht, sonst ja
218 ONDXKey aKey;
219 return ConvertToKey(&aKey, nRec, rValue) && getRoot()->Find(aKey);
220 }
221
222 //------------------------------------------------------------------
Insert(sal_uInt32 nRec,const ORowSetValue & rValue)223 sal_Bool ODbaseIndex::Insert(sal_uInt32 nRec, const ORowSetValue& rValue)
224 {
225 openIndexFile();
226 OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
227 ONDXKey aKey;
228
229 // Existiert der Wert bereits
230 // Find immer verwenden um das aktuelle Blatt zu bestimmen
231 if (!ConvertToKey(&aKey, nRec, rValue) || (getRoot()->Find(aKey) && isUnique()))
232 return sal_False;
233
234 ONDXNode aNewNode(aKey);
235
236 // einfuegen in das aktuelle Blatt
237 if (!m_aCurLeaf.Is())
238 return sal_False;
239
240 sal_Bool bResult = m_aCurLeaf->Insert(aNewNode);
241 Release(bResult);
242
243 return bResult;
244 }
245
246 //------------------------------------------------------------------
Update(sal_uInt32 nRec,const ORowSetValue & rOldValue,const ORowSetValue & rNewValue)247 sal_Bool ODbaseIndex::Update(sal_uInt32 nRec, const ORowSetValue& rOldValue,
248 const ORowSetValue& rNewValue)
249 {
250 openIndexFile();
251 OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
252 ONDXKey aKey;
253 if (!ConvertToKey(&aKey, nRec, rNewValue) || (isUnique() && getRoot()->Find(aKey)))
254 return sal_False;
255 else
256 return Delete(nRec, rOldValue) && Insert(nRec,rNewValue);
257 }
258
259 //------------------------------------------------------------------
Delete(sal_uInt32 nRec,const ORowSetValue & rValue)260 sal_Bool ODbaseIndex::Delete(sal_uInt32 nRec, const ORowSetValue& rValue)
261 {
262 openIndexFile();
263 OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
264 // Existiert der Wert bereits
265 // Find immer verwenden um das aktuelle Blatt zu bestimmen
266 ONDXKey aKey;
267 if (!ConvertToKey(&aKey, nRec, rValue) || !getRoot()->Find(aKey))
268 return sal_False;
269
270 ONDXNode aNewNode(aKey);
271
272 // einfuegen in das aktuelle Blatt
273 if (!m_aCurLeaf.Is())
274 return sal_False;
275 #if OSL_DEBUG_LEVEL > 1
276 m_aRoot->PrintPage();
277 #endif
278
279 return m_aCurLeaf->Delete(m_nCurNode);
280 }
281 //------------------------------------------------------------------
Collect(ONDXPage * pPage)282 void ODbaseIndex::Collect(ONDXPage* pPage)
283 {
284 if (pPage)
285 m_aCollector.push_back(pPage);
286 }
287 //------------------------------------------------------------------
Release(sal_Bool bSave)288 void ODbaseIndex::Release(sal_Bool bSave)
289 {
290 // Freigeben der Indexressourcen
291 m_bUseCollector = sal_False;
292
293 if (m_aCurLeaf.Is())
294 {
295 m_aCurLeaf->Release(bSave);
296 m_aCurLeaf.Clear();
297 }
298
299 // Wurzel freigeben
300 if (m_aRoot.Is())
301 {
302 m_aRoot->Release(bSave);
303 m_aRoot.Clear();
304 }
305 // alle Referenzen freigeben, bevor der FileStream geschlossen wird
306 for (sal_uIntPtr i = 0; i < m_aCollector.size(); i++)
307 m_aCollector[i]->QueryDelete();
308
309 m_aCollector.clear();
310
311 // Header modifiziert ?
312 if (bSave && (m_aHeader.db_rootpage != m_nRootPage ||
313 m_aHeader.db_pagecount != m_nPageCount))
314 {
315 m_aHeader.db_rootpage = m_nRootPage;
316 m_aHeader.db_pagecount = m_nPageCount;
317 (*m_pFileStream) << *this;
318 }
319 m_nRootPage = m_nPageCount = 0;
320 m_nCurNode = NODE_NOTFOUND;
321
322 closeImpl();
323 }
324 // -----------------------------------------------------------------------------
closeImpl()325 void ODbaseIndex::closeImpl()
326 {
327 if(m_pFileStream)
328 {
329 delete m_pFileStream;
330 m_pFileStream = NULL;
331 }
332 }
333 //------------------------------------------------------------------
CreatePage(sal_uInt32 nPagePos,ONDXPage * pParent,sal_Bool bLoad)334 ONDXPage* ODbaseIndex::CreatePage(sal_uInt32 nPagePos, ONDXPage* pParent, sal_Bool bLoad)
335 {
336 OSL_ENSURE(m_pFileStream,"FileStream is not opened!");
337
338 ONDXPage* pPage;
339 if ( !m_aCollector.empty() )
340 {
341 pPage = *(m_aCollector.rbegin());
342 m_aCollector.pop_back();
343 pPage->SetPagePos(nPagePos);
344 pPage->SetParent(pParent);
345 }
346 else
347 pPage = new ONDXPage(*this, nPagePos, pParent);
348
349 if (bLoad)
350 (*m_pFileStream) >> *pPage;
351
352 return pPage;
353 }
354
355 //------------------------------------------------------------------
operator >>(SvStream & rStream,ODbaseIndex & rIndex)356 SvStream& connectivity::dbase::operator >> (SvStream &rStream, ODbaseIndex& rIndex)
357 {
358 rStream.Seek(0);
359 rStream.Read(&rIndex.m_aHeader,PAGE_SIZE);
360
361 /* OJ: no longer needed
362 // Text convertierung
363 ByteString aText(rIndex.m_aHeader.db_name);
364 // aText.Convert(rIndex.m_pTable->getConnection()->GetCharacterSet(), m_pTable->getConnection()->getTextEncoding());
365 // aText.Convert(rIndex.m_pTable->getConnection()->GetCharacterSet(), m_pTable->getConnection()->getTextEncoding());
366 strcpy(rIndex.m_aHeader.db_name,aText.GetBuffer());
367 */
368 rIndex.m_nRootPage = rIndex.m_aHeader.db_rootpage;
369 rIndex.m_nPageCount = rIndex.m_aHeader.db_pagecount;
370 return rStream;
371 }
372 //------------------------------------------------------------------
operator <<(SvStream & rStream,ODbaseIndex & rIndex)373 SvStream& connectivity::dbase::operator << (SvStream &rStream, ODbaseIndex& rIndex)
374 {
375 rStream.Seek(0);
376 /* OJ: no longer needed
377 ByteString aText(rIndex.m_aHeader.db_name);
378 // aText.Convert(m_pTable->getConnection()->getTextEncoding(), rIndex.m_pTable->getConnection()->GetCharacterSet());
379 strcpy(rIndex.m_aHeader.db_name,aText.GetBuffer());
380 */
381 OSL_VERIFY_EQUALS( rStream.Write(&rIndex.m_aHeader,PAGE_SIZE), PAGE_SIZE, "Write not successful: Wrong header size for dbase index!");
382 return rStream;
383 }
384 // -------------------------------------------------------------------------
getCompletePath()385 ::rtl::OUString ODbaseIndex::getCompletePath()
386 {
387 ::rtl::OUString sDir = m_pTable->getConnection()->getURL();
388 sDir += OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DELIMITER);
389 sDir += m_Name;
390 sDir += ::rtl::OUString::createFromAscii(".ndx");
391 return sDir;
392 }
393 //------------------------------------------------------------------
createINFEntry()394 void ODbaseIndex::createINFEntry()
395 {
396 // inf Datei abgleichen
397 String sEntry = m_Name;
398 sEntry += String::CreateFromAscii(".ndx");
399
400 ::rtl::OUString sCfgFile(m_pTable->getConnection()->getURL());
401 sCfgFile += OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DELIMITER);
402 sCfgFile += m_pTable->getName();
403 sCfgFile += ::rtl::OUString::createFromAscii(".inf");
404
405 String sPhysicalPath;
406 LocalFileHelper::ConvertURLToPhysicalName(sCfgFile,sPhysicalPath);
407
408 Config aInfFile(sPhysicalPath);
409 aInfFile.SetGroup(dBASE_III_GROUP);
410
411 sal_uInt16 nSuffix = aInfFile.GetKeyCount();
412 ByteString aNewEntry,aKeyName;
413 sal_Bool bCase = isCaseSensitive();
414 while (!aNewEntry.Len())
415 {
416 aNewEntry = "NDX";
417 aNewEntry += ByteString::CreateFromInt32(++nSuffix);
418 for (sal_uInt16 i = 0; i < aInfFile.GetKeyCount(); i++)
419 {
420 aKeyName = aInfFile.GetKeyName(i);
421 if (bCase ? aKeyName == aNewEntry : aKeyName.EqualsIgnoreCaseAscii(aNewEntry))
422 {
423 aNewEntry.Erase();
424 break;
425 }
426 }
427 }
428 aInfFile.WriteKey(aNewEntry,ByteString(sEntry,m_pTable->getConnection()->getTextEncoding()));
429 }
430 // -------------------------------------------------------------------------
DropImpl()431 sal_Bool ODbaseIndex::DropImpl()
432 {
433 closeImpl();
434
435 ::rtl::OUString sPath = getCompletePath();
436 if(UCBContentHelper::Exists(sPath))
437 {
438 if(!UCBContentHelper::Kill(sPath))
439 m_pTable->getConnection()->throwGenericSQLException(STR_COULD_NOT_DELETE_INDEX,*m_pTable);
440 }
441
442 // InfDatei abgleichen
443
444 ::rtl::OUString sCfgFile(m_pTable->getConnection()->getURL());
445 sCfgFile += OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DELIMITER);
446 sCfgFile += m_pTable->getName();
447 sCfgFile += ::rtl::OUString::createFromAscii(".inf");
448
449 String sPhysicalPath;
450 String sNDX(sCfgFile);
451 OSL_VERIFY_RES( LocalFileHelper::ConvertURLToPhysicalName(sNDX,sPhysicalPath),"Can not convert Config Filename into Physical Name!");
452
453 Config aInfFile(sPhysicalPath);
454 aInfFile.SetGroup(dBASE_III_GROUP);
455 sal_uInt16 nKeyCnt = aInfFile.GetKeyCount();
456 ByteString aKeyName;
457 String sEntry = m_Name;
458 sEntry += String::CreateFromAscii(".ndx");
459
460 // delete entries from the inf file
461 for (sal_uInt16 nKey = 0; nKey < nKeyCnt; nKey++)
462 {
463 // Verweist der Key auf ein Indexfile?...
464 aKeyName = aInfFile.GetKeyName( nKey );
465 if (aKeyName.Copy(0,3) == "NDX")
466 {
467 if(sEntry == String(aInfFile.ReadKey(aKeyName),m_pTable->getConnection()->getTextEncoding()))
468 {
469 aInfFile.DeleteKey(aKeyName);
470 break;
471 }
472 }
473 }
474 return sal_True;
475 }
476 // -------------------------------------------------------------------------
impl_killFileAndthrowError_throw(sal_uInt16 _nErrorId,const::rtl::OUString & _sFile)477 void ODbaseIndex::impl_killFileAndthrowError_throw(sal_uInt16 _nErrorId,const ::rtl::OUString& _sFile)
478 {
479 closeImpl();
480 if(UCBContentHelper::Exists(_sFile))
481 UCBContentHelper::Kill(_sFile);
482 m_pTable->getConnection()->throwGenericSQLException(_nErrorId,*this);
483 }
484 //------------------------------------------------------------------
CreateImpl()485 sal_Bool ODbaseIndex::CreateImpl()
486 {
487 // Anlegen des Index
488 const ::rtl::OUString sFile = getCompletePath();
489 if(UCBContentHelper::Exists(sFile))
490 {
491 const ::rtl::OUString sError( m_pTable->getConnection()->getResources().getResourceStringWithSubstitution(
492 STR_COULD_NOT_CREATE_INDEX_NAME,
493 "$filename$", sFile
494 ) );
495 ::dbtools::throwGenericSQLException( sError, *this );
496 }
497 // Index ist nur einstufig
498 if (m_pColumns->getCount() > 1)
499 m_pTable->getConnection()->throwGenericSQLException(STR_ONL_ONE_COLUMN_PER_INDEX,*this);
500
501 Reference<XFastPropertySet> xCol(m_pColumns->getByIndex(0),UNO_QUERY);
502
503 // ist die Spalte schon indiziert ?
504 if ( !xCol.is() )
505 ::dbtools::throwFunctionSequenceException(*this);
506 // else if (pColumn && pColumn->IsIndexed())
507 // {
508 // String aText = String(OResId(STR_STAT_INDEX_COLUMN_ALREADY_INDEXED));
509 // aText.SearchAndReplace(String::CreateFromAscii("#"),pColumn->GetName());
510 // aStatus.Set(SDB_STAT_ERROR,
511 // String::CreateFromAscii("01000"),
512 // aStatus.CreateErrorMessage(aText),
513 // 0, String() );
514 // return sal_False;
515 // }
516
517 // create the index file
518 m_pFileStream = OFileTable::createStream_simpleError(sFile,STREAM_READWRITE | STREAM_SHARE_DENYWRITE | STREAM_TRUNC);
519 if (!m_pFileStream)
520 {
521 const ::rtl::OUString sError( m_pTable->getConnection()->getResources().getResourceStringWithSubstitution(
522 STR_COULD_NOT_LOAD_FILE,
523 "$filename$", sFile
524 ) );
525 ::dbtools::throwGenericSQLException( sError, *this );
526 }
527
528 m_pFileStream->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN);
529 m_pFileStream->SetBufferSize(PAGE_SIZE);
530 m_pFileStream->SetFiller('\0');
531
532 // Zunaechst muss das Ergebnis sortiert sein
533 utl::SharedUNOComponent<XStatement> xStmt;
534 utl::SharedUNOComponent<XResultSet> xSet;
535 String aName;
536 try
537 {
538 xStmt.set( m_pTable->getConnection()->createStatement(), UNO_SET_THROW);
539
540 aName = getString(xCol->getFastPropertyValue(PROPERTY_ID_NAME));
541
542 const String aQuote(m_pTable->getConnection()->getMetaData()->getIdentifierQuoteString());
543 String aStatement;
544 aStatement.AssignAscii("SELECT ");
545 aStatement += aQuote;
546 aStatement += aName;
547 aStatement += aQuote;
548 aStatement.AppendAscii(" FROM ");
549 aStatement += aQuote;
550 aStatement += m_pTable->getName().getStr();
551 aStatement += aQuote;
552 aStatement.AppendAscii(" ORDER BY ");
553 aStatement += aQuote;
554 aStatement += aName;
555 aStatement += aQuote;
556
557 // if (!m_IsUnique) // zusaetzlich sortierung mit der bookmarkspalte
558 // {
559 // aStatement.AppendAscii(" ,");
560 // aStatement += aQuote;
561 // aStatement.AppendAscii("[BOOKMARK]"); // this is a special column
562 // aStatement += aQuote;
563 // }
564
565 xSet.set( xStmt->executeQuery(aStatement),UNO_SET_THROW );
566 }
567 catch(const Exception& )
568 {
569 impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX,sFile);
570 }
571 if (!xSet.is())
572 {
573 impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX,sFile);
574 }
575
576 // Setzen der Headerinfo
577 memset(&m_aHeader,0,sizeof(m_aHeader));
578 sal_Int32 nType = 0;
579 ::vos::ORef<OSQLColumns> aCols = m_pTable->getTableColumns();
580 const Reference< XPropertySet > xTableCol(*find(aCols->get().begin(),aCols->get().end(),aName,::comphelper::UStringMixEqual(isCaseSensitive())));
581
582 xTableCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType;
583
584 m_aHeader.db_keytype = (nType == DataType::VARCHAR || nType == DataType::CHAR) ? 0 : 1;
585 m_aHeader.db_keylen = (m_aHeader.db_keytype) ? 8 : (sal_uInt16)getINT32(xTableCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)));
586 m_aHeader.db_keylen = (( m_aHeader.db_keylen - 1) / 4 + 1) * 4;
587 m_aHeader.db_maxkeys = (PAGE_SIZE - 4) / (8 + m_aHeader.db_keylen);
588 if ( m_aHeader.db_maxkeys < 3 )
589 {
590 impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX_KEYSIZE,sFile);
591 }
592
593 m_pFileStream->SetStreamSize(PAGE_SIZE);
594
595 ByteString aCol(aName,m_pTable->getConnection()->getTextEncoding());
596 strncpy(m_aHeader.db_name,aCol.GetBuffer(),std::min((sal_uInt16)sizeof(m_aHeader.db_name), aCol.Len()));
597 m_aHeader.db_unique = m_IsUnique ? 1: 0;
598 m_aHeader.db_keyrec = m_aHeader.db_keylen + 8;
599
600 // modifizierung am Header werden ueber Unterschiede zw. HeaderInfo und nRootPage
601 // bzw. nPageCout erkannt
602
603 m_nRootPage = 1;
604 m_nPageCount = 2;
605
606 // ODatabaseType eType = m_aHeader.db_keytype == 0 ? DataType::VARCHAR : DataType::DOUBLE;
607 m_aCurLeaf = m_aRoot = CreatePage(m_nRootPage);
608 m_aRoot->SetModified(sal_True);
609
610 m_bUseCollector = sal_True;
611
612 // sal_uIntPtr nRowsLeft = pCursor->RowCount();
613 sal_Int32 nRowsLeft = 0;
614 Reference<XRow> xRow(xSet,UNO_QUERY);
615
616 if(xSet->last())
617 {
618 Reference< XUnoTunnel> xTunnel(xSet,UNO_QUERY);
619 ODbaseResultSet* pDbaseRes = NULL;
620 if(xTunnel.is())
621 pDbaseRes = reinterpret_cast< ODbaseResultSet* >( xTunnel->getSomething(ODbaseResultSet::getUnoTunnelImplementationId()) );
622 OSL_ENSURE(pDbaseRes,"No dbase resultset found? What's going on here!");
623 Reference<XRowLocate> xRowLocate(xSet,UNO_QUERY);
624 nRowsLeft = xSet->getRow();
625
626 xSet->beforeFirst();
627 ORowSetValue atmpValue=ORowSetValue();
628 ONDXKey aKey(atmpValue, nType, 0);
629 ONDXKey aInsertKey(atmpValue, nType, 0);
630 // Erzeugen der Indexstruktur
631 while (xSet->next())
632 {
633 // ODbRow& rRow = *pCursor->GetRow();
634 ORowSetValue aValue(m_aHeader.db_keytype ? ORowSetValue(xRow->getDouble(1)) : ORowSetValue(xRow->getString(1)));
635 // ueberpruefen auf doppelten eintrag
636 if (m_IsUnique && m_nCurNode != NODE_NOTFOUND)
637 {
638 aKey.setValue(aValue);
639 if (aKey == (*m_aCurLeaf)[m_nCurNode].GetKey())
640 {
641 impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX_NOT_UNIQUE,sFile);
642 }
643 }
644 aInsertKey.setValue(aValue);
645 aInsertKey.setRecord(pDbaseRes->getCurrentFilePos());
646
647 ONDXNode aNewNode(aInsertKey);
648 if (!m_aCurLeaf->Insert(aNewNode, --nRowsLeft))
649 break;
650 }
651 }
652
653 if(nRowsLeft)
654 {
655 impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX,sFile);
656 }
657 Release();
658 createINFEntry();
659 return sal_True;
660 }
661 // -----------------------------------------------------------------------------
662 // -----------------------------------------------------------------------------
acquire()663 void SAL_CALL ODbaseIndex::acquire() throw()
664 {
665 ODbaseIndex_BASE::acquire();
666 }
667 // -----------------------------------------------------------------------------
release()668 void SAL_CALL ODbaseIndex::release() throw()
669 {
670 ODbaseIndex_BASE::release();
671 }
672 // -----------------------------------------------------------------------------
673
674
675
676