Bump for 3.6-28
[LibreOffice.git] / connectivity / source / drivers / dbase / dindexnode.cxx
blobe04ec3deefce165cab1ff3d6a6589cec641cb285
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include "dbase/dindexnode.hxx"
30 #include "connectivity/CommonTools.hxx"
31 #include <osl/thread.h>
32 #include "dbase/DIndex.hxx"
33 #include <tools/debug.hxx>
34 #include "diagnose_ex.h"
36 #include <algorithm>
37 #include <boost/scoped_array.hpp>
40 using namespace connectivity;
41 using namespace connectivity::dbase;
42 using namespace connectivity::file;
43 using namespace com::sun::star::sdbc;
44 // -----------------------------------------------------------------------------
45 ONDXKey::ONDXKey(sal_uInt32 nRec)
46 :nRecord(nRec)
49 // -----------------------------------------------------------------------------
50 ONDXKey::ONDXKey(const ORowSetValue& rVal, sal_Int32 eType, sal_uInt32 nRec)
51 : ONDXKey_BASE(eType)
52 , nRecord(nRec)
53 , xValue(rVal)
56 // -----------------------------------------------------------------------------
57 ONDXKey::ONDXKey(const rtl::OUString& aStr, sal_uInt32 nRec)
58 : ONDXKey_BASE(::com::sun::star::sdbc::DataType::VARCHAR)
59 ,nRecord(nRec)
61 if (!aStr.isEmpty())
63 xValue = aStr;
64 xValue.setBound(sal_True);
67 // -----------------------------------------------------------------------------
69 ONDXKey::ONDXKey(double aVal, sal_uInt32 nRec)
70 : ONDXKey_BASE(::com::sun::star::sdbc::DataType::DOUBLE)
71 ,nRecord(nRec)
72 ,xValue(aVal)
75 // -----------------------------------------------------------------------------
77 //==================================================================
78 // index page
79 //==================================================================
80 ONDXPage::ONDXPage(ODbaseIndex& rInd, sal_uInt32 nPos, ONDXPage* pParent)
81 :nPagePos(nPos)
82 ,bModified(sal_False)
83 ,nCount(0)
84 ,aParent(pParent)
85 ,rIndex(rInd)
86 ,ppNodes(NULL)
88 sal_uInt16 nT = rIndex.getHeader().db_maxkeys;
89 ppNodes = new ONDXNode[nT];
92 //------------------------------------------------------------------
93 ONDXPage::~ONDXPage()
95 delete[] ppNodes;
97 //------------------------------------------------------------------
98 void ONDXPage::QueryDelete()
100 // Store in GarbageCollector
101 if (IsModified() && rIndex.m_pFileStream)
102 (*rIndex.m_pFileStream) << *this;
104 bModified = sal_False;
105 if (rIndex.UseCollector())
107 if (aChild.Is())
108 aChild->Release(sal_False);
110 for (sal_uInt16 i = 0; i < rIndex.getHeader().db_maxkeys;i++)
112 if (ppNodes[i].GetChild().Is())
113 ppNodes[i].GetChild()->Release(sal_False);
115 ppNodes[i] = ONDXNode();
117 RestoreNoDelete();
119 nCount = 0;
120 aParent.Clear();
121 rIndex.Collect(this);
123 else
124 SvRefBase::QueryDelete();
126 //------------------------------------------------------------------
127 ONDXPagePtr& ONDXPage::GetChild(ODbaseIndex* pIndex)
129 if (!aChild.Is() && pIndex)
131 aChild = rIndex.CreatePage(aChild.GetPagePos(),this,aChild.HasPage());
133 return aChild;
136 //------------------------------------------------------------------
137 sal_uInt16 ONDXPage::FindPos(const ONDXKey& rKey) const
139 // searches the position for the given key in a page
140 sal_uInt16 i = 0;
141 while (i < nCount && rKey > ((*this)[i]).GetKey())
142 i++;
144 return i;
147 //------------------------------------------------------------------
148 sal_Bool ONDXPage::Find(const ONDXKey& rKey)
150 // searches the given key
151 // Speciality: At the end of the method
152 // the actual page and the position of the node, fulfilling the '<=' condition, are saved
153 // This is considered at insert.
154 sal_uInt16 i = 0;
155 while (i < nCount && rKey > ((*this)[i]).GetKey())
156 i++;
158 sal_Bool bResult = sal_False;
160 if (!IsLeaf())
162 // descend further
163 ONDXPagePtr aPage = (i==0) ? GetChild(&rIndex) : ((*this)[i-1]).GetChild(&rIndex, this);
164 bResult = aPage.Is() && aPage->Find(rKey);
166 else if (i == nCount)
168 rIndex.m_aCurLeaf = this;
169 rIndex.m_nCurNode = i - 1;
170 bResult = sal_False;
172 else
174 bResult = rKey == ((*this)[i]).GetKey();
175 rIndex.m_aCurLeaf = this;
176 rIndex.m_nCurNode = bResult ? i : i - 1;
178 return bResult;
181 //------------------------------------------------------------------
182 sal_Bool ONDXPage::Insert(ONDXNode& rNode, sal_uInt32 nRowsLeft)
184 // When creating an index there can be multiple nodes added,
185 // these are sorted ascending
186 sal_Bool bAppend = nRowsLeft > 0;
187 if (IsFull())
189 sal_Bool bResult = sal_True;
190 ONDXNode aSplitNode;
191 if (bAppend)
192 aSplitNode = rNode;
193 else
195 // Save the last node
196 aSplitNode = (*this)[nCount-1];
197 if(rNode.GetKey() <= aSplitNode.GetKey())
200 // this practically reduces the number of nodes by 1
201 if (IsLeaf() && this == &rIndex.m_aCurLeaf)
203 // assumes, that the node, for which the condition (<=) holds, is stored in m_nCurNode
204 --nCount; // (otherwise we might get Assertions and GPFs - 60593)
205 bResult = Insert(rIndex.m_nCurNode + 1, rNode);
207 else // position unknown
209 sal_uInt16 nPos = NODE_NOTFOUND;
210 while (++nPos < nCount && rNode.GetKey() > ((*this)[nPos]).GetKey()) ;
212 --nCount; // (otherwise we might get Assertions and GPFs - 60593)
213 bResult = Insert(nPos, rNode);
216 // can the new node be inserted
217 if (!bResult)
219 nCount++;
220 aSplitNode = rNode;
223 else
224 aSplitNode = rNode;
227 sal_uInt32 nNewPagePos = rIndex.GetPageCount();
228 sal_uInt32 nNewPageCount = nNewPagePos + 1;
230 // insert extracted node into parent node
231 if (!HasParent())
233 // No parent, then new root
234 ONDXPagePtr aNewRoot = rIndex.CreatePage(nNewPagePos + 1);
235 aNewRoot->SetChild(this);
237 rIndex.m_aRoot = aNewRoot;
238 rIndex.SetRootPos(nNewPagePos + 1);
239 rIndex.SetPageCount(++nNewPageCount);
242 // create new leaf and divide page
243 ONDXPagePtr aNewPage = rIndex.CreatePage(nNewPagePos,aParent);
244 rIndex.SetPageCount(nNewPageCount);
246 // How many nodes are being inserted?
247 // Enough, then we can fill the page to the brim
248 ONDXNode aInnerNode;
249 if (!IsLeaf() || nRowsLeft < (sal_uInt32)(rIndex.GetMaxNodes() / 2))
250 aInnerNode = Split(*aNewPage);
251 else
253 aInnerNode = (*this)[nCount - 1];
255 // Node points to the new page
256 aInnerNode.SetChild(aNewPage);
258 // Inner nodes have no record number
259 if (rIndex.isUnique())
260 aInnerNode.GetKey().ResetRecord();
262 // new page points to the page of the extracted node
263 if (!IsLeaf())
264 aNewPage->SetChild(aInnerNode.GetChild());
267 aNewPage->Append(aSplitNode);
268 ONDXPagePtr aTempParent = aParent;
269 if (IsLeaf())
271 rIndex.m_aCurLeaf = aNewPage;
272 rIndex.m_nCurNode = rIndex.m_aCurLeaf->Count() - 1;
274 // free not needed pages, there are no references to those on the page
275 // afterwards 'this' can't be valid anymore!!!
276 ReleaseFull();
279 // Insert extracted node
280 return aTempParent->Insert(aInnerNode);
282 else // Fill the page up
284 if (bAppend)
286 if (IsLeaf())
287 rIndex.m_nCurNode = nCount - 1;
288 return Append(rNode);
290 else
292 sal_uInt16 nNodePos = FindPos(rNode.GetKey());
293 if (IsLeaf())
294 rIndex.m_nCurNode = nNodePos;
296 return Insert(nNodePos, rNode);
301 //------------------------------------------------------------------
302 sal_Bool ONDXPage::Insert(sal_uInt16 nPos, ONDXNode& rNode)
304 sal_uInt16 nMaxCount = rIndex.getHeader().db_maxkeys;
305 if (nPos >= nMaxCount)
306 return sal_False;
308 if (nCount)
310 ++nCount;
311 // shift right
312 for (sal_uInt16 i = std::min((sal_uInt16)(nMaxCount-1), (sal_uInt16)(nCount-1)); nPos < i; --i)
313 (*this)[i] = (*this)[i-1];
315 else
316 if (nCount < nMaxCount)
317 nCount++;
319 // insert at the position
320 ONDXNode& rInsertNode = (*this)[nPos];
321 rInsertNode = rNode;
322 if (rInsertNode.GetChild().Is())
324 rInsertNode.GetChild()->SetParent(this);
325 rNode.GetChild()->SetParent(this);
328 bModified = sal_True;
330 return sal_True;
333 //------------------------------------------------------------------
334 sal_Bool ONDXPage::Append(ONDXNode& rNode)
336 DBG_ASSERT(!IsFull(), "kein Append moeglich");
337 return Insert(nCount, rNode);
339 //------------------------------------------------------------------
340 void ONDXPage::Release(sal_Bool bSave)
342 // free pages
343 if (aChild.Is())
344 aChild->Release(bSave);
346 // free pointer
347 aChild.Clear();
349 for (sal_uInt16 i = 0; i < rIndex.getHeader().db_maxkeys;i++)
351 if (ppNodes[i].GetChild())
352 ppNodes[i].GetChild()->Release(bSave);
354 ppNodes[i].GetChild().Clear();
356 aParent = NULL;
358 //------------------------------------------------------------------
359 void ONDXPage::ReleaseFull(sal_Bool bSave)
361 ONDXPagePtr aTempParent = aParent;
362 Release(bSave);
364 if (aTempParent.Is())
366 // Free pages not needed, there will be no reference anymore to the pages
367 // afterwards 'this' can't be valid anymore!!!
368 sal_uInt16 nParentPos = aTempParent->Search(this);
369 if (nParentPos != NODE_NOTFOUND)
370 (*aTempParent)[nParentPos].GetChild().Clear();
371 else
372 aTempParent->GetChild().Clear();
375 //------------------------------------------------------------------
376 sal_Bool ONDXPage::Delete(sal_uInt16 nNodePos)
378 if (IsLeaf())
380 // The last element will not be deleted
381 if (nNodePos == (nCount - 1))
383 ONDXNode aNode = (*this)[nNodePos];
385 // parent's KeyValue has to be replaced
386 if (HasParent())
387 aParent->SearchAndReplace(aNode.GetKey(),
388 (*this)[nNodePos-1].GetKey());
392 // Delete the node
393 Remove(nNodePos);
395 // Underflow
396 if (HasParent() && nCount < (rIndex.GetMaxNodes() / 2))
398 // determine, which node points to the page
399 sal_uInt16 nParentNodePos = aParent->Search(this);
400 // last element on parent-page -> merge with secondlast page
401 if (nParentNodePos == (aParent->Count() - 1))
403 if (!nParentNodePos)
404 // merge with left neighbour
405 Merge(nParentNodePos,aParent->GetChild(&rIndex));
406 else
407 Merge(nParentNodePos,(*aParent)[nParentNodePos-1].GetChild(&rIndex,aParent));
409 // otherwise merge page with next page
410 else
412 // merge with right neighbour
413 Merge(nParentNodePos + 1,((*aParent)[nParentNodePos + 1].GetChild(&rIndex,aParent)));
414 nParentNodePos++;
416 if (HasParent() && !(*aParent)[nParentNodePos].HasChild())
417 aParent->Delete(nParentNodePos);
419 else if (IsRoot())
420 // make sure that the position of the root is kept
421 rIndex.SetRootPos(nPagePos);
422 return sal_True;
426 //------------------------------------------------------------------
427 ONDXNode ONDXPage::Split(ONDXPage& rPage)
429 DBG_ASSERT(IsFull(), "Falsches Splitting");
430 /* devide one page into two
431 leaf:
432 Page 1 is (n - (n/2))
433 Page 2 is (n/2)
434 Node n/2 will be duplicated
435 inner node:
436 Page 1 is (n+1)/2
437 Page 2 is (n/2-1)
438 Node ((n+1)/2 + 1) : will be taken out
440 ONDXNode aResultNode;
441 if (IsLeaf())
443 for (sal_uInt16 i = (nCount - (nCount / 2)), j = 0 ; i < nCount; i++)
444 rPage.Insert(j++,(*this)[i]);
446 // this node contains a key that already exists in the tree and must be replaced
447 ONDXNode aLastNode = (*this)[nCount - 1];
448 nCount = nCount - (nCount / 2);
449 aResultNode = (*this)[nCount - 1];
451 if (HasParent())
452 aParent->SearchAndReplace(aLastNode.GetKey(),
453 aResultNode.GetKey());
455 else
457 for (sal_uInt16 i = (nCount + 1) / 2 + 1, j = 0 ; i < nCount; i++)
458 rPage.Insert(j++,(*this)[i]);
460 aResultNode = (*this)[(nCount + 1) / 2];
461 nCount = (nCount + 1) / 2;
463 // new page points to page with extraced node
464 rPage.SetChild(aResultNode.GetChild());
466 // node points to new page
467 aResultNode.SetChild(&rPage);
469 // inner nodes have no record number
470 if (rIndex.isUnique())
471 aResultNode.GetKey().ResetRecord();
472 bModified = sal_True;
473 return aResultNode;
476 //------------------------------------------------------------------
477 void ONDXPage::Merge(sal_uInt16 nParentNodePos, ONDXPagePtr xPage)
479 DBG_ASSERT(HasParent(), "kein Vater vorhanden");
480 DBG_ASSERT(nParentNodePos != NODE_NOTFOUND, "Falscher Indexaufbau");
482 /* Merge 2 pages */
483 ONDXNode aResultNode;
484 sal_uInt16 nMaxNodes = rIndex.GetMaxNodes(),
485 nMaxNodes_2 = nMaxNodes / 2;
487 // Determine if page is right or left neighbour
488 sal_Bool bRight = ((*xPage)[0].GetKey() > (*this)[0].GetKey()); // sal_True, whenn xPage the right side is
489 sal_uInt16 nNewCount = (*xPage).Count() + Count();
491 if (IsLeaf())
493 // Condition for merge
494 if (nNewCount < (nMaxNodes_2 * 2))
496 sal_uInt16 nLastNode = bRight ? Count() - 1 : xPage->Count() - 1;
497 if (bRight)
499 DBG_ASSERT(&xPage != this,"xPage und THIS duerfen nicht gleich sein: Endlosschleife");
500 // shift all nodes from xPage to the left node (append)
501 while (xPage->Count())
503 Append((*xPage)[0]);
504 xPage->Remove(0);
507 else
509 DBG_ASSERT(&xPage != this,"xPage und THIS duerfen nicht gleich sein: Endlosschleife");
510 // xPage is the left page and THIS the right one
511 while (xPage->Count())
513 Insert(0,(*xPage)[xPage->Count()-1]);
514 xPage->Remove(xPage->Count()-1);
516 // replace old position of xPage in parent with this
517 if (nParentNodePos)
518 (*aParent)[nParentNodePos-1].SetChild(this,aParent);
519 else // or set as right node
520 aParent->SetChild(this);
521 aParent->SetModified(sal_True);
525 // cancel Child-relationship at parent node
526 (*aParent)[nParentNodePos].SetChild();
527 // replace the Node-value, only if changed page is the left one, otherwise become
528 if(aParent->IsRoot() && aParent->Count() == 1)
530 (*aParent)[0].SetChild();
531 aParent->ReleaseFull();
532 aParent = NULL;
533 rIndex.SetRootPos(nPagePos);
534 rIndex.m_aRoot = this;
535 SetModified(sal_True);
537 else
538 aParent->SearchAndReplace((*this)[nLastNode].GetKey(),(*this)[nCount-1].GetKey());
540 xPage->SetModified(sal_False);
541 xPage->ReleaseFull(); // is not needed anymore
543 // balance the elements nNewCount >= (nMaxNodes_2 * 2)
544 else
546 if (bRight)
548 // shift all nodes from xPage to the left node (append)
549 ONDXNode aReplaceNode = (*this)[nCount - 1];
550 while (nCount < nMaxNodes_2)
552 Append((*xPage)[0]);
553 xPage->Remove(0);
555 // Replace the node values: replace old last value by the last of xPage
556 aParent->SearchAndReplace(aReplaceNode.GetKey(),(*this)[nCount-1].GetKey());
558 else
560 // insert all nodes from this in front of the xPage nodes
561 ONDXNode aReplaceNode = (*this)[nCount - 1];
562 while (xPage->Count() < nMaxNodes_2)
564 xPage->Insert(0,(*this)[nCount-1]);
565 Remove(nCount-1);
567 // Replace the node value
568 aParent->SearchAndReplace(aReplaceNode.GetKey(),(*this)[Count()-1].GetKey());
572 else // !IsLeaf()
574 // Condition for merge
575 if (nNewCount < nMaxNodes_2 * 2)
577 if (bRight)
579 DBG_ASSERT(&xPage != this,"xPage und THIS duerfen nicht gleich sein: Endlosschleife");
580 // Parent node will be integrated; is initialized with Child from xPage
581 (*aParent)[nParentNodePos].SetChild(xPage->GetChild(),aParent);
582 Append((*aParent)[nParentNodePos]);
583 for (sal_uInt16 i = 0 ; i < xPage->Count(); i++)
584 Append((*xPage)[i]);
586 else
588 DBG_ASSERT(&xPage != this,"xPage und THIS duerfen nicht gleich sein: Endlosschleife");
589 // Parent-node will be integrated; is initialized with child
590 (*aParent)[nParentNodePos].SetChild(GetChild(),aParent); // Parent memorizes my child
591 Insert(0,(*aParent)[nParentNodePos]); // insert parent node into myself
592 while (xPage->Count())
594 Insert(0,(*xPage)[xPage->Count()-1]);
595 xPage->Remove(xPage->Count()-1);
597 SetChild(xPage->GetChild());
599 if (nParentNodePos)
600 (*aParent)[nParentNodePos-1].SetChild(this,aParent);
601 else
602 aParent->SetChild(this);
605 // afterwards parent node will be reset
606 (*aParent)[nParentNodePos].SetChild();
607 aParent->SetModified(sal_True);
609 if(aParent->IsRoot() && aParent->Count() == 1)
611 (*aParent).SetChild();
612 aParent->ReleaseFull();
613 aParent = NULL;
614 rIndex.SetRootPos(nPagePos);
615 rIndex.m_aRoot = this;
616 SetModified(sal_True);
618 else if(nParentNodePos)
619 // replace the node value
620 // for Append the range will be enlarged, for Insert the old node from xPage will reference to this
621 // thats why the node must be updated here
622 aParent->SearchAndReplace((*aParent)[nParentNodePos-1].GetKey(),(*aParent)[nParentNodePos].GetKey());
624 xPage->SetModified(sal_False);
625 xPage->ReleaseFull();
627 // balance the elements
628 else
630 if (bRight)
632 while (nCount < nMaxNodes_2)
634 (*aParent)[nParentNodePos].SetChild(xPage->GetChild(),aParent);
635 Append((*aParent)[nParentNodePos]);
636 (*aParent)[nParentNodePos] = (*xPage)[0];
637 xPage->Remove(0);
639 xPage->SetChild((*aParent)[nParentNodePos].GetChild());
640 (*aParent)[nParentNodePos].SetChild(xPage,aParent);
642 else
644 while (nCount < nMaxNodes_2)
646 (*aParent)[nParentNodePos].SetChild(GetChild(),aParent);
647 Insert(0,(*aParent)[nParentNodePos]);
648 (*aParent)[nParentNodePos] = (*xPage)[xPage->Count()-1];
649 xPage->Remove(xPage->Count()-1);
651 SetChild((*aParent)[nParentNodePos].GetChild());
652 (*aParent)[nParentNodePos].SetChild(this,aParent);
655 aParent->SetModified(sal_True);
659 //==================================================================
660 // ONDXNode
661 //==================================================================
663 //------------------------------------------------------------------
664 void ONDXNode::Read(SvStream &rStream, ODbaseIndex& rIndex)
666 rStream >> aKey.nRecord; // key
668 if (rIndex.getHeader().db_keytype)
670 double aDbl;
671 rStream >> aDbl;
672 aKey = ONDXKey(aDbl,aKey.nRecord);
674 else
676 sal_uInt16 nLen = rIndex.getHeader().db_keylen;
677 rtl::OString aBuf = read_uInt8s_ToOString(rStream, nLen);
678 //get length minus trailing whitespace
679 sal_Int32 nContentLen = aBuf.getLength();
680 while (nContentLen && aBuf[nContentLen-1] == ' ')
681 --nContentLen;
682 aKey = ONDXKey(::rtl::OUString(aBuf.getStr(), nContentLen, rIndex.m_pTable->getConnection()->getTextEncoding()) ,aKey.nRecord);
684 rStream >> aChild;
687 //------------------------------------------------------------------
688 void ONDXNode::Write(SvStream &rStream, const ONDXPage& rPage) const
690 const ODbaseIndex& rIndex = rPage.GetIndex();
691 if (!rIndex.isUnique() || rPage.IsLeaf())
692 rStream << (sal_uInt32)aKey.nRecord; // key
693 else
694 rStream << (sal_uInt32)0; // key
696 if (rIndex.getHeader().db_keytype) // double
698 if (sizeof(double) != rIndex.getHeader().db_keylen)
700 OSL_TRACE("this key length cannot possibly be right?");
702 if (aKey.getValue().isNull())
704 sal_uInt8 buf[sizeof(double)];
705 memset(&buf[0], 0, sizeof(double));
706 rStream.Write(&buf[0], sizeof(double));
708 else
709 rStream << (double) aKey.getValue();
711 else
713 sal_uInt16 const nLen(rIndex.getHeader().db_keylen);
714 ::boost::scoped_array<sal_uInt8> pBuf(new sal_uInt8[nLen]);
715 memset(&pBuf[0], 0x20, nLen);
716 if (!aKey.getValue().isNull())
718 ::rtl::OUString sValue = aKey.getValue();
719 rtl::OString aText(rtl::OUStringToOString(sValue, rIndex.m_pTable->getConnection()->getTextEncoding()));
720 strncpy(reinterpret_cast<char *>(&pBuf[0]), aText.getStr(),
721 std::min<size_t>(nLen, aText.getLength()));
723 rStream.Write(&pBuf[0], nLen);
725 rStream << aChild;
729 //------------------------------------------------------------------
730 ONDXPagePtr& ONDXNode::GetChild(ODbaseIndex* pIndex, ONDXPage* pParent)
732 if (!aChild.Is() && pIndex)
734 aChild = pIndex->CreatePage(aChild.GetPagePos(),pParent,aChild.HasPage());
736 return aChild;
739 //==================================================================
740 // ONDXKey
741 //==================================================================
742 //------------------------------------------------------------------
743 sal_Bool ONDXKey::IsText(sal_Int32 eType)
745 return eType == DataType::VARCHAR || eType == DataType::CHAR;
748 //------------------------------------------------------------------
749 StringCompare ONDXKey::Compare(const ONDXKey& rKey) const
751 StringCompare eResult;
753 if (getValue().isNull())
755 if (rKey.getValue().isNull() || (rKey.IsText(getDBType()) && rKey.getValue().getString().isEmpty()))
756 eResult = COMPARE_EQUAL;
757 else
758 eResult = COMPARE_LESS;
760 else if (rKey.getValue().isNull())
762 if (getValue().isNull() || (IsText(getDBType()) && getValue().getString().isEmpty()))
763 eResult = COMPARE_EQUAL;
764 else
765 eResult = COMPARE_GREATER;
767 else if (IsText(getDBType()))
769 sal_Int32 nRes = getValue().getString().compareTo(rKey.getValue());
770 eResult = (nRes > 0) ? COMPARE_GREATER : (nRes == 0) ? COMPARE_EQUAL : COMPARE_LESS;
772 else
774 double m = getValue(),n = rKey.getValue();
775 eResult = (m > n) ? COMPARE_GREATER : (n == m) ? COMPARE_EQUAL : COMPARE_LESS;
778 // compare record, if index !Unique
779 if (eResult == COMPARE_EQUAL && nRecord && rKey.nRecord)
780 eResult = (nRecord > rKey.nRecord) ? COMPARE_GREATER :
781 (nRecord == rKey.nRecord) ? COMPARE_EQUAL : COMPARE_LESS;
783 return eResult;
785 // -----------------------------------------------------------------------------
786 void ONDXKey::setValue(const ORowSetValue& _rVal)
788 xValue = _rVal;
790 // -----------------------------------------------------------------------------
791 const ORowSetValue& ONDXKey::getValue() const
793 return xValue;
795 // -----------------------------------------------------------------------------
796 SvStream& connectivity::dbase::operator >> (SvStream &rStream, ONDXPagePtr& rPage)
798 rStream >> rPage.nPagePos;
799 return rStream;
801 // -----------------------------------------------------------------------------
802 SvStream& connectivity::dbase::operator << (SvStream &rStream, const ONDXPagePtr& rPage)
804 rStream << rPage.nPagePos;
805 return rStream;
807 // -----------------------------------------------------------------------------
808 //==================================================================
809 // ONDXPagePtr
810 //==================================================================
811 //------------------------------------------------------------------
812 ONDXPagePtr::ONDXPagePtr(const ONDXPagePtr& rRef)
813 :ONDXPageRef(rRef)
814 ,nPagePos(rRef.nPagePos)
818 //------------------------------------------------------------------
819 ONDXPagePtr::ONDXPagePtr(ONDXPage* pRefPage)
820 :ONDXPageRef(pRefPage)
821 ,nPagePos(0)
823 if (pRefPage)
824 nPagePos = pRefPage->GetPagePos();
826 //------------------------------------------------------------------
827 ONDXPagePtr& ONDXPagePtr::operator=(const ONDXPagePtr& rRef)
829 ONDXPageRef::operator=(rRef);
830 nPagePos = rRef.nPagePos;
831 return *this;
834 //------------------------------------------------------------------
835 ONDXPagePtr& ONDXPagePtr::operator= (ONDXPage* pRef)
837 ONDXPageRef::operator=(pRef);
838 nPagePos = (pRef) ? pRef->GetPagePos() : 0;
839 return *this;
841 // -----------------------------------------------------------------------------
842 static sal_uInt32 nValue;
843 //------------------------------------------------------------------
844 SvStream& connectivity::dbase::operator >> (SvStream &rStream, ONDXPage& rPage)
846 rStream.Seek(rPage.GetPagePos() * PAGE_SIZE);
847 rStream >> nValue >> rPage.aChild;
848 rPage.nCount = sal_uInt16(nValue);
850 for (sal_uInt16 i = 0; i < rPage.nCount; i++)
851 rPage[i].Read(rStream, rPage.GetIndex());
852 return rStream;
855 //------------------------------------------------------------------
856 SvStream& connectivity::dbase::operator << (SvStream &rStream, const ONDXPage& rPage)
858 // Page doesn't exist yet
859 sal_uIntPtr nSize = (rPage.GetPagePos() + 1) * PAGE_SIZE;
860 if (nSize > rStream.Seek(STREAM_SEEK_TO_END))
862 rStream.SetStreamSize(nSize);
863 rStream.Seek(rPage.GetPagePos() * PAGE_SIZE);
865 char aEmptyData[PAGE_SIZE];
866 memset(aEmptyData,0x00,PAGE_SIZE);
867 rStream.Write((sal_uInt8*)aEmptyData,PAGE_SIZE);
869 sal_uIntPtr nCurrentPos = rStream.Seek(rPage.GetPagePos() * PAGE_SIZE);
870 OSL_UNUSED( nCurrentPos );
872 nValue = rPage.nCount;
873 rStream << nValue << rPage.aChild;
875 sal_uInt16 i = 0;
876 for (; i < rPage.nCount; i++)
877 rPage[i].Write(rStream, rPage);
879 // check if we have to fill the stream with '\0'
880 if(i < rPage.rIndex.getHeader().db_maxkeys)
882 sal_uIntPtr nTell = rStream.Tell() % PAGE_SIZE;
883 sal_uInt16 nBufferSize = rStream.GetBufferSize();
884 sal_uIntPtr nRemainSize = nBufferSize - nTell;
885 if ( nRemainSize <= nBufferSize )
887 char* pEmptyData = new char[nRemainSize];
888 memset(pEmptyData,0x00,nRemainSize);
889 rStream.Write((sal_uInt8*)pEmptyData,nRemainSize);
890 rStream.Seek(nTell);
891 delete [] pEmptyData;
894 return rStream;
896 // -----------------------------------------------------------------------------
897 #if OSL_DEBUG_LEVEL > 1
898 //------------------------------------------------------------------
899 void ONDXPage::PrintPage()
901 OSL_TRACE("\nSDB: -----------Page: %d Parent: %d Count: %d Child: %d-----",
902 nPagePos, HasParent() ? aParent->GetPagePos() : 0 ,nCount, aChild.GetPagePos());
904 for (sal_uInt16 i = 0; i < nCount; i++)
906 ONDXNode rNode = (*this)[i];
907 ONDXKey& rKey = rNode.GetKey();
908 if (!IsLeaf())
909 rNode.GetChild(&rIndex, this);
911 if (rKey.getValue().isNull())
913 OSL_TRACE("SDB: [%d,NULL,%d]",rKey.GetRecord(), rNode.GetChild().GetPagePos());
915 else if (rIndex.getHeader().db_keytype)
917 OSL_TRACE("SDB: [%d,%f,%d]",rKey.GetRecord(), rKey.getValue().getDouble(),rNode.GetChild().GetPagePos());
919 else
921 OSL_TRACE("SDB: [%d,%s,%d]",rKey.GetRecord(), rtl::OUStringToOString(rKey.getValue().getString(), rIndex.m_pTable->getConnection()->getTextEncoding()).getStr(),rNode.GetChild().GetPagePos());
924 OSL_TRACE("SDB: -----------------------------------------------");
925 if (!IsLeaf())
927 #if OSL_DEBUG_LEVEL > 1
928 GetChild(&rIndex)->PrintPage();
929 for (sal_uInt16 i = 0; i < nCount; i++)
931 ONDXNode rNode = (*this)[i];
932 rNode.GetChild(&rIndex,this)->PrintPage();
934 #endif
936 OSL_TRACE("SDB: ===============================================");
938 #endif
939 // -----------------------------------------------------------------------------
940 sal_Bool ONDXPage::IsFull() const
942 return Count() == rIndex.getHeader().db_maxkeys;
944 // -----------------------------------------------------------------------------
945 //------------------------------------------------------------------
946 sal_uInt16 ONDXPage::Search(const ONDXKey& rSearch)
948 // binary search later
949 sal_uInt16 i = NODE_NOTFOUND;
950 while (++i < Count())
951 if ((*this)[i].GetKey() == rSearch)
952 break;
954 return (i < Count()) ? i : NODE_NOTFOUND;
957 //------------------------------------------------------------------
958 sal_uInt16 ONDXPage::Search(const ONDXPage* pPage)
960 sal_uInt16 i = NODE_NOTFOUND;
961 while (++i < Count())
962 if (((*this)[i]).GetChild() == pPage)
963 break;
965 // if not found, then we assume, that the page itself points to the page
966 return (i < Count()) ? i : NODE_NOTFOUND;
968 // -----------------------------------------------------------------------------
969 // runs recursively
970 void ONDXPage::SearchAndReplace(const ONDXKey& rSearch,
971 ONDXKey& rReplace)
973 OSL_ENSURE(rSearch != rReplace,"Invalid here:rSearch == rReplace");
974 if (rSearch != rReplace)
976 sal_uInt16 nPos = NODE_NOTFOUND;
977 ONDXPage* pPage = this;
979 while (pPage && (nPos = pPage->Search(rSearch)) == NODE_NOTFOUND)
980 pPage = pPage->aParent;
982 if (pPage)
984 (*pPage)[nPos].GetKey() = rReplace;
985 pPage->SetModified(sal_True);
989 // -----------------------------------------------------------------------------
990 ONDXNode& ONDXPage::operator[] (sal_uInt16 nPos)
992 DBG_ASSERT(nCount > nPos, "falscher Indexzugriff");
993 return ppNodes[nPos];
996 //------------------------------------------------------------------
997 const ONDXNode& ONDXPage::operator[] (sal_uInt16 nPos) const
999 DBG_ASSERT(nCount > nPos, "falscher Indexzugriff");
1000 return ppNodes[nPos];
1002 // -----------------------------------------------------------------------------
1003 void ONDXPage::Remove(sal_uInt16 nPos)
1005 DBG_ASSERT(nCount > nPos, "falscher Indexzugriff");
1007 for (sal_uInt16 i = nPos; i < (nCount-1); i++)
1008 (*this)[i] = (*this)[i+1];
1010 nCount--;
1011 bModified = sal_True;
1013 // -----------------------------------------------------------------------------
1015 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */