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_dbaccess.hxx"
26 
27 
28 #include "BookmarkSet.hxx"
29 #include "CRowSetColumn.hxx"
30 #include "CRowSetDataColumn.hxx"
31 #include "KeySet.hxx"
32 #include "OptimisticSet.hxx"
33 #include "RowSetBase.hxx"
34 #include "RowSetCache.hxx"
35 #include "StaticSet.hxx"
36 #include "WrappedResultSet.hxx"
37 #include "core_resource.hrc"
38 #include "core_resource.hxx"
39 #include "dbastrings.hrc"
40 
41 /** === begin UNO includes === **/
42 #include <com/sun/star/sdbc/ColumnValue.hpp>
43 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
44 #include <com/sun/star/sdbcx/CompareBookmark.hpp>
45 #include <com/sun/star/sdbcx/KeyType.hpp>
46 #include <com/sun/star/sdbcx/Privilege.hpp>
47 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
48 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
49 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
50 /** === end UNO includes === **/
51 
52 #include <comphelper/extract.hxx>
53 #include <comphelper/property.hxx>
54 #include <comphelper/seqstream.hxx>
55 #include <comphelper/uno3.hxx>
56 #include <connectivity/dbexception.hxx>
57 #include <connectivity/dbtools.hxx>
58 #include <connectivity/sqliterator.hxx>
59 #include <connectivity/sqlnode.hxx>
60 #include <connectivity/sqlparse.hxx>
61 #include <tools/debug.hxx>
62 #include <tools/diagnose_ex.h>
63 
64 #include <algorithm>
65 
66 using namespace dbaccess;
67 using namespace dbtools;
68 using namespace connectivity;
69 using namespace ::com::sun::star::uno;
70 using namespace ::com::sun::star::beans;
71 using namespace ::com::sun::star::sdbc;
72 using namespace ::com::sun::star::sdb;
73 using namespace ::com::sun::star::sdbcx;
74 using namespace ::com::sun::star::container;
75 using namespace ::com::sun::star::lang;
76 using namespace ::cppu;
77 using namespace ::osl;
78 
79 #define CHECK_MATRIX_POS(M) OSL_ENSURE(((M) >= static_cast<ORowSetMatrix::difference_type>(0)) && ((M) < static_cast<sal_Int32>(m_pMatrix->size())),"Position is invalid!")
80 
81 DBG_NAME(ORowSetCache)
82 // -------------------------------------------------------------------------
83 ORowSetCache::ORowSetCache(const Reference< XResultSet >& _xRs,
84 						   const Reference< XSingleSelectQueryAnalyzer >& _xAnalyzer,
85                            const ::comphelper::ComponentContext& _rContext,
86 						   const ::rtl::OUString& _rUpdateTableName,
87 						   sal_Bool&	_bModified,
88 						   sal_Bool&	_bNew,
89                            const ORowSetValueVector& _aParameterValueForCache,
90                            const ::rtl::OUString& i_sRowSetFilter,
91                            sal_Int32 i_nMaxRows)
92 	:m_xSet(_xRs)
93 	,m_xMetaData(Reference< XResultSetMetaDataSupplier >(_xRs,UNO_QUERY)->getMetaData())
94 	,m_aContext( _rContext )
95     ,m_pCacheSet(NULL)
96 	,m_pMatrix(NULL)
97 	,m_pInsertMatrix(NULL)
98     ,m_nLastColumnIndex(0)
99 	,m_nFetchSize(0)
100 	,m_nRowCount(0)
101     ,m_nPrivileges( Privilege::SELECT )
102 	,m_nPosition(0)
103     ,m_nStartPos(0)
104 	,m_nEndPos(0)
105 	,m_bRowCountFinal(sal_False)
106     ,m_bBeforeFirst(sal_True)
107 	,m_bAfterLast( sal_False )
108 	,m_bUpdated(sal_False)
109 	,m_bModified(_bModified)
110 	,m_bNew(_bNew)
111 {
112     DBG_CTOR(ORowSetCache,NULL);
113 
114     // first try if the result can be used to do inserts and updates
115     Reference< XPropertySet> xProp(_xRs,UNO_QUERY);
116     Reference< XPropertySetInfo > xPropInfo = xProp->getPropertySetInfo();
117 	sal_Bool bBookmarkable = sal_False;
118     try
119     {
120         Reference< XResultSetUpdate> xUp(_xRs,UNO_QUERY_THROW);
121 	    bBookmarkable = xPropInfo->hasPropertyByName(PROPERTY_ISBOOKMARKABLE) &&
122 							    any2bool(xProp->getPropertyValue(PROPERTY_ISBOOKMARKABLE)) && Reference< XRowLocate >(_xRs, UNO_QUERY).is();
123         if ( bBookmarkable )
124         {
125             xUp->moveToInsertRow();
126             xUp->cancelRowUpdates();
127             _xRs->beforeFirst();
128             m_nPrivileges = Privilege::SELECT|Privilege::DELETE|Privilege::INSERT|Privilege::UPDATE;
129             m_pCacheSet = new WrappedResultSet(i_nMaxRows);
130             m_xCacheSet = m_pCacheSet;
131 		    m_pCacheSet->construct(_xRs,i_sRowSetFilter);
132             return;
133         }
134     }
135     catch(const Exception& ex)
136     {
137         (void)ex;
138     }
139     try
140     {
141         if ( xPropInfo->hasPropertyByName(PROPERTY_RESULTSETTYPE) &&
142 							::comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETTYPE)) != ResultSetType::FORWARD_ONLY)
143             _xRs->beforeFirst();
144     }
145     catch(const SQLException& e)
146     {
147         (void)e;
148     }
149 
150 	// check if all keys of the updateable table are fetched
151 	sal_Bool bAllKeysFound = sal_False;
152 	sal_Int32 nTablesCount = 0;
153 
154 	sal_Bool bNeedKeySet = !bBookmarkable || (xPropInfo->hasPropertyByName(PROPERTY_RESULTSETCONCURRENCY) &&
155 							::comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY)) == ResultSetConcurrency::READ_ONLY);
156 
157     Reference< XIndexAccess> xUpdateTableKeys;
158 	::rtl::OUString aUpdateTableName = _rUpdateTableName;
159 	Reference< XConnection> xConnection;
160     // first we need a connection
161 	Reference< XStatement> xStmt(_xRs->getStatement(),UNO_QUERY);
162 	if(xStmt.is())
163 		xConnection = xStmt->getConnection();
164 	else
165 	{
166 		Reference< XPreparedStatement> xPrepStmt(_xRs->getStatement(),UNO_QUERY);
167 		xConnection = xPrepStmt->getConnection();
168 	}
169 	OSL_ENSURE(xConnection.is(),"No connection!");
170 	if(_xAnalyzer.is())
171 	{
172 		try
173 		{
174 			Reference<XTablesSupplier> xTabSup(_xAnalyzer,UNO_QUERY);
175 			OSL_ENSURE(xTabSup.is(),"ORowSet::execute composer isn't a tablesupplier!");
176 			Reference<XNameAccess> xTables = xTabSup->getTables();
177             Sequence< ::rtl::OUString> aTableNames = xTables->getElementNames();
178             if ( aTableNames.getLength() > 1 && !_rUpdateTableName.getLength() && bNeedKeySet )
179             {// here we have a join or union and nobody told us which table to update, so we update them all
180                 m_nPrivileges = Privilege::SELECT|Privilege::DELETE|Privilege::INSERT|Privilege::UPDATE;
181                 OptimisticSet* pCursor = new OptimisticSet(m_aContext,xConnection,_xAnalyzer,_aParameterValueForCache,i_nMaxRows,m_nRowCount);
182                 m_pCacheSet = pCursor;
183                 m_xCacheSet = m_pCacheSet;
184                 try
185                 {
186 		            m_pCacheSet->construct(_xRs,i_sRowSetFilter);
187                     if ( pCursor->isReadOnly() )
188                         m_nPrivileges = Privilege::SELECT;
189                     m_aKeyColumns = pCursor->getJoinedKeyColumns();
190                     return;
191                 }
192                 catch(const Exception&)
193                 {
194                     // DBG_UNHANDLED_EXCEPTION();
195                 }
196                 m_pCacheSet = NULL;
197                 m_xCacheSet.clear();
198             }
199             else
200             {
201 			    if(_rUpdateTableName.getLength() && xTables->hasByName(_rUpdateTableName))
202 				    xTables->getByName(_rUpdateTableName) >>= m_aUpdateTable;
203 			    else if(xTables->getElementNames().getLength())
204 			    {
205 				    aUpdateTableName = xTables->getElementNames()[0];
206 				    xTables->getByName(aUpdateTableName) >>= m_aUpdateTable;
207 			    }
208 			    Reference<XIndexAccess> xIndexAccess(xTables,UNO_QUERY);
209 			    if(xIndexAccess.is())
210 				    nTablesCount = xIndexAccess->getCount();
211 			    else
212 				    nTablesCount = xTables->getElementNames().getLength();
213 
214 			    if(m_aUpdateTable.is() && nTablesCount < 3) // for we can't handle more than 2 tables in our keyset
215 			    {
216                     Reference<XPropertySet> xSet(m_aUpdateTable,UNO_QUERY);
217                     const Reference<XNameAccess> xPrimaryKeyColumns = dbtools::getPrimaryKeyColumns_throw(xSet);
218                     if ( xPrimaryKeyColumns.is() )
219                     {
220 					    Reference<XColumnsSupplier> xColSup(_xAnalyzer,UNO_QUERY);
221 					    if ( xColSup.is() )
222 					    {
223 						    Reference<XNameAccess> xSelColumns = xColSup->getColumns();
224 						    Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
225                             SelectColumnsMetaData aColumnNames(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers() ? true : false);
226 						    ::dbaccess::getColumnPositions(xSelColumns,xPrimaryKeyColumns->getElementNames(),aUpdateTableName,aColumnNames);
227 						    bAllKeysFound = !aColumnNames.empty() && sal_Int32(aColumnNames.size()) == xPrimaryKeyColumns->getElementNames().getLength();
228 					    }
229 				    }
230 			    }
231             }
232 		}
233 		catch(Exception&)
234 		{
235 		}
236 	}
237 
238 	// first check if resultset is bookmarkable
239 	if(!bNeedKeySet)
240 	{
241 		try
242 		{
243 			m_pCacheSet = new OBookmarkSet(i_nMaxRows);
244 			m_xCacheSet = m_pCacheSet;
245 			m_pCacheSet->construct(_xRs,i_sRowSetFilter);
246 
247 			// check privileges
248 			m_nPrivileges = Privilege::SELECT;
249 			if(Reference<XResultSetUpdate>(_xRs,UNO_QUERY).is())  // this interface is optional so we have to check it
250 			{
251 				Reference<XPropertySet> xTable(m_aUpdateTable,UNO_QUERY);
252 				if(xTable.is() && xTable->getPropertySetInfo()->hasPropertyByName(PROPERTY_PRIVILEGES))
253 				{
254 					m_nPrivileges = 0;
255 					xTable->getPropertyValue(PROPERTY_PRIVILEGES) >>= m_nPrivileges;
256 					if(!m_nPrivileges)
257 						m_nPrivileges = Privilege::SELECT;
258 				}
259 			}
260 		}
261 		catch(const SQLException&)
262 		{
263 			bNeedKeySet = sal_True;
264 		}
265 
266 	}
267 	if(bNeedKeySet)
268 	{
269 		// need to check if we could handle this select clause
270 		bAllKeysFound = bAllKeysFound && (nTablesCount == 1 || checkJoin(xConnection,_xAnalyzer,aUpdateTableName));
271 
272 		// || !(comphelper::hasProperty(PROPERTY_CANUPDATEINSERTEDROWS,xProp) && any2bool(xProp->getPropertyValue(PROPERTY_CANUPDATEINSERTEDROWS)))
273 
274 		// oj removed because keyset uses only the next// || (xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_RESULTSETTYPE) && comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETTYPE)) == ResultSetType::FORWARD_ONLY)
275 		if(!bAllKeysFound )
276 		{
277 			if ( bBookmarkable )
278 			{
279 				// here I know that we have a read only bookmarable cursor
280 				_xRs->beforeFirst();
281 				m_nPrivileges = Privilege::SELECT;
282 				m_pCacheSet = new WrappedResultSet(i_nMaxRows);
283 				m_xCacheSet = m_pCacheSet;
284 				m_pCacheSet->construct(_xRs,i_sRowSetFilter);
285 				return;
286 			}
287 			m_pCacheSet = new OStaticSet(i_nMaxRows);
288 			m_xCacheSet = m_pCacheSet;
289 			m_pCacheSet->construct(_xRs,i_sRowSetFilter);
290 			m_nPrivileges = Privilege::SELECT;
291 		}
292 		else
293 		{
294 			Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
295             SelectColumnsMetaData aColumnNames(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers() ? true : false);
296 			Reference<XColumnsSupplier> xColSup(_xAnalyzer,UNO_QUERY);
297 			Reference<XNameAccess> xSelColumns	= xColSup->getColumns();
298 			Reference<XNameAccess> xColumns		= m_aUpdateTable->getColumns();
299 			::dbaccess::getColumnPositions(xSelColumns,xColumns->getElementNames(),aUpdateTableName,aColumnNames);
300 
301 			// check privileges
302 			m_nPrivileges = Privilege::SELECT;
303 			sal_Bool bNoInsert = sal_False;
304 
305 			Sequence< ::rtl::OUString> aNames(xColumns->getElementNames());
306 			const ::rtl::OUString* pIter	= aNames.getConstArray();
307 			const ::rtl::OUString* pEnd		= pIter + aNames.getLength();
308 			for(;pIter != pEnd;++pIter)
309 			{
310 				Reference<XPropertySet> xColumn(xColumns->getByName(*pIter),UNO_QUERY);
311 				OSL_ENSURE(xColumn.is(),"Column in table is null!");
312 				if(xColumn.is())
313 				{
314 					sal_Int32 nNullable = 0;
315 					xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable;
316 					if(nNullable == ColumnValue::NO_NULLS && aColumnNames.find(*pIter) == aColumnNames.end())
317 					{ // we found a column where null is not allowed so we can't insert new values
318 						bNoInsert = sal_True;
319 						break; // one column is enough
320 					}
321 				}
322 			}
323 
324 			OKeySet* pKeySet = new OKeySet(m_aUpdateTable,xUpdateTableKeys,aUpdateTableName ,_xAnalyzer,_aParameterValueForCache,i_nMaxRows,m_nRowCount);
325 			try
326 			{
327 				m_pCacheSet = pKeySet;
328 				m_xCacheSet = m_pCacheSet;
329 				pKeySet->construct(_xRs,i_sRowSetFilter);
330 
331 				if(Reference<XResultSetUpdate>(_xRs,UNO_QUERY).is())  // this interface is optional so we have to check it
332 				{
333 					Reference<XPropertySet> xTable(m_aUpdateTable,UNO_QUERY);
334 					if(xTable.is() && xTable->getPropertySetInfo()->hasPropertyByName(PROPERTY_PRIVILEGES))
335 					{
336 						m_nPrivileges = 0;
337 						xTable->getPropertyValue(PROPERTY_PRIVILEGES) >>= m_nPrivileges;
338 						if(!m_nPrivileges)
339 							m_nPrivileges = Privilege::SELECT;
340 					}
341 				}
342 				if(bNoInsert)
343 					m_nPrivileges |= ~Privilege::INSERT; // remove the insert privilege
344 			}
345 			catch(const SQLException&)
346 			{
347 				// we couldn't create a keyset here so we have to create a static cache
348 				if ( m_pCacheSet )
349 					m_pCacheSet = NULL;
350 				m_xCacheSet = NULL;
351 				m_pCacheSet = new OStaticSet(i_nMaxRows);
352 				m_xCacheSet = m_pCacheSet;
353 				m_pCacheSet->construct(_xRs,i_sRowSetFilter);
354 				m_nPrivileges = Privilege::SELECT;
355 			}
356 		}
357 
358 	}
359 	// last check
360 	if(!bAllKeysFound && xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_RESULTSETCONCURRENCY) &&
361 		::comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY)) == ResultSetConcurrency::READ_ONLY)
362 		m_nPrivileges = Privilege::SELECT;
363 }
364 
365 // -------------------------------------------------------------------------
366 ORowSetCache::~ORowSetCache()
367 {
368 	m_pCacheSet = NULL;
369 	m_xCacheSet = NULL;
370 	if(m_pMatrix)
371 	{
372 		m_pMatrix->clear();
373 		delete m_pMatrix;
374 	}
375 
376 	if(m_pInsertMatrix)
377 	{
378 		m_pInsertMatrix->clear();
379 		delete m_pInsertMatrix;
380 	}
381 	m_xSet			= WeakReference< XResultSet>();
382 	m_xMetaData		= NULL;
383 	m_aUpdateTable	= NULL;
384 
385     DBG_DTOR(ORowSetCache,NULL);
386 }
387 
388 // -------------------------------------------------------------------------
389 void ORowSetCache::setFetchSize(sal_Int32 _nSize)
390 {
391 	if(_nSize == m_nFetchSize)
392 		return;
393 
394 	m_nFetchSize = _nSize;
395 	if(!m_pMatrix)
396 	{
397 		m_pMatrix = new ORowSetMatrix(_nSize);
398 		m_aMatrixIter = m_pMatrix->end();
399 		m_aMatrixEnd = m_pMatrix->end();
400 
401 		m_pInsertMatrix = new ORowSetMatrix(1); // a little bit overkill but ??? :-)
402 		m_aInsertRow	= m_pInsertMatrix->end();
403 	}
404 	else
405 	{
406 		// now correct the iterator in our iterator vector
407 		::std::vector<sal_Int32> aPositions;
408 		::std::map<sal_Int32,sal_Bool> aCacheIterToChange;
409 		// first get the positions where they stand now
410 		ORowSetCacheMap::iterator aCacheIter = m_aCacheIterators.begin();
411         ORowSetCacheMap::iterator aCacheEnd = m_aCacheIterators.end();
412 		for(;aCacheIter != aCacheEnd;++aCacheIter)
413 		{
414 			aCacheIterToChange[aCacheIter->first] = sal_False;
415 			if ( !aCacheIter->second.pRowSet->isInsertRow()
416 				/*&& aCacheIter->second.aIterator != m_pMatrix->end()*/ && !m_bModified )
417 			{
418 				ptrdiff_t nDist = (aCacheIter->second.aIterator - m_pMatrix->begin());
419 				aPositions.push_back(nDist);
420 				aCacheIterToChange[aCacheIter->first] = sal_True;
421 			}
422 		}
423 		sal_Int32 nKeyPos = (m_aMatrixIter - m_pMatrix->begin());
424 		m_pMatrix->resize(_nSize);
425 
426         if ( nKeyPos < _nSize )
427 		    m_aMatrixIter = m_pMatrix->begin() + nKeyPos;
428         else
429             m_aMatrixIter = m_pMatrix->end();
430 		m_aMatrixEnd = m_pMatrix->end();
431 
432 		// now adjust their positions because a resize invalid all iterators
433 		::std::vector<sal_Int32>::const_iterator aIter = aPositions.begin();
434 		::std::map<sal_Int32,sal_Bool>::const_iterator aPosChangeIter = aCacheIterToChange.begin();
435 		for(	aCacheIter = m_aCacheIterators.begin();
436 				aPosChangeIter != aCacheIterToChange.end();
437 				++aPosChangeIter,++aCacheIter)
438 		{
439 			if ( aPosChangeIter->second )
440             {
441                 CHECK_MATRIX_POS(*aIter);
442                 if ( *aIter < _nSize )
443 				    aCacheIter->second.aIterator = m_pMatrix->begin() + *aIter++;
444                 else
445                     aCacheIter->second.aIterator = m_pMatrix->end();
446             }
447 		}
448 	}
449 	if(!m_nPosition)
450 	{
451 		sal_Int32 nNewSt = 1;
452 		fillMatrix(nNewSt,_nSize+1);
453 		m_nStartPos = 0;
454 		m_nEndPos = _nSize;
455 	}
456     else if (m_nStartPos < m_nPosition && m_nPosition < m_nEndPos)
457     {
458         sal_Int32 nNewSt = -1;
459         fillMatrix(nNewSt,_nSize+1);
460 		m_nStartPos = 0;
461 		m_nEndPos = _nSize;
462     }
463 }
464 // -------------------------------------------------------------------------
465 
466 // XResultSetMetaDataSupplier
467 Reference< XResultSetMetaData > ORowSetCache::getMetaData(  )
468 {
469 	return m_xMetaData;
470 }
471 // -------------------------------------------------------------------------
472 Any lcl_getBookmark(ORowSetValue& i_aValue,OCacheSet* i_pCacheSet)
473 {
474     switch ( i_aValue.getTypeKind() )
475 	{
476 		case DataType::TINYINT:
477 		case DataType::SMALLINT:
478 		case DataType::INTEGER:
479 			return makeAny((sal_Int32)i_aValue);
480 		default:
481 			if ( i_pCacheSet && i_aValue.isNull())
482 				i_aValue = i_pCacheSet->getBookmark();
483 			return i_aValue.getAny();
484 	}
485 }
486 // -------------------------------------------------------------------------
487 // ::com::sun::star::sdbcx::XRowLocate
488 Any ORowSetCache::getBookmark(  )
489 {
490 
491 	if(m_bAfterLast)
492 		throwFunctionSequenceException(m_xSet.get());
493 
494 	if ( m_aMatrixIter >= m_pMatrix->end() || m_aMatrixIter < m_pMatrix->begin() || !(*m_aMatrixIter).isValid())
495 	{
496 		return Any(); // this is allowed here because the rowset knowns what it is doing
497 	}
498 
499 	return lcl_getBookmark(((*m_aMatrixIter)->get())[0],m_pCacheSet);
500 }
501 // -------------------------------------------------------------------------
502 sal_Bool ORowSetCache::moveToBookmark( const Any& bookmark )
503 {
504 	if ( m_pCacheSet->moveToBookmark(bookmark) )
505 	{
506 		m_bBeforeFirst = sal_False;
507 		m_nPosition	= m_pCacheSet->getRow();
508 
509 		checkPositionFlags();
510 
511 		if(!m_bAfterLast)
512 		{
513 			moveWindow();
514 			checkPositionFlags();
515 			if ( !m_bAfterLast )
516 			{
517 				m_aMatrixIter = calcPosition();
518 				OSL_ENSURE(m_aMatrixIter->isValid(),"Iterator after moveToBookmark not valid");
519 			}
520 			else
521 				m_aMatrixIter = m_pMatrix->end();
522 		}
523 		else
524 			m_aMatrixIter = m_pMatrix->end();
525 	}
526 	else
527 		return sal_False;
528 
529 	return m_aMatrixIter != m_pMatrix->end() && (*m_aMatrixIter).isValid();
530 }
531 // -------------------------------------------------------------------------
532 sal_Bool ORowSetCache::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows )
533 {
534 	sal_Bool bRet( moveToBookmark( bookmark ) );
535 	if ( bRet )
536 	{
537 		m_nPosition = m_pCacheSet->getRow() + rows;
538 		absolute(m_nPosition);
539 		//	for(sal_Int32 i=0;i<rows && m_aMatrixIter != m_pMatrix->end();++i,++m_aMatrixIter) ;
540 
541 		bRet = m_aMatrixIter != m_pMatrix->end() && (*m_aMatrixIter).isValid();
542 	}
543 
544 	return bRet;
545 }
546 // -------------------------------------------------------------------------
547 sal_Int32 ORowSetCache::compareBookmarks( const Any& _first, const Any& _second )
548 {
549 	return (!_first.hasValue() || !_second.hasValue()) ? CompareBookmark::NOT_COMPARABLE : m_pCacheSet->compareBookmarks(_first,_second);
550 }
551 // -------------------------------------------------------------------------
552 sal_Bool ORowSetCache::hasOrderedBookmarks(  )
553 {
554 	return m_pCacheSet->hasOrderedBookmarks();
555 }
556 // -------------------------------------------------------------------------
557 sal_Int32 ORowSetCache::hashBookmark( const Any& bookmark )
558 {
559 	return m_pCacheSet->hashBookmark(bookmark);
560 }
561 // XRowUpdate
562 // -----------------------------------------------------------------------------
563 void ORowSetCache::updateNull(sal_Int32 columnIndex,ORowSetValueVector::Vector& io_aRow
564                               ,::std::vector<sal_Int32>& o_ChangedColumns
565                               )
566 {
567 	checkUpdateConditions(columnIndex);
568 
569     ORowSetValueVector::Vector& rInsert = ((*m_aInsertRow)->get());
570 	if ( !rInsert[columnIndex].isNull() )
571 	{
572 		rInsert[columnIndex].setBound(sal_True);
573 		rInsert[columnIndex].setNull();
574 		rInsert[columnIndex].setModified();
575     	io_aRow[columnIndex].setNull();
576 
577 	    m_pCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
578     	impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
579 	}
580 }
581 // -----------------------------------------------------------------------------
582 void ORowSetCache::updateValue(sal_Int32 columnIndex,const ORowSetValue& x
583                                ,ORowSetValueVector::Vector& io_aRow
584                                ,::std::vector<sal_Int32>& o_ChangedColumns
585                                )
586 {
587 	checkUpdateConditions(columnIndex);
588 
589     ORowSetValueVector::Vector& rInsert = ((*m_aInsertRow)->get());
590 	if ( rInsert[columnIndex] != x )
591 	{
592 		rInsert[columnIndex].setBound(sal_True);
593 		rInsert[columnIndex] = x;
594 		rInsert[columnIndex].setModified();
595 		io_aRow[columnIndex] = rInsert[columnIndex];
596 
597 		m_pCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
598 		impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
599 	}
600 }
601 // -------------------------------------------------------------------------
602 void ORowSetCache::updateCharacterStream( sal_Int32 columnIndex, const Reference< ::com::sun::star::io::XInputStream >& x
603                                          , sal_Int32 length,ORowSetValueVector::Vector& io_aRow
604                                          ,::std::vector<sal_Int32>& o_ChangedColumns
605                                          )
606 {
607 	checkUpdateConditions(columnIndex);
608 
609 	Sequence<sal_Int8> aSeq;
610 	if(x.is())
611 		x->readBytes(aSeq,length);
612 
613     ORowSetValueVector::Vector& rInsert = ((*m_aInsertRow)->get());
614     rInsert[columnIndex].setBound(sal_True);
615 	rInsert[columnIndex] = aSeq;
616 	rInsert[columnIndex].setModified();
617     io_aRow[columnIndex] = makeAny(x);
618 
619     m_pCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
620     impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
621 }
622 // -------------------------------------------------------------------------
623 void ORowSetCache::updateObject( sal_Int32 columnIndex, const Any& x
624                                 ,ORowSetValueVector::Vector& io_aRow
625                                 ,::std::vector<sal_Int32>& o_ChangedColumns
626                                 )
627 {
628 	checkUpdateConditions(columnIndex);
629 
630     ORowSetValueVector::Vector& rInsert = ((*m_aInsertRow)->get());
631 	ORowSetValue aTemp;
632 	aTemp.fill(x);
633 	if ( rInsert[columnIndex] != aTemp )
634 	{
635 		rInsert[columnIndex].setBound(sal_True);
636 		rInsert[columnIndex] = aTemp;
637 		rInsert[columnIndex].setModified();
638     	io_aRow[columnIndex] = rInsert[columnIndex];
639 
640 	    m_pCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
641     	impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
642 	}
643 }
644 // -------------------------------------------------------------------------
645 void ORowSetCache::updateNumericObject( sal_Int32 columnIndex, const Any& x, sal_Int32 /*scale*/
646                                        ,ORowSetValueVector::Vector& io_aRow
647                                        ,::std::vector<sal_Int32>& o_ChangedColumns
648                                        )
649 {
650 	checkUpdateConditions(columnIndex);
651 
652     ORowSetValueVector::Vector& rInsert = ((*m_aInsertRow)->get());
653 	ORowSetValue aTemp;
654 	aTemp.fill(x);
655 	if ( rInsert[columnIndex] != aTemp )
656 	{
657 		rInsert[columnIndex].setBound(sal_True);
658 		rInsert[columnIndex] = aTemp;
659 		rInsert[columnIndex].setModified();
660     	io_aRow[columnIndex] = rInsert[columnIndex];
661 
662 	    m_pCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
663     	impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
664 	}
665 }
666 // -------------------------------------------------------------------------
667 // XResultSet
668 sal_Bool ORowSetCache::next(  )
669 {
670 	if(!isAfterLast())
671 	{
672 		m_bBeforeFirst = sal_False;
673         ++m_nPosition;
674 
675 		// after we increment the position we have to check if we are already after the last row
676 		checkPositionFlags();
677 		if(!m_bAfterLast)
678 		{
679 			moveWindow();
680 
681 			OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
682 			m_aMatrixIter = calcPosition();
683 			checkPositionFlags();
684 		}
685 	}
686 
687 	return !m_bAfterLast;
688 }
689 // -------------------------------------------------------------------------
690 sal_Bool ORowSetCache::isBeforeFirst(  )
691 {
692 	return m_bBeforeFirst;
693 }
694 // -------------------------------------------------------------------------
695 sal_Bool ORowSetCache::isAfterLast(  )
696 {
697 	return m_bAfterLast;
698 }
699 // -------------------------------------------------------------------------
700 sal_Bool ORowSetCache::isFirst(  )
701 {
702 	return m_nPosition == 1; // ask resultset for
703 }
704 // -------------------------------------------------------------------------
705 sal_Bool ORowSetCache::isLast(  )
706 {
707 	return m_nPosition == m_nRowCount;
708 }
709 // -------------------------------------------------------------------------
710 sal_Bool ORowSetCache::beforeFirst(  )
711 {
712 	if(!m_bBeforeFirst)
713 	{
714 		m_bAfterLast	= sal_False;
715 		m_nPosition		= 0;
716 		m_bBeforeFirst	= sal_True;
717 		m_pCacheSet->beforeFirst();
718 		moveWindow();
719 		m_aMatrixIter = m_pMatrix->end();
720 	}
721     return sal_True;
722 }
723 // -------------------------------------------------------------------------
724 sal_Bool ORowSetCache::afterLast(  )
725 {
726 	if(!m_bAfterLast)
727 	{
728 		m_bBeforeFirst = sal_False;
729 		m_bAfterLast = sal_True;
730 
731 		if(!m_bRowCountFinal)
732 		{
733 			m_pCacheSet->last_checked(sal_False);
734 			m_bRowCountFinal = sal_True;
735 			m_nRowCount = m_pCacheSet->getRow();// + 1 removed
736 		}
737 		m_pCacheSet->afterLast();
738 
739 		m_nPosition = 0;
740 		m_aMatrixIter = m_pMatrix->end();
741 	}
742     return sal_True;
743 }
744 // -------------------------------------------------------------------------
745 sal_Bool ORowSetCache::fillMatrix(sal_Int32& _nNewStartPos,sal_Int32 _nNewEndPos)
746 {
747 	OSL_ENSURE(_nNewStartPos != _nNewEndPos,"ORowSetCache::fillMatrix: StartPos and EndPos can not be equal!");
748 	// fill the whole window with new data
749     ORowSetMatrix::iterator aIter;
750     sal_Int32 i;
751     sal_Bool bCheck;
752     if ( _nNewStartPos == -1 )
753     {
754 	    aIter = m_pMatrix->begin() + m_nEndPos;
755         i = m_nEndPos+1;
756     }
757     else
758     {
759         aIter = m_pMatrix->begin();
760         i = _nNewStartPos;
761     }
762     bCheck = m_pCacheSet->absolute(i); // -1 no need to
763 
764 
765 	for(;i<_nNewEndPos;++i,++aIter)
766 	{
767 		if(bCheck)
768 		{
769 			if(!aIter->isValid())
770 				*aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
771 			m_pCacheSet->fillValueRow(*aIter,i);
772 			if(!m_bRowCountFinal)
773                 ++m_nRowCount;
774 		}
775 		else
776 		{	// there are no more rows found so we can fetch some before start
777 
778 			if(!m_bRowCountFinal)
779 			{
780 				if(m_pCacheSet->previous_checked(sal_False)) // because we stand after the last row
781 					m_nRowCount = m_pCacheSet->getRow(); // here we have the row count
782 				if(!m_nRowCount)
783 					m_nRowCount = i-1; // it can be that getRow return zero
784 				m_bRowCountFinal = sal_True;
785 			}
786 			if(m_nRowCount > m_nFetchSize)
787 			{
788 				ORowSetMatrix::iterator aEnd = aIter;
789                 ORowSetMatrix::iterator aRealEnd = m_pMatrix->end();
790 				sal_Int32 nPos = m_nRowCount - m_nFetchSize + 1;
791 				_nNewStartPos = nPos;
792 				bCheck = m_pCacheSet->absolute(_nNewStartPos);
793 
794 				for(;bCheck && aIter != aRealEnd;++aIter)
795 				{
796 					if(bCheck)
797 					{
798 						if(!aIter->isValid())
799 							*aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
800 						m_pCacheSet->fillValueRow(*aIter,nPos++);
801 					}
802 					bCheck = m_pCacheSet->next();
803 				}
804 				if(aIter != aEnd)
805 					::std::rotate(m_pMatrix->begin(),aEnd,aRealEnd);
806 			}
807 			break;
808 		}
809         if ( i < (_nNewEndPos-1) )
810 		    bCheck = m_pCacheSet->next();
811 	}
812 	//	m_nStartPos = _nNewStartPos;
813 	// we have to read one row forward to ensure that we know when we are on last row
814 	// but only when we don't know it already
815     /*
816 	if(!m_bRowCountFinal)
817 	{
818 		if(!m_pCacheSet->next())
819 		{
820 			if(m_pCacheSet->previous_checked(sal_False)) // because we stand after the last row
821 				m_nRowCount = m_pCacheSet->getRow(); // here we have the row count
822 			m_bRowCountFinal = sal_True;
823 		}
824 		else
825 		   m_nRowCount = std::max(i,m_nRowCount);
826 
827 	}
828     */
829 	return bCheck;
830 }
831 // -------------------------------------------------------------------------
832 sal_Bool ORowSetCache::moveWindow()
833 {
834 
835 	sal_Bool bRet = sal_True;
836 
837 	sal_Int32 nDiff = (sal_Int32)(m_nFetchSize*0.5 -0.5);
838 	sal_Int32 nNewStartPos	= (m_nPosition - nDiff);
839 	//	sal_Int32 nNewEndPos	= (m_nPosition+m_nFetchSize*0.5);
840 	sal_Int32 nNewEndPos	= nNewStartPos + m_nFetchSize;
841 
842 	if ( m_nPosition <= m_nStartPos )
843 	{	// the window is behind the new start pos
844 		if(!m_nStartPos)
845 			return sal_False;
846 		// the new position should be the nPos - nFetchSize/2
847 		if ( nNewEndPos > m_nStartPos )
848 		{	// but the two regions are overlapping
849 			// fill the rows behind the new end
850 
851 			ORowSetMatrix::iterator aEnd; // the iterator we need for rotate
852 			ORowSetMatrix::iterator aIter; // the iterator we fill with new values
853 
854 			sal_Bool bCheck = sal_True;
855 			if ( nNewStartPos < 1 )
856 			{
857 				bCheck = m_pCacheSet->first();
858 				OSL_ENSURE((nNewEndPos - m_nStartPos - nNewStartPos) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
859 				aEnd = m_pMatrix->begin() + (nNewEndPos - m_nStartPos - nNewStartPos);
860 				aIter = aEnd;
861 				m_nStartPos = 0;
862 			}
863 			else
864 			{
865 				OSL_ENSURE((nNewEndPos - m_nStartPos -1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
866 				aEnd = m_pMatrix->begin() + ((nNewEndPos - m_nStartPos)-1);
867 				aIter = m_pMatrix->begin() + ((nNewEndPos - m_nStartPos)-1);
868 				bCheck = m_pCacheSet->absolute(nNewStartPos);
869 				m_nStartPos = nNewStartPos -1;
870 			}
871 
872 			if ( bCheck )
873 			{
874 				sal_Int32 nPos = m_nStartPos;
875 				bCheck = fill(aIter,m_pMatrix->end(),nPos,bCheck);
876 
877 				::std::rotate(m_pMatrix->begin(),aEnd,m_pMatrix->end());
878 				// now correct the iterator in our iterator vector
879 				//	rotateCacheIterator(aEnd-m_pMatrix->begin()); //can't be used because they decrement and here we need to increment
880 				ptrdiff_t nNewDist = aEnd - m_pMatrix->begin();
881 				ptrdiff_t nOffSet = m_pMatrix->end() - aEnd;
882 				ORowSetCacheMap::iterator aCacheIter = m_aCacheIterators.begin();
883 				ORowSetCacheMap::iterator aCacheEnd  = m_aCacheIterators.end();
884 		        for(;aCacheIter != aCacheEnd;++aCacheIter)
885 				{
886 					if ( !aCacheIter->second.pRowSet->isInsertRow()
887 						&& aCacheIter->second.aIterator != m_pMatrix->end() && !m_bModified )
888 					{
889 						ptrdiff_t nDist = (aCacheIter->second.aIterator - m_pMatrix->begin());
890 						if ( nDist >= nNewDist )
891 						{
892 							aCacheIter->second.aIterator = m_pMatrix->end();
893 						}
894 						else
895 						{
896 #if OSL_DEBUG_LEVEL > 0
897 							ORowSetMatrix::iterator aOldPos;
898                             aOldPos = aCacheIter->second.aIterator;
899 #endif
900                             CHECK_MATRIX_POS( ((aOldPos - m_pMatrix->begin()) + nOffSet) );
901 							aCacheIter->second.aIterator += nOffSet;
902 #if OSL_DEBUG_LEVEL > 0
903 							ORowSetMatrix::iterator aCurrentPos;
904                             aCurrentPos = aCacheIter->second.aIterator;
905 #endif
906 							OSL_ENSURE(aCacheIter->second.aIterator >= m_pMatrix->begin()
907 									&& aCacheIter->second.aIterator < m_pMatrix->end(),"Iterator out of area!");
908 						}
909 					}
910 				}
911 			}
912 			else
913 			{ // normaly this should never happen
914 				OSL_ENSURE(0,"What the hell is happen here!");
915 				return sal_False;
916 			}
917 		}
918 		else
919 		{// no rows can be reused so fill again
920 			if(nNewStartPos < 1) // special case
921 			{
922 				m_nStartPos = 0;
923 
924 				rotateCacheIterator(static_cast<sal_Int16>(m_nFetchSize+1)); // static_cast<sal_Int16>(m_nFetchSize+1)
925 
926 				m_pCacheSet->beforeFirst();
927 
928 				sal_Bool bCheck;
929 				ORowSetMatrix::iterator aIter = m_pMatrix->begin();
930 				for(sal_Int32 i=0;i<m_nFetchSize;++i,++aIter)
931 				{
932                     bCheck = m_pCacheSet->next();
933 					if ( bCheck )
934 					{
935 						if(!aIter->isValid())
936 							*aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
937 						m_pCacheSet->fillValueRow(*aIter,i+1);
938 					}
939 					else
940 						*aIter = NULL;
941 				}
942 			}
943 			else
944 				bRet = reFillMatrix(nNewStartPos,nNewEndPos);
945 		}
946 	}
947 	else if(m_nPosition > m_nStartPos)
948 	{	// the new start pos is above the startpos of the window
949 
950 		if(m_nPosition <= (m_nStartPos+m_nFetchSize))
951 		{	// position in window
952 			OSL_ENSURE((m_nPosition - m_nStartPos -1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
953 			m_aMatrixIter = calcPosition();
954 			if(!m_aMatrixIter->isValid())
955 			{
956 				sal_Bool bOk( m_pCacheSet->absolute( m_nPosition ) );
957 				if ( bOk )
958 				{
959 					*m_aMatrixIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
960 					m_pCacheSet->fillValueRow(*m_aMatrixIter,m_nPosition);
961 					// we have to read one row forward to ensure that we know when we are on last row
962 					// but only when we don't know it already
963 					if ( !m_bRowCountFinal )
964                     {
965                         bOk = m_pCacheSet->absolute_checked( m_nPosition + 1,sal_False );
966                         if ( bOk )
967 						    m_nRowCount = std::max(sal_Int32(m_nPosition+1),m_nRowCount);
968                     }
969 				}
970 				if(!bOk && !m_bRowCountFinal)
971 				{
972 					// because we stand after the last row
973 					m_nRowCount = m_pCacheSet->previous_checked(sal_False) ? m_pCacheSet->getRow() : 0;//  + 1 removed
974 					m_bRowCountFinal = sal_True;
975 				}
976 			}
977 		}
978 		else if(nNewStartPos < (m_nStartPos+m_nFetchSize))
979 		{	// position behind window but the region is overlapping
980 			// the rows from begin() to (begin + nNewStartPos - m_nStartPos) can be refilled with the new rows
981 			// the rows behind this can be reused
982 			ORowSetMatrix::iterator aIter = m_pMatrix->begin();
983             CHECK_MATRIX_POS(nNewStartPos - m_nStartPos - 1);
984 			ORowSetMatrix::iterator aEnd  = m_pMatrix->begin() + (nNewStartPos - m_nStartPos - 1);
985 
986 			sal_Int32 nPos = m_nStartPos + m_nFetchSize + 1;
987 			sal_Bool bCheck = m_pCacheSet->absolute(nPos);
988 			bCheck = fill(aIter,aEnd,nPos,bCheck); // refill the region wew don't need anymore
989 
990 			// we have to read one row forward to enshure that we know when we are on last row
991 			// but only when we don't know it already
992 			sal_Bool bOk = sal_True;
993 			if(bCheck && !m_bRowCountFinal)
994 				bOk = m_pCacheSet->next();
995 			// bind end to front
996 			if(bCheck)
997 			{	// rotate the end to the front
998 				::std::rotate(m_pMatrix->begin(),aIter,m_pMatrix->end());
999 				// now correct the iterator in our iterator vector
1000 				rotateCacheIterator( (sal_Int16)( aIter - m_pMatrix->begin() ) );
1001 				m_nStartPos = nNewStartPos - 1; // must be -1
1002 				// now I can say how many rows we have
1003 				if(!bOk)
1004 				{
1005 					m_pCacheSet->previous_checked(sal_False); // because we stand after the last row
1006 					m_nRowCount		 = nPos; // here we have the row count
1007 					m_bRowCountFinal = sal_True;
1008 				}
1009 				else if(!m_bRowCountFinal)
1010 					m_nRowCount = std::max(++nPos,m_nRowCount);
1011 			}
1012 			else
1013 			{	// the end was reached before end() so we can set the start before nNewStartPos
1014 
1015 				m_nStartPos += (aIter - m_pMatrix->begin());
1016 				//	m_nStartPos = (aIter - m_pMatrix->begin());
1017 				::std::rotate(m_pMatrix->begin(),aIter,m_pMatrix->end());
1018 				// now correct the iterator in our iterator vector
1019 				rotateCacheIterator( (sal_Int16)( aIter - m_pMatrix->begin() ) );
1020 
1021 				if ( !m_bRowCountFinal )
1022 				{
1023 					m_pCacheSet->previous_checked(sal_False);					// because we stand after the last row
1024 					m_nRowCount		 = std::max(m_nRowCount,--nPos);	// here we have the row count
1025 					OSL_ENSURE(nPos == m_pCacheSet->getRow(),"nPos isn't valid!");
1026 					m_bRowCountFinal = sal_True;
1027 				}
1028 				// TODO check
1029 				//	m_nStartPos = (nNewStartPos+m_nRowCount) - m_nFetchSize ;
1030 				if(m_nStartPos < 0)
1031 					m_nStartPos = 0;
1032 			}
1033 			// here we need only to check if the begining row is valid. If not we have to fetch it.
1034 			if(!m_pMatrix->begin()->isValid())
1035 			{
1036 				aIter = m_pMatrix->begin();
1037 
1038 				nPos	= m_nStartPos;
1039 				bCheck	= m_pCacheSet->absolute_checked(m_nStartPos,sal_False);
1040 				for(; !aIter->isValid() && bCheck;++aIter)
1041 				{
1042                     OSL_ENSURE(aIter != m_pMatrix->end(),"Invalid iterator");
1043                     bCheck = m_pCacheSet->next();
1044 					if ( bCheck ) // resultset stands on right position
1045 					{
1046 						*aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
1047 						m_pCacheSet->fillValueRow(*aIter,++nPos);
1048 					}
1049 				}
1050 			}
1051 		}
1052 		else // no rows can be reused so fill again
1053 			bRet = reFillMatrix(nNewStartPos,nNewEndPos);
1054 	}
1055 
1056 	if(!m_bRowCountFinal)
1057 	   m_nRowCount = std::max(m_nPosition,m_nRowCount);
1058 	OSL_ENSURE(m_nStartPos >= 0,"ORowSetCache::moveWindow: m_nStartPos is less than 0!");
1059 
1060 	return bRet;
1061 }
1062 // -------------------------------------------------------------------------
1063 sal_Bool ORowSetCache::first(  )
1064 {
1065 	// first move to the first row
1066 	// then check if the cache window is at the begining
1067 	// when not postionize the window and fill it with data
1068 	// smart moving of the window -> clear only the rows whom are out of range
1069 	sal_Bool bRet = m_pCacheSet->first();
1070 	if(bRet)
1071 	{
1072 		m_bBeforeFirst	= m_bAfterLast = sal_False;
1073 		m_nPosition		= 1;
1074 		moveWindow();
1075 		m_aMatrixIter	= m_pMatrix->begin();
1076 	}
1077 	else
1078 	{
1079 		m_bRowCountFinal = m_bBeforeFirst = m_bAfterLast = sal_True;
1080 		m_nRowCount = m_nPosition = 0;
1081 
1082 		OSL_ENSURE(m_bBeforeFirst || m_bNew,"ORowSetCache::first return false and BeforeFirst isn't true");
1083 		m_aMatrixIter = m_pMatrix->end();
1084 	}
1085 	return bRet;
1086 }
1087 // -------------------------------------------------------------------------
1088 sal_Bool ORowSetCache::last(  )
1089 {
1090 	sal_Bool bRet = m_pCacheSet->last();
1091 	if(bRet)
1092 	{
1093 		m_bBeforeFirst = m_bAfterLast = sal_False;
1094 		if(!m_bRowCountFinal)
1095 		{
1096 			m_bRowCountFinal = sal_True;
1097 			m_nRowCount = m_nPosition = m_pCacheSet->getRow(); // not  + 1
1098 		}
1099 		m_nPosition = m_pCacheSet->getRow();
1100 		moveWindow();
1101 		// we have to repositioning because moveWindow can modify the cache
1102 		m_pCacheSet->last();
1103 //		if(m_nPosition > m_nFetchSize)
1104 //			m_aMatrixIter = m_pMatrix->end() -1;
1105 //		else
1106 //			m_aMatrixIter = m_pMatrix->begin() + m_nPosition - 1;
1107 		OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
1108 		m_aMatrixIter = calcPosition();
1109 	}
1110 	else
1111 	{
1112 		m_bRowCountFinal = m_bBeforeFirst = m_bAfterLast = sal_True;
1113 		m_nRowCount = m_nPosition = 0;
1114 		OSL_ENSURE(m_bBeforeFirst,"ORowSetCache::last return false and BeforeFirst isn't true");
1115 		m_aMatrixIter = m_pMatrix->end();
1116 	}
1117 #if OSL_DEBUG_LEVEL > 1
1118 	if(bRet)
1119 	{
1120 		OSL_ENSURE((*m_aMatrixIter).isValid(),"ORowSetCache::last: Row not valid!");
1121 	}
1122 #endif
1123 
1124 	return bRet;
1125 }
1126 // -------------------------------------------------------------------------
1127 sal_Int32 ORowSetCache::getRow(  )
1128 {
1129 	return (isBeforeFirst() || isAfterLast()) ? 0 : m_nPosition;
1130 }
1131 // -------------------------------------------------------------------------
1132 sal_Bool ORowSetCache::absolute( sal_Int32 row )
1133 {
1134 	if(!row )
1135 		throw SQLException(DBACORE_RESSTRING(RID_STR_NO_ABS_ZERO),NULL,SQLSTATE_GENERAL,1000,Any() );
1136 
1137 	if(row < 0)
1138 	{
1139 		// here we have to scroll from the last row to backward so we have to go to last row and
1140 		// and two the previous
1141 		if(m_bRowCountFinal || last())
1142 		{
1143 			m_nPosition = m_nRowCount + row + 1; // + row because row is negative and +1 because row==-1 means last row
1144 			if(m_nPosition < 1)
1145 			{
1146 				m_bBeforeFirst = sal_True;
1147 				m_bAfterLast = sal_False;
1148 				m_aMatrixIter = m_pMatrix->end();
1149 			}
1150 			else
1151 			{
1152 				m_bBeforeFirst	= sal_False;
1153 				m_bAfterLast	= m_nPosition > m_nRowCount;
1154 				moveWindow();
1155 				OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
1156 				m_aMatrixIter = calcPosition();
1157 			}
1158 		}
1159 		else
1160 			m_aMatrixIter = m_pMatrix->end();
1161 	}
1162 	else
1163 	{
1164 		m_nPosition = row;
1165 		// the position flags
1166 		m_bBeforeFirst	= sal_False;
1167 		checkPositionFlags();
1168 
1169 		if(!m_bAfterLast)
1170 		{
1171 			moveWindow();
1172 			checkPositionFlags();
1173 			if(!m_bAfterLast)
1174 				m_aMatrixIter = calcPosition();
1175 			else
1176 				m_aMatrixIter = m_pMatrix->end();
1177 		}
1178 		else
1179 			m_aMatrixIter = m_pMatrix->end();
1180 	}
1181 
1182 	return !(m_bAfterLast || m_bBeforeFirst);
1183 }
1184 // -------------------------------------------------------------------------
1185 sal_Bool ORowSetCache::relative( sal_Int32 rows )
1186 {
1187 	sal_Bool bErg = sal_True;
1188 	if(rows)
1189 	{
1190         sal_Int32 nNewPosition = m_nPosition + rows;
1191 
1192         if ( m_bBeforeFirst && rows > 0 )
1193             nNewPosition = rows;
1194         else if ( m_bRowCountFinal && m_bAfterLast && rows < 0 )
1195             nNewPosition = m_nRowCount + 1 + rows;
1196         else
1197 		    if ( m_bBeforeFirst || ( m_bRowCountFinal && m_bAfterLast ) )
1198 			    throw SQLException( DBACORE_RESSTRING( RID_STR_NO_RELATIVE ), NULL, SQLSTATE_GENERAL, 1000, Any() );
1199 		if ( nNewPosition )
1200 		{
1201 			bErg = absolute( nNewPosition );
1202 			bErg = bErg && !isAfterLast() && !isBeforeFirst();
1203 		}
1204 		else
1205         {
1206             m_bBeforeFirst = sal_True;
1207 			bErg = sal_False;
1208         }
1209 	}
1210 	return bErg;
1211 }
1212 // -------------------------------------------------------------------------
1213 sal_Bool ORowSetCache::previous(  )
1214 {
1215 	sal_Bool bRet = sal_False;
1216 	if(!isBeforeFirst())
1217 	{
1218 		if(m_bAfterLast)   // we stand after the last row so one before is the last row
1219 			bRet = last();
1220 		else
1221 		{
1222 			m_bAfterLast = sal_False;
1223 			--m_nPosition;
1224 			moveWindow();
1225 			OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
1226 
1227 			checkPositionFlags();
1228 
1229 			if(!m_nPosition)
1230 			{
1231 				m_bBeforeFirst = sal_True;
1232 				m_aMatrixIter = m_pMatrix->end();
1233 			}
1234 			else
1235 			{
1236 				m_aMatrixIter = calcPosition();
1237 				bRet = (*m_aMatrixIter).isValid();
1238 			}
1239 		}
1240 	}
1241 	return bRet;
1242 }
1243 // -------------------------------------------------------------------------
1244 void ORowSetCache::refreshRow(  )
1245 {
1246 	if(isAfterLast())
1247 		throw SQLException(DBACORE_RESSTRING(RID_STR_NO_REFESH_AFTERLAST),NULL,SQLSTATE_GENERAL,1000,Any() );
1248 	OSL_ENSURE(m_aMatrixIter != m_pMatrix->end(),"refreshRow() called for invalid row!");
1249 	m_pCacheSet->refreshRow();
1250 	m_pCacheSet->fillValueRow(*m_aMatrixIter,m_nPosition);
1251 	if ( m_bNew )
1252 	{
1253 		cancelRowModification();
1254 	}
1255 }
1256 // -------------------------------------------------------------------------
1257 sal_Bool ORowSetCache::rowUpdated(  )
1258 {
1259 	return m_pCacheSet->rowUpdated();
1260 }
1261 // -------------------------------------------------------------------------
1262 sal_Bool ORowSetCache::rowInserted(  )
1263 {
1264 	return m_pCacheSet->rowInserted();
1265 }
1266 // -------------------------------------------------------------------------
1267 // XResultSetUpdate
1268 sal_Bool ORowSetCache::insertRow(::std::vector< Any >& o_aBookmarks)
1269 {
1270 	if ( !m_bNew || !m_aInsertRow->isValid() )
1271 		throw SQLException(DBACORE_RESSTRING(RID_STR_NO_MOVETOINSERTROW_CALLED),NULL,SQLSTATE_GENERAL,1000,Any() );
1272 
1273 	m_pCacheSet->insertRow(*m_aInsertRow,m_aUpdateTable);
1274 
1275 	sal_Bool bRet( rowInserted() );
1276 	if ( bRet )
1277 	{
1278 		++m_nRowCount;
1279 		Any aBookmark = ((*m_aInsertRow)->get())[0].makeAny();
1280 		m_bAfterLast = m_bBeforeFirst = sal_False;
1281 		if(aBookmark.hasValue())
1282         {
1283 			moveToBookmark(aBookmark);
1284             // update the cached values
1285             ORowSetValueVector::Vector& rCurrentRow = ((*m_aMatrixIter))->get();
1286             ORowSetMatrix::iterator aIter = m_pMatrix->begin();
1287             for(;aIter != m_pMatrix->end();++aIter)
1288             {
1289                 if ( m_aMatrixIter != aIter && aIter->isValid() && m_pCacheSet->columnValuesUpdated((*aIter)->get(),rCurrentRow) )
1290                 {
1291                     o_aBookmarks.push_back(lcl_getBookmark((*aIter)->get()[0],m_pCacheSet));
1292                 }
1293             }
1294         }
1295 		else
1296 		{
1297 			OSL_ENSURE(0,"There must be a bookmark after the row was inserted!");
1298 		}
1299 	}
1300 	return bRet;
1301 }
1302 // -------------------------------------------------------------------------
1303 void ORowSetCache::resetInsertRow(sal_Bool _bClearInsertRow)
1304 {
1305 	if ( _bClearInsertRow )
1306 		clearInsertRow();
1307 	m_bNew		= sal_False;
1308 	m_bModified = sal_False;
1309 }
1310 // -------------------------------------------------------------------------
1311 void ORowSetCache::cancelRowModification()
1312 {
1313 	// clear the insertrow references	-> implies that the current row of the rowset changes as well
1314 	ORowSetCacheMap::iterator aCacheIter = m_aCacheIterators.begin();
1315 	ORowSetCacheMap::iterator aCacheEnd = m_aCacheIterators.end();
1316 	for(;aCacheIter != aCacheEnd;++aCacheIter)
1317 	{
1318 		if ( aCacheIter->second.pRowSet->isInsertRow() && aCacheIter->second.aIterator == m_aInsertRow )
1319 			aCacheIter->second.aIterator = m_pMatrix->end();
1320 	} // for(;aCacheIter != aCacheEnd;++aCacheIter)
1321 	resetInsertRow(sal_False);
1322 }
1323 // -------------------------------------------------------------------------
1324 void ORowSetCache::updateRow( ORowSetMatrix::iterator& _rUpdateRow,::std::vector< Any >& o_aBookmarks )
1325 {
1326 	if(isAfterLast() || isBeforeFirst())
1327 		throw SQLException(DBACORE_RESSTRING(RID_STR_NO_UPDATEROW),NULL,SQLSTATE_GENERAL,1000,Any() );
1328 
1329 	Any aBookmark = ((*_rUpdateRow)->get())[0].makeAny();
1330 	OSL_ENSURE(aBookmark.hasValue(),"Bookmark must have a value!");
1331 	// here we don't have to reposition our CacheSet, when we try to update a row,
1332 	// the row was already fetched
1333 	moveToBookmark(aBookmark);
1334 	m_pCacheSet->updateRow(*_rUpdateRow,*m_aMatrixIter,m_aUpdateTable);
1335 	// refetch the whole row
1336 	(*m_aMatrixIter) = NULL;
1337 
1338 	if ( moveToBookmark(aBookmark) )
1339     {
1340         // update the cached values
1341         ORowSetValueVector::Vector& rCurrentRow = ((*m_aMatrixIter))->get();
1342         ORowSetMatrix::iterator aIter = m_pMatrix->begin();
1343         for(;aIter != m_pMatrix->end();++aIter)
1344         {
1345             if ( m_aMatrixIter != aIter && aIter->isValid() && m_pCacheSet->columnValuesUpdated((*aIter)->get(),rCurrentRow) )
1346             {
1347                 o_aBookmarks.push_back(lcl_getBookmark((*aIter)->get()[0],m_pCacheSet));
1348             }
1349         }
1350     }
1351 
1352 	m_bModified = sal_False;
1353 }
1354 // -------------------------------------------------------------------------
1355 bool ORowSetCache::deleteRow(  )
1356 {
1357 	if(isAfterLast() || isBeforeFirst())
1358 		throw SQLException(DBACORE_RESSTRING(RID_STR_NO_DELETEROW),NULL,SQLSTATE_GENERAL,1000,Any() );
1359 
1360 	//	m_pCacheSet->absolute(m_nPosition);
1361 	m_pCacheSet->deleteRow(*m_aMatrixIter,m_aUpdateTable);
1362     if ( !m_pCacheSet->rowDeleted() )
1363         return false;
1364 
1365     --m_nRowCount;
1366     OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
1367     ORowSetMatrix::iterator aPos = calcPosition();
1368     (*aPos)	  = NULL;
1369 
1370     ORowSetMatrix::iterator aEnd = m_pMatrix->end();
1371     for(++aPos;aPos != aEnd && aPos->isValid();++aPos)
1372     {
1373         *(aPos-1) = *aPos;
1374         (*aPos)	  = NULL;
1375     }
1376     m_aMatrixIter = m_pMatrix->end();
1377 
1378     --m_nPosition;
1379     return true;
1380 }
1381 // -------------------------------------------------------------------------
1382 void ORowSetCache::cancelRowUpdates(  )
1383 {
1384 	m_bNew = m_bModified = sal_False;
1385 	if(!m_nPosition)
1386 	{
1387 		OSL_ENSURE(0,"cancelRowUpdates:Invalid positions pos == 0");
1388 		::dbtools::throwFunctionSequenceException(NULL);
1389 	}
1390 
1391 	if(m_pCacheSet->absolute(m_nPosition))
1392 		m_pCacheSet->fillValueRow(*m_aMatrixIter,m_nPosition);
1393 	else
1394 	{
1395 		OSL_ENSURE(0,"cancelRowUpdates couldn't position right with absolute");
1396 		::dbtools::throwFunctionSequenceException(NULL);
1397 	}
1398 }
1399 // -------------------------------------------------------------------------
1400 void ORowSetCache::moveToInsertRow(  )
1401 {
1402 	m_bNew		= sal_True;
1403 	m_bUpdated	= m_bAfterLast = sal_False;
1404 
1405 	m_aInsertRow = m_pInsertMatrix->begin();
1406 	if(!m_aInsertRow->isValid())
1407 		*m_aInsertRow = new ORowSetValueVector(m_xMetaData->getColumnCount());
1408 
1409 	// we don't unbound the bookmark column
1410 	ORowSetValueVector::Vector::iterator aIter = (*m_aInsertRow)->get().begin()+1;
1411     ORowSetValueVector::Vector::iterator aEnd = (*m_aInsertRow)->get().end();
1412 	for(sal_Int32 i = 1;aIter != aEnd;++aIter,++i)
1413 	{
1414 		aIter->setBound(sal_False);
1415 		aIter->setModified(sal_False);
1416 		aIter->setNull();
1417         aIter->setTypeKind(m_xMetaData->getColumnType(i));
1418 	}
1419 }
1420 // -------------------------------------------------------------------------
1421 ORowSetCacheIterator ORowSetCache::createIterator(ORowSetBase* _pRowSet)
1422 {
1423 
1424 	ORowSetCacheIterator_Helper aHelper;
1425 	aHelper.aIterator = m_pMatrix->end();
1426     aHelper.pRowSet = _pRowSet;
1427     return ORowSetCacheIterator(m_aCacheIterators.insert(m_aCacheIterators.begin(),ORowSetCacheMap::value_type(m_aCacheIterators.size()+1,aHelper)),this,_pRowSet);
1428 }
1429 // -----------------------------------------------------------------------------
1430 void ORowSetCache::deleteIterator(const ORowSetBase* _pRowSet)
1431 {
1432     ORowSetCacheMap::iterator aCacheIter = m_aCacheIterators.begin();
1433 	for(;aCacheIter != m_aCacheIterators.end();)
1434     {
1435         if ( aCacheIter->second.pRowSet == _pRowSet )
1436         {
1437             m_aCacheIterators.erase(aCacheIter);
1438             aCacheIter = m_aCacheIterators.begin();
1439         } // if ( aCacheIter->second.pRowSet == _pRowSet )
1440         else
1441             ++aCacheIter;
1442     }
1443 }
1444 // -----------------------------------------------------------------------------
1445 void ORowSetCache::rotateCacheIterator(ORowSetMatrix::difference_type _nDist)
1446 {
1447 	if(_nDist)
1448 	{
1449 		// now correct the iterator in our iterator vector
1450 		ORowSetCacheMap::iterator aCacheIter = m_aCacheIterators.begin();
1451         ORowSetCacheMap::iterator aCacheEnd  = m_aCacheIterators.end();
1452 		for(;aCacheIter != aCacheEnd;++aCacheIter)
1453 		{
1454 			if ( !aCacheIter->second.pRowSet->isInsertRow()
1455 				&& aCacheIter->second.aIterator != m_pMatrix->end() && !m_bModified )
1456 			{
1457 				ptrdiff_t nDist = (aCacheIter->second.aIterator - m_pMatrix->begin());
1458 				if(nDist < _nDist)
1459 				{
1460 					aCacheIter->second.aIterator = m_pMatrix->end();
1461 				}
1462 				else
1463 				{
1464                     OSL_ENSURE((aCacheIter->second.aIterator - m_pMatrix->begin()) >= _nDist,"Invalid Dist value!");
1465 					aCacheIter->second.aIterator -= _nDist;
1466 					OSL_ENSURE(aCacheIter->second.aIterator >= m_pMatrix->begin()
1467 							&& aCacheIter->second.aIterator < m_pMatrix->end(),"Iterator out of area!");
1468 				}
1469 			}
1470 		}
1471 	}
1472 }
1473 // -------------------------------------------------------------------------
1474 void ORowSetCache::setUpdateIterator(const ORowSetMatrix::iterator& _rOriginalRow)
1475 {
1476 	m_aInsertRow = m_pInsertMatrix->begin();
1477 	if(!m_aInsertRow->isValid())
1478 		*m_aInsertRow = new ORowSetValueVector(m_xMetaData->getColumnCount());
1479 
1480 	(*(*m_aInsertRow)) = (*(*_rOriginalRow));
1481 	// we don't unbound the bookmark column
1482 	ORowSetValueVector::Vector::iterator aIter = (*m_aInsertRow)->get().begin();
1483     ORowSetValueVector::Vector::iterator aEnd = (*m_aInsertRow)->get().end();
1484 	for(;aIter != aEnd;++aIter)
1485 		aIter->setModified(sal_False);
1486 }
1487 // -----------------------------------------------------------------------------
1488 void ORowSetCache::checkPositionFlags()
1489 {
1490 	if(m_bRowCountFinal)
1491 	{
1492 		m_bAfterLast	= m_nPosition > m_nRowCount;
1493 		if(m_bAfterLast)
1494 			m_nPosition = 0;//m_nRowCount;
1495 	}
1496 }
1497 // -----------------------------------------------------------------------------
1498 void ORowSetCache::checkUpdateConditions(sal_Int32 columnIndex)
1499 {
1500 	if(m_bAfterLast || columnIndex >= (sal_Int32)(*m_aInsertRow)->get().size())
1501 		throwFunctionSequenceException(m_xSet.get());
1502 }
1503 //------------------------------------------------------------------------------
1504 sal_Bool ORowSetCache::checkInnerJoin(const ::connectivity::OSQLParseNode *pNode,const Reference< XConnection>& _xConnection,const ::rtl::OUString& _sUpdateTableName)
1505 {
1506 	sal_Bool bOk = sal_False;
1507 	if (pNode->count() == 3 &&	// Ausdruck is geklammert
1508 		SQL_ISPUNCTUATION(pNode->getChild(0),"(") &&
1509 		SQL_ISPUNCTUATION(pNode->getChild(2),")"))
1510 	{
1511 		bOk = checkInnerJoin(pNode->getChild(1),_xConnection,_sUpdateTableName);
1512 	}
1513 	else if ((SQL_ISRULE(pNode,search_condition) || SQL_ISRULE(pNode,boolean_term))	&&			// AND/OR-Verknuepfung:
1514 				pNode->count() == 3)
1515 	{
1516 		// nur AND Verkn�pfung zulassen
1517 		if ( SQL_ISTOKEN(pNode->getChild(1),AND) )
1518             bOk = checkInnerJoin(pNode->getChild(0),_xConnection,_sUpdateTableName)
1519                 && checkInnerJoin(pNode->getChild(2),_xConnection,_sUpdateTableName);
1520 	}
1521 	else if (SQL_ISRULE(pNode,comparison_predicate))
1522 	{
1523 		// only the comparison of columns is allowed
1524 		DBG_ASSERT(pNode->count() == 3,"checkInnerJoin: Fehler im Parse Tree");
1525 		if (!(SQL_ISRULE(pNode->getChild(0),column_ref) &&
1526 				SQL_ISRULE(pNode->getChild(2),column_ref) &&
1527 				pNode->getChild(1)->getNodeType() == SQL_NODE_EQUAL))
1528 		{
1529 			bOk = sal_False;
1530 		}
1531 		::rtl::OUString sColumnName,sTableRange;
1532 		OSQLParseTreeIterator::getColumnRange( pNode->getChild(0), _xConnection, sColumnName, sTableRange );
1533         bOk = sTableRange == _sUpdateTableName;
1534 		if ( !bOk )
1535 		{
1536 			OSQLParseTreeIterator::getColumnRange( pNode->getChild(2), _xConnection, sColumnName, sTableRange );
1537 			bOk =  sTableRange == _sUpdateTableName;
1538 		}
1539 	}
1540 	return bOk;
1541 }
1542 // -----------------------------------------------------------------------------
1543 sal_Bool ORowSetCache::checkJoin(const Reference< XConnection>& _xConnection,
1544 								 const Reference< XSingleSelectQueryAnalyzer >& _xAnalyzer,
1545 								 const ::rtl::OUString& _sUpdateTableName )
1546 {
1547 	sal_Bool bOk = sal_False;
1548 	::rtl::OUString sSql = _xAnalyzer->getQuery();
1549 	::rtl::OUString sErrorMsg;
1550 	::connectivity::OSQLParser aSqlParser( m_aContext.getLegacyServiceFactory() );
1551 	::std::auto_ptr< ::connectivity::OSQLParseNode> pSqlParseNode( aSqlParser.parseTree(sErrorMsg,sSql));
1552 	if ( pSqlParseNode.get() && SQL_ISRULE(pSqlParseNode, select_statement) )
1553 	{
1554 		OSQLParseNode* pTableRefCommalist = pSqlParseNode->getByRule(::connectivity::OSQLParseNode::table_ref_commalist);
1555 		OSL_ENSURE(pTableRefCommalist,"NO tables why!?");
1556 		if(pTableRefCommalist && pTableRefCommalist->count() == 1)
1557 		{
1558 			// we found only one element so it must some kind of join here
1559 			OSQLParseNode* pJoin = pTableRefCommalist->getByRule(::connectivity::OSQLParseNode::qualified_join);
1560 			if(pJoin)
1561 			{ // we are only intereseted in qualified joins like RIGHT or LEFT
1562 				OSQLParseNode* pJoinType	= pJoin->getChild(1);
1563 				OSQLParseNode* pOuterType	= NULL;
1564 				if(SQL_ISRULE(pJoinType,join_type) && pJoinType->count() == 2)
1565 					pOuterType = pJoinType->getChild(0);
1566 				else if(SQL_ISRULE(pJoinType,outer_join_type))
1567 					pOuterType = pJoinType;
1568 
1569 				sal_Bool bCheck		= sal_False;
1570 				sal_Bool bLeftSide	= sal_False;
1571 				if(pOuterType)
1572 				{ // found outer join
1573 					bLeftSide = SQL_ISTOKEN(pOuterType->getChild(0),LEFT);
1574 					bCheck = bLeftSide || SQL_ISTOKEN(pOuterType->getChild(0),RIGHT);
1575 				}
1576 
1577 				if(bCheck)
1578 				{ // here we know that we have to check on which side our table resides
1579 					const OSQLParseNode* pTableRef = pJoin->getByRule(::connectivity::OSQLParseNode::qualified_join);
1580 					if(bLeftSide)
1581 						pTableRef = pJoin->getChild(0);
1582 					else
1583 						pTableRef = pJoin->getChild(3);
1584 					OSL_ENSURE(SQL_ISRULE(pTableRef,table_ref),"Must be a tableref here!");
1585 
1586                     ::rtl::OUString sTableRange = OSQLParseNode::getTableRange(pTableRef);
1587 					if(!sTableRange.getLength())
1588 						pTableRef->getChild(0)->parseNodeToStr( sTableRange, _xConnection, NULL, sal_False, sal_False );
1589 					bOk =  sTableRange == _sUpdateTableName;
1590 				}
1591 			}
1592 		}
1593 		else
1594 		{
1595 			OSQLParseNode* pWhereOpt = pSqlParseNode->getChild(3)->getChild(1);
1596 			if ( pWhereOpt && !pWhereOpt->isLeaf() )
1597 				bOk = checkInnerJoin(pWhereOpt->getChild(1),_xConnection,_sUpdateTableName);
1598 		}
1599 	}
1600 	return bOk;
1601 }
1602 // -----------------------------------------------------------------------------
1603 void ORowSetCache::clearInsertRow()
1604 {
1605 	// we don't unbound the bookmark column
1606 	if ( m_aInsertRow != m_pInsertMatrix->end() && m_aInsertRow->isValid() )
1607 	{
1608 		ORowSetValueVector::Vector::iterator aIter = (*m_aInsertRow)->get().begin()+1;
1609 		ORowSetValueVector::Vector::iterator aEnd = (*m_aInsertRow)->get().end();
1610 		for(;aIter != aEnd;++aIter)
1611 		{
1612 			aIter->setBound(sal_False);
1613 			aIter->setModified(sal_False);
1614 			aIter->setNull();
1615 		} // for(;aIter != (*m_aInsertRow)->end();++aIter)
1616 	}
1617 }
1618 // -----------------------------------------------------------------------------
1619 ORowSetMatrix::iterator	ORowSetCache::calcPosition() const
1620 {
1621 	sal_Int32 nValue = (m_nPosition - m_nStartPos) - 1;
1622     CHECK_MATRIX_POS(nValue);
1623 	return ( nValue < 0 || nValue >= static_cast<sal_Int32>(m_pMatrix->size()) ) ? m_pMatrix->end() : (m_pMatrix->begin() + nValue);
1624 }
1625 // -----------------------------------------------------------------------------
1626 
1627 TORowSetOldRowHelperRef ORowSetCache::registerOldRow()
1628 {
1629 	TORowSetOldRowHelperRef pRef = new ORowSetOldRowHelper(ORowSetRow());
1630 	m_aOldRows.push_back(pRef);
1631 	return pRef;
1632 }
1633 // -----------------------------------------------------------------------------
1634 void ORowSetCache::deregisterOldRow(const TORowSetOldRowHelperRef& _rRow)
1635 {
1636     TOldRowSetRows::iterator aOldRowEnd = m_aOldRows.end();
1637 	for (TOldRowSetRows::iterator aOldRowIter = m_aOldRows.begin(); aOldRowIter != aOldRowEnd; ++aOldRowIter)
1638 	{
1639 		if ( aOldRowIter->getBodyPtr() == _rRow.getBodyPtr() )
1640 		{
1641 			m_aOldRows.erase(aOldRowIter);
1642 			break;
1643 		}
1644 
1645 	}
1646 }
1647 // -----------------------------------------------------------------------------
1648 sal_Bool ORowSetCache::reFillMatrix(sal_Int32 _nNewStartPos,sal_Int32 _nNewEndPos)
1649 {
1650     TOldRowSetRows::iterator aOldRowEnd = m_aOldRows.end();
1651 	for (TOldRowSetRows::iterator aOldRowIter = m_aOldRows.begin(); aOldRowIter != aOldRowEnd; ++aOldRowIter)
1652 	{
1653 		if ( aOldRowIter->isValid() && aOldRowIter->getBody().getRow().isValid() )
1654 			aOldRowIter->getBody().setRow(new ORowSetValueVector(aOldRowIter->getBody().getRow().getBody()) );
1655 	}
1656 	sal_Int32 nNewSt = _nNewStartPos;
1657 	sal_Bool bRet = fillMatrix(nNewSt,_nNewEndPos);
1658 	m_nStartPos = nNewSt - 1;
1659 	rotateCacheIterator(static_cast<sal_Int16>(m_nFetchSize+1)); // forces that every iterator will be set to null
1660 	return bRet;
1661 }
1662 // -----------------------------------------------------------------------------
1663 sal_Bool ORowSetCache::fill(ORowSetMatrix::iterator& _aIter,const ORowSetMatrix::iterator& _aEnd,sal_Int32& _nPos,sal_Bool _bCheck)
1664 {
1665 	sal_Int32 nColumnCount = m_xMetaData->getColumnCount();
1666 	for(; _bCheck && _aIter != _aEnd;)
1667 	{
1668 		if ( !_aIter->isValid() )
1669 			*_aIter = new ORowSetValueVector(nColumnCount);
1670 		else
1671 		{
1672             TOldRowSetRows::iterator aOldRowEnd = m_aOldRows.end();
1673 	        for (TOldRowSetRows::iterator aOldRowIter = m_aOldRows.begin(); aOldRowIter != aOldRowEnd; ++aOldRowIter)
1674 			{
1675 				if ( aOldRowIter->getBody().getRow().isEqualBody(*_aIter) )
1676 					*_aIter = new ORowSetValueVector(nColumnCount);
1677 			}
1678 		}
1679 		m_pCacheSet->fillValueRow(*_aIter++,++_nPos);
1680 		_bCheck = m_pCacheSet->next();
1681 	}
1682 	return _bCheck;
1683 }
1684 // -----------------------------------------------------------------------------
1685 bool ORowSetCache::isResultSetChanged() const
1686 {
1687     return m_pCacheSet->isResultSetChanged();
1688 }
1689 // -----------------------------------------------------------------------------
1690 void ORowSetCache::reset(const Reference< XResultSet>& _xDriverSet)
1691 {
1692     m_xMetaData.set(Reference< XResultSetMetaDataSupplier >(_xDriverSet,UNO_QUERY)->getMetaData());
1693     m_pCacheSet->reset(_xDriverSet);
1694 
1695     m_bRowCountFinal = sal_False;
1696     m_nRowCount = 0;
1697 	reFillMatrix(m_nStartPos+1,m_nEndPos+1);
1698 }
1699 // -----------------------------------------------------------------------------
1700 void ORowSetCache::impl_updateRowFromCache_throw(ORowSetValueVector::Vector& io_aRow
1701                                            ,::std::vector<sal_Int32>& o_ChangedColumns)
1702 {
1703     if ( o_ChangedColumns.size() > 1 )
1704     {
1705         ORowSetMatrix::iterator aIter = m_pMatrix->begin();
1706         for(;aIter != m_pMatrix->end();++aIter)
1707         {
1708             if ( aIter->isValid() && m_pCacheSet->updateColumnValues((*aIter)->get(),io_aRow,o_ChangedColumns))
1709             {
1710                 break;
1711             }
1712         }
1713 
1714         if ( aIter == m_pMatrix->end() )
1715         {
1716             m_pCacheSet->fillMissingValues(io_aRow);
1717         }
1718     }
1719 }
1720 // -----------------------------------------------------------------------------
1721