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