1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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"
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
)
52 // -----------------------------------------------------------------------------
53 ONDXKey::ONDXKey(const ORowSetValue
& rVal
, sal_Int32 eType
, UINT32 nRec
)
59 // -----------------------------------------------------------------------------
60 ONDXKey::ONDXKey(const rtl::OUString
& aStr
, UINT32 nRec
)
61 : ONDXKey_BASE(::com::sun::star::sdbc::DataType::VARCHAR
)
67 xValue
.setBound(sal_True
);
70 // -----------------------------------------------------------------------------
72 ONDXKey::ONDXKey(double aVal
, UINT32 nRec
)
73 : ONDXKey_BASE(::com::sun::star::sdbc::DataType::DOUBLE
)
78 // -----------------------------------------------------------------------------
80 //==================================================================
82 //==================================================================
83 ONDXPage::ONDXPage(ODbaseIndex
& rInd
, sal_uInt32 nPos
, ONDXPage
* pParent
)
91 sal_uInt16 nT
= rIndex
.getHeader().db_maxkeys
;
92 ppNodes
= new ONDXNode
[nT
];
95 //------------------------------------------------------------------
102 //------------------------------------------------------------------
103 void ONDXPage::QueryDelete()
105 // Ablegen im GarbageCollector
106 if (IsModified() && rIndex
.m_pFileStream
)
107 (*rIndex
.m_pFileStream
) << *this;
110 if (rIndex
.UseCollector())
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();
126 rIndex
.Collect(this);
129 SvRefBase::QueryDelete();
131 //------------------------------------------------------------------
132 ONDXPagePtr
& ONDXPage::GetChild(ODbaseIndex
* pIndex
)
134 if (!aChild
.Is() && pIndex
)
136 aChild
= rIndex
.CreatePage(aChild
.GetPagePos(),this,aChild
.HasPage());
141 //------------------------------------------------------------------
142 USHORT
ONDXPage::FindPos(const ONDXKey
& rKey
) const
144 // sucht nach Platz fuer den vorgegeben key auf einer Seite
146 while (i
< nCount
&& rKey
> ((*this)[i
]).GetKey())
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
161 while (i
< nCount
&& rKey
> ((*this)[i
]).GetKey())
164 BOOL bResult
= FALSE
;
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;
180 bResult
= rKey
== ((*this)[i
]).GetKey();
181 rIndex
.m_aCurLeaf
= this;
182 rIndex
.m_nCurNode
= bResult
? i
: i
- 1;
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;
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
234 sal_uInt32 nNewPagePos
= rIndex
.GetPageCount();
235 sal_uInt32 nNewPageCount
= nNewPagePos
+ 1;
237 // Herausgeloesten Knoten beim Vater einfuegen
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
257 if (!IsLeaf() || nRowsLeft
< (sal_uInt32
)(rIndex
.GetMaxNodes() / 2))
258 aInnerNode
= Split(*aNewPage
);
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
273 aNewPage
->SetChild(aInnerNode
.GetChild());
276 aNewPage
->Append(aSplitNode
);
277 ONDXPagePtr aTempParent
= aParent
;
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!!!
288 // Einfuegen des herausgeloesten Knotens
289 return aTempParent
->Insert(aInnerNode
);
291 else // Seite einfach weiter auffuellen
296 rIndex
.m_nCurNode
= nCount
- 1;
297 return Append(rNode
);
301 USHORT nNodePos
= FindPos(rNode
.GetKey());
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
)
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];
325 if (nCount
< nMaxCount
)
328 // einfuegen an der Position
329 ONDXNode
& rInsertNode
= (*this)[nPos
];
331 if (rInsertNode
.GetChild().Is())
333 rInsertNode
.GetChild()->SetParent(this);
334 rNode
.GetChild()->SetParent(this);
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
353 aChild
->Release(bSave
);
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();
367 //------------------------------------------------------------------
368 void ONDXPage::ReleaseFull(BOOL bSave
)
370 ONDXPagePtr aTempParent
= aParent
;
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();
381 aTempParent
->GetChild().Clear();
384 //------------------------------------------------------------------
385 BOOL
ONDXPage::Delete(USHORT nNodePos
)
389 // Letztes Element wird geloescht
390 if (nNodePos
== (nCount
- 1))
392 ONDXNode aNode
= (*this)[nNodePos
];
394 // beim Parent muss nun der KeyValue ausgetauscht werden
396 aParent
->SearchAndReplace(aNode
.GetKey(),
397 (*this)[nNodePos
-1].GetKey());
401 // Loeschen des Knoten
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))
414 // zusammenlegen mit linken nachbarn
415 Merge(nParentNodePos
,aParent
->GetChild(&rIndex
));
417 Merge(nParentNodePos
,(*aParent
)[nParentNodePos
-1].GetChild(&rIndex
,aParent
));
419 // sonst Seite mit naechster Seite zusammenlegen
422 // zusammenlegen mit rechten nachbarn
423 Merge(nParentNodePos
+ 1,((*aParent
)[nParentNodePos
+ 1].GetChild(&rIndex
,aParent
)));
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))
434 // zusammenlegen mit linken nachbarn
435 Merge(nParentNodePos,aParent->GetChild(&rIndex));
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)));
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));
453 if (HasParent() && !(*aParent)[nParentNodePos].HasChild())
454 aParent->Delete(nParentNodePos);
459 // Sicherstellen das die Position der Wurzel festgehalten wird
460 rIndex
.SetRootPos(nPagePos
);
465 //------------------------------------------------------------------
466 ONDXNode
ONDXPage::Split(ONDXPage
& rPage
)
468 DBG_ASSERT(IsFull(), "Falsches Splitting");
469 /* Aufteilen einer Seite auf zwei
471 Seite 1 behaelt (n - (n/2))
472 Seite 2 erhaelt (n/2)
473 Knoten n/2 wird dupliziert
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
;
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];
492 aParent
->SearchAndReplace(aLastNode
.GetKey(),
493 aResultNode
.GetKey());
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();
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();
533 // Bedingung fuers zusammenlegen
534 if (nNewCount
< (nMaxNodes_2
* 2))
536 USHORT nLastNode
= bRight
? Count() - 1 : xPage
->Count() - 1;
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())
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
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();
575 rIndex
.SetRootPos(nPagePos
);
576 rIndex
.m_aRoot
= this;
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)
590 // alle Knoten aus xPage auf den linken Knoten verschieben (anhaengen)
591 ONDXNode aReplaceNode
= (*this)[nCount
- 1];
592 while (nCount
< nMaxNodes_2
)
597 // Austauschen des KnotenWertes: Setzt alten letzten Wert durch den letzten von xPage
598 aParent
->SearchAndReplace(aReplaceNode
.GetKey(),(*this)[nCount
-1].GetKey());
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]);
609 // Austauschen des KnotenWertes
610 aParent
->SearchAndReplace(aReplaceNode
.GetKey(),(*this)[Count()-1].GetKey());
616 // Bedingung fuers zusammenlegen
617 if (nNewCount
< nMaxNodes_2
* 2)
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
++)
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());
644 (*aParent
)[nParentNodePos
-1].SetChild(this,aParent
);
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();
658 rIndex
.SetRootPos(nPagePos
);
659 rIndex
.m_aRoot
= this;
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
676 while (nCount
< nMaxNodes_2
)
678 (*aParent
)[nParentNodePos
].SetChild(xPage
->GetChild(),aParent
);
679 Append((*aParent
)[nParentNodePos
]);
680 (*aParent
)[nParentNodePos
] = (*xPage
)[0];
683 xPage
->SetChild((*aParent
)[nParentNodePos
].GetChild());
684 (*aParent
)[nParentNodePos
].SetChild(xPage
,aParent
);
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 //==================================================================
705 //==================================================================
707 //------------------------------------------------------------------
708 void ONDXNode::Read(SvStream
&rStream
, ODbaseIndex
& rIndex
)
710 rStream
>> aKey
.nRecord
; // schluessel
712 if (rIndex
.getHeader().db_keytype
)
716 aKey
= ONDXKey(aDbl
,aKey
.nRecord
);
721 USHORT nLen
= rIndex
.getHeader().db_keylen
;
722 char* pStr
= aBuf
.AllocBuffer(nLen
+1);
724 rStream
.Read(pStr
,nLen
);
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
);
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
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
);
757 rStream
<< (double) aKey
.getValue();
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
);
774 //------------------------------------------------------------------
775 ONDXPagePtr
& ONDXNode::GetChild(ODbaseIndex
* pIndex
, ONDXPage
* pParent
)
777 if (!aChild
.Is() && pIndex
)
779 aChild
= pIndex
->CreatePage(aChild
.GetPagePos(),pParent
,aChild
.HasPage());
784 //==================================================================
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
;
804 eResult
= COMPARE_LESS
;
806 else if (rKey
.getValue().isNull())
808 if (getValue().isNull() || (IsText(getDBType()) && !getValue().getString().getLength()))
809 eResult
= COMPARE_EQUAL
;
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
;
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
;
831 // -----------------------------------------------------------------------------
832 void ONDXKey::setValue(const ORowSetValue
& _rVal
)
836 // -----------------------------------------------------------------------------
837 const ORowSetValue
& ONDXKey::getValue() const
841 // -----------------------------------------------------------------------------
842 SvStream
& connectivity::dbase::operator >> (SvStream
&rStream
, ONDXPagePtr
& rPage
)
844 rStream
>> rPage
.nPagePos
;
847 // -----------------------------------------------------------------------------
848 SvStream
& connectivity::dbase::operator << (SvStream
&rStream
, const ONDXPagePtr
& rPage
)
850 rStream
<< rPage
.nPagePos
;
853 // -----------------------------------------------------------------------------
854 //==================================================================
856 //==================================================================
857 //------------------------------------------------------------------
858 ONDXPagePtr::ONDXPagePtr(const ONDXPagePtr
& rRef
)
860 ,nPagePos(rRef
.nPagePos
)
864 //------------------------------------------------------------------
865 ONDXPagePtr::ONDXPagePtr(ONDXPage
* pRefPage
)
866 :ONDXPageRef(pRefPage
)
870 nPagePos
= pRefPage
->GetPagePos();
872 //------------------------------------------------------------------
873 ONDXPagePtr
& ONDXPagePtr::operator=(const ONDXPagePtr
& rRef
)
875 ONDXPageRef::operator=(rRef
);
876 nPagePos
= rRef
.nPagePos
;
880 //------------------------------------------------------------------
881 ONDXPagePtr
& ONDXPagePtr::operator= (ONDXPage
* pRef
)
883 ONDXPageRef::operator=(pRef
);
884 nPagePos
= (pRef
) ? pRef
->GetPagePos() : 0;
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());
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
;
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
);
936 delete [] pEmptyData
;
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();
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());
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");
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();
980 DBG_TRACE("SDB: ===============================================\n");
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
)
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
)
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 // -----------------------------------------------------------------------------
1015 void ONDXPage::SearchAndReplace(const ONDXKey
& rSearch
,
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
;
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];
1058 // -----------------------------------------------------------------------------