LCOV - code coverage report
Current view: top level - dbaccess/source/core/api - RowSetCache.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 480 861 55.7 %
Date: 2014-04-11 Functions: 51 58 87.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10