xref: /AOO41X/main/connectivity/source/drivers/dbase/dindexnode.cxx (revision 9b5730f6ddef7eb82608ca4d31dc0d7678e652cf)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_connectivity.hxx"
26 #include "dbase/dindexnode.hxx"
27 #include "connectivity/CommonTools.hxx"
28 #include <osl/thread.h>
29 #include "dbase/DIndex.hxx"
30 #include <tools/debug.hxx>
31 #include "diagnose_ex.h"
32 
33 #include <algorithm>
34 
35 
36 using namespace connectivity;
37 using namespace connectivity::dbase;
38 using namespace connectivity::file;
39 using namespace com::sun::star::sdbc;
40 // -----------------------------------------------------------------------------
ONDXKey(sal_uInt32 nRec)41 ONDXKey::ONDXKey(sal_uInt32 nRec)
42     :nRecord(nRec)
43 {
44 }
45 // -----------------------------------------------------------------------------
ONDXKey(const ORowSetValue & rVal,sal_Int32 eType,sal_uInt32 nRec)46 ONDXKey::ONDXKey(const ORowSetValue& rVal, sal_Int32 eType, sal_uInt32 nRec)
47     : ONDXKey_BASE(eType)
48     , nRecord(nRec)
49     , xValue(rVal)
50 {
51 }
52 // -----------------------------------------------------------------------------
ONDXKey(const rtl::OUString & aStr,sal_uInt32 nRec)53 ONDXKey::ONDXKey(const rtl::OUString& aStr, sal_uInt32 nRec)
54     : ONDXKey_BASE(::com::sun::star::sdbc::DataType::VARCHAR)
55      ,nRecord(nRec)
56 {
57     if (aStr.getLength())
58     {
59         xValue = aStr;
60         xValue.setBound(sal_True);
61     }
62 }
63 // -----------------------------------------------------------------------------
64 
ONDXKey(double aVal,sal_uInt32 nRec)65 ONDXKey::ONDXKey(double aVal, sal_uInt32 nRec)
66     : ONDXKey_BASE(::com::sun::star::sdbc::DataType::DOUBLE)
67      ,nRecord(nRec)
68      ,xValue(aVal)
69 {
70 }
71 // -----------------------------------------------------------------------------
72 
73 //==================================================================
74 // Index Seite
75 //==================================================================
ONDXPage(ODbaseIndex & rInd,sal_uInt32 nPos,ONDXPage * pParent)76 ONDXPage::ONDXPage(ODbaseIndex& rInd, sal_uInt32 nPos, ONDXPage* pParent)
77            :nPagePos(nPos)
78            ,bModified(sal_False)
79            ,nCount(0)
80            ,aParent(pParent)
81            ,rIndex(rInd)
82            ,ppNodes(NULL)
83 {
84     sal_uInt16 nT = rIndex.getHeader().db_maxkeys;
85     ppNodes = new ONDXNode[nT];
86 }
87 
88 //------------------------------------------------------------------
~ONDXPage()89 ONDXPage::~ONDXPage()
90 {
91     delete[] ppNodes;
92     //  delete aParent;
93     //  delete aChild;
94 }
95 //------------------------------------------------------------------
QueryDelete()96 void ONDXPage::QueryDelete()
97 {
98     // Ablegen im GarbageCollector
99     if (IsModified() && rIndex.m_pFileStream)
100         (*rIndex.m_pFileStream) << *this;
101 
102     bModified = sal_False;
103     if (rIndex.UseCollector())
104     {
105         if (aChild.Is())
106             aChild->Release(sal_False);
107 
108         for (sal_uInt16 i = 0; i < rIndex.getHeader().db_maxkeys;i++)
109         {
110             if (ppNodes[i].GetChild().Is())
111                 ppNodes[i].GetChild()->Release(sal_False);
112 
113             ppNodes[i] = ONDXNode();
114         }
115         RestoreNoDelete();
116 
117         nCount = 0;
118         aParent.Clear();
119         rIndex.Collect(this);
120     }
121     else
122         SvRefBase::QueryDelete();
123 }
124 //------------------------------------------------------------------
GetChild(ODbaseIndex * pIndex)125 ONDXPagePtr& ONDXPage::GetChild(ODbaseIndex* pIndex)
126 {
127     if (!aChild.Is() && pIndex)
128     {
129         aChild = rIndex.CreatePage(aChild.GetPagePos(),this,aChild.HasPage());
130     }
131     return aChild;
132 }
133 
134 //------------------------------------------------------------------
FindPos(const ONDXKey & rKey) const135 sal_uInt16 ONDXPage::FindPos(const ONDXKey& rKey) const
136 {
137     // sucht nach Platz fuer den vorgegeben key auf einer Seite
138     sal_uInt16 i = 0;
139     while (i < nCount && rKey > ((*this)[i]).GetKey())
140            i++;
141 
142     return i;
143 }
144 
145 //------------------------------------------------------------------
Find(const ONDXKey & rKey)146 sal_Bool ONDXPage::Find(const ONDXKey& rKey)
147 {
148     // sucht den vorgegeben key
149     // Besonderheit: gelangt der Algorithmus ans Ende
150     // wird immer die aktuelle Seite und die Knotenposition vermerkt
151     // auf die die Bedingung <= zutrifft
152     // dieses findet beim Insert besondere Beachtung
153     sal_uInt16 i = 0;
154     while (i < nCount && rKey > ((*this)[i]).GetKey())
155            i++;
156 
157     sal_Bool bResult = sal_False;
158 
159     if (!IsLeaf())
160     {
161         // weiter absteigen
162         ONDXPagePtr aPage = (i==0) ? GetChild(&rIndex) : ((*this)[i-1]).GetChild(&rIndex, this);
163         bResult = aPage.Is() && aPage->Find(rKey);
164     }
165     else if (i == nCount)
166     {
167         rIndex.m_aCurLeaf = this;
168         rIndex.m_nCurNode = i - 1;
169         bResult = sal_False;
170     }
171     else
172     {
173         bResult = rKey == ((*this)[i]).GetKey();
174         rIndex.m_aCurLeaf = this;
175         rIndex.m_nCurNode = bResult ? i : i - 1;
176     }
177     return bResult;
178 }
179 
180 //------------------------------------------------------------------
Insert(ONDXNode & rNode,sal_uInt32 nRowsLeft)181 sal_Bool ONDXPage::Insert(ONDXNode& rNode, sal_uInt32 nRowsLeft)
182 {
183     // beim Erzeugen eines Index koennen auch mehrere Knoten eingefuegt werden
184     // diese sin dann aufsteigend sortiert
185     sal_Bool bAppend = nRowsLeft > 0;
186     if (IsFull())
187     {
188         sal_Bool bResult = sal_True;
189         ONDXNode aSplitNode;
190         if (bAppend)
191             aSplitNode = rNode;
192         else
193         {
194             // merken des letzten Knotens
195             aSplitNode = (*this)[nCount-1];
196             if(rNode.GetKey() <= aSplitNode.GetKey())
197             {
198 
199                 // und damit habe ich im folgenden praktisch eine Node weniger
200                 if (IsLeaf() && this == &rIndex.m_aCurLeaf)
201                 {
202                     // geht davon aus, dass der Knoten, auf dem die Bedingung (<=)
203                     // zutrifft, als m_nCurNode gesetzt ist
204                     --nCount;   // (sonst bekomme ich u.U. Assertions und GPFs - 60593)
205                     bResult = Insert(rIndex.m_nCurNode + 1, rNode);
206                 }
207                 else  // Position unbekannt
208                 {
209                     sal_uInt16 nPos = NODE_NOTFOUND;
210                     while (++nPos < nCount && rNode.GetKey() > ((*this)[nPos]).GetKey()) ;
211 
212                     --nCount;   // (sonst bekomme ich u.U. Assertions und GPFs - 60593)
213                     bResult = Insert(nPos, rNode);
214                 }
215 
216                 // konnte der neue Knoten eingefuegt werden
217                 if (!bResult)
218                 {
219                     nCount++;
220                     aSplitNode = rNode;
221                 }
222             }
223             else
224                 aSplitNode = rNode;
225         }
226 
227         sal_uInt32 nNewPagePos = rIndex.GetPageCount();
228         sal_uInt32 nNewPageCount = nNewPagePos + 1;
229 
230         // Herausgeloesten Knoten beim Vater einfuegen
231         if (!HasParent())
232         {
233             // Kein Vater, dann neue Wurzel
234             ONDXPagePtr aNewRoot = rIndex.CreatePage(nNewPagePos + 1);
235             aNewRoot->SetChild(this);
236 
237             rIndex.m_aRoot = aNewRoot;
238             rIndex.SetRootPos(nNewPagePos + 1);
239             rIndex.SetPageCount(++nNewPageCount);
240         }
241 
242         // neues blatt erzeugen und Seite aufteilen
243         ONDXPagePtr aNewPage = rIndex.CreatePage(nNewPagePos,aParent);
244         rIndex.SetPageCount(nNewPageCount);
245 
246         // wieviele Knoten weren noch eingefuegt
247         // kommen noch ausreichend, dann koennen die Seiten bis zum Rand vollgestopft werden
248 
249         ONDXNode aInnerNode;
250         if (!IsLeaf() || nRowsLeft < (sal_uInt32)(rIndex.GetMaxNodes() / 2))
251             aInnerNode = Split(*aNewPage);
252         else
253         {
254             aInnerNode = (*this)[nCount - 1];
255             //aInnerNode = aSplitNode;
256 
257             // Knoten zeigt auf neue Seite
258             aInnerNode.SetChild(aNewPage);
259 
260             // innere Knoten haben keine Recordnummer
261             if (rIndex.isUnique())
262                 aInnerNode.GetKey().ResetRecord();
263 
264             // neue Seite zeigt nun auf Seite des herausgeloesten Knoten
265             if (!IsLeaf())
266                 aNewPage->SetChild(aInnerNode.GetChild());
267         }
268 
269         aNewPage->Append(aSplitNode);
270         ONDXPagePtr aTempParent = aParent;
271         if (IsLeaf())
272         {
273             rIndex.m_aCurLeaf = aNewPage;
274             rIndex.m_nCurNode = rIndex.m_aCurLeaf->Count() - 1;
275 
276             // Freigeben nicht benoetigter Seiten, danach besteht keine Referenz
277             // mehr auf die Seite, danach kann 'this' nicht mehr gueltig sein!!!
278             ReleaseFull();
279         }
280 
281         // Einfuegen des herausgeloesten Knotens
282         return aTempParent->Insert(aInnerNode);
283     }
284     else // Seite einfach weiter auffuellen
285     {
286         if (bAppend)
287         {
288             if (IsLeaf())
289                 rIndex.m_nCurNode = nCount - 1;
290             return Append(rNode);
291         }
292         else
293         {
294             sal_uInt16 nNodePos = FindPos(rNode.GetKey());
295             if (IsLeaf())
296                 rIndex.m_nCurNode = nNodePos;
297 
298             return Insert(nNodePos, rNode);
299         }
300     }
301 }
302 
303 //------------------------------------------------------------------
Insert(sal_uInt16 nPos,ONDXNode & rNode)304 sal_Bool ONDXPage::Insert(sal_uInt16 nPos, ONDXNode& rNode)
305 {
306     sal_uInt16 nMaxCount = rIndex.getHeader().db_maxkeys;
307     if (nPos >= nMaxCount)
308         return sal_False;
309 
310     if (nCount)
311     {
312         ++nCount;
313         // nach rechts verschieben
314         for (sal_uInt16 i = std::min((sal_uInt16)(nMaxCount-1), (sal_uInt16)(nCount-1)); nPos < i; --i)
315             (*this)[i] = (*this)[i-1];
316     }
317     else
318         if (nCount < nMaxCount)
319             nCount++;
320 
321     // einfuegen an der Position
322     ONDXNode& rInsertNode = (*this)[nPos];
323     rInsertNode = rNode;
324     if (rInsertNode.GetChild().Is())
325     {
326         rInsertNode.GetChild()->SetParent(this);
327         rNode.GetChild()->SetParent(this);
328     }
329 
330     bModified = sal_True;
331 
332     return sal_True;
333 }
334 
335 //------------------------------------------------------------------
Append(ONDXNode & rNode)336 sal_Bool ONDXPage::Append(ONDXNode& rNode)
337 {
338     DBG_ASSERT(!IsFull(), "kein Append moeglich");
339     return Insert(nCount, rNode);
340 }
341 //------------------------------------------------------------------
Release(sal_Bool bSave)342 void ONDXPage::Release(sal_Bool bSave)
343 {
344     // freigeben der Pages
345     if (aChild.Is())
346         aChild->Release(bSave);
347 
348     // Pointer freigeben
349     aChild.Clear();
350 
351     for (sal_uInt16 i = 0; i < rIndex.getHeader().db_maxkeys;i++)
352     {
353         if (ppNodes[i].GetChild())
354             ppNodes[i].GetChild()->Release(bSave);
355 
356         ppNodes[i].GetChild().Clear();
357     }
358     aParent = NULL;
359 }
360 //------------------------------------------------------------------
ReleaseFull(sal_Bool bSave)361 void ONDXPage::ReleaseFull(sal_Bool bSave)
362 {
363     ONDXPagePtr aTempParent = aParent;
364     Release(bSave);
365 
366     if (aTempParent.Is())
367     {
368         // Freigeben nicht benoetigter Seiten, danach besteht keine Referenz
369         // mehr auf die Seite, danach kann 'this' nicht mehr gueltig sein!!!
370         sal_uInt16 nParentPos = aTempParent->Search(this);
371         if (nParentPos != NODE_NOTFOUND)
372             (*aTempParent)[nParentPos].GetChild().Clear();
373         else
374             aTempParent->GetChild().Clear();
375     }
376 }
377 //------------------------------------------------------------------
Delete(sal_uInt16 nNodePos)378 sal_Bool ONDXPage::Delete(sal_uInt16 nNodePos)
379 {
380     if (IsLeaf())
381     {
382         // Letztes Element wird geloescht
383         if (nNodePos == (nCount - 1))
384         {
385             ONDXNode aNode = (*this)[nNodePos];
386 
387             // beim Parent muss nun der KeyValue ausgetauscht werden
388             if (HasParent())
389                 aParent->SearchAndReplace(aNode.GetKey(),
390                                           (*this)[nNodePos-1].GetKey());
391         }
392     }
393 
394     // Loeschen des Knoten
395     Remove(nNodePos);
396 
397     // Unterlauf
398     if (HasParent() && nCount < (rIndex.GetMaxNodes() / 2))
399     {
400         // Feststellen, welcher Knoten auf die Seite zeigt
401         sal_uInt16 nParentNodePos = aParent->Search(this);
402         // letzte Element auf Vaterseite
403         // -> zusammenlegen mit vorletzter Seite
404         if (nParentNodePos == (aParent->Count() - 1))
405         {
406             if (!nParentNodePos)
407             // zusammenlegen mit linken nachbarn
408                 Merge(nParentNodePos,aParent->GetChild(&rIndex));
409             else
410                 Merge(nParentNodePos,(*aParent)[nParentNodePos-1].GetChild(&rIndex,aParent));
411         }
412         // sonst Seite mit naechster Seite zusammenlegen
413         else
414         {
415             // zusammenlegen mit rechten nachbarn
416             Merge(nParentNodePos + 1,((*aParent)[nParentNodePos + 1].GetChild(&rIndex,aParent)));
417             nParentNodePos++;
418         }
419         if (HasParent() && !(*aParent)[nParentNodePos].HasChild())
420             aParent->Delete(nParentNodePos);
421 /*
422         // letzte Element auf Vaterseite
423         // -> zusammenlegen mit vorletzter Seite
424         if (nParentNodePos == (aParent->Count() - 1))
425         {
426             if (!nParentNodePos)
427             // zusammenlegen mit linken nachbarn
428                 Merge(nParentNodePos,aParent->GetChild(&rIndex));
429             else
430                 Merge(nParentNodePos,(*aParent)[nParentNodePos-1].GetChild(&rIndex,aParent));
431         }
432         // sonst Seite mit naechster Seite zusammenlegen
433         else if(nParentNodePos != NODE_NOTFOUND)
434         {
435             // zusammenlegen mit rechten nachbarn
436             Merge(nParentNodePos + 1,((*aParent)[nParentNodePos + 1].GetChild(&rIndex,aParent)));
437             nParentNodePos++;
438         }
439         else // Sonderbehandlung
440         {
441             // Page ist aChild Page vom Parent => erste Page aus ppNodes an aChild anhaengen
442             Merge(0,(*aParent)[0].GetChild(&rIndex,aParent));
443             nParentNodePos = 0;
444         }
445 
446         if (HasParent() && !(*aParent)[nParentNodePos].HasChild())
447             aParent->Delete(nParentNodePos);
448 */
449 
450     }
451     else if (IsRoot())
452         // Sicherstellen das die Position der Wurzel festgehalten wird
453         rIndex.SetRootPos(nPagePos);
454     return sal_True;
455 }
456 
457 
458 //------------------------------------------------------------------
Split(ONDXPage & rPage)459 ONDXNode ONDXPage::Split(ONDXPage& rPage)
460 {
461     DBG_ASSERT(IsFull(), "Falsches Splitting");
462     /*  Aufteilen einer Seite auf zwei
463         Blatt:
464             Seite 1 behaelt (n - (n/2))
465             Seite 2 erhaelt (n/2)
466             Knoten n/2 wird dupliziert
467         Innerer Knoten:
468             Seite 1 behaelt (n+1)/2
469             Seite 2 erhaelt (n/2-1)
470             Knoten ((n+1)/2 + 1) : wird herausgenommen
471     */
472     ONDXNode aResultNode;
473     if (IsLeaf())
474     {
475         for (sal_uInt16 i = (nCount - (nCount / 2)), j = 0 ; i < nCount; i++)
476             rPage.Insert(j++,(*this)[i]);
477 
478         // dieser Knoten enthaelt einen Schluessel der noch einmal im Tree vorkommt
479         // und ersetzt werden muss
480         ONDXNode aLastNode = (*this)[nCount - 1];
481         nCount = nCount - (nCount / 2);
482         aResultNode = (*this)[nCount - 1];
483 
484         if (HasParent())
485             aParent->SearchAndReplace(aLastNode.GetKey(),
486                                       aResultNode.GetKey());
487     }
488     else
489     {
490         for (sal_uInt16 i = (nCount + 1) / 2 + 1, j = 0 ; i < nCount; i++)
491             rPage.Insert(j++,(*this)[i]);
492 
493         aResultNode = (*this)[(nCount + 1) / 2];
494         nCount = (nCount + 1) / 2;
495 
496         // neue Seite zeigt nun auf Seite des herausgeloesten Knoten
497         rPage.SetChild(aResultNode.GetChild());
498     }
499     // Knoten zeigt auf neue Seite
500     aResultNode.SetChild(&rPage);
501 
502     // innere Knoten haben keine Recordnummer
503     if (rIndex.isUnique())
504         aResultNode.GetKey().ResetRecord();
505     bModified = sal_True;
506     return aResultNode;
507 }
508 
509 //------------------------------------------------------------------
Merge(sal_uInt16 nParentNodePos,ONDXPagePtr xPage)510 void ONDXPage::Merge(sal_uInt16 nParentNodePos, ONDXPagePtr xPage)
511 {
512     DBG_ASSERT(HasParent(), "kein Vater vorhanden");
513     DBG_ASSERT(nParentNodePos != NODE_NOTFOUND, "Falscher Indexaufbau");
514 
515     /*  Zusammenlegen zweier Seiten */
516     ONDXNode aResultNode;
517     sal_uInt16 nMaxNodes = rIndex.GetMaxNodes(),
518            nMaxNodes_2 = nMaxNodes / 2;
519 
520     // Feststellen ob Seite rechter oder linker Nachbar
521     sal_Bool    bRight    = ((*xPage)[0].GetKey() > (*this)[0].GetKey()); // sal_True, wenn xPage die rechte Seite ist
522     sal_uInt16  nNewCount = (*xPage).Count() + Count();
523 
524     if (IsLeaf())
525     {
526         // Bedingung fuers zusammenlegen
527         if (nNewCount < (nMaxNodes_2 * 2))
528         {
529             sal_uInt16 nLastNode = bRight ? Count() - 1 : xPage->Count() - 1;
530             if (bRight)
531             {
532                 DBG_ASSERT(&xPage != this,"xPage und THIS duerfen nicht gleich sein: Endlosschleife");
533                 // alle Knoten aus xPage auf den linken Knoten verschieben (anhaengen)
534                 while (xPage->Count())
535                 {
536                     Append((*xPage)[0]);
537                     xPage->Remove(0);
538                 }
539             }
540             else
541             {
542                 DBG_ASSERT(&xPage != this,"xPage und THIS duerfen nicht gleich sein: Endlosschleife");
543                 // xPage ist die linke Page und THIS die rechte
544                 while (xPage->Count())
545                 {
546                     Insert(0,(*xPage)[xPage->Count()-1]);
547                     xPage->Remove(xPage->Count()-1);
548                 }
549                 // alte Position von xPage beim Parent mit this ersetzen
550                 if (nParentNodePos)
551                     (*aParent)[nParentNodePos-1].SetChild(this,aParent);
552                 else // oder als rechten Knoten setzen
553                     aParent->SetChild(this);
554                 aParent->SetModified(sal_True);
555 
556             }
557 
558             // Child beziehung beim Vaterknoten aufheben
559             (*aParent)[nParentNodePos].SetChild();
560             // Austauschen des KnotenWertes, nur wenn geaenderte Page
561             // die linke ist, ansonsten werde
562 
563             if(aParent->IsRoot() && aParent->Count() == 1)
564             {
565                 (*aParent)[0].SetChild();
566                 aParent->ReleaseFull();
567                 aParent = NULL;
568                 rIndex.SetRootPos(nPagePos);
569                 rIndex.m_aRoot = this;
570                 SetModified(sal_True);
571             }
572             else
573                 aParent->SearchAndReplace((*this)[nLastNode].GetKey(),(*this)[nCount-1].GetKey());
574 
575             xPage->SetModified(sal_False);
576             xPage->ReleaseFull(); // wird nicht mehr benoetigt
577         }
578         // Ausgleichen der Elemente   nNewCount >= (nMaxNodes_2 * 2)
579         else
580         {
581             if (bRight)
582             {
583                 // alle Knoten aus xPage auf den linken Knoten verschieben (anhaengen)
584                 ONDXNode aReplaceNode = (*this)[nCount - 1];
585                 while (nCount < nMaxNodes_2)
586                 {
587                     Append((*xPage)[0]);
588                     xPage->Remove(0);
589                 }
590                 // Austauschen des KnotenWertes: Setzt alten letzten Wert durch den letzten von xPage
591                 aParent->SearchAndReplace(aReplaceNode.GetKey(),(*this)[nCount-1].GetKey());
592             }
593             else
594             {
595                 // alle Knoten aus this vor die xPage Knoten einfuegen
596                 ONDXNode aReplaceNode = (*this)[nCount - 1];
597                 while (xPage->Count() < nMaxNodes_2)
598                 {
599                     xPage->Insert(0,(*this)[nCount-1]);
600                     Remove(nCount-1);
601                 }
602                 // Austauschen des KnotenWertes
603                 aParent->SearchAndReplace(aReplaceNode.GetKey(),(*this)[Count()-1].GetKey());
604             }
605         }
606     }
607     else // !IsLeaf()
608     {
609         // Bedingung fuers zusammenlegen
610         if (nNewCount < nMaxNodes_2 * 2)
611         {
612             if (bRight)
613             {
614                 DBG_ASSERT(&xPage != this,"xPage und THIS duerfen nicht gleich sein: Endlosschleife");
615                 // Vaterknoten wird mit integriert
616                 // erhaelt zunaechst Child von xPage
617                 (*aParent)[nParentNodePos].SetChild(xPage->GetChild(),aParent);
618                 Append((*aParent)[nParentNodePos]);
619                 for (sal_uInt16 i = 0 ; i < xPage->Count(); i++)
620                     Append((*xPage)[i]);
621             }
622             else
623             {
624                 DBG_ASSERT(&xPage != this,"xPage und THIS duerfen nicht gleich sein: Endlosschleife");
625                 // Vaterknoten wird mit integriert
626                 // erhaelt zunaechst Child
627                 (*aParent)[nParentNodePos].SetChild(GetChild(),aParent); // Parent merkt sich mein Child
628                 Insert(0,(*aParent)[nParentNodePos]); // Node vom Parent bei mir einfuegen
629                 while (xPage->Count())
630                 {
631                     Insert(0,(*xPage)[xPage->Count()-1]);
632                     xPage->Remove(xPage->Count()-1);
633                 }
634                 SetChild(xPage->GetChild());
635 
636                 if (nParentNodePos)
637                     (*aParent)[nParentNodePos-1].SetChild(this,aParent);
638                 else
639                     aParent->SetChild(this);
640             }
641 
642             // danach wird der Vaterknoten zurueckgesetzt
643             (*aParent)[nParentNodePos].SetChild();
644             aParent->SetModified(sal_True);
645 
646             if(aParent->IsRoot() && aParent->Count() == 1)
647             {
648                 (*aParent).SetChild();
649                 aParent->ReleaseFull();
650                 aParent = NULL;
651                 rIndex.SetRootPos(nPagePos);
652                 rIndex.m_aRoot = this;
653                 SetModified(sal_True);
654             }
655             else if(nParentNodePos)
656                 // Austauschen des KnotenWertes
657                 // beim Append wird der Bereich erweitert, beim INsert verweist der alte Knoten von xPage auf this
658                 // deshalb muss der Knoten auch hier aktualisiert werden
659                 aParent->SearchAndReplace((*aParent)[nParentNodePos-1].GetKey(),(*aParent)[nParentNodePos].GetKey());
660 
661             xPage->SetModified(sal_False);
662             xPage->ReleaseFull();
663         }
664         // Ausgleichen der Elemente
665         else
666         {
667             if (bRight)
668             {
669                 while (nCount < nMaxNodes_2)
670                 {
671                     (*aParent)[nParentNodePos].SetChild(xPage->GetChild(),aParent);
672                     Append((*aParent)[nParentNodePos]);
673                     (*aParent)[nParentNodePos] = (*xPage)[0];
674                     xPage->Remove(0);
675                 }
676                 xPage->SetChild((*aParent)[nParentNodePos].GetChild());
677                 (*aParent)[nParentNodePos].SetChild(xPage,aParent);
678             }
679             else
680             {
681                 while (nCount < nMaxNodes_2)
682                 {
683                     (*aParent)[nParentNodePos].SetChild(GetChild(),aParent);
684                     Insert(0,(*aParent)[nParentNodePos]);
685                     (*aParent)[nParentNodePos] = (*xPage)[xPage->Count()-1];
686                     xPage->Remove(xPage->Count()-1);
687                 }
688                 SetChild((*aParent)[nParentNodePos].GetChild());
689                 (*aParent)[nParentNodePos].SetChild(this,aParent);
690 
691             }
692             aParent->SetModified(sal_True);
693         }
694     }
695 }
696 //==================================================================
697 // ONDXNode
698 //==================================================================
699 
700 //------------------------------------------------------------------
Read(SvStream & rStream,ODbaseIndex & rIndex)701 void ONDXNode::Read(SvStream &rStream, ODbaseIndex& rIndex)
702 {
703     rStream >> aKey.nRecord; // schluessel
704 
705     if (rIndex.getHeader().db_keytype)
706     {
707         double aDbl;
708         rStream >> aDbl;
709         aKey = ONDXKey(aDbl,aKey.nRecord);
710     }
711     else
712     {
713         ByteString aBuf;
714         sal_uInt16 nLen = rIndex.getHeader().db_keylen;
715         char* pStr = aBuf.AllocBuffer(nLen+1);
716 
717         rStream.Read(pStr,nLen);
718         pStr[nLen] = 0;
719         aBuf.ReleaseBufferAccess();
720         aBuf.EraseTrailingChars();
721 
722         //  aKey = ONDXKey((aBuf,rIndex.GetDBFConnection()->GetCharacterSet()) ,aKey.nRecord);
723         aKey = ONDXKey(::rtl::OUString(aBuf.GetBuffer(),aBuf.Len(),rIndex.m_pTable->getConnection()->getTextEncoding()) ,aKey.nRecord);
724     }
725     rStream >> aChild;
726 }
727 
728 union NodeData
729 {
730     double aDbl;
731     char   aData[128];
732 } aNodeData;
733 //------------------------------------------------------------------
Write(SvStream & rStream,const ONDXPage & rPage) const734 void ONDXNode::Write(SvStream &rStream, const ONDXPage& rPage) const
735 {
736     const ODbaseIndex& rIndex = rPage.GetIndex();
737     if (!rIndex.isUnique() || rPage.IsLeaf())
738         rStream << (sal_uInt32)aKey.nRecord; // schluessel
739     else
740         rStream << (sal_uInt32)0;   // schluessel
741 
742     if (rIndex.getHeader().db_keytype) // double
743     {
744         if (aKey.getValue().isNull())
745         {
746             memset(aNodeData.aData,0,rIndex.getHeader().db_keylen);
747             rStream.Write((sal_uInt8*)aNodeData.aData,rIndex.getHeader().db_keylen);
748         }
749         else
750             rStream << (double) aKey.getValue();
751     }
752     else
753     {
754         memset(aNodeData.aData,0x20,rIndex.getHeader().db_keylen);
755         if (!aKey.getValue().isNull())
756         {
757             ::rtl::OUString sValue = aKey.getValue();
758             ByteString aText(sValue.getStr(), rIndex.m_pTable->getConnection()->getTextEncoding());
759             strncpy(aNodeData.aData,aText.GetBuffer(),std::min(rIndex.getHeader().db_keylen, aText.Len()));
760         }
761         rStream.Write((sal_uInt8*)aNodeData.aData,rIndex.getHeader().db_keylen);
762     }
763     rStream << aChild;
764 }
765 
766 
767 //------------------------------------------------------------------
GetChild(ODbaseIndex * pIndex,ONDXPage * pParent)768 ONDXPagePtr& ONDXNode::GetChild(ODbaseIndex* pIndex, ONDXPage* pParent)
769 {
770     if (!aChild.Is() && pIndex)
771     {
772         aChild = pIndex->CreatePage(aChild.GetPagePos(),pParent,aChild.HasPage());
773     }
774     return aChild;
775 }
776 
777 //==================================================================
778 // ONDXKey
779 //==================================================================
780 //------------------------------------------------------------------
IsText(sal_Int32 eType)781 sal_Bool ONDXKey::IsText(sal_Int32 eType)
782 {
783     return eType == DataType::VARCHAR || eType == DataType::CHAR;
784 }
785 
786 //------------------------------------------------------------------
Compare(const ONDXKey & rKey) const787 StringCompare ONDXKey::Compare(const ONDXKey& rKey) const
788 {
789     //  DBG_ASSERT(is(), "Falscher Indexzugriff");
790     StringCompare eResult;
791 
792     if (getValue().isNull())
793     {
794         if (rKey.getValue().isNull() || (rKey.IsText(getDBType()) && !rKey.getValue().getString().getLength()))
795             eResult = COMPARE_EQUAL;
796         else
797             eResult = COMPARE_LESS;
798     }
799     else if (rKey.getValue().isNull())
800     {
801         if (getValue().isNull() || (IsText(getDBType()) && !getValue().getString().getLength()))
802             eResult = COMPARE_EQUAL;
803         else
804             eResult = COMPARE_GREATER;
805     }
806     else if (IsText(getDBType()))
807     {
808         sal_Int32 nRes = getValue().getString().compareTo(rKey.getValue());
809         eResult = (nRes > 0) ? COMPARE_GREATER : (nRes == 0) ? COMPARE_EQUAL : COMPARE_LESS;
810     }
811     else
812     {
813         double m = getValue(),n = rKey.getValue();
814         eResult = (m > n) ? COMPARE_GREATER : (n == m) ? COMPARE_EQUAL : COMPARE_LESS;
815     }
816 
817     // Record vergleich, wenn Index !Unique
818     if (eResult == COMPARE_EQUAL && nRecord && rKey.nRecord)
819         eResult = (nRecord > rKey.nRecord) ? COMPARE_GREATER :
820                   (nRecord == rKey.nRecord) ? COMPARE_EQUAL : COMPARE_LESS;
821 
822     return eResult;
823 }
824 // -----------------------------------------------------------------------------
setValue(const ORowSetValue & _rVal)825 void ONDXKey::setValue(const ORowSetValue& _rVal)
826 {
827     xValue = _rVal;
828 }
829 // -----------------------------------------------------------------------------
getValue() const830 const ORowSetValue& ONDXKey::getValue() const
831 {
832     return xValue;
833 }
834 // -----------------------------------------------------------------------------
operator >>(SvStream & rStream,ONDXPagePtr & rPage)835 SvStream& connectivity::dbase::operator >> (SvStream &rStream, ONDXPagePtr& rPage)
836 {
837     rStream >> rPage.nPagePos;
838     return rStream;
839 }
840 // -----------------------------------------------------------------------------
operator <<(SvStream & rStream,const ONDXPagePtr & rPage)841 SvStream& connectivity::dbase::operator << (SvStream &rStream, const ONDXPagePtr& rPage)
842 {
843     rStream << rPage.nPagePos;
844     return rStream;
845 }
846 // -----------------------------------------------------------------------------
847 //==================================================================
848 // ONDXPagePtr
849 //==================================================================
850 //------------------------------------------------------------------
ONDXPagePtr(const ONDXPagePtr & rRef)851 ONDXPagePtr::ONDXPagePtr(const ONDXPagePtr& rRef)
852               :ONDXPageRef(rRef)
853               ,nPagePos(rRef.nPagePos)
854 {
855 }
856 
857 //------------------------------------------------------------------
ONDXPagePtr(ONDXPage * pRefPage)858 ONDXPagePtr::ONDXPagePtr(ONDXPage* pRefPage)
859               :ONDXPageRef(pRefPage)
860               ,nPagePos(0)
861 {
862     if (pRefPage)
863         nPagePos = pRefPage->GetPagePos();
864 }
865 //------------------------------------------------------------------
operator =(const ONDXPagePtr & rRef)866 ONDXPagePtr& ONDXPagePtr::operator=(const ONDXPagePtr& rRef)
867 {
868     ONDXPageRef::operator=(rRef);
869     nPagePos = rRef.nPagePos;
870     return *this;
871 }
872 
873 //------------------------------------------------------------------
operator =(ONDXPage * pRef)874 ONDXPagePtr& ONDXPagePtr::operator= (ONDXPage* pRef)
875 {
876     ONDXPageRef::operator=(pRef);
877     nPagePos = (pRef) ? pRef->GetPagePos() : 0;
878     return *this;
879 }
880 // -----------------------------------------------------------------------------
881 static sal_uInt32 nValue;
882 //------------------------------------------------------------------
operator >>(SvStream & rStream,ONDXPage & rPage)883 SvStream& connectivity::dbase::operator >> (SvStream &rStream, ONDXPage& rPage)
884 {
885     rStream.Seek(rPage.GetPagePos() * PAGE_SIZE);
886     rStream >> nValue >> rPage.aChild;
887     rPage.nCount = sal_uInt16(nValue);
888 
889 //  DBG_ASSERT(rPage.nCount && rPage.nCount < rPage.GetIndex().GetMaxNodes(), "Falscher Count");
890     for (sal_uInt16 i = 0; i < rPage.nCount; i++)
891         rPage[i].Read(rStream, rPage.GetIndex());
892     return rStream;
893 }
894 
895 //------------------------------------------------------------------
operator <<(SvStream & rStream,const ONDXPage & rPage)896 SvStream& connectivity::dbase::operator << (SvStream &rStream, const ONDXPage& rPage)
897 {
898     // Seite existiert noch nicht
899     sal_uIntPtr nSize = (rPage.GetPagePos() + 1) * PAGE_SIZE;
900     if (nSize > rStream.Seek(STREAM_SEEK_TO_END))
901     {
902         rStream.SetStreamSize(nSize);
903         rStream.Seek(rPage.GetPagePos() * PAGE_SIZE);
904 
905         char aEmptyData[PAGE_SIZE];
906         memset(aEmptyData,0x00,PAGE_SIZE);
907         rStream.Write((sal_uInt8*)aEmptyData,PAGE_SIZE);
908     }
909     sal_uIntPtr nCurrentPos = rStream.Seek(rPage.GetPagePos() * PAGE_SIZE);
910     OSL_UNUSED( nCurrentPos );
911 
912     nValue = rPage.nCount;
913     rStream << nValue << rPage.aChild;
914 
915     sal_uInt16 i = 0;
916     for (; i < rPage.nCount; i++)
917         rPage[i].Write(rStream, rPage);
918 
919     // check if we have to fill the stream with '\0'
920     if(i < rPage.rIndex.getHeader().db_maxkeys)
921     {
922         sal_uIntPtr nTell = rStream.Tell() % PAGE_SIZE;
923         sal_uInt16 nBufferSize = rStream.GetBufferSize();
924         sal_uIntPtr nRemainSize = nBufferSize - nTell;
925         if ( nRemainSize <= nBufferSize )
926         {
927             char* pEmptyData = new char[nRemainSize];
928             memset(pEmptyData,0x00,nRemainSize);
929             rStream.Write((sal_uInt8*)pEmptyData,nRemainSize);
930             rStream.Seek(nTell);
931             delete [] pEmptyData;
932         }
933     }
934     return rStream;
935 }
936 // -----------------------------------------------------------------------------
937 #if OSL_DEBUG_LEVEL > 1
938 //------------------------------------------------------------------
PrintPage()939 void ONDXPage::PrintPage()
940 {
941     DBG_TRACE4("\nSDB: -----------Page: %d  Parent: %d  Count: %d  Child: %d-----",
942         nPagePos, HasParent() ? aParent->GetPagePos() : 0 ,nCount, aChild.GetPagePos());
943 
944     for (sal_uInt16 i = 0; i < nCount; i++)
945     {
946         ONDXNode rNode = (*this)[i];
947         ONDXKey&  rKey = rNode.GetKey();
948         if (!IsLeaf())
949             rNode.GetChild(&rIndex, this);
950 
951         if (rKey.getValue().isNull())
952         {
953             DBG_TRACE2("SDB: [%d,NULL,%d]",rKey.GetRecord(), rNode.GetChild().GetPagePos());
954         }
955         else if (rIndex.getHeader().db_keytype)
956         {
957             DBG_TRACE3("SDB: [%d,%f,%d]",rKey.GetRecord(), rKey.getValue().getDouble(),rNode.GetChild().GetPagePos());
958         }
959         else
960         {
961             DBG_TRACE3("SDB: [%d,%s,%d]",rKey.GetRecord(), (const char* )ByteString(rKey.getValue().getString().getStr(), rIndex.m_pTable->getConnection()->getTextEncoding()).GetBuffer(),rNode.GetChild().GetPagePos());
962         }
963     }
964     DBG_TRACE("SDB: -----------------------------------------------\n");
965     if (!IsLeaf())
966     {
967 #if OSL_DEBUG_LEVEL > 1
968         GetChild(&rIndex)->PrintPage();
969         for (sal_uInt16 i = 0; i < nCount; i++)
970         {
971             ONDXNode rNode = (*this)[i];
972             rNode.GetChild(&rIndex,this)->PrintPage();
973         }
974 #endif
975     }
976     DBG_TRACE("SDB: ===============================================\n");
977 }
978 #endif
979 // -----------------------------------------------------------------------------
IsFull() const980 sal_Bool ONDXPage::IsFull() const
981 {
982     return Count() == rIndex.getHeader().db_maxkeys;
983 }
984 // -----------------------------------------------------------------------------
985 //------------------------------------------------------------------
Search(const ONDXKey & rSearch)986 sal_uInt16 ONDXPage::Search(const ONDXKey& rSearch)
987 {
988     // binare Suche spaeter
989     sal_uInt16 i = NODE_NOTFOUND;
990     while (++i < Count())
991         if ((*this)[i].GetKey() == rSearch)
992             break;
993 
994     return (i < Count()) ? i : NODE_NOTFOUND;
995 }
996 
997 //------------------------------------------------------------------
Search(const ONDXPage * pPage)998 sal_uInt16 ONDXPage::Search(const ONDXPage* pPage)
999 {
1000     sal_uInt16 i = NODE_NOTFOUND;
1001     while (++i < Count())
1002         if (((*this)[i]).GetChild() == pPage)
1003             break;
1004 
1005     // wenn nicht gefunden, dann wird davon ausgegangen, dass die Seite selbst
1006     // auf die Page zeigt
1007     return (i < Count()) ? i : NODE_NOTFOUND;
1008 }
1009 // -----------------------------------------------------------------------------
1010 // laeuft rekursiv
SearchAndReplace(const ONDXKey & rSearch,ONDXKey & rReplace)1011 void ONDXPage::SearchAndReplace(const ONDXKey& rSearch,
1012                                   ONDXKey& rReplace)
1013 {
1014     OSL_ENSURE(rSearch != rReplace,"Invalid here:rSearch == rReplace");
1015     if (rSearch != rReplace)
1016     {
1017         sal_uInt16 nPos = NODE_NOTFOUND;
1018         ONDXPage* pPage = this;
1019 
1020         while (pPage && (nPos = pPage->Search(rSearch)) == NODE_NOTFOUND)
1021             pPage = pPage->aParent;
1022 
1023         if (pPage)
1024         {
1025             (*pPage)[nPos].GetKey() = rReplace;
1026             pPage->SetModified(sal_True);
1027         }
1028     }
1029 }
1030 // -----------------------------------------------------------------------------
operator [](sal_uInt16 nPos)1031 ONDXNode& ONDXPage::operator[] (sal_uInt16 nPos)
1032 {
1033     DBG_ASSERT(nCount > nPos, "falscher Indexzugriff");
1034     return ppNodes[nPos];
1035 }
1036 
1037 //------------------------------------------------------------------
operator [](sal_uInt16 nPos) const1038 const ONDXNode& ONDXPage::operator[] (sal_uInt16 nPos) const
1039 {
1040     DBG_ASSERT(nCount > nPos, "falscher Indexzugriff");
1041     return ppNodes[nPos];
1042 }
1043 // -----------------------------------------------------------------------------
Remove(sal_uInt16 nPos)1044 void ONDXPage::Remove(sal_uInt16 nPos)
1045 {
1046     DBG_ASSERT(nCount > nPos, "falscher Indexzugriff");
1047 
1048     for (sal_uInt16 i = nPos; i < (nCount-1); i++)
1049         (*this)[i] = (*this)[i+1];
1050 
1051     nCount--;
1052     bModified = sal_True;
1053 }
1054 // -----------------------------------------------------------------------------
1055 
1056