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