Files
libreoffice/dbaccess/source/core/api/RowSetCache.cxx
Norbert Thiebaud 256f6ca67d Merge commit 'ooo/DEV300_m101' into integration/dev300_m101
* commit 'ooo/DEV300_m101': (76 commits)
  masterfix DEV300: #i10000# usage of L10N build_type
  removetooltypes01: Fix build problems after rebase to DEV300m99 in basctl, cui, reportdesign, sw
  hr75: #i116747#: remove obsolete copyright notices
  gnumake3: remove comphelper version; fix including extract.hxx
  removetooltypes01: #i112600# Replace missing tools types replacement
  removetooltypes01: #i112600# remove tooltypes from reportdesign
  removetooltypes01: #i112600# remove tooltypes from dbaccess
  undoapi: don't use deprecated JUnit API, this seems to fail now (but didn't before the rebase)
  undoapi: those two classes do not belong into JAVATESTFILES, but JAVAFILES only
  undoapi: (I|Sfx)UndoManager now working with size_t instead of USHORT
  gridsort: give the UnoControl(Model/Base) classes a ctor taking a service factory, so we have access to the factory which created us, and don't need to resort to the process'es service factory
  dba34b: #109956# notify column value in correct order
  dba34b: #i114309# set default values for bit boolean and reset when we are on the insertrow
  undoapi: assert unknown slots in ImplInvalidateFeature
  dba34b: #i110907# check if design handle event
  dba34b: #i109956# notify column values when row is refreshed
  dba34b: #i115753# add test again
  undoapi: renamed Undo.* to RptUndo.*, to not confuse a certain IDE with different same-named files in the source tree ...
  undoapi: migrated report designer to use an own, model-bound UndoManager, instead of the UndoManager formerly bound to the controller
  undoapi: split OSingleDocumentController into DBSubComponentController (which the report design's controller will be derived from) and the still-so-named OSingleDocumentController. Module reportdesign does not compile with this change, this is yet to come.
  ...

Conflicts:
	dbaccess/inc/IEnvironment.hxx
	dbaccess/inc/dataview.hxx
	dbaccess/qa/complex/dbaccess/RowSet.java
	dbaccess/source/core/api/CacheSet.cxx
	dbaccess/source/core/api/KeySet.hxx
	dbaccess/source/core/api/OptimisticSet.hxx
	dbaccess/source/core/api/RowSet.cxx
	dbaccess/source/core/api/RowSetCache.cxx
	dbaccess/source/ext/adabas/Acomponentmodule.cxx
	dbaccess/source/ext/adabas/Aservices.cxx
	dbaccess/source/filter/migration/cfgimport.cxx
	dbaccess/source/filter/migration/cfgimport.hxx
	dbaccess/source/filter/migration/cfgservices.cxx
	dbaccess/source/filter/migration/makefile.mk
	dbaccess/source/inc/cfg_reghelper.hxx
	dbaccess/source/sdbtools/misc/sdbt_services.cxx
	dbaccess/source/shared/cfg_reghelper.cxx
	dbaccess/source/shared/cfgstrings.cxx
	dbaccess/source/shared/registrationhelper.cxx
	dbaccess/source/ui/app/AppController.cxx
	dbaccess/source/ui/app/AppDetailPageHelper.cxx
	dbaccess/source/ui/app/AppDetailPageHelper.hxx
	dbaccess/source/ui/app/AppDetailView.cxx
	dbaccess/source/ui/app/AppIconControl.cxx
	dbaccess/source/ui/app/AppSwapWindow.cxx
	dbaccess/source/ui/browser/brwctrlr.cxx
	dbaccess/source/ui/browser/dataview.cxx
	dbaccess/source/ui/browser/unodatbr.cxx
	dbaccess/source/ui/control/dbtreelistbox.cxx
	dbaccess/source/ui/control/opendoccontrols.cxx
	dbaccess/source/ui/control/tabletree.cxx
	dbaccess/source/ui/dlg/ConnectionHelper.cxx
	dbaccess/source/ui/dlg/ConnectionPage.src
	dbaccess/source/ui/dlg/ExtensionNotPresent.cxx
	dbaccess/source/ui/dlg/ExtensionNotPresent.hrc
	dbaccess/source/ui/dlg/ExtensionNotPresent.src
	dbaccess/source/ui/dlg/TablesSingleDlg.cxx
	dbaccess/source/ui/dlg/adodatalinks.hxx
	dbaccess/source/ui/dlg/dbadmin2.src
	dbaccess/source/ui/dlg/dbadminsetup.src
	dbaccess/source/ui/dlg/dlgattr.cxx
	dbaccess/source/ui/dlg/dlgsize.src
	dbaccess/source/ui/dlg/makefile.mk
	dbaccess/source/ui/dlg/sqlmessage.cxx
	dbaccess/source/ui/inc/ExtensionNotPresent.hxx
	dbaccess/source/ui/inc/TokenWriter.hxx
	dbaccess/source/ui/inc/imageprovider.hxx
	dbaccess/source/ui/misc/DExport.cxx
	dbaccess/source/ui/misc/HtmlReader.cxx
	dbaccess/source/ui/misc/RowSetDrop.cxx
	dbaccess/source/ui/misc/RtfReader.cxx
	dbaccess/source/ui/misc/TokenWriter.cxx
	dbaccess/source/ui/misc/imageprovider.cxx
	dbaccess/source/ui/misc/linkeddocuments.cxx
	dbaccess/source/ui/misc/singledoccontroller.cxx
	dbaccess/source/ui/querydesign/ConnectionData.hxx
	dbaccess/source/ui/querydesign/JoinTableView.cxx
	dbaccess/source/ui/querydesign/SelectionBrowseBox.cxx
	dbaccess/source/ui/querydesign/TableConnectionData.cxx
	dbaccess/source/ui/querydesign/TableWindowListBox.cxx
	dbaccess/source/ui/relationdesign/RelationController.cxx
	dbaccess/source/ui/relationdesign/RelationTableView.cxx
	dbaccess/source/ui/tabledesign/table.src
	reportdesign/inc/RptPage.hxx
	reportdesign/qa/complex/reportdesign/ReportDesignerTest.java
	reportdesign/source/core/api/ReportDefinition.cxx
	reportdesign/source/core/sdr/ReportUndoFactory.cxx
	reportdesign/source/core/sdr/UndoEnv.cxx
	reportdesign/source/filter/xml/xmlservices.cxx
	reportdesign/source/ui/dlg/GroupsSorting.cxx
	reportdesign/source/ui/dlg/Navigator.cxx
	reportdesign/source/ui/inspection/metadata.cxx
	reportdesign/source/ui/misc/RptUndo.cxx
	reportdesign/source/ui/misc/UITools.cxx
	reportdesign/source/ui/misc/rptuiservices.cxx
	reportdesign/source/ui/report/DesignView.cxx
	reportdesign/source/ui/report/FixedTextColor.cxx
	reportdesign/source/ui/report/ReportController.cxx
	reportdesign/source/ui/report/ReportSection.cxx
	reportdesign/source/ui/report/SectionView.cxx
	reportdesign/source/ui/report/SectionWindow.cxx
	reportdesign/source/ui/report/StartMarker.cxx
	reportdesign/source/ui/report/ViewsWindow.cxx
	reportdesign/source/ui/report/dlgedfunc.cxx
	reportdesign/source/ui/report/report.src
2011-03-09 23:17:51 -06:00

1653 lines
60 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
*
* 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"
#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>
#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 <osl/diagnose.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,
sal_Int32 i_nMaxRows)
: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(i_nMaxRows);
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,i_nMaxRows);
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&)
{
}
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(i_nMaxRows);
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));
if(!bAllKeysFound )
{
m_pCacheSet = new OStaticSet(i_nMaxRows);
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,i_nMaxRows);
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(i_nMaxRows);
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::setFetchSize(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 invalidates 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).is())
{
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->is(),"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).is();
}
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);
bRet = m_aMatrixIter != m_pMatrix->end() && (*m_aMatrixIter).is();
}
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_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->is())
*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->is())
*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();
}
// 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 = 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();
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
{ // normally 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->is())
*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->is())
{
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 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());
::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()->is())
{
aIter = m_pMatrix->begin();
nPos = m_nStartPos;
bCheck = m_pCacheSet->absolute(m_nStartPos);
for(; !aIter->is() && 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();
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).is(),"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).is();
}
}
}
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->is() )
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->is() && 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();
}
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->is() && 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->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->is();++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->is())
*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();
}
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->is())
*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 link
pNode->count() == 3)
{
// only allow an AND link
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
OSL_ENSURE(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->is() )
{
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();
}
}
}
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->get() == _rRow.get() )
{
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->is() && (*aOldRowIter)->getRow().is() )
(*aOldRowIter)->setRow(new ORowSetValueVector( *((*aOldRowIter)->getRow()) ) );
}
sal_Int32 nNewSt = _nNewStartPos;
sal_Bool bRet = fillMatrix(nNewSt,_nNewEndPos);
m_nStartPos = nNewSt - 1;
rotateCacheIterator(static_cast<sal_Int16>(m_nFetchSize+1)); // forces every iterator 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->is() )
*_aIter = new ORowSetValueVector(nColumnCount);
else
{
TOldRowSetRows::iterator aOldRowEnd = m_aOldRows.end();
for (TOldRowSetRows::iterator aOldRowIter = m_aOldRows.begin(); aOldRowIter != aOldRowEnd; ++aOldRowIter)
{
if ( (*aOldRowIter)->getRow() == *_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->is() && m_pCacheSet->updateColumnValues((*aIter)->get(),io_aRow,o_ChangedColumns))
{
break;
}
}
if ( aIter == m_pMatrix->end() )
{
m_pCacheSet->fillMissingValues(io_aRow);
}
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */