1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_connectivity.hxx"
30 #include "dbase/DIndexIter.hxx"
31 #include <com/sun/star/sdb/SQLFilterOperator.hpp>
32 
33 using namespace ::com::sun::star::sdb;
34 using namespace connectivity;
35 using namespace connectivity::dbase;
36 using namespace connectivity::file;
37 using namespace ::com::sun::star::sdb;
38 //==================================================================
39 // OIndexIterator
40 //==================================================================
41 //------------------------------------------------------------------
42 OIndexIterator::~OIndexIterator()
43 {
44 	//	m_pIndex->UnLock();
45 	m_pIndex->release();
46 }
47 
48 //------------------------------------------------------------------
49 sal_uIntPtr OIndexIterator::First()
50 {
51 	return Find(sal_True);
52 }
53 
54 //------------------------------------------------------------------
55 sal_uIntPtr OIndexIterator::Next()
56 {
57 	return Find(sal_False);
58 }
59 //------------------------------------------------------------------
60 sal_uIntPtr OIndexIterator::Find(sal_Bool bFirst)
61 {
62 	//	ONDXIndex* m_pIndex = GetNDXIndex();
63 
64 	sal_uIntPtr nRes = STRING_NOTFOUND;
65 //	if (!m_pIndex->IsOpen())
66 //		return nRes;
67 
68 	if (bFirst)
69 	{
70 		m_aRoot = m_pIndex->getRoot();
71 		m_aCurLeaf = NULL;
72 	}
73 
74 	if (!m_pOperator)
75 	{
76 		// Vorbereitung , auf kleinstes Element positionieren
77 		if (bFirst)
78 		{
79 			ONDXPage* pPage = m_aRoot;
80 			while (pPage && !pPage->IsLeaf())
81 				pPage = pPage->GetChild(m_pIndex);
82 
83 			m_aCurLeaf = pPage;
84 			m_nCurNode = NODE_NOTFOUND;
85 		}
86 		ONDXKey* pKey = GetNextKey();
87 		nRes = pKey ? pKey->GetRecord() : STRING_NOTFOUND;
88 	}
89 	else if (m_pOperator->IsA(TYPE(OOp_ISNOTNULL)))
90 		nRes = GetNotNull(bFirst);
91 	else if (m_pOperator->IsA(TYPE(OOp_ISNULL)))
92 		nRes = GetNull(bFirst);
93 	else if (m_pOperator->IsA(TYPE(OOp_LIKE)))
94 		nRes = GetLike(bFirst);
95 	else if (m_pOperator->IsA(TYPE(OOp_COMPARE)))
96 		nRes = GetCompare(bFirst);
97 
98 	return nRes;
99 }
100 
101 //------------------------------------------------------------------
102 ONDXKey* OIndexIterator::GetFirstKey(ONDXPage* pPage, const OOperand& rKey)
103 {
104 	// sucht den vorgegeben key
105 	// Besonderheit: gelangt der Algorithmus ans Ende
106 	// wird immer die aktuelle Seite und die Knotenposition vermerkt
107 	// auf die die Bedingung <= zutrifft
108 	// dieses findet beim Insert besondere Beachtung
109 	//	ONDXIndex* m_pIndex = GetNDXIndex();
110 	OOp_COMPARE aTempOp(SQLFilterOperator::GREATER);
111 	sal_uInt16 i = 0;
112 
113 	if (pPage->IsLeaf())
114 	{
115 		// im blatt wird die eigentliche Operation ausgefuehrt, sonst die temp. (>)
116 		while (i < pPage->Count() && !m_pOperator->operate(&((*pPage)[i]).GetKey(),&rKey))
117 			   i++;
118 	}
119 	else
120 		while (i < pPage->Count() && !aTempOp.operate(&((*pPage)[i]).GetKey(),&rKey))
121 			   i++;
122 
123 
124 	ONDXKey* pFoundKey = NULL;
125 	if (!pPage->IsLeaf())
126 	{
127 		// weiter absteigen
128 		ONDXPagePtr aPage = (i==0) ? pPage->GetChild(m_pIndex)
129 									 : ((*pPage)[i-1]).GetChild(m_pIndex, pPage);
130 		pFoundKey = aPage.Is() ? GetFirstKey(aPage, rKey) : NULL;
131 	}
132 	else if (i == pPage->Count())
133 	{
134 		pFoundKey = NULL;
135 	}
136 	else
137 	{
138 		pFoundKey = &(*pPage)[i].GetKey();
139 		if (!m_pOperator->operate(pFoundKey,&rKey))
140 			pFoundKey = NULL;
141 
142 		m_aCurLeaf = pPage;
143 		m_nCurNode = pFoundKey ? i : i - 1;
144 	}
145 	return pFoundKey;
146 }
147 
148 //------------------------------------------------------------------
149 sal_uIntPtr OIndexIterator::GetCompare(sal_Bool bFirst)
150 {
151 	ONDXKey* pKey = NULL;
152 	//	ONDXIndex* m_pIndex = GetNDXIndex();
153 	sal_Int32 ePredicateType = PTR_CAST(file::OOp_COMPARE,m_pOperator)->getPredicateType();
154 
155 	if (bFirst)
156 	{
157 		// Vorbereitung , auf kleinstes Element positionieren
158 		ONDXPage* pPage = m_aRoot;
159 		switch (ePredicateType)
160 		{
161 			case SQLFilterOperator::NOT_EQUAL:
162 			case SQLFilterOperator::LESS:
163 			case SQLFilterOperator::LESS_EQUAL:
164 				while (pPage && !pPage->IsLeaf())
165 					pPage = pPage->GetChild(m_pIndex);
166 
167 				m_aCurLeaf = pPage;
168 				m_nCurNode = NODE_NOTFOUND;
169 		}
170 
171 
172 		switch (ePredicateType)
173 		{
174 			case SQLFilterOperator::NOT_EQUAL:
175 				while ( ( ( pKey = GetNextKey() ) != NULL ) && !m_pOperator->operate(pKey,m_pOperand)) ;
176 				break;
177 			case SQLFilterOperator::LESS:
178                 while ( ( ( pKey = GetNextKey() ) != NULL ) && pKey->getValue().isNull()) ;
179 				break;
180 			case SQLFilterOperator::LESS_EQUAL:
181                 while ( ( pKey = GetNextKey() ) != NULL ) ;
182 				break;
183 			case SQLFilterOperator::GREATER_EQUAL:
184 			case SQLFilterOperator::EQUAL:
185 				pKey = GetFirstKey(m_aRoot,*m_pOperand);
186 				break;
187 			case SQLFilterOperator::GREATER:
188                 pKey = GetFirstKey(m_aRoot,*m_pOperand);
189                 if ( !pKey )
190                     while ( ( ( pKey = GetNextKey() ) != NULL ) && !m_pOperator->operate(pKey,m_pOperand)) ;
191 		}
192 	}
193 	else
194 	{
195 		switch (ePredicateType)
196 		{
197 			case SQLFilterOperator::NOT_EQUAL:
198 				while ( ( ( pKey = GetNextKey() ) != NULL ) && !m_pOperator->operate(pKey,m_pOperand))
199 					;
200 				break;
201 			case SQLFilterOperator::LESS:
202 			case SQLFilterOperator::LESS_EQUAL:
203 			case SQLFilterOperator::EQUAL:
204 				if ( ( ( pKey = GetNextKey() ) == NULL )  || !m_pOperator->operate(pKey,m_pOperand))
205 				{
206 					pKey = NULL;
207 					m_aCurLeaf = NULL;
208 				}
209 				break;
210 			case SQLFilterOperator::GREATER_EQUAL:
211 			case SQLFilterOperator::GREATER:
212 				pKey = GetNextKey();
213 		}
214 	}
215 
216 	return pKey ? pKey->GetRecord() : STRING_NOTFOUND;
217 }
218 
219 //------------------------------------------------------------------
220 sal_uIntPtr OIndexIterator::GetLike(sal_Bool bFirst)
221 {
222 	//	ONDXIndex* m_pIndex = GetNDXIndex();
223 	if (bFirst)
224 	{
225 		ONDXPage* pPage = m_aRoot;
226 
227 		while (pPage && !pPage->IsLeaf())
228 			pPage = pPage->GetChild(m_pIndex);
229 
230 		m_aCurLeaf = pPage;
231 		m_nCurNode = NODE_NOTFOUND;
232 	}
233 
234 	ONDXKey* pKey;
235 	while ( ( ( pKey = GetNextKey() ) != NULL ) && !m_pOperator->operate(pKey,m_pOperand))
236 		;
237 	return pKey ? pKey->GetRecord() : STRING_NOTFOUND;
238 }
239 
240 //------------------------------------------------------------------
241 sal_uIntPtr OIndexIterator::GetNull(sal_Bool bFirst)
242 {
243 	//	ONDXIndex* m_pIndex = GetNDXIndex();
244 	if (bFirst)
245 	{
246 		ONDXPage* pPage = m_aRoot;
247 		while (pPage && !pPage->IsLeaf())
248 			pPage = pPage->GetChild(m_pIndex);
249 
250 		m_aCurLeaf = pPage;
251 		m_nCurNode = NODE_NOTFOUND;
252 	}
253 
254 	ONDXKey* pKey;
255 	if ( ( ( pKey = GetNextKey() ) == NULL ) || !pKey->getValue().isNull())
256 	{
257 		pKey = NULL;
258 		m_aCurLeaf = NULL;
259 	}
260 	return pKey ? pKey->GetRecord() : STRING_NOTFOUND;
261 }
262 
263 //------------------------------------------------------------------
264 sal_uIntPtr OIndexIterator::GetNotNull(sal_Bool bFirst)
265 {
266 	ONDXKey* pKey;
267 	//	ONDXIndex* m_pIndex = GetNDXIndex();
268 	if (bFirst)
269 	{
270 		// erst alle NULL werte abklappern
271 		for (sal_uIntPtr nRec = GetNull(bFirst);
272 			 nRec != STRING_NOTFOUND;
273 			 nRec = GetNull(sal_False))
274 				 ;
275 		pKey = m_aCurLeaf.Is() ? &(*m_aCurLeaf)[m_nCurNode].GetKey() : NULL;
276 	}
277 	else
278 		pKey = GetNextKey();
279 
280 	return pKey ? pKey->GetRecord() : STRING_NOTFOUND;
281 }
282 
283 //------------------------------------------------------------------
284 ONDXKey* OIndexIterator::GetNextKey()
285 {
286 	//	ONDXIndex* m_pIndex = GetNDXIndex();
287 	if (m_aCurLeaf.Is() && ((++m_nCurNode) >= m_aCurLeaf->Count()))
288 	{
289 		ONDXPage* pPage = m_aCurLeaf;
290 		// naechste Seite suchen
291 		while (pPage)
292 		{
293 			ONDXPage* pParentPage = pPage->GetParent();
294 			if (pParentPage)
295 			{
296 				sal_uInt16 nPos = pParentPage->Search(pPage);
297 				if (nPos != pParentPage->Count() - 1)
298 				{	// Seite gefunden
299 					pPage = (*pParentPage)[nPos+1].GetChild(m_pIndex,pParentPage);
300 					break;
301 				}
302 			}
303 			pPage = pParentPage;
304 		}
305 
306 		// jetzt wieder zum Blatt
307 		while (pPage && !pPage->IsLeaf())
308 			pPage = pPage->GetChild(m_pIndex);
309 
310 		m_aCurLeaf = pPage;
311 		m_nCurNode = 0;
312 	}
313 	return m_aCurLeaf.Is() ? &(*m_aCurLeaf)[m_nCurNode].GetKey() : NULL;
314 }
315 
316