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