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

Generated by: LCOV version 1.10