summaryrefslogtreecommitdiff
path: root/dbaccess/source/core/api/RowSetCache.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'dbaccess/source/core/api/RowSetCache.cxx')
-rw-r--r--dbaccess/source/core/api/RowSetCache.cxx1685
1 files changed, 1685 insertions, 0 deletions
diff --git a/dbaccess/source/core/api/RowSetCache.cxx b/dbaccess/source/core/api/RowSetCache.cxx
new file mode 100644
index 000000000000..e4e468b13779
--- /dev/null
+++ b/dbaccess/source/core/api/RowSetCache.cxx
@@ -0,0 +1,1685 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_dbaccess.hxx"
+
+
+#include "BookmarkSet.hxx"
+#include "CRowSetColumn.hxx"
+#include "CRowSetDataColumn.hxx"
+#include "KeySet.hxx"
+#include "OptimisticSet.hxx"
+#include "RowSetBase.hxx"
+#include "RowSetCache.hxx"
+#include "StaticSet.hxx"
+#include "WrappedResultSet.hxx"
+#include "core_resource.hrc"
+#include "core_resource.hxx"
+#include "dbastrings.hrc"
+
+/** === begin UNO includes === **/
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbcx/CompareBookmark.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+/** === end UNO includes === **/
+
+#include <comphelper/extract.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/seqstream.hxx>
+#include <comphelper/uno3.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/sqliterator.hxx>
+#include <connectivity/sqlnode.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <algorithm>
+
+using namespace dbaccess;
+using namespace dbtools;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::cppu;
+using namespace ::osl;
+
+#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!")
+
+DBG_NAME(ORowSetCache)
+// -------------------------------------------------------------------------
+ORowSetCache::ORowSetCache(const Reference< XResultSet >& _xRs,
+ const Reference< XSingleSelectQueryAnalyzer >& _xAnalyzer,
+ const ::comphelper::ComponentContext& _rContext,
+ const ::rtl::OUString& _rUpdateTableName,
+ sal_Bool& _bModified,
+ sal_Bool& _bNew,
+ const ORowSetValueVector& _aParameterValueForCache,
+ const ::rtl::OUString& i_sRowSetFilter)
+ :m_xSet(_xRs)
+ ,m_xMetaData(Reference< XResultSetMetaDataSupplier >(_xRs,UNO_QUERY)->getMetaData())
+ ,m_aContext( _rContext )
+ ,m_pCacheSet(NULL)
+ ,m_pMatrix(NULL)
+ ,m_pInsertMatrix(NULL)
+ ,m_nLastColumnIndex(0)
+ ,m_nFetchSize(0)
+ ,m_nRowCount(0)
+ ,m_nPrivileges( Privilege::SELECT )
+ ,m_nPosition(0)
+ ,m_nStartPos(0)
+ ,m_nEndPos(0)
+ ,m_bRowCountFinal(sal_False)
+ ,m_bBeforeFirst(sal_True)
+ ,m_bAfterLast( sal_False )
+ ,m_bUpdated(sal_False)
+ ,m_bModified(_bModified)
+ ,m_bNew(_bNew)
+{
+ DBG_CTOR(ORowSetCache,NULL);
+
+ // first try if the result can be used to do inserts and updates
+ try
+ {
+ Reference< XResultSetUpdate> xUp(_xRs,UNO_QUERY_THROW);
+ Reference< XPropertySet> xProp(_xRs,UNO_QUERY);
+ Reference< XPropertySetInfo > xPropInfo = xProp->getPropertySetInfo();
+ sal_Bool bBookmarkable = xPropInfo->hasPropertyByName(PROPERTY_ISBOOKMARKABLE) &&
+ any2bool(xProp->getPropertyValue(PROPERTY_ISBOOKMARKABLE)) && Reference< XRowLocate >(_xRs, UNO_QUERY).is();
+ if ( bBookmarkable )
+ {
+ xUp->moveToInsertRow();
+ xUp->cancelRowUpdates();
+ _xRs->beforeFirst();
+ m_nPrivileges = Privilege::SELECT|Privilege::DELETE|Privilege::INSERT|Privilege::UPDATE;
+ m_pCacheSet = new WrappedResultSet();
+ m_xCacheSet = m_pCacheSet;
+ m_pCacheSet->construct(_xRs,i_sRowSetFilter);
+ return;
+ }
+ }
+ catch(const Exception& ex)
+ {
+ (void)ex;
+ }
+ _xRs->beforeFirst();
+
+ // check if all keys of the updateable table are fetched
+ sal_Bool bAllKeysFound = sal_False;
+ sal_Int32 nTablesCount = 0;
+
+ Reference< XPropertySet> xProp(_xRs,UNO_QUERY);
+ Reference< XPropertySetInfo > xPropInfo = xProp->getPropertySetInfo();
+ sal_Bool bNeedKeySet = !(xPropInfo->hasPropertyByName(PROPERTY_ISBOOKMARKABLE) &&
+ any2bool(xProp->getPropertyValue(PROPERTY_ISBOOKMARKABLE)) && Reference< XRowLocate >(_xRs, UNO_QUERY).is() );
+ bNeedKeySet = bNeedKeySet || (xPropInfo->hasPropertyByName(PROPERTY_RESULTSETCONCURRENCY) &&
+ ::comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY)) == ResultSetConcurrency::READ_ONLY);
+
+ Reference< XIndexAccess> xUpdateTableKeys;
+ ::rtl::OUString aUpdateTableName = _rUpdateTableName;
+ Reference< XConnection> xConnection;
+ // first we need a connection
+ Reference< XStatement> xStmt(_xRs->getStatement(),UNO_QUERY);
+ if(xStmt.is())
+ xConnection = xStmt->getConnection();
+ else
+ {
+ Reference< XPreparedStatement> xPrepStmt(_xRs->getStatement(),UNO_QUERY);
+ xConnection = xPrepStmt->getConnection();
+ }
+ OSL_ENSURE(xConnection.is(),"No connection!");
+ if(_xAnalyzer.is())
+ {
+ try
+ {
+ Reference<XTablesSupplier> xTabSup(_xAnalyzer,UNO_QUERY);
+ OSL_ENSURE(xTabSup.is(),"ORowSet::execute composer isn't a tablesupplier!");
+ Reference<XNameAccess> xTables = xTabSup->getTables();
+ Sequence< ::rtl::OUString> aTableNames = xTables->getElementNames();
+ if ( aTableNames.getLength() > 1 && !_rUpdateTableName.getLength() && bNeedKeySet )
+ {// here we have a join or union and nobody told us which table to update, so we update them all
+ m_nPrivileges = Privilege::SELECT|Privilege::DELETE|Privilege::INSERT|Privilege::UPDATE;
+ OptimisticSet* pCursor = new OptimisticSet(m_aContext,xConnection,_xAnalyzer,_aParameterValueForCache);
+ m_pCacheSet = pCursor;
+ m_xCacheSet = m_pCacheSet;
+ try
+ {
+ m_pCacheSet->construct(_xRs,i_sRowSetFilter);
+ if ( pCursor->isReadOnly() )
+ m_nPrivileges = Privilege::SELECT;
+ m_aKeyColumns = pCursor->getJoinedKeyColumns();
+ return;
+ }
+ catch(const Exception&)
+ {
+ // DBG_UNHANDLED_EXCEPTION();
+ }
+ m_pCacheSet = NULL;
+ m_xCacheSet.clear();
+ }
+ else
+ {
+ if(_rUpdateTableName.getLength() && xTables->hasByName(_rUpdateTableName))
+ xTables->getByName(_rUpdateTableName) >>= m_aUpdateTable;
+ else if(xTables->getElementNames().getLength())
+ {
+ aUpdateTableName = xTables->getElementNames()[0];
+ xTables->getByName(aUpdateTableName) >>= m_aUpdateTable;
+ }
+ Reference<XIndexAccess> xIndexAccess(xTables,UNO_QUERY);
+ if(xIndexAccess.is())
+ nTablesCount = xIndexAccess->getCount();
+ else
+ nTablesCount = xTables->getElementNames().getLength();
+
+ if(m_aUpdateTable.is() && nTablesCount < 3) // for we can't handle more than 2 tables in our keyset
+ {
+ Reference<XPropertySet> xSet(m_aUpdateTable,UNO_QUERY);
+ const Reference<XNameAccess> xPrimaryKeyColumns = dbtools::getPrimaryKeyColumns_throw(xSet);
+ if ( xPrimaryKeyColumns.is() )
+ {
+ Reference<XColumnsSupplier> xColSup(_xAnalyzer,UNO_QUERY);
+ if ( xColSup.is() )
+ {
+ Reference<XNameAccess> xSelColumns = xColSup->getColumns();
+ Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
+ SelectColumnsMetaData aColumnNames(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers() ? true : false);
+ ::dbaccess::getColumnPositions(xSelColumns,xPrimaryKeyColumns->getElementNames(),aUpdateTableName,aColumnNames);
+ bAllKeysFound = !aColumnNames.empty() && sal_Int32(aColumnNames.size()) == xPrimaryKeyColumns->getElementNames().getLength();
+ }
+ }
+ }
+ }
+ }
+ catch(Exception&)
+ {
+ }
+ }
+
+ // first check if resultset is bookmarkable
+ if(!bNeedKeySet)
+ {
+ try
+ {
+ m_pCacheSet = new OBookmarkSet();
+ m_xCacheSet = m_pCacheSet;
+ m_pCacheSet->construct(_xRs,i_sRowSetFilter);
+
+ // check privileges
+ m_nPrivileges = Privilege::SELECT;
+ if(Reference<XResultSetUpdate>(_xRs,UNO_QUERY).is()) // this interface is optional so we have to check it
+ {
+ Reference<XPropertySet> xTable(m_aUpdateTable,UNO_QUERY);
+ if(xTable.is() && xTable->getPropertySetInfo()->hasPropertyByName(PROPERTY_PRIVILEGES))
+ {
+ m_nPrivileges = 0;
+ xTable->getPropertyValue(PROPERTY_PRIVILEGES) >>= m_nPrivileges;
+ if(!m_nPrivileges)
+ m_nPrivileges = Privilege::SELECT;
+ }
+ }
+ }
+ catch(const SQLException&)
+ {
+ bNeedKeySet = sal_True;
+ }
+
+ }
+ if(bNeedKeySet)
+ {
+ // need to check if we could handle this select clause
+ bAllKeysFound = bAllKeysFound && (nTablesCount == 1 || checkJoin(xConnection,_xAnalyzer,aUpdateTableName));
+
+ // || !(comphelper::hasProperty(PROPERTY_CANUPDATEINSERTEDROWS,xProp) && any2bool(xProp->getPropertyValue(PROPERTY_CANUPDATEINSERTEDROWS)))
+
+ // oj removed because keyset uses only the next// || (xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_RESULTSETTYPE) && comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETTYPE)) == ResultSetType::FORWARD_ONLY)
+ if(!bAllKeysFound )
+ {
+ m_pCacheSet = new OStaticSet();
+ m_xCacheSet = m_pCacheSet;
+ m_pCacheSet->construct(_xRs,i_sRowSetFilter);
+ m_nPrivileges = Privilege::SELECT;
+ }
+ else
+ {
+ Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
+ SelectColumnsMetaData aColumnNames(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers() ? true : false);
+ Reference<XColumnsSupplier> xColSup(_xAnalyzer,UNO_QUERY);
+ Reference<XNameAccess> xSelColumns = xColSup->getColumns();
+ Reference<XNameAccess> xColumns = m_aUpdateTable->getColumns();
+ ::dbaccess::getColumnPositions(xSelColumns,xColumns->getElementNames(),aUpdateTableName,aColumnNames);
+
+ // check privileges
+ m_nPrivileges = Privilege::SELECT;
+ sal_Bool bNoInsert = sal_False;
+
+ Sequence< ::rtl::OUString> aNames(xColumns->getElementNames());
+ const ::rtl::OUString* pIter = aNames.getConstArray();
+ const ::rtl::OUString* pEnd = pIter + aNames.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ Reference<XPropertySet> xColumn(xColumns->getByName(*pIter),UNO_QUERY);
+ OSL_ENSURE(xColumn.is(),"Column in table is null!");
+ if(xColumn.is())
+ {
+ sal_Int32 nNullable = 0;
+ xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable;
+ if(nNullable == ColumnValue::NO_NULLS && aColumnNames.find(*pIter) == aColumnNames.end())
+ { // we found a column where null is not allowed so we can't insert new values
+ bNoInsert = sal_True;
+ break; // one column is enough
+ }
+ }
+ }
+
+ OKeySet* pKeySet = new OKeySet(m_aUpdateTable,xUpdateTableKeys,aUpdateTableName ,_xAnalyzer,_aParameterValueForCache);
+ try
+ {
+ m_pCacheSet = pKeySet;
+ m_xCacheSet = m_pCacheSet;
+ pKeySet->construct(_xRs,i_sRowSetFilter);
+
+ if(Reference<XResultSetUpdate>(_xRs,UNO_QUERY).is()) // this interface is optional so we have to check it
+ {
+ Reference<XPropertySet> xTable(m_aUpdateTable,UNO_QUERY);
+ if(xTable.is() && xTable->getPropertySetInfo()->hasPropertyByName(PROPERTY_PRIVILEGES))
+ {
+ m_nPrivileges = 0;
+ xTable->getPropertyValue(PROPERTY_PRIVILEGES) >>= m_nPrivileges;
+ if(!m_nPrivileges)
+ m_nPrivileges = Privilege::SELECT;
+ }
+ }
+ if(bNoInsert)
+ m_nPrivileges |= ~Privilege::INSERT; // remove the insert privilege
+ }
+ catch(const SQLException&)
+ {
+ // we couldn't create a keyset here so we have to create a static cache
+ if ( m_pCacheSet )
+ m_pCacheSet = NULL;
+ m_xCacheSet = NULL;
+ m_pCacheSet = new OStaticSet();
+ m_xCacheSet = m_pCacheSet;
+ m_pCacheSet->construct(_xRs,i_sRowSetFilter);
+ m_nPrivileges = Privilege::SELECT;
+ }
+ }
+
+ }
+ // last check
+ if(!bAllKeysFound && xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_RESULTSETCONCURRENCY) &&
+ ::comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY)) == ResultSetConcurrency::READ_ONLY)
+ m_nPrivileges = Privilege::SELECT;
+}
+
+// -------------------------------------------------------------------------
+ORowSetCache::~ORowSetCache()
+{
+ m_pCacheSet = NULL;
+ m_xCacheSet = NULL;
+ if(m_pMatrix)
+ {
+ m_pMatrix->clear();
+ delete m_pMatrix;
+ }
+
+ if(m_pInsertMatrix)
+ {
+ m_pInsertMatrix->clear();
+ delete m_pInsertMatrix;
+ }
+ m_xSet = WeakReference< XResultSet>();
+ m_xMetaData = NULL;
+ m_aUpdateTable = NULL;
+
+ DBG_DTOR(ORowSetCache,NULL);
+}
+
+// -------------------------------------------------------------------------
+void ORowSetCache::setMaxRowSize(sal_Int32 _nSize)
+{
+
+ if(_nSize == m_nFetchSize)
+ return;
+
+ m_nFetchSize = _nSize;
+ if(!m_pMatrix)
+ {
+ m_pMatrix = new ORowSetMatrix(_nSize);
+ m_aMatrixIter = m_pMatrix->end();
+ m_aMatrixEnd = m_pMatrix->end();
+
+ m_pInsertMatrix = new ORowSetMatrix(1); // a little bit overkill but ??? :-)
+ m_aInsertRow = m_pInsertMatrix->end();
+ }
+ else
+ {
+ // now correct the iterator in our iterator vector
+ ::std::vector<sal_Int32> aPositions;
+ ::std::map<sal_Int32,sal_Bool> aCacheIterToChange;
+ // first get the positions where they stand now
+ ORowSetCacheMap::iterator aCacheIter = m_aCacheIterators.begin();
+ ORowSetCacheMap::iterator aCacheEnd = m_aCacheIterators.end();
+ for(;aCacheIter != aCacheEnd;++aCacheIter)
+ {
+ aCacheIterToChange[aCacheIter->first] = sal_False;
+ if ( !aCacheIter->second.pRowSet->isInsertRow()
+ /*&& aCacheIter->second.aIterator != m_pMatrix->end()*/ && !m_bModified )
+ {
+ ptrdiff_t nDist = (aCacheIter->second.aIterator - m_pMatrix->begin());
+ aPositions.push_back(nDist);
+ aCacheIterToChange[aCacheIter->first] = sal_True;
+ }
+ }
+ sal_Int32 nKeyPos = (m_aMatrixIter - m_pMatrix->begin());
+ m_pMatrix->resize(_nSize);
+
+ if ( nKeyPos < _nSize )
+ m_aMatrixIter = m_pMatrix->begin() + nKeyPos;
+ else
+ m_aMatrixIter = m_pMatrix->end();
+ m_aMatrixEnd = m_pMatrix->end();
+
+ // now adjust their positions because a resize invalid all iterators
+ ::std::vector<sal_Int32>::const_iterator aIter = aPositions.begin();
+ ::std::map<sal_Int32,sal_Bool>::const_iterator aPosChangeIter = aCacheIterToChange.begin();
+ for( aCacheIter = m_aCacheIterators.begin();
+ aPosChangeIter != aCacheIterToChange.end();
+ ++aPosChangeIter,++aCacheIter)
+ {
+ if ( aPosChangeIter->second )
+ {
+ CHECK_MATRIX_POS(*aIter);
+ if ( *aIter < _nSize )
+ aCacheIter->second.aIterator = m_pMatrix->begin() + *aIter++;
+ else
+ aCacheIter->second.aIterator = m_pMatrix->end();
+ }
+ }
+ }
+ if(!m_nPosition)
+ {
+ sal_Int32 nNewSt = 1;
+ fillMatrix(nNewSt,_nSize+1);
+ m_nStartPos = 0;
+ m_nEndPos = _nSize;
+ }
+}
+// -------------------------------------------------------------------------
+
+// XResultSetMetaDataSupplier
+Reference< XResultSetMetaData > ORowSetCache::getMetaData( )
+{
+ return m_xMetaData;
+}
+// -------------------------------------------------------------------------
+Any lcl_getBookmark(ORowSetValue& i_aValue,OCacheSet* i_pCacheSet)
+{
+ switch ( i_aValue.getTypeKind() )
+ {
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ return makeAny((sal_Int32)i_aValue);
+ default:
+ if ( i_pCacheSet && i_aValue.isNull())
+ i_aValue = i_pCacheSet->getBookmark();
+ return i_aValue.getAny();
+ }
+}
+// -------------------------------------------------------------------------
+// ::com::sun::star::sdbcx::XRowLocate
+Any ORowSetCache::getBookmark( )
+{
+
+ if(m_bAfterLast)
+ throwFunctionSequenceException(m_xSet.get());
+
+ if ( m_aMatrixIter >= m_pMatrix->end() || m_aMatrixIter < m_pMatrix->begin() || !(*m_aMatrixIter).isValid())
+ {
+ return Any(); // this is allowed here because the rowset knowns what it is doing
+ }
+
+ return lcl_getBookmark(((*m_aMatrixIter)->get())[0],m_pCacheSet);
+}
+// -------------------------------------------------------------------------
+sal_Bool ORowSetCache::moveToBookmark( const Any& bookmark )
+{
+ if ( m_pCacheSet->moveToBookmark(bookmark) )
+ {
+ m_bBeforeFirst = sal_False;
+ m_nPosition = m_pCacheSet->getRow();
+
+ checkPositionFlags();
+
+ if(!m_bAfterLast)
+ {
+ moveWindow();
+ checkPositionFlags();
+ if ( !m_bAfterLast )
+ {
+ m_aMatrixIter = calcPosition();
+ OSL_ENSURE(m_aMatrixIter->isValid(),"Iterator after moveToBookmark not valid");
+ }
+ else
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ else
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ else
+ return sal_False;
+
+ return m_aMatrixIter != m_pMatrix->end() && (*m_aMatrixIter).isValid();
+}
+// -------------------------------------------------------------------------
+sal_Bool ORowSetCache::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows )
+{
+ sal_Bool bRet( moveToBookmark( bookmark ) );
+ if ( bRet )
+ {
+ m_nPosition = m_pCacheSet->getRow() + rows;
+ absolute(m_nPosition);
+ // for(sal_Int32 i=0;i<rows && m_aMatrixIter != m_pMatrix->end();++i,++m_aMatrixIter) ;
+
+ bRet = m_aMatrixIter != m_pMatrix->end() && (*m_aMatrixIter).isValid();
+ }
+
+ return bRet;
+}
+// -------------------------------------------------------------------------
+sal_Int32 ORowSetCache::compareBookmarks( const Any& _first, const Any& _second )
+{
+ return (!_first.hasValue() || !_second.hasValue()) ? CompareBookmark::NOT_COMPARABLE : m_pCacheSet->compareBookmarks(_first,_second);
+}
+// -------------------------------------------------------------------------
+sal_Bool ORowSetCache::hasOrderedBookmarks( )
+{
+ return m_pCacheSet->hasOrderedBookmarks();
+}
+// -------------------------------------------------------------------------
+sal_Int32 ORowSetCache::hashBookmark( const Any& bookmark )
+{
+ return m_pCacheSet->hashBookmark(bookmark);
+}
+// XRowUpdate
+// -----------------------------------------------------------------------------
+void ORowSetCache::updateNull(sal_Int32 columnIndex,ORowSetValueVector::Vector& io_aRow
+ ,::std::vector<sal_Int32>& o_ChangedColumns
+ )
+{
+ checkUpdateConditions(columnIndex);
+
+ ORowSetValueVector::Vector& rInsert = ((*m_aInsertRow)->get());
+ rInsert[columnIndex].setBound(sal_True);
+ rInsert[columnIndex].setNull();
+ rInsert[columnIndex].setModified();
+ io_aRow[columnIndex].setNull();
+
+ m_pCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
+ impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
+}
+// -----------------------------------------------------------------------------
+void ORowSetCache::updateValue(sal_Int32 columnIndex,const ORowSetValue& x
+ ,ORowSetValueVector::Vector& io_aRow
+ ,::std::vector<sal_Int32>& o_ChangedColumns
+ )
+{
+ checkUpdateConditions(columnIndex);
+
+ ORowSetValueVector::Vector& rInsert = ((*m_aInsertRow)->get());
+ rInsert[columnIndex].setBound(sal_True);
+ rInsert[columnIndex] = x;
+ rInsert[columnIndex].setModified();
+ io_aRow[columnIndex] = rInsert[columnIndex];
+
+ m_pCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
+ impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
+}
+// -------------------------------------------------------------------------
+void ORowSetCache::updateCharacterStream( sal_Int32 columnIndex, const Reference< ::com::sun::star::io::XInputStream >& x
+ , sal_Int32 length,ORowSetValueVector::Vector& io_aRow
+ ,::std::vector<sal_Int32>& o_ChangedColumns
+ )
+{
+ checkUpdateConditions(columnIndex);
+
+ Sequence<sal_Int8> aSeq;
+ if(x.is())
+ x->readBytes(aSeq,length);
+
+ ORowSetValueVector::Vector& rInsert = ((*m_aInsertRow)->get());
+ rInsert[columnIndex].setBound(sal_True);
+ rInsert[columnIndex] = aSeq;
+ rInsert[columnIndex].setModified();
+ io_aRow[columnIndex] = makeAny(x);
+
+ m_pCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
+ impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
+}
+// -------------------------------------------------------------------------
+void ORowSetCache::updateObject( sal_Int32 columnIndex, const Any& x
+ ,ORowSetValueVector::Vector& io_aRow
+ ,::std::vector<sal_Int32>& o_ChangedColumns
+ )
+{
+ checkUpdateConditions(columnIndex);
+
+ ORowSetValueVector::Vector& rInsert = ((*m_aInsertRow)->get());
+ rInsert[columnIndex].setBound(sal_True);
+ rInsert[columnIndex] = x;
+ rInsert[columnIndex].setModified();
+ io_aRow[columnIndex] = rInsert[columnIndex];
+
+ m_pCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
+ impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
+}
+// -------------------------------------------------------------------------
+void ORowSetCache::updateNumericObject( sal_Int32 columnIndex, const Any& x, sal_Int32 /*scale*/
+ ,ORowSetValueVector::Vector& io_aRow
+ ,::std::vector<sal_Int32>& o_ChangedColumns
+ )
+{
+ checkUpdateConditions(columnIndex);
+
+ ORowSetValueVector::Vector& rInsert = ((*m_aInsertRow)->get());
+ rInsert[columnIndex].setBound(sal_True);
+ rInsert[columnIndex] = x;
+ rInsert[columnIndex].setModified();
+ io_aRow[columnIndex] = rInsert[columnIndex];
+
+ m_pCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
+ impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
+}
+// -------------------------------------------------------------------------
+// XResultSet
+sal_Bool ORowSetCache::next( )
+{
+ if(!isAfterLast())
+ {
+ m_bBeforeFirst = sal_False;
+ ++m_nPosition;
+
+ // after we increment the position we have to check if we are already after the last row
+ checkPositionFlags();
+ if(!m_bAfterLast)
+ {
+ moveWindow();
+
+ OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
+ m_aMatrixIter = calcPosition();
+ checkPositionFlags();
+ }
+ }
+
+ return !m_bAfterLast;
+}
+// -------------------------------------------------------------------------
+sal_Bool ORowSetCache::isBeforeFirst( )
+{
+ // return !m_nPosition;
+
+ return m_bBeforeFirst;
+}
+// -------------------------------------------------------------------------
+sal_Bool ORowSetCache::isAfterLast( )
+{
+
+ return m_bAfterLast;
+}
+// -------------------------------------------------------------------------
+sal_Bool ORowSetCache::isFirst( )
+{
+
+ return m_nPosition == 1; // ask resultset for
+}
+// -------------------------------------------------------------------------
+sal_Bool ORowSetCache::isLast( )
+{
+ // return m_bRowCountFinal ? (m_nPosition==m_nRowCount) : m_pCacheSet->isLast();
+
+ return m_nPosition == m_nRowCount;
+}
+// -------------------------------------------------------------------------
+sal_Bool ORowSetCache::beforeFirst( )
+{
+
+
+ if(!m_bBeforeFirst)
+ {
+ m_bAfterLast = sal_False;
+ m_nPosition = 0;
+ m_bBeforeFirst = sal_True;
+ m_pCacheSet->beforeFirst();
+ moveWindow();
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ return sal_True;
+}
+// -------------------------------------------------------------------------
+sal_Bool ORowSetCache::afterLast( )
+{
+
+
+ if(!m_bAfterLast)
+ {
+ m_bBeforeFirst = sal_False;
+ m_bAfterLast = sal_True;
+
+ if(!m_bRowCountFinal)
+ {
+ m_pCacheSet->last();
+ m_bRowCountFinal = sal_True;
+ m_nRowCount = m_pCacheSet->getRow();// + 1 removed
+ }
+ m_pCacheSet->afterLast();
+
+ m_nPosition = 0;
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ return sal_True;
+}
+// -------------------------------------------------------------------------
+sal_Bool ORowSetCache::fillMatrix(sal_Int32& _nNewStartPos,sal_Int32 _nNewEndPos)
+{
+ OSL_ENSURE(_nNewStartPos != _nNewEndPos,"ORowSetCache::fillMatrix: StartPos and EndPos can not be equal!");
+ // fill the whole window with new data
+ ORowSetMatrix::iterator aIter = m_pMatrix->begin();
+ sal_Bool bCheck = m_pCacheSet->absolute(_nNewStartPos); // -1 no need to
+
+ sal_Int32 i=_nNewStartPos;
+ for(;i<_nNewEndPos;++i,++aIter)
+ {
+ if(bCheck)
+ {
+ if(!aIter->isValid())
+ *aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
+ m_pCacheSet->fillValueRow(*aIter,i);
+ }
+ else
+ { // there are no more rows found so we can fetch some before start
+
+ if(!m_bRowCountFinal)
+ {
+ if(m_pCacheSet->previous()) // because we stand after the last row
+ m_nRowCount = m_pCacheSet->getRow(); // here we have the row count
+ if(!m_nRowCount)
+ m_nRowCount = i-1; // it can be that getRow return zero
+ m_bRowCountFinal = sal_True;
+ }
+ if(m_nRowCount > m_nFetchSize)
+ {
+ ORowSetMatrix::iterator aEnd = aIter;
+ ORowSetMatrix::iterator aRealEnd = m_pMatrix->end();
+ sal_Int32 nPos = m_nRowCount - m_nFetchSize + 1;
+ _nNewStartPos = nPos;
+ bCheck = m_pCacheSet->absolute(_nNewStartPos);
+
+ for(;bCheck && aIter != aRealEnd;++aIter)
+ {
+ if(bCheck)
+ {
+ if(!aIter->isValid())
+ *aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
+ m_pCacheSet->fillValueRow(*aIter,nPos++);
+ }
+ bCheck = m_pCacheSet->next();
+ }
+ if(aIter != aEnd)
+ ::std::rotate(m_pMatrix->begin(),aEnd,aRealEnd);
+ }
+ break;
+ }
+ bCheck = m_pCacheSet->next();
+ }
+ // m_nStartPos = _nNewStartPos;
+ // we have to read one row forward to enshure that we know when we are on last row
+ // but only when we don't know it already
+ if(!m_bRowCountFinal)
+ {
+ if(!m_pCacheSet->next())
+ {
+ if(m_pCacheSet->previous()) // because we stand after the last row
+ m_nRowCount = m_pCacheSet->getRow(); // here we have the row count
+ m_bRowCountFinal = sal_True;
+ }
+ else
+ m_nRowCount = std::max(i,m_nRowCount);
+
+ }
+ return bCheck;
+}
+// -------------------------------------------------------------------------
+sal_Bool ORowSetCache::moveWindow()
+{
+
+ sal_Bool bRet = sal_True;
+
+ sal_Int32 nDiff = (sal_Int32)(m_nFetchSize*0.5 -0.5);
+ sal_Int32 nNewStartPos = (m_nPosition - nDiff);
+ // sal_Int32 nNewEndPos = (m_nPosition+m_nFetchSize*0.5);
+ sal_Int32 nNewEndPos = nNewStartPos + m_nFetchSize;
+
+ if ( m_nPosition <= m_nStartPos )
+ { // the window is behind the new start pos
+ if(!m_nStartPos)
+ return sal_False;
+ // the new position should be the nPos - nFetchSize/2
+ if ( nNewEndPos > m_nStartPos )
+ { // but the two regions are overlapping
+ // fill the rows behind the new end
+
+ ORowSetMatrix::iterator aEnd; // the iterator we need for rotate
+ ORowSetMatrix::iterator aIter; // the iterator we fill with new values
+
+ sal_Bool bCheck = sal_True;
+ if ( nNewStartPos < 1 )
+ {
+ bCheck = m_pCacheSet->first();
+ // aEnd = m_pMatrix->begin() + (sal_Int32)(m_nFetchSize*0.5);
+ OSL_ENSURE((nNewEndPos - m_nStartPos - nNewStartPos) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
+ aEnd = m_pMatrix->begin() + (nNewEndPos - m_nStartPos - nNewStartPos);
+ aIter = aEnd;
+ m_nStartPos = 0;
+ }
+ else
+ {
+ OSL_ENSURE((nNewEndPos - m_nStartPos -1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
+ aEnd = m_pMatrix->begin() + ((nNewEndPos - m_nStartPos)-1);
+ aIter = m_pMatrix->begin() + ((nNewEndPos - m_nStartPos)-1);
+ bCheck = m_pCacheSet->absolute(nNewStartPos);
+ m_nStartPos = nNewStartPos -1;
+ }
+
+ if ( bCheck )
+ {
+ sal_Int32 nPos = m_nStartPos;
+ bCheck = fill(aIter,m_pMatrix->end(),nPos,bCheck);
+
+ ::std::rotate(m_pMatrix->begin(),aEnd,m_pMatrix->end());
+ // now correct the iterator in our iterator vector
+ // rotateCacheIterator(aEnd-m_pMatrix->begin()); //can't be used because they decrement and here we need to increment
+ ptrdiff_t nNewDist = aEnd - m_pMatrix->begin();
+ ptrdiff_t nOffSet = m_pMatrix->end() - aEnd;
+ ORowSetCacheMap::iterator aCacheIter = m_aCacheIterators.begin();
+ ORowSetCacheMap::iterator aCacheEnd = m_aCacheIterators.end();
+ for(;aCacheIter != aCacheEnd;++aCacheIter)
+ {
+ if ( !aCacheIter->second.pRowSet->isInsertRow()
+ && aCacheIter->second.aIterator != m_pMatrix->end() && !m_bModified )
+ {
+ ptrdiff_t nDist = (aCacheIter->second.aIterator - m_pMatrix->begin());
+ if ( nDist >= nNewDist )
+ {
+ aCacheIter->second.aIterator = m_pMatrix->end();
+ }
+ else
+ {
+#if OSL_DEBUG_LEVEL > 0
+ ORowSetMatrix::iterator aOldPos;
+ aOldPos = aCacheIter->second.aIterator;
+#endif
+ CHECK_MATRIX_POS( ((aOldPos - m_pMatrix->begin()) + nOffSet) );
+ aCacheIter->second.aIterator += nOffSet;
+#if OSL_DEBUG_LEVEL > 0
+ ORowSetMatrix::iterator aCurrentPos;
+ aCurrentPos = aCacheIter->second.aIterator;
+#endif
+ OSL_ENSURE(aCacheIter->second.aIterator >= m_pMatrix->begin()
+ && aCacheIter->second.aIterator < m_pMatrix->end(),"Iterator out of area!");
+ }
+ }
+ }
+ }
+ else
+ { // normaly this should never happen
+ OSL_ENSURE(0,"What the hell is happen here!");
+ return sal_False;
+ }
+ }
+ else
+ {// no rows can be reused so fill again
+ if(nNewStartPos < 1) // special case
+ {
+ m_nStartPos = 0;
+
+ rotateCacheIterator(static_cast<sal_Int16>(m_nFetchSize+1)); // static_cast<sal_Int16>(m_nFetchSize+1)
+
+ m_pCacheSet->beforeFirst();
+
+ sal_Bool bCheck;
+ ORowSetMatrix::iterator aIter = m_pMatrix->begin();
+ for(sal_Int32 i=0;i<m_nFetchSize;++i,++aIter)
+ {
+ bCheck = m_pCacheSet->next();
+ if ( bCheck )
+ {
+ if(!aIter->isValid())
+ *aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
+ m_pCacheSet->fillValueRow(*aIter,i+1);
+ }
+ else
+ *aIter = NULL;
+ }
+ }
+ else
+ bRet = reFillMatrix(nNewStartPos,nNewEndPos);
+ }
+ }
+ else if(m_nPosition > m_nStartPos)
+ { // the new start pos is above the startpos of the window
+
+ if(m_nPosition <= (m_nStartPos+m_nFetchSize))
+ { // position in window
+ OSL_ENSURE((m_nPosition - m_nStartPos -1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
+ m_aMatrixIter = calcPosition();
+ if(!m_aMatrixIter->isValid())
+ {
+ sal_Bool bOk( m_pCacheSet->absolute( m_nPosition ) );
+ if ( bOk )
+ {
+ *m_aMatrixIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
+ m_pCacheSet->fillValueRow(*m_aMatrixIter,m_nPosition);
+ // we have to read one row forward to ensure that we know when we are on last row
+ // but only when we don't know it already
+ if ( !m_bRowCountFinal )
+ {
+ bOk = m_pCacheSet->absolute( m_nPosition + 1 );
+ if ( bOk )
+ m_nRowCount = std::max(sal_Int32(m_nPosition+1),m_nRowCount);
+ }
+ }
+ if(!bOk)
+ {
+ if(!m_bRowCountFinal)
+ {
+ // because we stand after the last row
+ m_nRowCount = m_pCacheSet->previous() ? m_pCacheSet->getRow() : 0;// + 1 removed
+ m_bRowCountFinal = sal_True;
+ }
+ }
+ }
+ }
+ else if(nNewStartPos < (m_nStartPos+m_nFetchSize))
+ { // position behind window but the region is overlapping
+ // the rows from begin() to (begin + nNewStartPos - m_nStartPos) can be refilled with the new rows
+ // the rows behind this can be reused
+ ORowSetMatrix::iterator aIter = m_pMatrix->begin();
+ CHECK_MATRIX_POS(nNewStartPos - m_nStartPos - 1);
+ ORowSetMatrix::iterator aEnd = m_pMatrix->begin() + (nNewStartPos - m_nStartPos - 1);
+
+ sal_Int32 nPos = m_nStartPos + m_nFetchSize + 1;
+ sal_Bool bCheck = m_pCacheSet->absolute(nPos);
+ bCheck = fill(aIter,aEnd,nPos,bCheck); // refill the region wew don't need anymore
+
+// // we know that this is the current maximal rowcount here
+// if ( !m_bRowCountFinal && bCheck )
+// m_nRowCount = std::max(nPos,m_nRowCount);
+ // we have to read one row forward to enshure that we know when we are on last row
+ // but only when we don't know it already
+ sal_Bool bOk = sal_True;
+ if(bCheck && !m_bRowCountFinal)
+ bOk = m_pCacheSet->next();
+ // bind end to front
+ if(bCheck)
+ { // rotate the end to the front
+ ::std::rotate(m_pMatrix->begin(),aIter,m_pMatrix->end());
+ // now correct the iterator in our iterator vector
+ rotateCacheIterator( (sal_Int16)( aIter - m_pMatrix->begin() ) );
+ m_nStartPos = nNewStartPos - 1; // must be -1
+ // now I can say how many rows we have
+ if(!bOk)
+ {
+ m_pCacheSet->previous(); // because we stand after the last row
+ m_nRowCount = nPos; // here we have the row count
+ m_bRowCountFinal = sal_True;
+ }
+ else if(!m_bRowCountFinal)
+ m_nRowCount = std::max(++nPos,m_nRowCount);
+ }
+ else
+ { // the end was reached before end() so we can set the start before nNewStartPos
+
+ m_nStartPos += (aIter - m_pMatrix->begin());
+ // m_nStartPos = (aIter - m_pMatrix->begin());
+ ::std::rotate(m_pMatrix->begin(),aIter,m_pMatrix->end());
+ // now correct the iterator in our iterator vector
+ rotateCacheIterator( (sal_Int16)( aIter - m_pMatrix->begin() ) );
+
+ if ( !m_bRowCountFinal )
+ {
+ m_pCacheSet->previous(); // because we stand after the last row
+ m_nRowCount = std::max(m_nRowCount,--nPos); // here we have the row count
+ OSL_ENSURE(nPos == m_pCacheSet->getRow(),"nPos isn't valid!");
+ m_bRowCountFinal = sal_True;
+ }
+ // TODO check
+ // m_nStartPos = (nNewStartPos+m_nRowCount) - m_nFetchSize ;
+ if(m_nStartPos < 0)
+ m_nStartPos = 0;
+ }
+ // here we need only to check if the begining row is valid. If not we have to fetch it.
+ if(!m_pMatrix->begin()->isValid())
+ {
+ aIter = m_pMatrix->begin();
+
+ nPos = m_nStartPos;
+ bCheck = m_pCacheSet->absolute(m_nStartPos);
+ for(; !aIter->isValid() && bCheck;++aIter)
+ {
+ OSL_ENSURE(aIter != m_pMatrix->end(),"Invalid iterator");
+ bCheck = m_pCacheSet->next();
+ if ( bCheck ) // resultset stands on right position
+ {
+ *aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
+ m_pCacheSet->fillValueRow(*aIter,++nPos);
+ }
+ }
+ }
+ }
+ else // no rows can be reused so fill again
+ bRet = reFillMatrix(nNewStartPos,nNewEndPos);
+ }
+
+ if(!m_bRowCountFinal)
+ m_nRowCount = std::max(m_nPosition,m_nRowCount);
+ OSL_ENSURE(m_nStartPos >= 0,"ORowSetCache::moveWindow: m_nStartPos is less than 0!");
+
+ return bRet;
+}
+// -------------------------------------------------------------------------
+sal_Bool ORowSetCache::first( )
+{
+ // first move to the first row
+ // then check if the cache window is at the begining
+ // when not postionize the window and fill it with data
+ // smart moving of the window -> clear only the rows whom are out of range
+ sal_Bool bRet = m_pCacheSet->first();
+ if(bRet)
+ {
+ m_bBeforeFirst = m_bAfterLast = sal_False;
+ m_nPosition = 1;
+ moveWindow();
+ m_aMatrixIter = m_pMatrix->begin();
+ }
+ else
+ {
+ m_bRowCountFinal = m_bBeforeFirst = m_bAfterLast = sal_True;
+ m_nRowCount = m_nPosition = 0;
+
+ OSL_ENSURE(m_bBeforeFirst || m_bNew,"ORowSetCache::first return false and BeforeFirst isn't true");
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ return bRet;
+}
+// -------------------------------------------------------------------------
+sal_Bool ORowSetCache::last( )
+{
+ sal_Bool bRet = m_pCacheSet->last();
+ if(bRet)
+ {
+ m_bBeforeFirst = m_bAfterLast = sal_False;
+ if(!m_bRowCountFinal)
+ {
+ m_bRowCountFinal = sal_True;
+ m_nRowCount = m_nPosition = m_pCacheSet->getRow(); // not + 1
+ }
+ m_nPosition = m_pCacheSet->getRow();
+ moveWindow();
+ // we have to repositioning because moveWindow can modify the cache
+ m_pCacheSet->last();
+// if(m_nPosition > m_nFetchSize)
+// m_aMatrixIter = m_pMatrix->end() -1;
+// else
+// m_aMatrixIter = m_pMatrix->begin() + m_nPosition - 1;
+ OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
+ m_aMatrixIter = calcPosition();
+ }
+ else
+ {
+ m_bRowCountFinal = m_bBeforeFirst = m_bAfterLast = sal_True;
+ m_nRowCount = m_nPosition = 0;
+ OSL_ENSURE(m_bBeforeFirst,"ORowSetCache::last return false and BeforeFirst isn't true");
+ m_aMatrixIter = m_pMatrix->end();
+ }
+#if OSL_DEBUG_LEVEL > 1
+ if(bRet)
+ {
+ OSL_ENSURE((*m_aMatrixIter).isValid(),"ORowSetCache::last: Row not valid!");
+ }
+#endif
+
+ return bRet;
+}
+// -------------------------------------------------------------------------
+sal_Int32 ORowSetCache::getRow( )
+{
+ return (isBeforeFirst() || isAfterLast()) ? 0 : m_nPosition;
+}
+// -------------------------------------------------------------------------
+sal_Bool ORowSetCache::absolute( sal_Int32 row )
+{
+ if(!row )
+ throw SQLException(DBACORE_RESSTRING(RID_STR_NO_ABS_ZERO),NULL,SQLSTATE_GENERAL,1000,Any() );
+
+ if(row < 0)
+ {
+ // here we have to scroll from the last row to backward so we have to go to last row and
+ // and two the previous
+ if(m_bRowCountFinal || last())
+ {
+ m_nPosition = m_nRowCount + row + 1; // + row because row is negative and +1 because row==-1 means last row
+ if(m_nPosition < 1)
+ {
+ m_bBeforeFirst = sal_True;
+ m_bAfterLast = sal_False;
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ else
+ {
+ m_bBeforeFirst = sal_False;
+ m_bAfterLast = m_nPosition > m_nRowCount;
+ moveWindow();
+ OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
+ m_aMatrixIter = calcPosition();
+ }
+ }
+ else
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ else
+ {
+ m_nPosition = row;
+ // the position flags
+ m_bBeforeFirst = sal_False;
+ checkPositionFlags();
+
+ if(!m_bAfterLast)
+ {
+ moveWindow();
+ checkPositionFlags();
+ if(!m_bAfterLast)
+ m_aMatrixIter = calcPosition();
+ else
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ else
+ m_aMatrixIter = m_pMatrix->end();
+ }
+
+ return !(m_bAfterLast || m_bBeforeFirst);
+}
+// -------------------------------------------------------------------------
+sal_Bool ORowSetCache::relative( sal_Int32 rows )
+{
+ sal_Bool bErg = sal_True;
+ if(rows)
+ {
+ sal_Int32 nNewPosition = m_nPosition + rows;
+
+ if ( m_bBeforeFirst && rows > 0 )
+ nNewPosition = rows;
+ else if ( m_bRowCountFinal && m_bAfterLast && rows < 0 )
+ nNewPosition = m_nRowCount + 1 + rows;
+ else
+ if ( m_bBeforeFirst || ( m_bRowCountFinal && m_bAfterLast ) )
+ throw SQLException( DBACORE_RESSTRING( RID_STR_NO_RELATIVE ), NULL, SQLSTATE_GENERAL, 1000, Any() );
+ if ( nNewPosition )
+ {
+ bErg = absolute( nNewPosition );
+ bErg = bErg && !isAfterLast() && !isBeforeFirst();
+ }
+ else
+ {
+ m_bBeforeFirst = sal_True;
+ bErg = sal_False;
+ }
+ }
+ return bErg;
+}
+// -------------------------------------------------------------------------
+sal_Bool ORowSetCache::previous( )
+{
+ sal_Bool bRet = sal_False;
+ if(!isBeforeFirst())
+ {
+ if(m_bAfterLast) // we stand after the last row so one before is the last row
+ bRet = last();
+ else
+ {
+ m_bAfterLast = sal_False;
+ --m_nPosition;
+ moveWindow();
+ OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
+
+ checkPositionFlags();
+
+ if(!m_nPosition)
+ {
+ m_bBeforeFirst = sal_True;
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ else
+ {
+ m_aMatrixIter = calcPosition();
+ bRet = (*m_aMatrixIter).isValid();
+ }
+ }
+ }
+ return bRet;
+}
+// -------------------------------------------------------------------------
+void ORowSetCache::refreshRow( )
+{
+ if(isAfterLast())
+ throw SQLException(DBACORE_RESSTRING(RID_STR_NO_REFESH_AFTERLAST),NULL,SQLSTATE_GENERAL,1000,Any() );
+ OSL_ENSURE(m_aMatrixIter != m_pMatrix->end(),"refreshRow() called for invalid row!");
+ m_pCacheSet->refreshRow();
+ m_pCacheSet->fillValueRow(*m_aMatrixIter,m_nPosition);
+ if ( m_bNew )
+ {
+ cancelRowModification();
+ }
+}
+// -------------------------------------------------------------------------
+sal_Bool ORowSetCache::rowUpdated( )
+{
+ return m_pCacheSet->rowUpdated();
+}
+// -------------------------------------------------------------------------
+sal_Bool ORowSetCache::rowInserted( )
+{
+ return m_pCacheSet->rowInserted();
+}
+// -------------------------------------------------------------------------
+// XResultSetUpdate
+sal_Bool ORowSetCache::insertRow(::std::vector< Any >& o_aBookmarks)
+{
+ if ( !m_bNew || !m_aInsertRow->isValid() )
+ throw SQLException(DBACORE_RESSTRING(RID_STR_NO_MOVETOINSERTROW_CALLED),NULL,SQLSTATE_GENERAL,1000,Any() );
+
+ m_pCacheSet->insertRow(*m_aInsertRow,m_aUpdateTable);
+
+ sal_Bool bRet( rowInserted() );
+ if ( bRet )
+ {
+ ++m_nRowCount;
+ Any aBookmark = ((*m_aInsertRow)->get())[0].makeAny();
+ m_bAfterLast = m_bBeforeFirst = sal_False;
+ if(aBookmark.hasValue())
+ {
+ moveToBookmark(aBookmark);
+ // update the cached values
+ ORowSetValueVector::Vector& rCurrentRow = ((*m_aMatrixIter))->get();
+ ORowSetMatrix::iterator aIter = m_pMatrix->begin();
+ for(;aIter != m_pMatrix->end();++aIter)
+ {
+ if ( m_aMatrixIter != aIter && aIter->isValid() && m_pCacheSet->columnValuesUpdated((*aIter)->get(),rCurrentRow) )
+ {
+ o_aBookmarks.push_back(lcl_getBookmark((*aIter)->get()[0],m_pCacheSet));
+ }
+ }
+ }
+ else
+ {
+ OSL_ENSURE(0,"There must be a bookmark after the row was inserted!");
+ }
+ }
+ return bRet;
+}
+// -------------------------------------------------------------------------
+void ORowSetCache::resetInsertRow(sal_Bool _bClearInsertRow)
+{
+ if ( _bClearInsertRow )
+ clearInsertRow();
+ m_bNew = sal_False;
+ m_bModified = sal_False;
+}
+// -------------------------------------------------------------------------
+void ORowSetCache::cancelRowModification()
+{
+ // clear the insertrow references -> implies that the current row of the rowset changes as well
+ ORowSetCacheMap::iterator aCacheIter = m_aCacheIterators.begin();
+ ORowSetCacheMap::iterator aCacheEnd = m_aCacheIterators.end();
+ for(;aCacheIter != aCacheEnd;++aCacheIter)
+ {
+ if ( aCacheIter->second.pRowSet->isInsertRow() && aCacheIter->second.aIterator == m_aInsertRow )
+ aCacheIter->second.aIterator = m_pMatrix->end();
+ } // for(;aCacheIter != aCacheEnd;++aCacheIter)
+ resetInsertRow(sal_False);
+}
+// -------------------------------------------------------------------------
+void ORowSetCache::updateRow( ORowSetMatrix::iterator& _rUpdateRow,::std::vector< Any >& o_aBookmarks )
+{
+ if(isAfterLast() || isBeforeFirst())
+ throw SQLException(DBACORE_RESSTRING(RID_STR_NO_UPDATEROW),NULL,SQLSTATE_GENERAL,1000,Any() );
+
+ Any aBookmark = ((*_rUpdateRow)->get())[0].makeAny();
+ OSL_ENSURE(aBookmark.hasValue(),"Bookmark must have a value!");
+ // here we don't have to reposition our CacheSet, when we try to update a row,
+ // the row was already fetched
+ moveToBookmark(aBookmark);
+ m_pCacheSet->updateRow(*_rUpdateRow,*m_aMatrixIter,m_aUpdateTable);
+ // refetch the whole row
+ (*m_aMatrixIter) = NULL;
+
+ if ( moveToBookmark(aBookmark) )
+ {
+ // update the cached values
+ ORowSetValueVector::Vector& rCurrentRow = ((*m_aMatrixIter))->get();
+ ORowSetMatrix::iterator aIter = m_pMatrix->begin();
+ for(;aIter != m_pMatrix->end();++aIter)
+ {
+ if ( m_aMatrixIter != aIter && aIter->isValid() && m_pCacheSet->columnValuesUpdated((*aIter)->get(),rCurrentRow) )
+ {
+ o_aBookmarks.push_back(lcl_getBookmark((*aIter)->get()[0],m_pCacheSet));
+ }
+ }
+ }
+
+ m_bModified = sal_False;
+}
+// -------------------------------------------------------------------------
+bool ORowSetCache::deleteRow( )
+{
+ if(isAfterLast() || isBeforeFirst())
+ throw SQLException(DBACORE_RESSTRING(RID_STR_NO_DELETEROW),NULL,SQLSTATE_GENERAL,1000,Any() );
+
+ // m_pCacheSet->absolute(m_nPosition);
+ m_pCacheSet->deleteRow(*m_aMatrixIter,m_aUpdateTable);
+ if ( !m_pCacheSet->rowDeleted() )
+ return false;
+
+ --m_nRowCount;
+ OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
+ ORowSetMatrix::iterator aPos = calcPosition();
+ (*aPos) = NULL;
+
+ ORowSetMatrix::iterator aEnd = m_pMatrix->end();
+ for(++aPos;aPos != aEnd && aPos->isValid();++aPos)
+ {
+ *(aPos-1) = *aPos;
+ (*aPos) = NULL;
+ }
+ m_aMatrixIter = m_pMatrix->end();
+
+ --m_nPosition;
+ return true;
+}
+// -------------------------------------------------------------------------
+void ORowSetCache::cancelRowUpdates( )
+{
+ m_bNew = m_bModified = sal_False;
+ if(!m_nPosition)
+ {
+ OSL_ENSURE(0,"cancelRowUpdates:Invalid positions pos == 0");
+ ::dbtools::throwFunctionSequenceException(NULL);
+ }
+
+ if(m_pCacheSet->absolute(m_nPosition))
+ m_pCacheSet->fillValueRow(*m_aMatrixIter,m_nPosition);
+ else
+ {
+ OSL_ENSURE(0,"cancelRowUpdates couldn't position right with absolute");
+ ::dbtools::throwFunctionSequenceException(NULL);
+ }
+}
+// -------------------------------------------------------------------------
+void ORowSetCache::moveToInsertRow( )
+{
+ m_bNew = sal_True;
+ m_bUpdated = m_bAfterLast = sal_False;
+
+ m_aInsertRow = m_pInsertMatrix->begin();
+ if(!m_aInsertRow->isValid())
+ *m_aInsertRow = new ORowSetValueVector(m_xMetaData->getColumnCount());
+
+ // we don't unbound the bookmark column
+ ORowSetValueVector::Vector::iterator aIter = (*m_aInsertRow)->get().begin()+1;
+ ORowSetValueVector::Vector::iterator aEnd = (*m_aInsertRow)->get().end();
+ for(sal_Int32 i = 1;aIter != aEnd;++aIter,++i)
+ {
+ aIter->setBound(sal_False);
+ aIter->setModified(sal_False);
+ aIter->setNull();
+ aIter->setTypeKind(m_xMetaData->getColumnType(i));
+ }
+}
+// -------------------------------------------------------------------------
+ORowSetCacheIterator ORowSetCache::createIterator(ORowSetBase* _pRowSet)
+{
+
+ ORowSetCacheIterator_Helper aHelper;
+ aHelper.aIterator = m_pMatrix->end();
+ aHelper.pRowSet = _pRowSet;
+ return ORowSetCacheIterator(m_aCacheIterators.insert(m_aCacheIterators.begin(),ORowSetCacheMap::value_type(m_aCacheIterators.size()+1,aHelper)),this,_pRowSet);
+}
+// -----------------------------------------------------------------------------
+void ORowSetCache::deleteIterator(const ORowSetBase* _pRowSet)
+{
+ ORowSetCacheMap::iterator aCacheIter = m_aCacheIterators.begin();
+ for(;aCacheIter != m_aCacheIterators.end();)
+ {
+ if ( aCacheIter->second.pRowSet == _pRowSet )
+ {
+ m_aCacheIterators.erase(aCacheIter);
+ aCacheIter = m_aCacheIterators.begin();
+ } // if ( aCacheIter->second.pRowSet == _pRowSet )
+ else
+ ++aCacheIter;
+ }
+}
+// -----------------------------------------------------------------------------
+void ORowSetCache::rotateCacheIterator(ORowSetMatrix::difference_type _nDist)
+{
+ if(_nDist)
+ {
+ // now correct the iterator in our iterator vector
+ ORowSetCacheMap::iterator aCacheIter = m_aCacheIterators.begin();
+ ORowSetCacheMap::iterator aCacheEnd = m_aCacheIterators.end();
+ for(;aCacheIter != aCacheEnd;++aCacheIter)
+ {
+ if ( !aCacheIter->second.pRowSet->isInsertRow()
+ && aCacheIter->second.aIterator != m_pMatrix->end() && !m_bModified )
+ {
+ ptrdiff_t nDist = (aCacheIter->second.aIterator - m_pMatrix->begin());
+ if(nDist < _nDist)
+ {
+ aCacheIter->second.aIterator = m_pMatrix->end();
+ }
+ else
+ {
+ OSL_ENSURE((aCacheIter->second.aIterator - m_pMatrix->begin()) >= _nDist,"Invalid Dist value!");
+ aCacheIter->second.aIterator -= _nDist;
+ OSL_ENSURE(aCacheIter->second.aIterator >= m_pMatrix->begin()
+ && aCacheIter->second.aIterator < m_pMatrix->end(),"Iterator out of area!");
+ }
+ }
+ }
+ }
+}
+// -------------------------------------------------------------------------
+void ORowSetCache::setUpdateIterator(const ORowSetMatrix::iterator& _rOriginalRow)
+{
+ m_aInsertRow = m_pInsertMatrix->begin();
+ if(!m_aInsertRow->isValid())
+ *m_aInsertRow = new ORowSetValueVector(m_xMetaData->getColumnCount());
+
+ (*(*m_aInsertRow)) = (*(*_rOriginalRow));
+ // we don't unbound the bookmark column
+ ORowSetValueVector::Vector::iterator aIter = (*m_aInsertRow)->get().begin();
+ ORowSetValueVector::Vector::iterator aEnd = (*m_aInsertRow)->get().end();
+ for(;aIter != aEnd;++aIter)
+ aIter->setModified(sal_False);
+}
+// -----------------------------------------------------------------------------
+void ORowSetCache::checkPositionFlags()
+{
+ if(m_bRowCountFinal)
+ {
+ m_bAfterLast = m_nPosition > m_nRowCount;
+ if(m_bAfterLast)
+ m_nPosition = 0;//m_nRowCount;
+ }
+}
+// -----------------------------------------------------------------------------
+void ORowSetCache::checkUpdateConditions(sal_Int32 columnIndex)
+{
+ if(m_bAfterLast || columnIndex >= (sal_Int32)(*m_aInsertRow)->get().size())
+ throwFunctionSequenceException(m_xSet.get());
+}
+//------------------------------------------------------------------------------
+sal_Bool ORowSetCache::checkInnerJoin(const ::connectivity::OSQLParseNode *pNode,const Reference< XConnection>& _xConnection,const ::rtl::OUString& _sUpdateTableName)
+{
+ sal_Bool bOk = sal_False;
+ if (pNode->count() == 3 && // Ausdruck is geklammert
+ SQL_ISPUNCTUATION(pNode->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pNode->getChild(2),")"))
+ {
+ bOk = checkInnerJoin(pNode->getChild(1),_xConnection,_sUpdateTableName);
+ }
+ else if ((SQL_ISRULE(pNode,search_condition) || SQL_ISRULE(pNode,boolean_term)) && // AND/OR-Verknuepfung:
+ pNode->count() == 3)
+ {
+ // nur AND Verknüpfung zulassen
+ if ( SQL_ISTOKEN(pNode->getChild(1),AND) )
+ bOk = checkInnerJoin(pNode->getChild(0),_xConnection,_sUpdateTableName)
+ && checkInnerJoin(pNode->getChild(2),_xConnection,_sUpdateTableName);
+ }
+ else if (SQL_ISRULE(pNode,comparison_predicate))
+ {
+ // only the comparison of columns is allowed
+ DBG_ASSERT(pNode->count() == 3,"checkInnerJoin: Fehler im Parse Tree");
+ if (!(SQL_ISRULE(pNode->getChild(0),column_ref) &&
+ SQL_ISRULE(pNode->getChild(2),column_ref) &&
+ pNode->getChild(1)->getNodeType() == SQL_NODE_EQUAL))
+ {
+ bOk = sal_False;
+ }
+ ::rtl::OUString sColumnName,sTableRange;
+ OSQLParseTreeIterator::getColumnRange( pNode->getChild(0), _xConnection, sColumnName, sTableRange );
+ bOk = sTableRange == _sUpdateTableName;
+ if ( !bOk )
+ {
+ OSQLParseTreeIterator::getColumnRange( pNode->getChild(2), _xConnection, sColumnName, sTableRange );
+ bOk = sTableRange == _sUpdateTableName;
+ }
+ }
+ return bOk;
+}
+// -----------------------------------------------------------------------------
+sal_Bool ORowSetCache::checkJoin(const Reference< XConnection>& _xConnection,
+ const Reference< XSingleSelectQueryAnalyzer >& _xAnalyzer,
+ const ::rtl::OUString& _sUpdateTableName )
+{
+ sal_Bool bOk = sal_False;
+ ::rtl::OUString sSql = _xAnalyzer->getQuery();
+ ::rtl::OUString sErrorMsg;
+ ::connectivity::OSQLParser aSqlParser( m_aContext.getLegacyServiceFactory() );
+ ::std::auto_ptr< ::connectivity::OSQLParseNode> pSqlParseNode( aSqlParser.parseTree(sErrorMsg,sSql));
+ if ( pSqlParseNode.get() && SQL_ISRULE(pSqlParseNode, select_statement) )
+ {
+ OSQLParseNode* pTableRefCommalist = pSqlParseNode->getByRule(::connectivity::OSQLParseNode::table_ref_commalist);
+ OSL_ENSURE(pTableRefCommalist,"NO tables why!?");
+ if(pTableRefCommalist && pTableRefCommalist->count() == 1)
+ {
+ // we found only one element so it must some kind of join here
+ OSQLParseNode* pJoin = pTableRefCommalist->getByRule(::connectivity::OSQLParseNode::qualified_join);
+ if(pJoin)
+ { // we are only intereseted in qualified joins like RIGHT or LEFT
+ OSQLParseNode* pJoinType = pJoin->getChild(1);
+ OSQLParseNode* pOuterType = NULL;
+ if(SQL_ISRULE(pJoinType,join_type) && pJoinType->count() == 2)
+ pOuterType = pJoinType->getChild(0);
+ else if(SQL_ISRULE(pJoinType,outer_join_type))
+ pOuterType = pJoinType;
+
+ sal_Bool bCheck = sal_False;
+ sal_Bool bLeftSide = sal_False;
+ if(pOuterType)
+ { // found outer join
+ bLeftSide = SQL_ISTOKEN(pOuterType->getChild(0),LEFT);
+ bCheck = bLeftSide || SQL_ISTOKEN(pOuterType->getChild(0),RIGHT);
+ }
+
+ if(bCheck)
+ { // here we know that we have to check on which side our table resides
+ const OSQLParseNode* pTableRef = pJoin->getByRule(::connectivity::OSQLParseNode::qualified_join);
+ if(bLeftSide)
+ pTableRef = pJoin->getChild(0);
+ else
+ pTableRef = pJoin->getChild(3);
+ OSL_ENSURE(SQL_ISRULE(pTableRef,table_ref),"Must be a tableref here!");
+
+ ::rtl::OUString sTableRange = OSQLParseNode::getTableRange(pTableRef);
+ if(!sTableRange.getLength())
+ pTableRef->getChild(0)->parseNodeToStr( sTableRange, _xConnection, NULL, sal_False, sal_False );
+ bOk = sTableRange == _sUpdateTableName;
+ }
+ }
+ }
+ else
+ {
+ OSQLParseNode* pWhereOpt = pSqlParseNode->getChild(3)->getChild(1);
+ if ( pWhereOpt && !pWhereOpt->isLeaf() )
+ bOk = checkInnerJoin(pWhereOpt->getChild(1),_xConnection,_sUpdateTableName);
+ }
+ }
+ return bOk;
+}
+// -----------------------------------------------------------------------------
+void ORowSetCache::clearInsertRow()
+{
+ // we don't unbound the bookmark column
+ if ( m_aInsertRow != m_pInsertMatrix->end() && m_aInsertRow->isValid() )
+ {
+ ORowSetValueVector::Vector::iterator aIter = (*m_aInsertRow)->get().begin()+1;
+ ORowSetValueVector::Vector::iterator aEnd = (*m_aInsertRow)->get().end();
+ for(;aIter != aEnd;++aIter)
+ {
+ aIter->setBound(sal_False);
+ aIter->setModified(sal_False);
+ aIter->setNull();
+ } // for(;aIter != (*m_aInsertRow)->end();++aIter)
+ }
+}
+// -----------------------------------------------------------------------------
+ORowSetMatrix::iterator ORowSetCache::calcPosition() const
+{
+ sal_Int32 nValue = (m_nPosition - m_nStartPos) - 1;
+ CHECK_MATRIX_POS(nValue);
+ return ( nValue < 0 || nValue >= static_cast<sal_Int32>(m_pMatrix->size()) ) ? m_pMatrix->end() : (m_pMatrix->begin() + nValue);
+}
+// -----------------------------------------------------------------------------
+
+TORowSetOldRowHelperRef ORowSetCache::registerOldRow()
+{
+ TORowSetOldRowHelperRef pRef = new ORowSetOldRowHelper(ORowSetRow());
+ m_aOldRows.push_back(pRef);
+ return pRef;
+}
+// -----------------------------------------------------------------------------
+void ORowSetCache::deregisterOldRow(const TORowSetOldRowHelperRef& _rRow)
+{
+ TOldRowSetRows::iterator aOldRowEnd = m_aOldRows.end();
+ for (TOldRowSetRows::iterator aOldRowIter = m_aOldRows.begin(); aOldRowIter != aOldRowEnd; ++aOldRowIter)
+ {
+ if ( aOldRowIter->getBodyPtr() == _rRow.getBodyPtr() )
+ {
+ m_aOldRows.erase(aOldRowIter);
+ break;
+ }
+
+ }
+}
+// -----------------------------------------------------------------------------
+sal_Bool ORowSetCache::reFillMatrix(sal_Int32 _nNewStartPos,sal_Int32 _nNewEndPos)
+{
+ TOldRowSetRows::iterator aOldRowEnd = m_aOldRows.end();
+ for (TOldRowSetRows::iterator aOldRowIter = m_aOldRows.begin(); aOldRowIter != aOldRowEnd; ++aOldRowIter)
+ {
+ if ( aOldRowIter->isValid() && aOldRowIter->getBody().getRow().isValid() )
+ aOldRowIter->getBody().setRow(new ORowSetValueVector(aOldRowIter->getBody().getRow().getBody()) );
+ }
+ sal_Int32 nNewSt = _nNewStartPos;
+ sal_Bool bRet = fillMatrix(nNewSt,_nNewEndPos);
+ m_nStartPos = nNewSt - 1;
+ rotateCacheIterator(static_cast<sal_Int16>(m_nFetchSize+1)); // forces that every iterator will be set to null
+ return bRet;
+}
+// -----------------------------------------------------------------------------
+sal_Bool ORowSetCache::fill(ORowSetMatrix::iterator& _aIter,const ORowSetMatrix::iterator& _aEnd,sal_Int32& _nPos,sal_Bool _bCheck)
+{
+ sal_Int32 nColumnCount = m_xMetaData->getColumnCount();
+ for(; _bCheck && _aIter != _aEnd;)
+ {
+ if ( !_aIter->isValid() )
+ *_aIter = new ORowSetValueVector(nColumnCount);
+ else
+ {
+ TOldRowSetRows::iterator aOldRowEnd = m_aOldRows.end();
+ for (TOldRowSetRows::iterator aOldRowIter = m_aOldRows.begin(); aOldRowIter != aOldRowEnd; ++aOldRowIter)
+ {
+ if ( aOldRowIter->getBody().getRow().isEqualBody(*_aIter) )
+ *_aIter = new ORowSetValueVector(nColumnCount);
+ }
+ }
+ m_pCacheSet->fillValueRow(*_aIter++,++_nPos);
+ _bCheck = m_pCacheSet->next();
+ }
+ return _bCheck;
+}
+// -----------------------------------------------------------------------------
+bool ORowSetCache::isResultSetChanged() const
+{
+ return m_pCacheSet->isResultSetChanged();
+}
+// -----------------------------------------------------------------------------
+void ORowSetCache::reset(const Reference< XResultSet>& _xDriverSet)
+{
+ m_xMetaData.set(Reference< XResultSetMetaDataSupplier >(_xDriverSet,UNO_QUERY)->getMetaData());
+ m_pCacheSet->reset(_xDriverSet);
+
+ m_bRowCountFinal = sal_False;
+ m_nRowCount = 0;
+ reFillMatrix(m_nStartPos+1,m_nEndPos+1);
+}
+// -----------------------------------------------------------------------------
+void ORowSetCache::impl_updateRowFromCache_throw(ORowSetValueVector::Vector& io_aRow
+ ,::std::vector<sal_Int32>& o_ChangedColumns)
+{
+ if ( o_ChangedColumns.size() > 1 )
+ {
+ ORowSetMatrix::iterator aIter = m_pMatrix->begin();
+ for(;aIter != m_pMatrix->end();++aIter)
+ {
+ if ( aIter->isValid() && m_pCacheSet->updateColumnValues((*aIter)->get(),io_aRow,o_ChangedColumns))
+ {
+ break;
+ }
+ }
+
+ if ( aIter == m_pMatrix->end() )
+ {
+ m_pCacheSet->fillMissingValues(io_aRow);
+ }
+ }
+}
+// -----------------------------------------------------------------------------