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

Generated by: LCOV version 1.11