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