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

Generated by: LCOV version 1.10