merge the formfield patch from ooo-build
[ooovba.git] / connectivity / source / drivers / dbase / dindexnode.cxx
blobf8bf4dd7b4f9519b31fb96082b3567255a38ef99
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dindexnode.cxx,v $
10 * $Revision: 1.21.66.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_connectivity.hxx"
33 #include "dbase/dindexnode.hxx"
34 #include "connectivity/CommonTools.hxx"
35 #include <osl/thread.h>
36 #include "dbase/DIndex.hxx"
37 #include <tools/debug.hxx>
38 #include "diagnose_ex.h"
40 #include <algorithm>
43 using namespace connectivity;
44 using namespace connectivity::dbase;
45 using namespace connectivity::file;
46 using namespace com::sun::star::sdbc;
47 // -----------------------------------------------------------------------------
48 ONDXKey::ONDXKey(UINT32 nRec)
49 :nRecord(nRec)
52 // -----------------------------------------------------------------------------
53 ONDXKey::ONDXKey(const ORowSetValue& rVal, sal_Int32 eType, UINT32 nRec)
54 : ONDXKey_BASE(eType)
55 , nRecord(nRec)
56 , xValue(rVal)
59 // -----------------------------------------------------------------------------
60 ONDXKey::ONDXKey(const rtl::OUString& aStr, UINT32 nRec)
61 : ONDXKey_BASE(::com::sun::star::sdbc::DataType::VARCHAR)
62 ,nRecord(nRec)
64 if (aStr.getLength())
66 xValue = aStr;
67 xValue.setBound(sal_True);
70 // -----------------------------------------------------------------------------
72 ONDXKey::ONDXKey(double aVal, UINT32 nRec)
73 : ONDXKey_BASE(::com::sun::star::sdbc::DataType::DOUBLE)
74 ,nRecord(nRec)
75 ,xValue(aVal)
78 // -----------------------------------------------------------------------------
80 //==================================================================
81 // Index Seite
82 //==================================================================
83 ONDXPage::ONDXPage(ODbaseIndex& rInd, sal_uInt32 nPos, ONDXPage* pParent)
84 :nPagePos(nPos)
85 ,bModified(FALSE)
86 ,nCount(0)
87 ,aParent(pParent)
88 ,rIndex(rInd)
89 ,ppNodes(NULL)
91 sal_uInt16 nT = rIndex.getHeader().db_maxkeys;
92 ppNodes = new ONDXNode[nT];
95 //------------------------------------------------------------------
96 ONDXPage::~ONDXPage()
98 delete[] ppNodes;
99 // delete aParent;
100 // delete aChild;
102 //------------------------------------------------------------------
103 void ONDXPage::QueryDelete()
105 // Ablegen im GarbageCollector
106 if (IsModified() && rIndex.m_pFileStream)
107 (*rIndex.m_pFileStream) << *this;
109 bModified = FALSE;
110 if (rIndex.UseCollector())
112 if (aChild.Is())
113 aChild->Release(FALSE);
115 for (USHORT i = 0; i < rIndex.getHeader().db_maxkeys;i++)
117 if (ppNodes[i].GetChild().Is())
118 ppNodes[i].GetChild()->Release(FALSE);
120 ppNodes[i] = ONDXNode();
122 RestoreNoDelete();
124 nCount = 0;
125 aParent.Clear();
126 rIndex.Collect(this);
128 else
129 SvRefBase::QueryDelete();
131 //------------------------------------------------------------------
132 ONDXPagePtr& ONDXPage::GetChild(ODbaseIndex* pIndex)
134 if (!aChild.Is() && pIndex)
136 aChild = rIndex.CreatePage(aChild.GetPagePos(),this,aChild.HasPage());
138 return aChild;
141 //------------------------------------------------------------------
142 USHORT ONDXPage::FindPos(const ONDXKey& rKey) const
144 // sucht nach Platz fuer den vorgegeben key auf einer Seite
145 USHORT i = 0;
146 while (i < nCount && rKey > ((*this)[i]).GetKey())
147 i++;
149 return i;
152 //------------------------------------------------------------------
153 BOOL ONDXPage::Find(const ONDXKey& rKey)
155 // sucht den vorgegeben key
156 // Besonderheit: gelangt der Algorithmus ans Ende
157 // wird immer die aktuelle Seite und die Knotenposition vermerkt
158 // auf die die Bedingung <= zutrifft
159 // dieses findet beim Insert besondere Beachtung
160 USHORT i = 0;
161 while (i < nCount && rKey > ((*this)[i]).GetKey())
162 i++;
164 BOOL bResult = FALSE;
166 if (!IsLeaf())
168 // weiter absteigen
169 ONDXPagePtr aPage = (i==0) ? GetChild(&rIndex) : ((*this)[i-1]).GetChild(&rIndex, this);
170 bResult = aPage.Is() && aPage->Find(rKey);
172 else if (i == nCount)
174 rIndex.m_aCurLeaf = this;
175 rIndex.m_nCurNode = i - 1;
176 bResult = FALSE;
178 else
180 bResult = rKey == ((*this)[i]).GetKey();
181 rIndex.m_aCurLeaf = this;
182 rIndex.m_nCurNode = bResult ? i : i - 1;
184 return bResult;
187 //------------------------------------------------------------------
188 BOOL ONDXPage::Insert(ONDXNode& rNode, sal_uInt32 nRowsLeft)
190 // beim Erzeugen eines Index koennen auch mehrere Knoten eingefuegt werden
191 // diese sin dann aufsteigend sortiert
192 BOOL bAppend = nRowsLeft > 0;
193 if (IsFull())
195 BOOL bResult = TRUE;
196 ONDXNode aSplitNode;
197 if (bAppend)
198 aSplitNode = rNode;
199 else
201 // merken des letzten Knotens
202 aSplitNode = (*this)[nCount-1];
203 if(rNode.GetKey() <= aSplitNode.GetKey())
206 // und damit habe ich im folgenden praktisch eine Node weniger
207 if (IsLeaf() && this == &rIndex.m_aCurLeaf)
209 // geht davon aus, dass der Knoten, auf dem die Bedingung (<=)
210 // zutrifft, als m_nCurNode gesetzt ist
211 --nCount; // (sonst bekomme ich u.U. Assertions und GPFs - 60593)
212 bResult = Insert(rIndex.m_nCurNode + 1, rNode);
214 else // Position unbekannt
216 USHORT nPos = NODE_NOTFOUND;
217 while (++nPos < nCount && rNode.GetKey() > ((*this)[nPos]).GetKey()) ;
219 --nCount; // (sonst bekomme ich u.U. Assertions und GPFs - 60593)
220 bResult = Insert(nPos, rNode);
223 // konnte der neue Knoten eingefuegt werden
224 if (!bResult)
226 nCount++;
227 aSplitNode = rNode;
230 else
231 aSplitNode = rNode;
234 sal_uInt32 nNewPagePos = rIndex.GetPageCount();
235 sal_uInt32 nNewPageCount = nNewPagePos + 1;
237 // Herausgeloesten Knoten beim Vater einfuegen
238 if (!HasParent())
240 // Kein Vater, dann neue Wurzel
241 ONDXPagePtr aNewRoot = rIndex.CreatePage(nNewPagePos + 1);
242 aNewRoot->SetChild(this);
244 rIndex.m_aRoot = aNewRoot;
245 rIndex.SetRootPos(nNewPagePos + 1);
246 rIndex.SetPageCount(++nNewPageCount);
249 // neues blatt erzeugen und Seite aufteilen
250 ONDXPagePtr aNewPage = rIndex.CreatePage(nNewPagePos,aParent);
251 rIndex.SetPageCount(nNewPageCount);
253 // wieviele Knoten weren noch eingefuegt
254 // kommen noch ausreichend, dann koennen die Seiten bis zum Rand vollgestopft werden
256 ONDXNode aInnerNode;
257 if (!IsLeaf() || nRowsLeft < (sal_uInt32)(rIndex.GetMaxNodes() / 2))
258 aInnerNode = Split(*aNewPage);
259 else
261 aInnerNode = (*this)[nCount - 1];
262 //aInnerNode = aSplitNode;
264 // Knoten zeigt auf neue Seite
265 aInnerNode.SetChild(aNewPage);
267 // innere Knoten haben keine Recordnummer
268 if (rIndex.isUnique())
269 aInnerNode.GetKey().ResetRecord();
271 // neue Seite zeigt nun auf Seite des herausgeloesten Knoten
272 if (!IsLeaf())
273 aNewPage->SetChild(aInnerNode.GetChild());
276 aNewPage->Append(aSplitNode);
277 ONDXPagePtr aTempParent = aParent;
278 if (IsLeaf())
280 rIndex.m_aCurLeaf = aNewPage;
281 rIndex.m_nCurNode = rIndex.m_aCurLeaf->Count() - 1;
283 // Freigeben nicht benoetigter Seiten, danach besteht keine Referenz
284 // mehr auf die Seite, danach kann 'this' nicht mehr gueltig sein!!!
285 ReleaseFull();
288 // Einfuegen des herausgeloesten Knotens
289 return aTempParent->Insert(aInnerNode);
291 else // Seite einfach weiter auffuellen
293 if (bAppend)
295 if (IsLeaf())
296 rIndex.m_nCurNode = nCount - 1;
297 return Append(rNode);
299 else
301 USHORT nNodePos = FindPos(rNode.GetKey());
302 if (IsLeaf())
303 rIndex.m_nCurNode = nNodePos;
305 return Insert(nNodePos, rNode);
310 //------------------------------------------------------------------
311 BOOL ONDXPage::Insert(USHORT nPos, ONDXNode& rNode)
313 USHORT nMaxCount = rIndex.getHeader().db_maxkeys;
314 if (nPos >= nMaxCount)
315 return FALSE;
317 if (nCount)
319 ++nCount;
320 // nach rechts verschieben
321 for (USHORT i = std::min((USHORT)(nMaxCount-1), (USHORT)(nCount-1)); nPos < i; --i)
322 (*this)[i] = (*this)[i-1];
324 else
325 if (nCount < nMaxCount)
326 nCount++;
328 // einfuegen an der Position
329 ONDXNode& rInsertNode = (*this)[nPos];
330 rInsertNode = rNode;
331 if (rInsertNode.GetChild().Is())
333 rInsertNode.GetChild()->SetParent(this);
334 rNode.GetChild()->SetParent(this);
337 bModified = TRUE;
339 return TRUE;
342 //------------------------------------------------------------------
343 BOOL ONDXPage::Append(ONDXNode& rNode)
345 DBG_ASSERT(!IsFull(), "kein Append moeglich");
346 return Insert(nCount, rNode);
348 //------------------------------------------------------------------
349 void ONDXPage::Release(BOOL bSave)
351 // freigeben der Pages
352 if (aChild.Is())
353 aChild->Release(bSave);
355 // Pointer freigeben
356 aChild.Clear();
358 for (USHORT i = 0; i < rIndex.getHeader().db_maxkeys;i++)
360 if (ppNodes[i].GetChild())
361 ppNodes[i].GetChild()->Release(bSave);
363 ppNodes[i].GetChild().Clear();
365 aParent = NULL;
367 //------------------------------------------------------------------
368 void ONDXPage::ReleaseFull(BOOL bSave)
370 ONDXPagePtr aTempParent = aParent;
371 Release(bSave);
373 if (aTempParent.Is())
375 // Freigeben nicht benoetigter Seiten, danach besteht keine Referenz
376 // mehr auf die Seite, danach kann 'this' nicht mehr gueltig sein!!!
377 USHORT nParentPos = aTempParent->Search(this);
378 if (nParentPos != NODE_NOTFOUND)
379 (*aTempParent)[nParentPos].GetChild().Clear();
380 else
381 aTempParent->GetChild().Clear();
384 //------------------------------------------------------------------
385 BOOL ONDXPage::Delete(USHORT nNodePos)
387 if (IsLeaf())
389 // Letztes Element wird geloescht
390 if (nNodePos == (nCount - 1))
392 ONDXNode aNode = (*this)[nNodePos];
394 // beim Parent muss nun der KeyValue ausgetauscht werden
395 if (HasParent())
396 aParent->SearchAndReplace(aNode.GetKey(),
397 (*this)[nNodePos-1].GetKey());
401 // Loeschen des Knoten
402 Remove(nNodePos);
404 // Unterlauf
405 if (HasParent() && nCount < (rIndex.GetMaxNodes() / 2))
407 // Feststellen, welcher Knoten auf die Seite zeigt
408 USHORT nParentNodePos = aParent->Search(this);
409 // letzte Element auf Vaterseite
410 // -> zusammenlegen mit vorletzter Seite
411 if (nParentNodePos == (aParent->Count() - 1))
413 if (!nParentNodePos)
414 // zusammenlegen mit linken nachbarn
415 Merge(nParentNodePos,aParent->GetChild(&rIndex));
416 else
417 Merge(nParentNodePos,(*aParent)[nParentNodePos-1].GetChild(&rIndex,aParent));
419 // sonst Seite mit naechster Seite zusammenlegen
420 else
422 // zusammenlegen mit rechten nachbarn
423 Merge(nParentNodePos + 1,((*aParent)[nParentNodePos + 1].GetChild(&rIndex,aParent)));
424 nParentNodePos++;
426 if (HasParent() && !(*aParent)[nParentNodePos].HasChild())
427 aParent->Delete(nParentNodePos);
429 // letzte Element auf Vaterseite
430 // -> zusammenlegen mit vorletzter Seite
431 if (nParentNodePos == (aParent->Count() - 1))
433 if (!nParentNodePos)
434 // zusammenlegen mit linken nachbarn
435 Merge(nParentNodePos,aParent->GetChild(&rIndex));
436 else
437 Merge(nParentNodePos,(*aParent)[nParentNodePos-1].GetChild(&rIndex,aParent));
439 // sonst Seite mit naechster Seite zusammenlegen
440 else if(nParentNodePos != NODE_NOTFOUND)
442 // zusammenlegen mit rechten nachbarn
443 Merge(nParentNodePos + 1,((*aParent)[nParentNodePos + 1].GetChild(&rIndex,aParent)));
444 nParentNodePos++;
446 else // Sonderbehandlung
448 // Page ist aChild Page vom Parent => erste Page aus ppNodes an aChild anhaengen
449 Merge(0,(*aParent)[0].GetChild(&rIndex,aParent));
450 nParentNodePos = 0;
453 if (HasParent() && !(*aParent)[nParentNodePos].HasChild())
454 aParent->Delete(nParentNodePos);
458 else if (IsRoot())
459 // Sicherstellen das die Position der Wurzel festgehalten wird
460 rIndex.SetRootPos(nPagePos);
461 return TRUE;
465 //------------------------------------------------------------------
466 ONDXNode ONDXPage::Split(ONDXPage& rPage)
468 DBG_ASSERT(IsFull(), "Falsches Splitting");
469 /* Aufteilen einer Seite auf zwei
470 Blatt:
471 Seite 1 behaelt (n - (n/2))
472 Seite 2 erhaelt (n/2)
473 Knoten n/2 wird dupliziert
474 Innerer Knoten:
475 Seite 1 behaelt (n+1)/2
476 Seite 2 erhaelt (n/2-1)
477 Knoten ((n+1)/2 + 1) : wird herausgenommen
479 ONDXNode aResultNode;
480 if (IsLeaf())
482 for (USHORT i = (nCount - (nCount / 2)), j = 0 ; i < nCount; i++)
483 rPage.Insert(j++,(*this)[i]);
485 // dieser Knoten enthaelt einen Schluessel der noch einmal im Tree vorkommt
486 // und ersetzt werden muss
487 ONDXNode aLastNode = (*this)[nCount - 1];
488 nCount = nCount - (nCount / 2);
489 aResultNode = (*this)[nCount - 1];
491 if (HasParent())
492 aParent->SearchAndReplace(aLastNode.GetKey(),
493 aResultNode.GetKey());
495 else
497 for (USHORT i = (nCount + 1) / 2 + 1, j = 0 ; i < nCount; i++)
498 rPage.Insert(j++,(*this)[i]);
500 aResultNode = (*this)[(nCount + 1) / 2];
501 nCount = (nCount + 1) / 2;
503 // neue Seite zeigt nun auf Seite des herausgeloesten Knoten
504 rPage.SetChild(aResultNode.GetChild());
506 // Knoten zeigt auf neue Seite
507 aResultNode.SetChild(&rPage);
509 // innere Knoten haben keine Recordnummer
510 if (rIndex.isUnique())
511 aResultNode.GetKey().ResetRecord();
512 bModified = TRUE;
513 return aResultNode;
516 //------------------------------------------------------------------
517 void ONDXPage::Merge(USHORT nParentNodePos, ONDXPagePtr xPage)
519 DBG_ASSERT(HasParent(), "kein Vater vorhanden");
520 DBG_ASSERT(nParentNodePos != NODE_NOTFOUND, "Falscher Indexaufbau");
522 /* Zusammenlegen zweier Seiten */
523 ONDXNode aResultNode;
524 USHORT nMaxNodes = rIndex.GetMaxNodes(),
525 nMaxNodes_2 = nMaxNodes / 2;
527 // Feststellen ob Seite rechter oder linker Nachbar
528 BOOL bRight = ((*xPage)[0].GetKey() > (*this)[0].GetKey()); // TRUE, wenn xPage die rechte Seite ist
529 USHORT nNewCount = (*xPage).Count() + Count();
531 if (IsLeaf())
533 // Bedingung fuers zusammenlegen
534 if (nNewCount < (nMaxNodes_2 * 2))
536 USHORT nLastNode = bRight ? Count() - 1 : xPage->Count() - 1;
537 if (bRight)
539 DBG_ASSERT(&xPage != this,"xPage und THIS duerfen nicht gleich sein: Endlosschleife");
540 // alle Knoten aus xPage auf den linken Knoten verschieben (anhaengen)
541 while (xPage->Count())
543 Append((*xPage)[0]);
544 xPage->Remove(0);
547 else
549 DBG_ASSERT(&xPage != this,"xPage und THIS duerfen nicht gleich sein: Endlosschleife");
550 // xPage ist die linke Page und THIS die rechte
551 while (xPage->Count())
553 Insert(0,(*xPage)[xPage->Count()-1]);
554 xPage->Remove(xPage->Count()-1);
556 // alte Position von xPage beim Parent mit this ersetzen
557 if (nParentNodePos)
558 (*aParent)[nParentNodePos-1].SetChild(this,aParent);
559 else // oder als rechten Knoten setzen
560 aParent->SetChild(this);
561 aParent->SetModified(TRUE);
565 // Child beziehung beim Vaterknoten aufheben
566 (*aParent)[nParentNodePos].SetChild();
567 // Austauschen des KnotenWertes, nur wenn geaenderte Page
568 // die linke ist, ansonsten werde
570 if(aParent->IsRoot() && aParent->Count() == 1)
572 (*aParent)[0].SetChild();
573 aParent->ReleaseFull();
574 aParent = NULL;
575 rIndex.SetRootPos(nPagePos);
576 rIndex.m_aRoot = this;
577 SetModified(TRUE);
579 else
580 aParent->SearchAndReplace((*this)[nLastNode].GetKey(),(*this)[nCount-1].GetKey());
582 xPage->SetModified(FALSE);
583 xPage->ReleaseFull(); // wird nicht mehr benoetigt
585 // Ausgleichen der Elemente nNewCount >= (nMaxNodes_2 * 2)
586 else
588 if (bRight)
590 // alle Knoten aus xPage auf den linken Knoten verschieben (anhaengen)
591 ONDXNode aReplaceNode = (*this)[nCount - 1];
592 while (nCount < nMaxNodes_2)
594 Append((*xPage)[0]);
595 xPage->Remove(0);
597 // Austauschen des KnotenWertes: Setzt alten letzten Wert durch den letzten von xPage
598 aParent->SearchAndReplace(aReplaceNode.GetKey(),(*this)[nCount-1].GetKey());
600 else
602 // alle Knoten aus this vor die xPage Knoten einfuegen
603 ONDXNode aReplaceNode = (*this)[nCount - 1];
604 while (xPage->Count() < nMaxNodes_2)
606 xPage->Insert(0,(*this)[nCount-1]);
607 Remove(nCount-1);
609 // Austauschen des KnotenWertes
610 aParent->SearchAndReplace(aReplaceNode.GetKey(),(*this)[Count()-1].GetKey());
614 else // !IsLeaf()
616 // Bedingung fuers zusammenlegen
617 if (nNewCount < nMaxNodes_2 * 2)
619 if (bRight)
621 DBG_ASSERT(&xPage != this,"xPage und THIS duerfen nicht gleich sein: Endlosschleife");
622 // Vaterknoten wird mit integriert
623 // erhaelt zunaechst Child von xPage
624 (*aParent)[nParentNodePos].SetChild(xPage->GetChild(),aParent);
625 Append((*aParent)[nParentNodePos]);
626 for (USHORT i = 0 ; i < xPage->Count(); i++)
627 Append((*xPage)[i]);
629 else
631 DBG_ASSERT(&xPage != this,"xPage und THIS duerfen nicht gleich sein: Endlosschleife");
632 // Vaterknoten wird mit integriert
633 // erhaelt zunaechst Child
634 (*aParent)[nParentNodePos].SetChild(GetChild(),aParent); // Parent merkt sich mein Child
635 Insert(0,(*aParent)[nParentNodePos]); // Node vom Parent bei mir einfuegen
636 while (xPage->Count())
638 Insert(0,(*xPage)[xPage->Count()-1]);
639 xPage->Remove(xPage->Count()-1);
641 SetChild(xPage->GetChild());
643 if (nParentNodePos)
644 (*aParent)[nParentNodePos-1].SetChild(this,aParent);
645 else
646 aParent->SetChild(this);
649 // danach wird der Vaterknoten zurueckgesetzt
650 (*aParent)[nParentNodePos].SetChild();
651 aParent->SetModified(TRUE);
653 if(aParent->IsRoot() && aParent->Count() == 1)
655 (*aParent).SetChild();
656 aParent->ReleaseFull();
657 aParent = NULL;
658 rIndex.SetRootPos(nPagePos);
659 rIndex.m_aRoot = this;
660 SetModified(TRUE);
662 else if(nParentNodePos)
663 // Austauschen des KnotenWertes
664 // beim Append wird der Bereich erweitert, beim INsert verweist der alte Knoten von xPage auf this
665 // deshalb muss der Knoten auch hier aktualisiert werden
666 aParent->SearchAndReplace((*aParent)[nParentNodePos-1].GetKey(),(*aParent)[nParentNodePos].GetKey());
668 xPage->SetModified(FALSE);
669 xPage->ReleaseFull();
671 // Ausgleichen der Elemente
672 else
674 if (bRight)
676 while (nCount < nMaxNodes_2)
678 (*aParent)[nParentNodePos].SetChild(xPage->GetChild(),aParent);
679 Append((*aParent)[nParentNodePos]);
680 (*aParent)[nParentNodePos] = (*xPage)[0];
681 xPage->Remove(0);
683 xPage->SetChild((*aParent)[nParentNodePos].GetChild());
684 (*aParent)[nParentNodePos].SetChild(xPage,aParent);
686 else
688 while (nCount < nMaxNodes_2)
690 (*aParent)[nParentNodePos].SetChild(GetChild(),aParent);
691 Insert(0,(*aParent)[nParentNodePos]);
692 (*aParent)[nParentNodePos] = (*xPage)[xPage->Count()-1];
693 xPage->Remove(xPage->Count()-1);
695 SetChild((*aParent)[nParentNodePos].GetChild());
696 (*aParent)[nParentNodePos].SetChild(this,aParent);
699 aParent->SetModified(TRUE);
703 //==================================================================
704 // ONDXNode
705 //==================================================================
707 //------------------------------------------------------------------
708 void ONDXNode::Read(SvStream &rStream, ODbaseIndex& rIndex)
710 rStream >> aKey.nRecord; // schluessel
712 if (rIndex.getHeader().db_keytype)
714 double aDbl;
715 rStream >> aDbl;
716 aKey = ONDXKey(aDbl,aKey.nRecord);
718 else
720 ByteString aBuf;
721 USHORT nLen = rIndex.getHeader().db_keylen;
722 char* pStr = aBuf.AllocBuffer(nLen+1);
724 rStream.Read(pStr,nLen);
725 pStr[nLen] = 0;
726 aBuf.ReleaseBufferAccess();
727 aBuf.EraseTrailingChars();
729 // aKey = ONDXKey((aBuf,rIndex.GetDBFConnection()->GetCharacterSet()) ,aKey.nRecord);
730 aKey = ONDXKey(::rtl::OUString(aBuf.GetBuffer(),aBuf.Len(),rIndex.m_pTable->getConnection()->getTextEncoding()) ,aKey.nRecord);
732 rStream >> aChild;
735 union NodeData
737 double aDbl;
738 char aData[128];
739 } aNodeData;
740 //------------------------------------------------------------------
741 void ONDXNode::Write(SvStream &rStream, const ONDXPage& rPage) const
743 const ODbaseIndex& rIndex = rPage.GetIndex();
744 if (!rIndex.isUnique() || rPage.IsLeaf())
745 rStream << (sal_uInt32)aKey.nRecord; // schluessel
746 else
747 rStream << (sal_uInt32)0; // schluessel
749 if (rIndex.getHeader().db_keytype) // double
751 if (aKey.getValue().isNull())
753 memset(aNodeData.aData,0,rIndex.getHeader().db_keylen);
754 rStream.Write((BYTE*)aNodeData.aData,rIndex.getHeader().db_keylen);
756 else
757 rStream << (double) aKey.getValue();
759 else
761 memset(aNodeData.aData,0x20,rIndex.getHeader().db_keylen);
762 if (!aKey.getValue().isNull())
764 ::rtl::OUString sValue = aKey.getValue();
765 ByteString aText(sValue.getStr(), rIndex.m_pTable->getConnection()->getTextEncoding());
766 strncpy(aNodeData.aData,aText.GetBuffer(),std::min(rIndex.getHeader().db_keylen, aText.Len()));
768 rStream.Write((BYTE*)aNodeData.aData,rIndex.getHeader().db_keylen);
770 rStream << aChild;
774 //------------------------------------------------------------------
775 ONDXPagePtr& ONDXNode::GetChild(ODbaseIndex* pIndex, ONDXPage* pParent)
777 if (!aChild.Is() && pIndex)
779 aChild = pIndex->CreatePage(aChild.GetPagePos(),pParent,aChild.HasPage());
781 return aChild;
784 //==================================================================
785 // ONDXKey
786 //==================================================================
787 //------------------------------------------------------------------
788 BOOL ONDXKey::IsText(sal_Int32 eType)
790 return eType == DataType::VARCHAR || eType == DataType::CHAR;
793 //------------------------------------------------------------------
794 StringCompare ONDXKey::Compare(const ONDXKey& rKey) const
796 // DBG_ASSERT(is(), "Falscher Indexzugriff");
797 StringCompare eResult;
799 if (getValue().isNull())
801 if (rKey.getValue().isNull() || (rKey.IsText(getDBType()) && !rKey.getValue().getString().getLength()))
802 eResult = COMPARE_EQUAL;
803 else
804 eResult = COMPARE_LESS;
806 else if (rKey.getValue().isNull())
808 if (getValue().isNull() || (IsText(getDBType()) && !getValue().getString().getLength()))
809 eResult = COMPARE_EQUAL;
810 else
811 eResult = COMPARE_GREATER;
813 else if (IsText(getDBType()))
815 INT32 nRes = getValue().getString().compareTo(rKey.getValue());
816 eResult = (nRes > 0) ? COMPARE_GREATER : (nRes == 0) ? COMPARE_EQUAL : COMPARE_LESS;
818 else
820 double m = getValue(),n = rKey.getValue();
821 eResult = (m > n) ? COMPARE_GREATER : (n == m) ? COMPARE_EQUAL : COMPARE_LESS;
824 // Record vergleich, wenn Index !Unique
825 if (eResult == COMPARE_EQUAL && nRecord && rKey.nRecord)
826 eResult = (nRecord > rKey.nRecord) ? COMPARE_GREATER :
827 (nRecord == rKey.nRecord) ? COMPARE_EQUAL : COMPARE_LESS;
829 return eResult;
831 // -----------------------------------------------------------------------------
832 void ONDXKey::setValue(const ORowSetValue& _rVal)
834 xValue = _rVal;
836 // -----------------------------------------------------------------------------
837 const ORowSetValue& ONDXKey::getValue() const
839 return xValue;
841 // -----------------------------------------------------------------------------
842 SvStream& connectivity::dbase::operator >> (SvStream &rStream, ONDXPagePtr& rPage)
844 rStream >> rPage.nPagePos;
845 return rStream;
847 // -----------------------------------------------------------------------------
848 SvStream& connectivity::dbase::operator << (SvStream &rStream, const ONDXPagePtr& rPage)
850 rStream << rPage.nPagePos;
851 return rStream;
853 // -----------------------------------------------------------------------------
854 //==================================================================
855 // ONDXPagePtr
856 //==================================================================
857 //------------------------------------------------------------------
858 ONDXPagePtr::ONDXPagePtr(const ONDXPagePtr& rRef)
859 :ONDXPageRef(rRef)
860 ,nPagePos(rRef.nPagePos)
864 //------------------------------------------------------------------
865 ONDXPagePtr::ONDXPagePtr(ONDXPage* pRefPage)
866 :ONDXPageRef(pRefPage)
867 ,nPagePos(0)
869 if (pRefPage)
870 nPagePos = pRefPage->GetPagePos();
872 //------------------------------------------------------------------
873 ONDXPagePtr& ONDXPagePtr::operator=(const ONDXPagePtr& rRef)
875 ONDXPageRef::operator=(rRef);
876 nPagePos = rRef.nPagePos;
877 return *this;
880 //------------------------------------------------------------------
881 ONDXPagePtr& ONDXPagePtr::operator= (ONDXPage* pRef)
883 ONDXPageRef::operator=(pRef);
884 nPagePos = (pRef) ? pRef->GetPagePos() : 0;
885 return *this;
887 // -----------------------------------------------------------------------------
888 static UINT32 nValue;
889 //------------------------------------------------------------------
890 SvStream& connectivity::dbase::operator >> (SvStream &rStream, ONDXPage& rPage)
892 rStream.Seek(rPage.GetPagePos() * PAGE_SIZE);
893 rStream >> nValue >> rPage.aChild;
894 rPage.nCount = USHORT(nValue);
896 // DBG_ASSERT(rPage.nCount && rPage.nCount < rPage.GetIndex().GetMaxNodes(), "Falscher Count");
897 for (USHORT i = 0; i < rPage.nCount; i++)
898 rPage[i].Read(rStream, rPage.GetIndex());
899 return rStream;
902 //------------------------------------------------------------------
903 SvStream& connectivity::dbase::operator << (SvStream &rStream, const ONDXPage& rPage)
905 // Seite existiert noch nicht
906 ULONG nSize = (rPage.GetPagePos() + 1) * PAGE_SIZE;
907 if (nSize > rStream.Seek(STREAM_SEEK_TO_END))
909 rStream.SetStreamSize(nSize);
910 rStream.Seek(rPage.GetPagePos() * PAGE_SIZE);
912 char aEmptyData[PAGE_SIZE];
913 memset(aEmptyData,0x00,PAGE_SIZE);
914 rStream.Write((BYTE*)aEmptyData,PAGE_SIZE);
916 ULONG nCurrentPos = rStream.Seek(rPage.GetPagePos() * PAGE_SIZE);
917 OSL_UNUSED( nCurrentPos );
919 nValue = rPage.nCount;
920 rStream << nValue << rPage.aChild;
922 USHORT i = 0;
923 for (; i < rPage.nCount; i++)
924 rPage[i].Write(rStream, rPage);
926 // check if we have to fill the stream with '\0'
927 if(i < rPage.rIndex.getHeader().db_maxkeys)
929 ULONG nTell = rStream.Tell() % PAGE_SIZE;
930 USHORT nBufferSize = rStream.GetBufferSize();
931 ULONG nRemainSize = nBufferSize - nTell;
932 char* pEmptyData = new char[nRemainSize];
933 memset(pEmptyData,0x00,nRemainSize);
934 rStream.Write((BYTE*)pEmptyData,nRemainSize);
935 rStream.Seek(nTell);
936 delete [] pEmptyData;
938 return rStream;
940 // -----------------------------------------------------------------------------
941 #if OSL_DEBUG_LEVEL > 1
942 //------------------------------------------------------------------
943 void ONDXPage::PrintPage()
945 DBG_TRACE4("\nSDB: -----------Page: %d Parent: %d Count: %d Child: %d-----",
946 nPagePos, HasParent() ? aParent->GetPagePos() : 0 ,nCount, aChild.GetPagePos());
948 for (USHORT i = 0; i < nCount; i++)
950 ONDXNode rNode = (*this)[i];
951 ONDXKey& rKey = rNode.GetKey();
952 if (!IsLeaf())
953 rNode.GetChild(&rIndex, this);
955 if (rKey.getValue().isNull())
957 DBG_TRACE2("SDB: [%d,NULL,%d]",rKey.GetRecord(), rNode.GetChild().GetPagePos());
959 else if (rIndex.getHeader().db_keytype)
961 DBG_TRACE3("SDB: [%d,%f,%d]",rKey.GetRecord(), rKey.getValue().getDouble(),rNode.GetChild().GetPagePos());
963 else
965 DBG_TRACE3("SDB: [%d,%s,%d]",rKey.GetRecord(), (const char* )ByteString(rKey.getValue().getString().getStr(), rIndex.m_pTable->getConnection()->getTextEncoding()).GetBuffer(),rNode.GetChild().GetPagePos());
968 DBG_TRACE("SDB: -----------------------------------------------\n");
969 if (!IsLeaf())
971 #if OSL_DEBUG_LEVEL > 1
972 GetChild(&rIndex)->PrintPage();
973 for (USHORT i = 0; i < nCount; i++)
975 ONDXNode rNode = (*this)[i];
976 rNode.GetChild(&rIndex,this)->PrintPage();
978 #endif
980 DBG_TRACE("SDB: ===============================================\n");
982 #endif
983 // -----------------------------------------------------------------------------
984 BOOL ONDXPage::IsFull() const
986 return Count() == rIndex.getHeader().db_maxkeys;
988 // -----------------------------------------------------------------------------
989 //------------------------------------------------------------------
990 USHORT ONDXPage::Search(const ONDXKey& rSearch)
992 // binare Suche spaeter
993 USHORT i = NODE_NOTFOUND;
994 while (++i < Count())
995 if ((*this)[i].GetKey() == rSearch)
996 break;
998 return (i < Count()) ? i : NODE_NOTFOUND;
1001 //------------------------------------------------------------------
1002 USHORT ONDXPage::Search(const ONDXPage* pPage)
1004 USHORT i = NODE_NOTFOUND;
1005 while (++i < Count())
1006 if (((*this)[i]).GetChild() == pPage)
1007 break;
1009 // wenn nicht gefunden, dann wird davon ausgegangen, dass die Seite selbst
1010 // auf die Page zeigt
1011 return (i < Count()) ? i : NODE_NOTFOUND;
1013 // -----------------------------------------------------------------------------
1014 // laeuft rekursiv
1015 void ONDXPage::SearchAndReplace(const ONDXKey& rSearch,
1016 ONDXKey& rReplace)
1018 OSL_ENSURE(rSearch != rReplace,"Invalid here:rSearch == rReplace");
1019 if (rSearch != rReplace)
1021 USHORT nPos = NODE_NOTFOUND;
1022 ONDXPage* pPage = this;
1024 while (pPage && (nPos = pPage->Search(rSearch)) == NODE_NOTFOUND)
1025 pPage = pPage->aParent;
1027 if (pPage)
1029 (*pPage)[nPos].GetKey() = rReplace;
1030 pPage->SetModified(TRUE);
1034 // -----------------------------------------------------------------------------
1035 ONDXNode& ONDXPage::operator[] (USHORT nPos)
1037 DBG_ASSERT(nCount > nPos, "falscher Indexzugriff");
1038 return ppNodes[nPos];
1041 //------------------------------------------------------------------
1042 const ONDXNode& ONDXPage::operator[] (USHORT nPos) const
1044 DBG_ASSERT(nCount > nPos, "falscher Indexzugriff");
1045 return ppNodes[nPos];
1047 // -----------------------------------------------------------------------------
1048 void ONDXPage::Remove(USHORT nPos)
1050 DBG_ASSERT(nCount > nPos, "falscher Indexzugriff");
1052 for (USHORT i = nPos; i < (nCount-1); i++)
1053 (*this)[i] = (*this)[i+1];
1055 nCount--;
1056 bModified = TRUE;
1058 // -----------------------------------------------------------------------------