diff options
author | Ocke Janssen [oj] <Ocke.Janssen@sun.com> | 2010-02-15 10:24:00 +0100 |
---|---|---|
committer | Ocke Janssen [oj] <Ocke.Janssen@sun.com> | 2010-02-15 10:24:00 +0100 |
commit | a4bc14c0d6c2d2d6af476f9fc446381be615e752 (patch) | |
tree | be1815c66b0ed6907d1aba6505ce7aad96283847 /dbaccess/source/core/api | |
parent | dba33f: fix delete (diff) | |
parent | dba33f: #i53377# impl join rowse helper resultset which is updateable (diff) | |
download | core-a4bc14c0d6c2d2d6af476f9fc446381be615e752.tar.gz core-a4bc14c0d6c2d2d6af476f9fc446381be615e752.zip |
Automated merge with http://hg.services.openoffice.org/cws/dba33f
Diffstat (limited to 'dbaccess/source/core/api')
19 files changed, 2805 insertions, 345 deletions
diff --git a/dbaccess/source/core/api/CRowSetColumn.cxx b/dbaccess/source/core/api/CRowSetColumn.cxx index 20e3c639eb88..d7bb2e9f097a 100644 --- a/dbaccess/source/core/api/CRowSetColumn.cxx +++ b/dbaccess/source/core/api/CRowSetColumn.cxx @@ -73,7 +73,7 @@ ORowSetColumn::ORowSetColumn( const Reference < XResultSetMetaData >& _xMetaDa DECL_PROP1_BOOL( ISCURRENCY, READONLY ); DECL_PROP1_BOOL( ISDEFINITELYWRITABLE, READONLY ); DECL_PROP1( ISNULLABLE, sal_Int32, READONLY ); - DECL_PROP1_BOOL( ISREADONLY, READONLY ); + DECL_PROP1_BOOL( ISREADONLY, BOUND ); DECL_PROP1_BOOL( ISROWVERSION, READONLY ); DECL_PROP1_BOOL( ISSEARCHABLE, READONLY ); DECL_PROP1_BOOL( ISSIGNED, READONLY ); diff --git a/dbaccess/source/core/api/CRowSetDataColumn.cxx b/dbaccess/source/core/api/CRowSetDataColumn.cxx index 4b1c3649bf6a..7e64afb9a16e 100644 --- a/dbaccess/source/core/api/CRowSetDataColumn.cxx +++ b/dbaccess/source/core/api/CRowSetDataColumn.cxx @@ -107,7 +107,7 @@ ORowSetDataColumn::~ORowSetDataColumn() DECL_PROP1_BOOL( ISCURRENCY, READONLY ); DECL_PROP1_BOOL( ISDEFINITELYWRITABLE, READONLY ); DECL_PROP1( ISNULLABLE, sal_Int32, READONLY ); - DECL_PROP1_BOOL( ISREADONLY, READONLY ); + DECL_PROP1_BOOL( ISREADONLY, BOUND ); DECL_PROP1_BOOL( ISROWVERSION, READONLY ); DECL_PROP1_BOOL( ISSEARCHABLE, READONLY ); DECL_PROP1_BOOL( ISSIGNED, READONLY ); @@ -160,13 +160,21 @@ void SAL_CALL ORowSetDataColumn::getFastPropertyValue( Any& rValue, sal_Int32 nH // ------------------------------------------------------------------------- void SAL_CALL ORowSetDataColumn::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue )throw (Exception) { - if ( PROPERTY_ID_VALUE == nHandle ) - { - updateObject(rValue); - } - else + switch( nHandle ) { - ODataColumn::setFastPropertyValue_NoBroadcast( nHandle,rValue ); + case PROPERTY_ID_VALUE: + updateObject(rValue); + break; + case PROPERTY_ID_ISREADONLY: + { + sal_Bool bVal = sal_False; + rValue >>= bVal; + m_isReadOnly.reset(bVal); + } + break; + default: + ODataColumn::setFastPropertyValue_NoBroadcast( nHandle,rValue ); + break; } } // ------------------------------------------------------------------------- @@ -176,14 +184,26 @@ sal_Bool SAL_CALL ORowSetDataColumn::convertFastPropertyValue( Any & rConvertedV const Any& rValue ) throw (IllegalArgumentException) { sal_Bool bModified = sal_False; - if ( PROPERTY_ID_VALUE == nHandle ) + switch( nHandle ) { - rConvertedValue = rValue; - getFastPropertyValue(rOldValue, PROPERTY_ID_VALUE); - bModified = rConvertedValue != rOldValue; + case PROPERTY_ID_VALUE: + { + rConvertedValue = rValue; + getFastPropertyValue(rOldValue, PROPERTY_ID_VALUE); + bModified = rConvertedValue != rOldValue; + } + break; + case PROPERTY_ID_ISREADONLY: + { + rConvertedValue = rValue; + getFastPropertyValue(rOldValue, PROPERTY_ID_ISREADONLY); + bModified = rConvertedValue != rOldValue; + } + break; + default: + bModified = ODataColumn::convertFastPropertyValue(rConvertedValue, rOldValue, nHandle, rValue); + break; } - else - bModified = ODataColumn::convertFastPropertyValue(rConvertedValue, rOldValue, nHandle, rValue); return bModified; } diff --git a/dbaccess/source/core/api/CRowSetDataColumn.hxx b/dbaccess/source/core/api/CRowSetDataColumn.hxx index f6a3446755df..056111ddf266 100644 --- a/dbaccess/source/core/api/CRowSetDataColumn.hxx +++ b/dbaccess/source/core/api/CRowSetDataColumn.hxx @@ -83,7 +83,6 @@ namespace dbaccess virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const ::com::sun::star::uno::Any& rValue )throw (::com::sun::star::uno::Exception); virtual void fireValueChange(const ::connectivity::ORowSetValue& _rOldValue); - protected: using ODataColumn::getFastPropertyValue; }; diff --git a/dbaccess/source/core/api/CacheSet.cxx b/dbaccess/source/core/api/CacheSet.cxx index cdff43ca52af..04ee584bb38b 100644 --- a/dbaccess/source/core/api/CacheSet.cxx +++ b/dbaccess/source/core/api/CacheSet.cxx @@ -274,32 +274,8 @@ void OCacheSet::fillParameters( const ORowSetRow& _rRow RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OCacheSet::fillParameters" ); // use keys and indexes for excat postioning // first the keys - Reference<XKeysSupplier> xKeySup(_xTable,UNO_QUERY); - Reference<XIndexAccess> xKeys; - if(xKeySup.is()) - xKeys = xKeySup->getKeys(); - - Reference<XColumnsSupplier> xKeyColsSup; - Reference<XNameAccess> xKeyColumns; - if(xKeys.is() && xKeys->getCount()) - { - Reference<XPropertySet> xProp; - Reference<XColumnsSupplier> xColumnsSupplier; - // search the one and only primary key - for(sal_Int32 i=0;i< xKeys->getCount();++i) - { - ::cppu::extractInterface(xProp,xKeys->getByIndex(i)); - sal_Int32 nKeyType = 0; - xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType; - if(KeyType::PRIMARY == nKeyType) - { - xKeyColsSup.set(xProp,UNO_QUERY); - break; - } - } - if(xKeyColsSup.is()) - xKeyColumns = xKeyColsSup->getColumns(); - } + Reference<XPropertySet> xSet(_xTable,UNO_QUERY); + const Reference<XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(xSet); // second the indexes Reference<XIndexesSupplier> xIndexSup(_xTable,UNO_QUERY); Reference<XIndexAccess> xIndexes; @@ -314,7 +290,7 @@ void OCacheSet::fillParameters( const ORowSetRow& _rRow { for(sal_Int32 j=0;j<xIndexes->getCount();++j) { - ::cppu::extractInterface(xIndexColsSup,xIndexes->getByIndex(j)); + xIndexColsSup.set(xIndexes->getByIndex(j),UNO_QUERY); if( xIndexColsSup.is() && comphelper::getBOOL(xIndexColsSup->getPropertyValue(PROPERTY_ISUNIQUE)) && !comphelper::getBOOL(xIndexColsSup->getPropertyValue(PROPERTY_ISPRIMARYKEYINDEX)) @@ -340,7 +316,7 @@ void OCacheSet::fillParameters( const ORowSetRow& _rRow for(; aIter != aEnd;++aIter,++nCheckCount,++i) { aColumnName = m_xSetMetaData->getColumnName(i); - if(xKeyColumns.is() && xKeyColumns->hasByName(aColumnName)) + if(xPrimaryKeyColumns.is() && xPrimaryKeyColumns->hasByName(aColumnName)) { _sCondition.append(::dbtools::quoteName( aQuote,aColumnName)); if(aIter->isNull()) @@ -350,7 +326,7 @@ void OCacheSet::fillParameters( const ORowSetRow& _rRow _sCondition.append(aAnd); _rOrgValues.push_back(nCheckCount); - } // if(xKeyColumns.is() && xKeyColumns->hasByName(aColumnName)) + } // if(xPrimaryKeyColumns.is() && xPrimaryKeyColumns->hasByName(aColumnName)) ::std::vector< Reference<XNameAccess> >::const_iterator aIndexEnd = aAllIndexColumns.end(); for( ::std::vector< Reference<XNameAccess> >::const_iterator aIndexIter = aAllIndexColumns.begin(); aIndexIter != aIndexEnd;++aIndexIter) @@ -439,32 +415,7 @@ void SAL_CALL OCacheSet::deleteRow(const ORowSetRow& _rDeleteRow ,const connecti // use keys and indexes for excat postioning // first the keys - Reference<XKeysSupplier> xKeySup(_xTable,UNO_QUERY); - Reference<XIndexAccess> xKeys; - if(xKeySup.is()) - xKeys = xKeySup->getKeys(); - - Reference<XColumnsSupplier> xKeyColsSup; - Reference<XNameAccess> xKeyColumns; - if(xKeys.is() && xKeys->getCount()) - { - Reference<XPropertySet> xProp; - Reference<XColumnsSupplier> xColumnsSupplier; - // search the one and only primary key - for(sal_Int32 i=0;i< xKeys->getCount();++i) - { - ::cppu::extractInterface(xProp,xKeys->getByIndex(i)); - sal_Int32 nKeyType = 0; - xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType; - if(KeyType::PRIMARY == nKeyType) - { - xKeyColsSup.set(xProp,UNO_QUERY); - break; - } - } - if(xKeyColsSup.is()) - xKeyColumns = xKeyColsSup->getColumns(); - } + const Reference<XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(xSet); // second the indexes Reference<XIndexesSupplier> xIndexSup(_xTable,UNO_QUERY); Reference<XIndexAccess> xIndexes; @@ -511,7 +462,7 @@ void OCacheSet::setParameter(sal_Int32 nPos ,const Reference< XParameters >& _xParameter ,const ORowSetValue& _rValue ,sal_Int32 _nType - ,sal_Int32 _nScale) + ,sal_Int32 _nScale) const { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OCacheSet::setParameter" ); sal_Int32 nType = ( _nType != DataType::OTHER ) ? _nType : _rValue.getTypeKind(); @@ -773,3 +724,33 @@ Reference< XInterface > SAL_CALL OCacheSet::getStatement( ) throw(SQLException, return m_xDriverSet->getStatement(); } // ----------------------------------------------------------------------------- +bool OCacheSet::isResultSetChanged() const +{ + return false; +} +// ----------------------------------------------------------------------------- +void OCacheSet::reset(const Reference< XResultSet>& /*_xDriverSet*/) +{ + OSL_ENSURE(0,"Illegal call!"); +} +// ----------------------------------------------------------------------------- +void OCacheSet::mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& /*io_aInsertRow*/,ORowSetValueVector::Vector& /*io_aRow*/,::std::vector<sal_Int32>& o_aChangedColumns) +{ + o_aChangedColumns.push_back(i_nColumnIndex); +} +// ----------------------------------------------------------------------------- +bool OCacheSet::columnValuesUpdated(ORowSetValueVector::Vector& /*io_aCachedRow*/,const ORowSetValueVector::Vector& /*io_aRow*/) +{ + return false; +} +// ----------------------------------------------------------------------------- +bool OCacheSet::updateColumnValues(const ORowSetValueVector::Vector& /*io_aCachedRow*/,ORowSetValueVector::Vector& /*io_aRow*/,const ::std::vector<sal_Int32>& /*i_aChangedColumns*/) +{ + return true; +} +// ----------------------------------------------------------------------------- +void OCacheSet::fillMissingValues(ORowSetValueVector::Vector& /*io_aRow*/) const +{ +} +// ----------------------------------------------------------------------------- + diff --git a/dbaccess/source/core/api/CacheSet.hxx b/dbaccess/source/core/api/CacheSet.hxx index e0fcf981f2ba..d206cb5815bd 100644 --- a/dbaccess/source/core/api/CacheSet.hxx +++ b/dbaccess/source/core/api/CacheSet.hxx @@ -98,7 +98,7 @@ namespace dbaccess ,const connectivity::ORowSetValue& _rValue ,sal_Int32 _nType ,sal_Int32 _nScale - ); + ) const; void fillParameters( const ORowSetRow& _rRow ,const connectivity::OSQLTable& _xTable ,::rtl::OUStringBuffer& _sCondition @@ -169,6 +169,13 @@ namespace dbaccess virtual void SAL_CALL cancelRowUpdates( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException) = 0; virtual void SAL_CALL moveToInsertRow( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException) = 0; virtual void SAL_CALL moveToCurrentRow( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException) = 0; + + virtual bool isResultSetChanged() const; + virtual void reset(const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSet>& _xDriverSet); + virtual void mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& io_aInsertRow,ORowSetValueVector::Vector& io_aRow,::std::vector<sal_Int32>& o_aChangedColumns); + virtual bool columnValuesUpdated(ORowSetValueVector::Vector& o_aCachedRow,const ORowSetValueVector::Vector& i_aRow); + virtual bool updateColumnValues(const ORowSetValueVector::Vector& io_aCachedRow,ORowSetValueVector::Vector& io_aRow,const ::std::vector<sal_Int32>& i_aChangedColumns); + virtual void fillMissingValues(ORowSetValueVector::Vector& io_aRow) const; }; } #endif //DBACCESS_CORE_API_CACHESET_HXX diff --git a/dbaccess/source/core/api/KeySet.cxx b/dbaccess/source/core/api/KeySet.cxx index 193aef7e8e77..dac7f125de4a 100644 --- a/dbaccess/source/core/api/KeySet.cxx +++ b/dbaccess/source/core/api/KeySet.cxx @@ -225,7 +225,6 @@ void OKeySet::construct(const Reference< XResultSet>& _xDriverSet,const ::rtl::O xPara->getPropertyValue(PROPERTY_REALNAME) >>= aParameterColumns[i]; } - ::rtl::OUString sCatalog,sSchema,sTable; Reference<XPropertySet> xTableProp(m_xTable,UNO_QUERY); @@ -987,9 +986,9 @@ Reference<XNameAccess> OKeySet::getKeyColumns() const Reference<XIndexAccess> xKeys = m_xTableKeys; if ( !xKeys.is() ) { - Reference<XKeysSupplier> xKeySup(m_xTable,UNO_QUERY); - if(xKeySup.is()) - xKeys = xKeySup->getKeys(); + Reference<XPropertySet> xSet(m_xTable,UNO_QUERY); + const Reference<XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(xSet); + return xPrimaryKeyColumns; } Reference<XColumnsSupplier> xKeyColsSup; @@ -1477,49 +1476,62 @@ namespace dbaccess void getColumnPositions(const Reference<XNameAccess>& _rxQueryColumns, const Sequence< ::rtl::OUString>& _aColumnNames, const ::rtl::OUString& _rsUpdateTableName, - SelectColumnsMetaData& _rColumnNames) + SelectColumnsMetaData& o_rColumnNames, + bool i_bAppendTableName) { // get the real name of the columns Sequence< ::rtl::OUString> aSelNames(_rxQueryColumns->getElementNames()); - const ::rtl::OUString* pSelBegin = aSelNames.getConstArray(); - const ::rtl::OUString* pSelEnd = pSelBegin + aSelNames.getLength(); + const ::rtl::OUString* pSelIter = aSelNames.getConstArray(); + const ::rtl::OUString* pSelEnd = pSelIter + aSelNames.getLength(); - const ::rtl::OUString* pColumnIter = _aColumnNames.getConstArray(); - const ::rtl::OUString* pColumnEnd = pColumnIter + _aColumnNames.getLength(); + const ::rtl::OUString* pTblColumnIter = _aColumnNames.getConstArray(); + const ::rtl::OUString* pTblColumnEnd = pTblColumnIter + _aColumnNames.getLength(); - ::comphelper::UStringMixLess aTmp(_rColumnNames.key_comp()); + ::comphelper::UStringMixLess aTmp(o_rColumnNames.key_comp()); ::comphelper::UStringMixEqual bCase(static_cast< ::comphelper::UStringMixLess*>(&aTmp)->isCaseSensitive()); - for(sal_Int32 nPos = 1;pSelBegin != pSelEnd;++pSelBegin,++nPos) + for(sal_Int32 nPos = 1;pSelIter != pSelEnd;++pSelIter,++nPos) { - Reference<XPropertySet> xColumnProp(_rxQueryColumns->getByName(*pSelBegin),UNO_QUERY); + Reference<XPropertySet> xQueryColumnProp(_rxQueryColumns->getByName(*pSelIter),UNO_QUERY_THROW); ::rtl::OUString sRealName,sTableName; - OSL_ENSURE(xColumnProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME),"Property REALNAME not available!"); - OSL_ENSURE(xColumnProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME),"Property TABLENAME not available!"); - xColumnProp->getPropertyValue(PROPERTY_REALNAME) >>= sRealName; - xColumnProp->getPropertyValue(PROPERTY_TABLENAME) >>= sTableName; + OSL_ENSURE(xQueryColumnProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME),"Property REALNAME not available!"); + OSL_ENSURE(xQueryColumnProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME),"Property TABLENAME not available!"); + xQueryColumnProp->getPropertyValue(PROPERTY_REALNAME) >>= sRealName; + xQueryColumnProp->getPropertyValue(PROPERTY_TABLENAME) >>= sTableName; - for(;pColumnIter != pColumnEnd;++pColumnIter) + for(;pTblColumnIter != pTblColumnEnd;++pTblColumnIter) { - if(bCase(sRealName,*pColumnIter) && bCase(_rsUpdateTableName,sTableName) && _rColumnNames.find(*pColumnIter) == _rColumnNames.end()) + if(bCase(sRealName,*pTblColumnIter) && bCase(_rsUpdateTableName,sTableName) && o_rColumnNames.find(*pTblColumnIter) == o_rColumnNames.end()) { sal_Int32 nType = 0; - xColumnProp->getPropertyValue(PROPERTY_TYPE) >>= nType; + xQueryColumnProp->getPropertyValue(PROPERTY_TYPE) >>= nType; sal_Int32 nScale = 0; - xColumnProp->getPropertyValue(PROPERTY_SCALE) >>= nScale; + xQueryColumnProp->getPropertyValue(PROPERTY_SCALE) >>= nScale; ::rtl::OUString sColumnDefault; - if ( xColumnProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_DEFAULTVALUE) ) - xColumnProp->getPropertyValue(PROPERTY_DEFAULTVALUE) >>= sColumnDefault; + if ( xQueryColumnProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_DEFAULTVALUE) ) + xQueryColumnProp->getPropertyValue(PROPERTY_DEFAULTVALUE) >>= sColumnDefault; - sal_Int32 bNullable = sal_False; - xColumnProp->getPropertyValue(PROPERTY_ISNULLABLE) >>= bNullable; + sal_Int32 nNullable = ColumnValue::NULLABLE_UNKNOWN; + OSL_VERIFY( xQueryColumnProp->getPropertyValue( PROPERTY_ISNULLABLE ) >>= nNullable ); + if ( i_bAppendTableName ) + { + ::rtl::OUStringBuffer sName; + sName.append(sTableName); + sName.appendAscii("."); + sName.append(sRealName); + SelectColumnDescription aColDesc( nPos, nType,nScale,nNullable != sdbc::ColumnValue::NO_NULLS, sColumnDefault ); + aColDesc.sRealName = sRealName; + aColDesc.sTableName = sTableName; + o_rColumnNames[sName.makeStringAndClear()] = aColDesc; + } + else + o_rColumnNames[sRealName] = SelectColumnDescription( nPos, nType,nScale,nNullable != sdbc::ColumnValue::NO_NULLS, sColumnDefault ); - _rColumnNames[sRealName] = SelectColumnDescription( nPos, nType,nScale,bNullable != sdbc::ColumnValue::NO_NULLS, sColumnDefault ); break; } } - pColumnIter = _aColumnNames.getConstArray(); + pTblColumnIter = _aColumnNames.getConstArray(); } } } diff --git a/dbaccess/source/core/api/KeySet.hxx b/dbaccess/source/core/api/KeySet.hxx index 7db5c176e9ff..d0e81c1f1548 100644 --- a/dbaccess/source/core/api/KeySet.hxx +++ b/dbaccess/source/core/api/KeySet.hxx @@ -54,28 +54,30 @@ namespace dbaccess { struct SelectColumnDescription { + ::rtl::OUString sRealName; // may be empty + ::rtl::OUString sTableName; // may be empty + ::rtl::OUString sDefaultValue; sal_Int32 nPosition; sal_Int32 nType; sal_Int32 nScale; sal_Bool bNullable; - ::rtl::OUString sDefaultValue; + SelectColumnDescription() :nPosition( 0 ) ,nType( 0 ) ,nScale( 0 ) ,bNullable(sal_False) - ,sDefaultValue() { } SelectColumnDescription( sal_Int32 _nPosition, sal_Int32 _nType, sal_Int32 _nScale,sal_Bool _bNullable, const ::rtl::OUString& _rDefaultValue ) - :nPosition( _nPosition ) + :sDefaultValue( _rDefaultValue ) + ,nPosition( _nPosition ) ,nType( _nType ) ,nScale( _nScale ) ,bNullable(_bNullable) - ,sDefaultValue( _rDefaultValue ) { } }; @@ -85,7 +87,8 @@ namespace dbaccess void getColumnPositions(const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >& _rxQueryColumns, const ::com::sun::star::uno::Sequence< ::rtl::OUString>& _aColumnNames, const ::rtl::OUString& _rsUpdateTableName, - SelectColumnsMetaData& _rColumnNames /* out */); + SelectColumnsMetaData& o_rColumnNames /* out */, + bool i_bAppendTableName = false); typedef ::std::pair<ORowSetRow,sal_Int32> OKeySetValue; typedef ::std::map<sal_Int32,OKeySetValue > OKeySetMatrix; diff --git a/dbaccess/source/core/api/OptimisticSet.cxx b/dbaccess/source/core/api/OptimisticSet.cxx new file mode 100644 index 000000000000..71de01e4d3b6 --- /dev/null +++ b/dbaccess/source/core/api/OptimisticSet.cxx @@ -0,0 +1,1689 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: OptimisticSet.cxx,v $ + * $Revision: 1.73 $ + * + * 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 "OptimisticSet.hxx" +#include "core_resource.hxx" +#include "core_resource.hrc" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/XPreparedStatement.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/XGeneratedResultSet.hpp> +#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp> +#include <com/sun/star/sdb/SQLFilterOperator.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include "dbastrings.hrc" +#include "apitools.hxx" +#include <com/sun/star/sdbcx/XKeysSupplier.hpp> +#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp> +#include <com/sun/star/sdbcx/XIndexesSupplier.hpp> +#include <cppuhelper/typeprovider.hxx> +#include <comphelper/types.hxx> +#include <com/sun/star/sdbcx/KeyType.hpp> +#include <connectivity/dbtools.hxx> +#include <connectivity/dbexception.hxx> +#include <list> +#include <algorithm> +#include <string.h> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include "querycomposer.hxx" +#include "composertools.hxx" +#include <tools/debug.hxx> +#include <string.h> +#include <rtl/logfile.hxx> + +using namespace dbaccess; +using namespace ::connectivity; +using namespace ::dbtools; +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 ::com::sun::star::util; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star; +using namespace ::cppu; +using namespace ::osl; + +DECLARE_STL_USTRINGACCESS_MAP(::rtl::OUStringBuffer,TSQLStatements); +namespace +{ + void lcl_fillIndexColumns(const Reference<XIndexAccess>& _xIndexes, ::std::vector< Reference<XNameAccess> >& _rAllIndexColumns) + { + if ( _xIndexes.is() ) + { + Reference<XPropertySet> xIndexColsSup; + sal_Int32 nCount = _xIndexes->getCount(); + for(sal_Int32 j = 0 ; j < nCount ; ++j) + { + xIndexColsSup.set(_xIndexes->getByIndex(j),UNO_QUERY); + if( xIndexColsSup.is() + && comphelper::getBOOL(xIndexColsSup->getPropertyValue(PROPERTY_ISUNIQUE)) + && !comphelper::getBOOL(xIndexColsSup->getPropertyValue(PROPERTY_ISPRIMARYKEYINDEX)) + ) + _rAllIndexColumns.push_back(Reference<XColumnsSupplier>(xIndexColsSup,UNO_QUERY)->getColumns()); + } + } + } + void lcl_fillKeyCondition(const ::rtl::OUString& i_sTableName,const ::rtl::OUString& i_sQuotedColumnName,const ORowSetValue& i_aValue,TSQLStatements& io_aKeyConditions) + { + ::rtl::OUStringBuffer& rKeyCondition = io_aKeyConditions[i_sTableName]; + if ( rKeyCondition.getLength() ) + rKeyCondition.appendAscii(" AND "); + rKeyCondition.append(i_sQuotedColumnName); + if ( i_aValue.isNull() ) + rKeyCondition.appendAscii(" IS NULL"); + else + rKeyCondition.appendAscii(" = ?"); + } +} + +DBG_NAME(OptimisticSet) +// ------------------------------------------------------------------------- +OptimisticSet::OptimisticSet(const ::comphelper::ComponentContext& _rContext, + const Reference< XConnection>& i_xConnection, + const Reference< XSingleSelectQueryAnalyzer >& _xComposer, + const ORowSetValueVector& _aParameterValueForCache) + :m_aSqlParser( _rContext.getLegacyServiceFactory() ) + ,m_aSqlIterator( i_xConnection, Reference<XTablesSupplier>(_xComposer,UNO_QUERY)->getTables(), m_aSqlParser, NULL ) + ,m_aParameterValueForCache(_aParameterValueForCache) + ,m_pKeyColumnNames(NULL) + ,m_pColumnNames(NULL) + ,m_pParameterNames(NULL) + ,m_xComposer(_xComposer) + ,m_bRowCountFinal(sal_False) + ,m_bResultSetChanged(false) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::OptimisticSet" ); + DBG_CTOR(OptimisticSet,NULL); +} +// ----------------------------------------------------------------------------- +OptimisticSet::~OptimisticSet() +{ + try + { + ::comphelper::disposeComponent(m_xStatement); + } + catch(Exception&) + { + m_xStatement.clear(); + } + catch(...) + { + OSL_ENSURE(0,"Unknown Exception occured"); + } + m_xComposer.clear(); + + DBG_DTOR(OptimisticSet,NULL); +} +// ----------------------------------------------------------------------------- +void OptimisticSet::construct(const Reference< XResultSet>& _xDriverSet,const ::rtl::OUString& i_sRowSetFilter) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::construct" ); + OCacheSet::construct(_xDriverSet,i_sRowSetFilter); + + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + bool bCase = (xMeta.is() && xMeta->storesMixedCaseQuotedIdentifiers()) ? true : false; + + m_pKeyColumnNames.reset( new SelectColumnsMetaData(bCase) ); + m_pColumnNames.reset( new SelectColumnsMetaData(bCase) ); + m_pParameterNames.reset( new SelectColumnsMetaData(bCase) ); + + Reference<XColumnsSupplier> xQueryColSup(m_xComposer,UNO_QUERY); + const Reference<XNameAccess> xQueryColumns = xQueryColSup->getColumns(); + const Reference<XTablesSupplier> xTabSup(m_xComposer,UNO_QUERY); + const Reference<XNameAccess> xTables = xTabSup->getTables(); + const Sequence< ::rtl::OUString> aTableNames = xTables->getElementNames(); + const ::rtl::OUString* pTableNameIter = aTableNames.getConstArray(); + const ::rtl::OUString* pTableNameEnd = pTableNameIter + aTableNames.getLength(); + for( ; pTableNameIter != pTableNameEnd ; ++pTableNameIter) + { + findTableColumnsMatching_throw(xTables->getByName(*pTableNameIter),xMeta,xQueryColumns); + } + + // the first row is empty because it's now easier for us to distinguish when we are beforefirst or first + // without extra variable to be set + m_aKeyMap.insert(OKeySetMatrix::value_type(0,OKeySetValue(NULL,0))); + m_aKeyIter = m_aKeyMap.begin(); + + static ::rtl::OUString aAnd = ::rtl::OUString::createFromAscii(" AND "); + const ::rtl::OUString aQuote = getIdentifierQuoteString(); + ::rtl::OUStringBuffer aFilter; + static ::rtl::OUString s_sDot(RTL_CONSTASCII_USTRINGPARAM(".")); + static ::rtl::OUString s_sParam(RTL_CONSTASCII_USTRINGPARAM(" = ?")); + // create the where clause + SelectColumnsMetaData::iterator aPosEnd = m_pKeyColumnNames->end(); + for(SelectColumnsMetaData::iterator aPosIter = m_pKeyColumnNames->begin();aPosIter != aPosEnd;) + { + aFilter.append(::dbtools::quoteName( aQuote,aPosIter->second.sTableName)); + aFilter.append(s_sDot); + aFilter.append(::dbtools::quoteName( aQuote,aPosIter->second.sRealName)); + aFilter.append(s_sParam); + ++aPosIter; + if(aPosIter != aPosEnd) + aFilter.append(aAnd); + } + + Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW); + Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY); + Reference<XSingleSelectQueryComposer> xComp2(m_xComposer,UNO_QUERY_THROW); + ::rtl::OUString sQuery = xComp2->getQuery(); + xAnalyzer->setQuery(sQuery); + // check for joins + ::rtl::OUString aErrorMsg; + ::std::auto_ptr<OSQLParseNode> pStatementNode( m_aSqlParser.parseTree( aErrorMsg, sQuery ) ); + m_aSqlIterator.setParseTree( pStatementNode.get() ); + m_aSqlIterator.traverseAll(); + fillJoinedColumns_throw(m_aSqlIterator.getJoinConditions()); + + const ::rtl::OUString sComposerFilter = m_xComposer->getFilter(); + if ( i_sRowSetFilter.getLength() || (sComposerFilter.getLength() && sComposerFilter != i_sRowSetFilter) ) + { + FilterCreator aFilterCreator; + if ( sComposerFilter.getLength() && sComposerFilter != i_sRowSetFilter ) + aFilterCreator.append( sComposerFilter ); + aFilterCreator.append( i_sRowSetFilter ); + aFilterCreator.append( aFilter.makeStringAndClear() ); + aFilter = aFilterCreator.getComposedAndClear(); + } + xAnalyzer->setFilter(aFilter.makeStringAndClear()); + m_xStatement = m_xConnection->prepareStatement(xAnalyzer->getQueryWithSubstitution()); + ::comphelper::disposeComponent(xAnalyzer); +} +// ------------------------------------------------------------------------- +Any SAL_CALL OptimisticSet::getBookmark() throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getBookmark" ); + OSL_ENSURE(m_aKeyIter != m_aKeyMap.end() && m_aKeyIter != m_aKeyMap.begin(), + "getBookmark is only possible when we stand on a valid row!"); + return makeAny(m_aKeyIter->first); +} + +// ------------------------------------------------------------------------- +sal_Bool SAL_CALL OptimisticSet::moveToBookmark( const Any& bookmark ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::moveToBookmark" ); + m_bInserted = m_bUpdated = m_bDeleted = sal_False; + m_aKeyIter = m_aKeyMap.find(::comphelper::getINT32(bookmark)); + return m_aKeyIter != m_aKeyMap.end(); +} +// ------------------------------------------------------------------------- +sal_Bool SAL_CALL OptimisticSet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::moveRelativeToBookmark" ); + m_bInserted = m_bUpdated = m_bDeleted = sal_False; + m_aKeyIter = m_aKeyMap.find(::comphelper::getINT32(bookmark)); + if(m_aKeyIter != m_aKeyMap.end()) + { + relative(rows); + } + + return !isBeforeFirst() && !isAfterLast(); +} +// ------------------------------------------------------------------------- +sal_Int32 SAL_CALL OptimisticSet::compareBookmarks( const Any& _first, const Any& _second ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::compareBookmarks" ); + sal_Int32 nFirst = 0, nSecond = 0; + _first >>= nFirst; + _second >>= nSecond; + + return (nFirst != nSecond) ? CompareBookmark::NOT_EQUAL : CompareBookmark::EQUAL; +} +// ------------------------------------------------------------------------- +sal_Bool SAL_CALL OptimisticSet::hasOrderedBookmarks( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::hasOrderedBookmarks" ); + return sal_True; +} +// ------------------------------------------------------------------------- +sal_Int32 SAL_CALL OptimisticSet::hashBookmark( const Any& bookmark ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::hashBookmark" ); + return ::comphelper::getINT32(bookmark); +} +// ------------------------------------------------------------------------- +// ::com::sun::star::sdbcx::XDeleteRows +Sequence< sal_Int32 > SAL_CALL OptimisticSet::deleteRows( const Sequence< Any >& /*rows*/ ,const connectivity::OSQLTable& /*_xTable*/) throw(SQLException, RuntimeException) +{ + Sequence< sal_Int32 > aRet; + return aRet; +} +// ------------------------------------------------------------------------- +void SAL_CALL OptimisticSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOrginalRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::updateRow" ); + if ( m_aJoinedKeyColumns.empty() ) + throw SQLException(); + // list all cloumns that should be set + static ::rtl::OUString s_sPara = ::rtl::OUString::createFromAscii(" = ?"); + ::rtl::OUString aQuote = getIdentifierQuoteString(); + static ::rtl::OUString aAnd = ::rtl::OUString::createFromAscii(" AND "); + ::rtl::OUString sIsNull(RTL_CONSTASCII_USTRINGPARAM(" IS NULL")); + ::rtl::OUString sParam(RTL_CONSTASCII_USTRINGPARAM(" = ?")); + + ::rtl::OUString aColumnName; + ::rtl::OUStringBuffer sKeyCondition; + ::std::map< ::rtl::OUString,bool > aResultSetChanged; + TSQLStatements aKeyConditions; + TSQLStatements aIndexConditions; + TSQLStatements aSql; + + // sal_Int32 i = 1; + // here we build the condition part for the update statement + SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin(); + SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end(); + for(;aIter != aEnd;++aIter) + { + if ( aResultSetChanged.find( aIter->second.sTableName ) == aResultSetChanged.end() ) + aResultSetChanged[aIter->second.sTableName] = false; + const ::rtl::OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aIter->second.sRealName); + if ( m_pKeyColumnNames->find(aIter->first) != m_pKeyColumnNames->end() ) + { + aResultSetChanged[aIter->second.sTableName] = m_aJoinedKeyColumns.find(aIter->second.nPosition) != m_aJoinedKeyColumns.end(); + lcl_fillKeyCondition(aIter->second.sTableName,sQuotedColumnName,(_rOrginalRow->get())[aIter->second.nPosition],aKeyConditions); + } + if((_rInsertRow->get())[aIter->second.nPosition].isModified()) + { + if ( m_aJoinedKeyColumns.find(aIter->second.nPosition) != m_aJoinedKeyColumns.end() ) + throw SQLException(); + + ::std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(aIter->second.nPosition); + if ( aJoinIter != m_aJoinedColumns.end() ) + { + (_rInsertRow->get())[aJoinIter->second] = (_rInsertRow->get())[aIter->second.nPosition]; + } + ::rtl::OUStringBuffer& rPart = aSql[aIter->second.sTableName]; + if ( rPart.getLength() ) + rPart.appendAscii(", "); + rPart.append(sQuotedColumnName); + rPart.append(s_sPara); + } + } + + if( aSql.empty() ) + ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED ), SQL_GENERAL_ERROR, m_xConnection ); + + if( aKeyConditions.empty() ) + ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_CONDITION_FOR_PK ), SQL_GENERAL_ERROR, m_xConnection ); + + static const ::rtl::OUString s_sUPDATE(RTL_CONSTASCII_USTRINGPARAM("UPDATE ")); + static const ::rtl::OUString s_sSET(RTL_CONSTASCII_USTRINGPARAM(" SET ")); + + Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData(); + + TSQLStatements::iterator aSqlIter = aSql.begin(); + TSQLStatements::iterator aSqlEnd = aSql.end(); + for(;aSqlIter != aSqlEnd ; ++aSqlIter) + { + if ( aSqlIter->second.getLength() ) + { + m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[aSqlIter->first]; + ::rtl::OUStringBuffer sSql(s_sUPDATE); + ::rtl::OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation); + sSql.append( ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) ); + sSql.append(s_sSET); + sSql.append(aSqlIter->second); + ::rtl::OUStringBuffer& rCondition = aKeyConditions[aSqlIter->first]; + bool bAddWhere = true; + if ( rCondition.getLength() ) + { + bAddWhere = false; + sSql.appendAscii(" WHERE "); + sSql.append( rCondition ); + } + executeUpdate(_rInsertRow ,_rOrginalRow,sSql.makeStringAndClear(),aSqlIter->first); + } + } +} +// ------------------------------------------------------------------------- +void SAL_CALL OptimisticSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::insertRow" ); + TSQLStatements aSql; + TSQLStatements aParameter; + TSQLStatements aKeyConditions; + ::std::map< ::rtl::OUString,bool > aResultSetChanged; + ::rtl::OUString aQuote = getIdentifierQuoteString(); + static ::rtl::OUString aAnd = ::rtl::OUString::createFromAscii(" AND "); + ::rtl::OUString sIsNull(RTL_CONSTASCII_USTRINGPARAM(" IS NULL")); + ::rtl::OUString sParam(RTL_CONSTASCII_USTRINGPARAM(" = ?")); + + // here we build the condition part for the update statement + SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin(); + SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end(); + for(;aIter != aEnd;++aIter) + { + if ( aResultSetChanged.find( aIter->second.sTableName ) == aResultSetChanged.end() ) + aResultSetChanged[aIter->second.sTableName] = false; + + const ::rtl::OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aIter->second.sRealName); + if ( (_rInsertRow->get())[aIter->second.nPosition].isModified() ) + { + if ( m_aJoinedKeyColumns.find(aIter->second.nPosition) != m_aJoinedKeyColumns.end() ) + { + lcl_fillKeyCondition(aIter->second.sTableName,sQuotedColumnName,(_rInsertRow->get())[aIter->second.nPosition],aKeyConditions); + aResultSetChanged[aIter->second.sTableName] = true; + } + ::std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(aIter->second.nPosition); + if ( aJoinIter != m_aJoinedColumns.end() ) + { + (_rInsertRow->get())[aJoinIter->second] = (_rInsertRow->get())[aIter->second.nPosition]; + } + ::rtl::OUStringBuffer& rPart = aSql[aIter->second.sTableName]; + if ( rPart.getLength() ) + rPart.appendAscii(", "); + rPart.append(sQuotedColumnName); + ::rtl::OUStringBuffer& rParam = aParameter[aIter->second.sTableName]; + if ( rParam.getLength() ) + rParam.appendAscii(", "); + rParam.appendAscii("?"); + } + } + if ( aParameter.empty() ) + ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED ), SQL_GENERAL_ERROR, m_xConnection ); + + Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData(); + static const ::rtl::OUString s_sINSERT(RTL_CONSTASCII_USTRINGPARAM("INSERT INTO ")); + static const ::rtl::OUString s_sVALUES(RTL_CONSTASCII_USTRINGPARAM(") VALUES ( ")); + TSQLStatements::iterator aSqlIter = aSql.begin(); + TSQLStatements::iterator aSqlEnd = aSql.end(); + for(;aSqlIter != aSqlEnd ; ++aSqlIter) + { + if ( aSqlIter->second.getLength() ) + { + m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[aSqlIter->first]; + ::rtl::OUStringBuffer sSql(s_sINSERT); + ::rtl::OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation); + ::rtl::OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ); + sSql.append(sComposedTableName); + sSql.appendAscii(" ( "); + sSql.append(aSqlIter->second); + sSql.append(s_sVALUES); + sSql.append(aParameter[aSqlIter->first]); + sSql.appendAscii(" )"); + + ::rtl::OUStringBuffer& rCondition = aKeyConditions[aSqlIter->first]; + if ( rCondition.getLength() ) + { + ::rtl::OUStringBuffer sQuery; + sQuery.appendAscii("SELECT "); + sQuery.append(aSqlIter->second); + sQuery.appendAscii(" FROM "); + sQuery.append(sComposedTableName); + sQuery.appendAscii(" WHERE "); + sQuery.append(rCondition); + + try + { + Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery.makeStringAndClear())); + Reference< XParameters > xParameter(xPrep,UNO_QUERY); + // and then the values of the where condition + SelectColumnsMetaData::iterator aIter = m_pKeyColumnNames->begin(); + SelectColumnsMetaData::iterator aEnd = m_pKeyColumnNames->end(); + sal_Int32 i = 1; + for(;aIter != aEnd;++aIter) + { + if ( aIter->second.sTableName == aSqlIter->first ) + { + setParameter(i++,xParameter,(_rInsertRow->get())[aIter->second.nPosition],aIter->second.nType,aIter->second.nScale); + } + } + Reference<XResultSet> xRes = xPrep->executeQuery(); + Reference<XRow> xRow(xRes,UNO_QUERY); + if ( xRow.is() && xRes->next() ) + { + m_bResultSetChanged = true; + continue; + } + } + catch(const SQLException&) + { + } + } + + executeInsert(_rInsertRow,sSql.makeStringAndClear(),aSqlIter->first); + } + } +} +// ------------------------------------------------------------------------- +void OptimisticSet::executeInsert( const ORowSetRow& _rInsertRow,const ::rtl::OUString& i_sSQL,const ::rtl::OUString& i_sTableName ) +{ + // now create,fill and execute the prepared statement + Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL)); + Reference< XParameters > xParameter(xPrep,UNO_QUERY); + + SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin(); + SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end(); + for(sal_Int32 i = 1;aIter != aEnd;++aIter) + { + if ( aIter->second.sTableName == i_sTableName ) + { + const sal_Int32 nPos = aIter->second.nPosition; + if((_rInsertRow->get())[nPos].isModified()) + { + if((_rInsertRow->get())[nPos].isNull()) + xParameter->setNull(i++,(_rInsertRow->get())[nPos].getTypeKind()); + else + { + impl_convertValue_throw(_rInsertRow,aIter->second); + (_rInsertRow->get())[nPos].setSigned(m_aSignedFlags[nPos-1]); + setParameter(i++,xParameter,(_rInsertRow->get())[nPos],aIter->second.nType,aIter->second.nScale); + } + } + } + } + + m_bInserted = xPrep->executeUpdate() > 0; + sal_Bool bAutoValuesFetched = sal_False; + if ( m_bInserted ) + { + // first insert the default values into the insertrow + aIter = m_pColumnNames->begin(); + for(;aIter != aEnd;++aIter) + { + if ( !(_rInsertRow->get())[aIter->second.nPosition].isModified() ) + (_rInsertRow->get())[aIter->second.nPosition] = aIter->second.sDefaultValue; + } + try + { + Reference< XGeneratedResultSet > xGRes(xPrep, UNO_QUERY); + if ( xGRes.is() ) + { + Reference< XResultSet > xRes = xGRes->getGeneratedValues(); + Reference< XRow > xRow(xRes,UNO_QUERY); + if ( xRow.is() && xRes->next() ) + { + Reference< XResultSetMetaDataSupplier > xMdSup(xRes,UNO_QUERY); + Reference< XResultSetMetaData > xMd = xMdSup->getMetaData(); + sal_Int32 nColumnCount = xMd->getColumnCount(); + ::std::vector< ::rtl::OUString >::iterator aAutoIter = m_aAutoColumns.begin(); + ::std::vector< ::rtl::OUString >::iterator aAutoEnd = m_aAutoColumns.end(); + for (sal_Int32 i = 1;aAutoIter != aAutoEnd && i <= nColumnCount; ++aAutoIter,++i) + { +#if OSL_DEBUG_LEVEL > 1 + ::rtl::OUString sColumnName( xMd->getColumnName(i) ); +#endif + SelectColumnsMetaData::iterator aFind = m_pKeyColumnNames->find(*aAutoIter); + if ( aFind != m_pKeyColumnNames->end() ) + (_rInsertRow->get())[aFind->second.nPosition].fill(i,aFind->second.nType,aFind->second.bNullable,xRow); + } + bAutoValuesFetched = sal_True; + } + } + } + catch(Exception&) + { + OSL_ENSURE(0,"Could not execute GeneratedKeys() stmt"); + } + } + + ::comphelper::disposeComponent(xPrep); +/* + if ( !bAutoValuesFetched && m_bInserted ) + { + // first check if all key column values were set + const ::rtl::OUString sMax(RTL_CONSTASCII_USTRINGPARAM(" MAX(")); + const ::rtl::OUString sMaxEnd(RTL_CONSTASCII_USTRINGPARAM("),")); + const ::rtl::OUString sQuote = getIdentifierQuoteString(); + ::rtl::OUString sMaxStmt; + aEnd = m_pKeyColumnNames->end(); + ::std::vector< ::rtl::OUString >::iterator aAutoIter = m_aAutoColumns.begin(); + ::std::vector< ::rtl::OUString >::iterator aAutoEnd = m_aAutoColumns.end(); + for (;aAutoIter != aAutoEnd; ++aAutoIter) + { + // we will only fetch values which are keycolumns + if ( m_pKeyColumnNames->find(*aAutoIter) != aEnd ) + { + sMaxStmt += sMax; + sMaxStmt += ::dbtools::quoteName( sQuote,*aAutoIter); + sMaxStmt += sMaxEnd; + } + } + + if(sMaxStmt.getLength()) + { + sMaxStmt = sMaxStmt.replaceAt(sMaxStmt.getLength()-1,1,::rtl::OUString::createFromAscii(" ")); + ::rtl::OUString sStmt = ::rtl::OUString::createFromAscii("SELECT "); + sStmt += sMaxStmt; + sStmt += ::rtl::OUString::createFromAscii("FROM "); + sStmt += m_aSelectComposedTableName; + try + { + // now fetch the autoincrement values + Reference<XStatement> xStatement = m_xConnection->createStatement(); + Reference<XResultSet> xRes = xStatement->executeQuery(sStmt); + Reference<XRow> xRow(xRes,UNO_QUERY); + if(xRow.is() && xRes->next()) + { + aAutoIter = m_aAutoColumns.begin(); + for (sal_Int32 i=1;aAutoIter != aAutoEnd; ++aAutoIter,++i) + { + // we will only fetch values which are keycolumns + SelectColumnsMetaData::iterator aFind = m_pKeyColumnNames->find(*aAutoIter); + if ( aFind != aEnd ) + (_rInsertRow->get())[aFind->second.nPosition].fill(i,aFind->second.nType,aFind->second.bNullable,xRow); + } + } + ::comphelper::disposeComponent(xStatement); + } + catch(SQLException&) + { + OSL_ENSURE(0,"Could not fetch with MAX() "); + } + } + } + */ + if ( m_bInserted ) + { + OKeySetMatrix::iterator aKeyIter = m_aKeyMap.end(); + --aKeyIter; + ORowSetRow aKeyRow = new connectivity::ORowVector< ORowSetValue >(m_pKeyColumnNames->size()); + copyRowValue(_rInsertRow,aKeyRow,aKeyIter->first + 1); + + m_aKeyIter = m_aKeyMap.insert(OKeySetMatrix::value_type(aKeyIter->first + 1,OKeySetValue(aKeyRow,1))).first; + // now we set the bookmark for this row + (_rInsertRow->get())[0] = makeAny((sal_Int32)m_aKeyIter->first); + } +} +// ----------------------------------------------------------------------------- +void OptimisticSet::copyRowValue(const ORowSetRow& _rInsertRow,ORowSetRow& _rKeyRow,sal_Int32 i_nBookmark) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::copyRowValue" ); + connectivity::ORowVector< ORowSetValue >::Vector::iterator aIter = _rKeyRow->get().begin(); + + // check the if the parameter values have been changed + OSL_ENSURE((m_aParameterValueForCache.get().size()-1) == m_pParameterNames->size(),"OptimisticSet::copyRowValue: Parameter values and names differ!"); + connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aParaValuesIter = m_aParameterValueForCache.get().begin() +1; + + bool bChanged = false; + SelectColumnsMetaData::const_iterator aParaIter = (*m_pParameterNames).begin(); + SelectColumnsMetaData::const_iterator aParaEnd = (*m_pParameterNames).end(); + for(sal_Int32 i = 1;aParaIter != aParaEnd;++aParaIter,++aParaValuesIter,++i) + { + ORowSetValue aValue(*aParaValuesIter); + aValue.setSigned(m_aSignedFlags[aParaIter->second.nPosition]); + if ( (_rInsertRow->get())[aParaIter->second.nPosition] != aValue ) + { + ORowSetValueVector aCopy(m_aParameterValueForCache); + (aCopy.get())[i] = (_rInsertRow->get())[aParaIter->second.nPosition]; + m_aUpdatedParameter[i_nBookmark] = aCopy; + bChanged = true; + } + } + if ( !bChanged ) + { + m_aUpdatedParameter.erase(i_nBookmark); + } + + // update the key values + SelectColumnsMetaData::const_iterator aPosIter = m_pKeyColumnNames->begin(); + SelectColumnsMetaData::const_iterator aPosEnd = m_pKeyColumnNames->end(); + for(;aPosIter != aPosEnd;++aPosIter,++aIter) + { + ORowSetValue aValue((_rInsertRow->get())[aPosIter->second.nPosition]); + switch(aPosIter->second.nType) + { + case DataType::DECIMAL: + case DataType::NUMERIC: + { + ::rtl::OUString sValue = aValue.getString(); + sal_Int32 nIndex = sValue.indexOf('.'); + if ( nIndex != -1 ) + { + aValue = sValue.copy(0,nIndex + (aPosIter->second.nScale > 0 ? aPosIter->second.nScale + 1 : 0)); + } + } + break; + default: + break; + } + *aIter = aValue; + aIter->setTypeKind(aPosIter->second.nType); + } +} +// ------------------------------------------------------------------------- +void SAL_CALL OptimisticSet::deleteRow(const ORowSetRow& _rDeleteRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException) +{ + ::rtl::OUString sParam(RTL_CONSTASCII_USTRINGPARAM(" = ?")); + ::rtl::OUString sIsNull(RTL_CONSTASCII_USTRINGPARAM(" IS NULL")); + static const ::rtl::OUString s_sAnd(RTL_CONSTASCII_USTRINGPARAM(" AND ")); + ::rtl::OUString aQuote = getIdentifierQuoteString(); + ::rtl::OUString aColumnName; + ::rtl::OUStringBuffer sKeyCondition,sIndexCondition; + ::std::vector<sal_Int32> aIndexColumnPositions; + TSQLStatements aKeyConditions; + TSQLStatements aIndexConditions; + TSQLStatements aSql; + + // sal_Int32 i = 1; + // here we build the condition part for the update statement + SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin(); + SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end(); + for(;aIter != aEnd;++aIter) + { + if ( m_aJoinedKeyColumns.find(aIter->second.nPosition) == m_aJoinedKeyColumns.end() && m_pKeyColumnNames->find(aIter->first) != m_pKeyColumnNames->end() ) + { + // only delete rows which aren't the key in the join + const ::rtl::OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aIter->second.sRealName); + lcl_fillKeyCondition(aIter->second.sTableName,sQuotedColumnName,(_rDeleteRow->get())[aIter->second.nPosition],aKeyConditions); + } + } + Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData(); + TSQLStatements::iterator aSqlIter = aKeyConditions.begin(); + TSQLStatements::iterator aSqlEnd = aKeyConditions.end(); + for(;aSqlIter != aSqlEnd ; ++aSqlIter) + { + ::rtl::OUStringBuffer& rCondition = aSqlIter->second; + if ( rCondition.getLength() ) + { + ::rtl::OUStringBuffer sSql; + sSql.appendAscii("DELETE FROM "); + ::rtl::OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation); + sSql.append( ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) ); + sSql.appendAscii(" WHERE "); + sSql.append( rCondition ); + executeDelete(_rDeleteRow,sSql.makeStringAndClear(),aSqlIter->first); + } + } +} +// ------------------------------------------------------------------------- +void OptimisticSet::executeDelete(const ORowSetRow& _rDeleteRow,const ::rtl::OUString& i_sSQL,const ::rtl::OUString& i_sTableName) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::executeDelete" ); + + // now create end execute the prepared statement + Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL)); + Reference< XParameters > xParameter(xPrep,UNO_QUERY); + + SelectColumnsMetaData::const_iterator aIter = m_pKeyColumnNames->begin(); + SelectColumnsMetaData::const_iterator aEnd = m_pKeyColumnNames->end(); + sal_Int32 i = 1; + for(;aIter != aEnd;++aIter) + { + if ( aIter->second.sTableName == i_sTableName ) + setParameter(i++,xParameter,(_rDeleteRow->get())[aIter->second.nPosition],aIter->second.nType,aIter->second.nScale); + } + m_bDeleted = xPrep->executeUpdate() > 0; + + if(m_bDeleted) + { + sal_Int32 nBookmark = ::comphelper::getINT32((_rDeleteRow->get())[0].getAny()); + if(m_aKeyIter == m_aKeyMap.find(nBookmark) && m_aKeyIter != m_aKeyMap.end()) + ++m_aKeyIter; + m_aKeyMap.erase(nBookmark); + m_bDeleted = sal_True; + } +} +// ------------------------------------------------------------------------- +void SAL_CALL OptimisticSet::cancelRowUpdates( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::cancelRowUpdates" ); + m_bInserted = m_bUpdated = m_bDeleted = sal_False; +} +// ------------------------------------------------------------------------- +void SAL_CALL OptimisticSet::moveToInsertRow( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::moveToInsertRow" ); +} +// ------------------------------------------------------------------------- +void SAL_CALL OptimisticSet::moveToCurrentRow( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::moveToCurrentRow" ); +} +// ----------------------------------------------------------------------------- +sal_Bool SAL_CALL OptimisticSet::next( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::next" ); + m_bInserted = m_bUpdated = m_bDeleted = sal_False; + + if(isAfterLast()) + return sal_False; + if(!m_bRowCountFinal) // not yet all records fetched + { + ++m_aKeyIter; // this is possible because we stand on begin() and this is the "beforefirst" row + if(m_aKeyIter == m_aKeyMap.end() && !fetchRow()) + m_aKeyIter = m_aKeyMap.end(); + } + else if(!isAfterLast()) + ++m_aKeyIter; + + refreshRow(); + return !isAfterLast(); +} +// ----------------------------------------------------------------------------- +sal_Bool SAL_CALL OptimisticSet::isBeforeFirst( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::isBeforeFirst" ); + return m_aKeyIter == m_aKeyMap.begin(); +} +// ----------------------------------------------------------------------------- +sal_Bool SAL_CALL OptimisticSet::isAfterLast( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::isAfterLast" ); + return m_bRowCountFinal && m_aKeyIter == m_aKeyMap.end(); +} +// ----------------------------------------------------------------------------- +sal_Bool SAL_CALL OptimisticSet::isFirst( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::isFirst" ); + OKeySetMatrix::iterator aTemp = m_aKeyMap.begin(); + ++aTemp; + return m_aKeyIter == aTemp && m_aKeyIter != m_aKeyMap.end(); +} +// ----------------------------------------------------------------------------- +sal_Bool SAL_CALL OptimisticSet::isLast( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::isLast" ); + if(!m_bRowCountFinal) + return sal_False; + + OKeySetMatrix::iterator aTemp = m_aKeyMap.end(); + --aTemp; + return m_aKeyIter == aTemp; +} +// ----------------------------------------------------------------------------- +void SAL_CALL OptimisticSet::beforeFirst( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::beforeFirst" ); + m_bInserted = m_bUpdated = m_bDeleted = sal_False; + m_aKeyIter = m_aKeyMap.begin(); + m_xSet = NULL; + ::comphelper::disposeComponent(m_xRow); +} +// ----------------------------------------------------------------------------- +void SAL_CALL OptimisticSet::afterLast( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::afterLast" ); + m_bInserted = m_bUpdated = m_bDeleted = sal_False; + fillAllRows(); + m_aKeyIter = m_aKeyMap.end(); + m_xSet = NULL; + ::comphelper::disposeComponent(m_xRow); +} +// ----------------------------------------------------------------------------- +sal_Bool SAL_CALL OptimisticSet::first( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::first" ); + m_bInserted = m_bUpdated = m_bDeleted = sal_False; + m_aKeyIter = m_aKeyMap.begin(); + ++m_aKeyIter; + if(m_aKeyIter == m_aKeyMap.end() && !fetchRow()) + m_aKeyIter = m_aKeyMap.end(); + + refreshRow(); + return m_aKeyIter != m_aKeyMap.end() && m_aKeyIter != m_aKeyMap.begin(); +} +// ----------------------------------------------------------------------------- +sal_Bool SAL_CALL OptimisticSet::last( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::last" ); + m_bInserted = m_bUpdated = m_bDeleted = sal_False; + fillAllRows(); + + m_aKeyIter = m_aKeyMap.end(); + --m_aKeyIter; + refreshRow(); + return m_aKeyIter != m_aKeyMap.end() && m_aKeyIter != m_aKeyMap.begin(); +} +// ----------------------------------------------------------------------------- +sal_Int32 SAL_CALL OptimisticSet::getRow( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getRow" ); + OSL_ENSURE(!isAfterLast(),"getRow is not allowed when afterlast record!"); + OSL_ENSURE(!isBeforeFirst(),"getRow is not allowed when beforefirst record!"); + + return ::std::distance(m_aKeyMap.begin(),m_aKeyIter); +} +// ----------------------------------------------------------------------------- +sal_Bool SAL_CALL OptimisticSet::absolute( sal_Int32 row ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::absolute" ); + m_bInserted = m_bUpdated = m_bDeleted = sal_False; + OSL_ENSURE(row,"absolute(0) isn't allowed!"); + if(row < 0) + { + if(!m_bRowCountFinal) + fillAllRows(); + + for(;row < 0 && m_aKeyIter != m_aKeyMap.begin();++row) + m_aKeyIter--; + } + else + { + if(row >= (sal_Int32)m_aKeyMap.size()) + { + if(!m_bRowCountFinal) + { + sal_Bool bNext = sal_True; + for(sal_Int32 i=m_aKeyMap.size()-1;i < row && bNext;++i) + bNext = fetchRow(); + } + else + m_aKeyIter = m_aKeyMap.end(); + } + else + { + m_aKeyIter = m_aKeyMap.begin(); + for(;row > 0 && m_aKeyIter != m_aKeyMap.end();--row) + ++m_aKeyIter; + } + } + refreshRow(); + + return m_aKeyIter != m_aKeyMap.end() && m_aKeyIter != m_aKeyMap.begin(); +} +// ----------------------------------------------------------------------------- +sal_Bool SAL_CALL OptimisticSet::relative( sal_Int32 rows ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::relative" ); + if(!rows) + { + refreshRow(); + return sal_True; + } + return absolute(getRow()+rows); +} +// ----------------------------------------------------------------------------- +sal_Bool SAL_CALL OptimisticSet::previous( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::previous" ); + m_bInserted = m_bUpdated = m_bDeleted = sal_False; + if(m_aKeyIter != m_aKeyMap.begin()) + { + --m_aKeyIter; + refreshRow(); + } + return m_aKeyIter != m_aKeyMap.begin(); +} +// ----------------------------------------------------------------------------- +void SAL_CALL OptimisticSet::refreshRow() throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::refreshRow" ); + if(isBeforeFirst() || isAfterLast() || !m_xStatement.is()) + return; + + m_xSet.clear(); + ::comphelper::disposeComponent(m_xRow); + // we just reassign the base members + Reference< XParameters > xParameter(m_xStatement,UNO_QUERY); + OSL_ENSURE(xParameter.is(),"No Parameter interface!"); + xParameter->clearParameters(); + + sal_Int32 nPos=1; + connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aParaIter; + connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aParaEnd; + OUpdatedParameter::iterator aUpdateFind = m_aUpdatedParameter.find(m_aKeyIter->first); + if ( aUpdateFind == m_aUpdatedParameter.end() ) + { + aParaIter = m_aParameterValueForCache.get().begin(); + aParaEnd = m_aParameterValueForCache.get().end(); + } + else + { + aParaIter = aUpdateFind->second.get().begin(); + aParaEnd = aUpdateFind->second.get().end(); + } + + // first put the parameters set by the outer rowset + for(++aParaIter;aParaIter != aParaEnd;++aParaIter,++nPos) + { + ::dbtools::setObjectWithInfo( xParameter, nPos, aParaIter->makeAny(), aParaIter->getTypeKind() ); + } + + // now set the primary key column values + connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aIter = m_aKeyIter->second.first->get().begin(); + SelectColumnsMetaData::const_iterator aPosIter = m_pKeyColumnNames->begin(); + SelectColumnsMetaData::const_iterator aPosEnd = m_pKeyColumnNames->end(); + for(;aPosIter != aPosEnd;++aPosIter,++aIter,++nPos) + setParameter(nPos,xParameter,*aIter,aPosIter->second.nType,aPosIter->second.nScale); + + m_xSet = m_xStatement->executeQuery(); + OSL_ENSURE(m_xSet.is(),"No resultset form statement!"); + sal_Bool bOK = m_xSet->next(); + if ( !bOK ) + m_aKeyIter = m_aKeyMap.end(); + m_xRow.set(m_xSet,UNO_QUERY); + OSL_ENSURE(m_xRow.is(),"No row form statement!"); +} +// ----------------------------------------------------------------------------- +sal_Bool OptimisticSet::fetchRow() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::fetchRow" ); + // fetch the next row and append on the OptimisticSet + sal_Bool bRet = sal_False; + if ( !m_bRowCountFinal ) + bRet = m_xDriverSet->next(); + if ( bRet ) + { + ORowSetRow aKeyRow = new connectivity::ORowVector< ORowSetValue >(m_pKeyColumnNames->size()); + connectivity::ORowVector< ORowSetValue >::Vector::iterator aIter = aKeyRow->get().begin(); + // first fetch the values needed for the key column + SelectColumnsMetaData::const_iterator aPosIter = m_pKeyColumnNames->begin(); + SelectColumnsMetaData::const_iterator aPosEnd = m_pKeyColumnNames->end(); + for(;aPosIter != aPosEnd;++aPosIter,++aIter) + { + const SelectColumnDescription& rColDesc = aPosIter->second; + aIter->fill(rColDesc.nPosition,rColDesc.nType,rColDesc.bNullable,m_xDriverRow); + } + m_aKeyIter = m_aKeyMap.insert(OKeySetMatrix::value_type(m_aKeyMap.rbegin()->first+1,OKeySetValue(aKeyRow,0))).first; + } + else + m_bRowCountFinal = sal_True; + return bRet; +} +// ------------------------------------------------------------------------- +void OptimisticSet::fillAllRows() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::fillAllRows" ); + if(!m_bRowCountFinal) + { + while(fetchRow()) + ; + } +} +// XRow +sal_Bool SAL_CALL OptimisticSet::wasNull( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::wasNull" ); + return m_xRow->wasNull(); +} +// ------------------------------------------------------------------------- +::rtl::OUString SAL_CALL OptimisticSet::getString( sal_Int32 columnIndex ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getString" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getString(columnIndex); +} +// ------------------------------------------------------------------------- +sal_Bool SAL_CALL OptimisticSet::getBoolean( sal_Int32 columnIndex ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getBoolean" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getBoolean(columnIndex); +} +// ------------------------------------------------------------------------- +sal_Int8 SAL_CALL OptimisticSet::getByte( sal_Int32 columnIndex ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getByte" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getByte(columnIndex); +} +// ------------------------------------------------------------------------- +sal_Int16 SAL_CALL OptimisticSet::getShort( sal_Int32 columnIndex ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getShort" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getShort(columnIndex); +} +// ------------------------------------------------------------------------- +sal_Int32 SAL_CALL OptimisticSet::getInt( sal_Int32 columnIndex ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getInt" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getInt(columnIndex); +} +// ------------------------------------------------------------------------- +sal_Int64 SAL_CALL OptimisticSet::getLong( sal_Int32 columnIndex ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getLong" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getLong(columnIndex); +} +// ------------------------------------------------------------------------- +float SAL_CALL OptimisticSet::getFloat( sal_Int32 columnIndex ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getFloat" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getFloat(columnIndex); +} +// ------------------------------------------------------------------------- +double SAL_CALL OptimisticSet::getDouble( sal_Int32 columnIndex ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getDouble" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getDouble(columnIndex); +} +// ------------------------------------------------------------------------- +Sequence< sal_Int8 > SAL_CALL OptimisticSet::getBytes( sal_Int32 columnIndex ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getBytes" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getBytes(columnIndex); +} +// ------------------------------------------------------------------------- +::com::sun::star::util::Date SAL_CALL OptimisticSet::getDate( sal_Int32 columnIndex ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getDate" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getDate(columnIndex); +} +// ------------------------------------------------------------------------- +::com::sun::star::util::Time SAL_CALL OptimisticSet::getTime( sal_Int32 columnIndex ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getTime" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getTime(columnIndex); +} +// ------------------------------------------------------------------------- +::com::sun::star::util::DateTime SAL_CALL OptimisticSet::getTimestamp( sal_Int32 columnIndex ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getTimestamp" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getTimestamp(columnIndex); +} +// ------------------------------------------------------------------------- +Reference< ::com::sun::star::io::XInputStream > SAL_CALL OptimisticSet::getBinaryStream( sal_Int32 columnIndex ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getBinaryStream" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getBinaryStream(columnIndex); +} +// ------------------------------------------------------------------------- +Reference< ::com::sun::star::io::XInputStream > SAL_CALL OptimisticSet::getCharacterStream( sal_Int32 columnIndex ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getCharacterStream" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getCharacterStream(columnIndex); +} +// ------------------------------------------------------------------------- +Any SAL_CALL OptimisticSet::getObject( sal_Int32 columnIndex, const Reference< ::com::sun::star::container::XNameAccess >& typeMap ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getObject" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getObject(columnIndex,typeMap); +} +// ------------------------------------------------------------------------- +Reference< XRef > SAL_CALL OptimisticSet::getRef( sal_Int32 columnIndex ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getRef" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getRef(columnIndex); +} +// ------------------------------------------------------------------------- +Reference< XBlob > SAL_CALL OptimisticSet::getBlob( sal_Int32 columnIndex ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getBlob" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getBlob(columnIndex); +} +// ------------------------------------------------------------------------- +Reference< XClob > SAL_CALL OptimisticSet::getClob( sal_Int32 columnIndex ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getClob" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getClob(columnIndex); +} +// ------------------------------------------------------------------------- +Reference< XArray > SAL_CALL OptimisticSet::getArray( sal_Int32 columnIndex ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getArray" ); + OSL_ENSURE(m_xRow.is(),"m_xRow is null!"); + return m_xRow->getArray(columnIndex); +} +// ------------------------------------------------------------------------- +sal_Bool SAL_CALL OptimisticSet::rowUpdated( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::rowUpdated" ); + return m_aKeyIter != m_aKeyMap.begin() && m_aKeyIter != m_aKeyMap.end() && m_aKeyIter->second.second == 2; +} +// ------------------------------------------------------------------------- +sal_Bool SAL_CALL OptimisticSet::rowInserted( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::rowInserted" ); + return m_aKeyIter != m_aKeyMap.begin() && m_aKeyIter != m_aKeyMap.end() && m_aKeyIter->second.second == 1; +} +// ------------------------------------------------------------------------- +sal_Bool SAL_CALL OptimisticSet::rowDeleted( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::rowDeleted" ); + sal_Bool bDeleted = m_bDeleted; + m_bDeleted = sal_False; + return bDeleted; +} +// ----------------------------------------------------------------------------- +::rtl::OUString OptimisticSet::getComposedTableName(const ::rtl::OUString& /*_sCatalog*/, + const ::rtl::OUString& /*_sSchema*/, + const ::rtl::OUString& /*_sTable*/) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getComposedTableName" ); + ::rtl::OUString aComposedName; +/* + Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData(); + + if( xMetaData.is() && xMetaData->supportsTableCorrelationNames() ) + { + aComposedName = ::dbtools::composeTableName( xMetaData, _sCatalog, _sSchema, _sTable, sal_False, ::dbtools::eInDataManipulation ); + // first we have to check if the composed tablename is in the select clause or if an alias is used + Reference<XTablesSupplier> xTabSup(m_xComposer,UNO_QUERY); + Reference<XNameAccess> xSelectTables = xTabSup->getTables(); + OSL_ENSURE(xSelectTables.is(),"No Select tables!"); + if(xSelectTables.is()) + { + if(!xSelectTables->hasByName(aComposedName)) + { // the composed name isn't used in the select clause so we have to find out which name is used instead + ::rtl::OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(xMetaData,m_sUpdateTableName,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation); + aComposedName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ); + } + else + aComposedName = ::dbtools::composeTableNameForSelect( m_xConnection, _sCatalog, _sSchema, _sTable ); + } + } + else + aComposedName = ::dbtools::composeTableNameForSelect( m_xConnection, _sCatalog, _sSchema, _sTable ); +*/ + return aComposedName; +} +// ----------------------------------------------------------------------------- +/* +namespace dbaccess +{ + void getColumnPositions(const Reference<XNameAccess>& _rxQueryColumns, + const Sequence< ::rtl::OUString>& _aColumnNames, + const ::rtl::OUString& _rsUpdateTableName, + SelectColumnsMetaData& _rColumnNames) + { + // get the real name of the columns + Sequence< ::rtl::OUString> aSelNames(_rxQueryColumns->getElementNames()); + const ::rtl::OUString* pSelBegin = aSelNames.getConstArray(); + const ::rtl::OUString* pSelEnd = pSelBegin + aSelNames.getLength(); + + const ::rtl::OUString* pColumnIter = _aColumnNames.getConstArray(); + const ::rtl::OUString* pColumnEnd = pColumnIter + _aColumnNames.getLength(); + + ::comphelper::UStringMixLess aTmp(_rColumnNames.key_comp()); + ::comphelper::UStringMixEqual bCase(static_cast< ::comphelper::UStringMixLess*>(&aTmp)->isCaseSensitive()); + + for(sal_Int32 nPos = 1;pSelBegin != pSelEnd;++pSelBegin,++nPos) + { + Reference<XPropertySet> xColumnProp(_rxQueryColumns->getByName(*pSelBegin),UNO_QUERY); + ::rtl::OUString sRealName,sTableName; + OSL_ENSURE(xColumnProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME),"Property REALNAME not available!"); + OSL_ENSURE(xColumnProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME),"Property TABLENAME not available!"); + xColumnProp->getPropertyValue(PROPERTY_REALNAME) >>= sRealName; + xColumnProp->getPropertyValue(PROPERTY_TABLENAME) >>= sTableName; + + for(;pColumnIter != pColumnEnd;++pColumnIter) + { + if(bCase(sRealName,*pColumnIter) && bCase(_rsUpdateTableName,sTableName) && _rColumnNames.find(*pColumnIter) == _rColumnNames.end()) + { + sal_Int32 nType = 0; + xColumnProp->getPropertyValue(PROPERTY_TYPE) >>= nType; + sal_Int32 nScale = 0; + xColumnProp->getPropertyValue(PROPERTY_SCALE) >>= nScale; + ::rtl::OUString sColumnDefault; + if ( xColumnProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_DEFAULTVALUE) ) + xColumnProp->getPropertyValue(PROPERTY_DEFAULTVALUE) >>= sColumnDefault; + + sal_Int32 bNullable = sal_False; + xColumnProp->getPropertyValue(PROPERTY_ISNULLABLE) >>= bNullable; + + + _rColumnNames[sRealName] = SelectColumnDescription( nPos, nType,nScale,bNullable != sdbc::ColumnValue::NO_NULLS, sColumnDefault ); + break; + } + } + pColumnIter = _aColumnNames.getConstArray(); + } + } +} +*/ +// ----------------------------------------------------------------------------- +void OptimisticSet::impl_convertValue_throw(const ORowSetRow& _rInsertRow,const SelectColumnDescription& i_aMetaData) +{ + ORowSetValue& aValue((_rInsertRow->get())[i_aMetaData.nPosition]); + switch(i_aMetaData.nType) + { + case DataType::DECIMAL: + case DataType::NUMERIC: + { + ::rtl::OUString sValue = aValue.getString(); + sal_Int32 nIndex = sValue.indexOf('.'); + if ( nIndex != -1 ) + { + aValue = sValue.copy(0,nIndex + (i_aMetaData.nScale > 0 ? i_aMetaData.nScale + 1 : 0)); + } + } + break; + default: + break; + } +} +// ----------------------------------------------------------------------------- +void OptimisticSet::findTableColumnsMatching_throw(const Any& i_aTable + ,const Reference<XDatabaseMetaData>& i_xMeta + ,const Reference<XNameAccess>& i_xQueryColumns) +{ + ::rtl::OUString sCatalog,sSchema,sTable; + Reference<XPropertySet> xTableProp(i_aTable,UNO_QUERY); + Any aCatalog = xTableProp->getPropertyValue(PROPERTY_CATALOGNAME); + aCatalog >>= sCatalog; + xTableProp->getPropertyValue(PROPERTY_SCHEMANAME) >>= sSchema; + xTableProp->getPropertyValue(PROPERTY_NAME) >>= sTable; + + // first ask the database itself for the best columns which can be used + ::std::vector< ::rtl::OUString> aBestRowColumnNames; + Reference<XResultSet> xBestRes(i_xMeta->getBestRowIdentifier(aCatalog,sSchema,sTable,0,sal_False)); + Reference<XRow> xBestRow(xBestRes,uno::UNO_QUERY); + while ( xBestRes->next() ) + { + aBestRowColumnNames.push_back(xBestRow->getString(2)); + } + + Sequence< ::rtl::OUString> aBestColumnNames; + if ( aBestRowColumnNames.empty() ) + { + Reference<XNameAccess> xKeyColumns = getPrimaryKeyColumns_throw(i_aTable); + if ( xKeyColumns.is() ) + aBestColumnNames = xKeyColumns->getElementNames(); + } + else + aBestColumnNames = Sequence< ::rtl::OUString>(&aBestRowColumnNames[0],aBestRowColumnNames.size()); + + const Reference<XColumnsSupplier> xTblColSup(i_aTable,UNO_QUERY_THROW); + const Reference<XNameAccess> xTblColumns = xTblColSup->getColumns(); + const ::rtl::OUString sComposedUpdateTableName = dbtools::composeTableName( i_xMeta, sCatalog, sSchema, sTable, sal_False, ::dbtools::eInDataManipulation ); + ::dbaccess::getColumnPositions(i_xQueryColumns,aBestColumnNames,sComposedUpdateTableName,(*m_pKeyColumnNames),true); + ::dbaccess::getColumnPositions(i_xQueryColumns,xTblColumns->getElementNames(),sComposedUpdateTableName,(*m_pColumnNames),true); + + // locate parameter in select columns + Reference<XParametersSupplier> xParaSup(m_xComposer,UNO_QUERY); + Reference<XIndexAccess> xQueryParameters = xParaSup->getParameters(); + const sal_Int32 nParaCount = xQueryParameters->getCount(); + Sequence< ::rtl::OUString> aParameterColumns(nParaCount); + for(sal_Int32 i = 0; i< nParaCount;++i) + { + Reference<XPropertySet> xPara(xQueryParameters->getByIndex(i),UNO_QUERY_THROW); + xPara->getPropertyValue(PROPERTY_REALNAME) >>= aParameterColumns[i]; + } + ::dbaccess::getColumnPositions(i_xQueryColumns,aParameterColumns,sComposedUpdateTableName,(*m_pParameterNames),true); + + SelectColumnsMetaData::const_iterator aPosIter = m_pKeyColumnNames->begin(); + SelectColumnsMetaData::const_iterator aPosEnd = m_pKeyColumnNames->end(); + for(;aPosIter != aPosEnd;++aPosIter) + { + if ( xTblColumns->hasByName(aPosIter->second.sRealName) ) + { + Reference<XPropertySet> xProp(xTblColumns->getByName(aPosIter->second.sRealName),UNO_QUERY); + sal_Bool bAuto = sal_False; + if( (xProp->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bAuto) && bAuto) + m_aAutoColumns.push_back(aPosIter->first); + } + } +} +// ----------------------------------------------------------------------------- +void OptimisticSet::executeUpdate(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOrginalRow,const ::rtl::OUString& i_sSQL,const ::rtl::OUString& i_sTableName) +{ + // now create end execute the prepared statement + Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL)); + Reference< XParameters > xParameter(xPrep,UNO_QUERY); + + sal_Int32 i = 1; + // first the set values + SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin(); + SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end(); + sal_uInt16 j = 0; + for(;aIter != aEnd;++aIter,++j) + { + if ( aIter->second.sTableName == i_sTableName ) + { + sal_Int32 nPos = aIter->second.nPosition; + if((_rInsertRow->get())[nPos].isModified()) + { + impl_convertValue_throw(_rInsertRow,aIter->second); + (_rInsertRow->get())[nPos].setSigned((_rOrginalRow->get())[nPos].isSigned()); + setParameter(i++,xParameter,(_rInsertRow->get())[nPos],aIter->second.nType,aIter->second.nScale); + } + } + } + // and then the values of the where condition + aIter = m_pKeyColumnNames->begin(); + aEnd = m_pKeyColumnNames->end(); + j = 0; + for(;aIter != aEnd;++aIter,++j) + { + if ( aIter->second.sTableName == i_sTableName ) + { + setParameter(i++,xParameter,(_rOrginalRow->get())[aIter->second.nPosition],aIter->second.nType,aIter->second.nScale); + } + } +/* + // now we have to set the index values + ::std::vector<sal_Int32>::iterator aIdxColIter = aIndexColumnPositions.begin(); + ::std::vector<sal_Int32>::iterator aIdxColEnd = aIndexColumnPositions.end(); + j = 0; + aIter = m_pColumnNames->begin(); + for(;aIdxColIter != aIdxColEnd;++aIdxColIter,++i,++j,++aIter) + { + setParameter(i,xParameter,(_rOrginalRow->get())[*aIdxColIter],(_rOrginalRow->get())[*aIdxColIter].getTypeKind(),aIter->second.nScale); + } +*/ + const sal_Int32 nRowsUpdated = xPrep->executeUpdate(); + m_bUpdated = nRowsUpdated > 0; + if(m_bUpdated) + { + const sal_Int32 nBookmark = ::comphelper::getINT32((_rInsertRow->get())[0].getAny()); + m_aKeyIter = m_aKeyMap.find(nBookmark); + m_aKeyIter->second.second = 2; + copyRowValue(_rInsertRow,m_aKeyIter->second.first,nBookmark); + } +} +// ----------------------------------------------------------------------------- +void OptimisticSet::fillJoinedColumns_throw(const ::std::vector< TNodePair >& i_aJoinColumns) +{ + ::std::vector< TNodePair >::const_iterator aIter = i_aJoinColumns.begin(); + for(;aIter != i_aJoinColumns.end();++aIter) + { + ::rtl::OUString sColumnName,sTableName; + m_aSqlIterator.getColumnRange(aIter->first,sColumnName,sTableName); + ::rtl::OUStringBuffer sLeft,sRight; + sLeft.append(sTableName); + sLeft.appendAscii("."); + sLeft.append(sColumnName); + m_aSqlIterator.getColumnRange(aIter->second,sColumnName,sTableName); + sRight.append(sTableName); + sRight.appendAscii("."); + sRight.append(sColumnName); + fillJoinedColumns_throw(sLeft.makeStringAndClear(),sRight.makeStringAndClear()); + } +} +// ----------------------------------------------------------------------------- +void OptimisticSet::fillJoinedColumns_throw(const ::rtl::OUString& i_sLeftColumn,const ::rtl::OUString& i_sRightColumn) +{ + sal_Int32 nLeft = 0,nRight = 0; + SelectColumnsMetaData::const_iterator aLeftIter = m_pKeyColumnNames->find(i_sLeftColumn); + SelectColumnsMetaData::const_iterator aRightIter = m_pKeyColumnNames->find(i_sRightColumn); + + bool bLeftKey = aLeftIter != m_pKeyColumnNames->end(); + if ( bLeftKey ) + { + nLeft = aLeftIter->second.nPosition; + } + else + { + aLeftIter = m_pColumnNames->find(i_sLeftColumn); + if ( aLeftIter != m_pColumnNames->end() ) + nLeft = aLeftIter->second.nPosition; + } + + bool bRightKey = aRightIter != m_pKeyColumnNames->end(); + if ( bRightKey ) + { + nRight = aRightIter->second.nPosition; + } + else + { + aRightIter = m_pColumnNames->find(i_sRightColumn); + if ( aRightIter != m_pColumnNames->end() ) + nRight = aRightIter->second.nPosition; + } + + if (bLeftKey) + m_aJoinedKeyColumns[nLeft] = nRight; + else + m_aJoinedColumns[nLeft] = nRight; + if (bRightKey) + m_aJoinedKeyColumns[nRight] = nLeft; + else + m_aJoinedColumns[nRight] = nLeft; +} +// ----------------------------------------------------------------------------- +bool OptimisticSet::isResultSetChanged() const +{ + bool bOld = m_bResultSetChanged; + m_bResultSetChanged = false; + return bOld; +} +// ----------------------------------------------------------------------------- +void OptimisticSet::reset(const Reference< XResultSet>& _xDriverSet) +{ + OCacheSet::construct(_xDriverSet,::rtl::OUString()); + m_bRowCountFinal = sal_False; + m_aKeyMap.clear(); + m_aKeyMap.insert(OKeySetMatrix::value_type(0,OKeySetValue(NULL,0))); + m_aKeyIter = m_aKeyMap.begin(); +} +// ----------------------------------------------------------------------------- +void OptimisticSet::mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& io_aInsertRow,ORowSetValueVector::Vector& io_aRow,::std::vector<sal_Int32>& o_aChangedColumns) +{ + o_aChangedColumns.push_back(i_nColumnIndex); + ::std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(i_nColumnIndex); + if ( aJoinIter != m_aJoinedColumns.end() ) + { + io_aRow[aJoinIter->second] = io_aRow[i_nColumnIndex]; + io_aInsertRow[aJoinIter->second] = io_aInsertRow[i_nColumnIndex]; + io_aRow[aJoinIter->second].setModified(); + o_aChangedColumns.push_back(aJoinIter->second); + } +} +namespace +{ + struct PositionFunctor : ::std::unary_function<SelectColumnsMetaData::value_type,bool> + { + sal_Int32 m_nPos; + PositionFunctor(sal_Int32 i_nPos) + : m_nPos(i_nPos) + { + } + + inline bool operator()(const SelectColumnsMetaData::value_type& _aType) + { + return m_nPos == _aType.second.nPosition; + } + }; + struct TableNameFunctor : ::std::unary_function<SelectColumnsMetaData::value_type,bool> + { + ::rtl::OUString m_sTableName; + TableNameFunctor(const ::rtl::OUString& i_sTableName) + : m_sTableName(i_sTableName) + { + } + + inline bool operator()(const SelectColumnsMetaData::value_type& _aType) + { + return m_sTableName == _aType.second.sTableName; + } + }; +} +// ----------------------------------------------------------------------------- +bool OptimisticSet::updateColumnValues(const ORowSetValueVector::Vector& io_aCachedRow,ORowSetValueVector::Vector& io_aRow,const ::std::vector<sal_Int32>& i_aChangedColumns) +{ + bool bRet = false; + ::std::vector<sal_Int32>::const_iterator aColIdxIter = i_aChangedColumns.begin(); + for(;aColIdxIter != i_aChangedColumns.end();++aColIdxIter) + { + SelectColumnsMetaData::const_iterator aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),PositionFunctor(*aColIdxIter)); + if ( aFind != m_pKeyColumnNames->end() ) + { + const ::rtl::OUString sTableName = aFind->second.sTableName; + aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),TableNameFunctor(sTableName)); + while( aFind != m_pKeyColumnNames->end() ) + { + io_aRow[aFind->second.nPosition].setSigned(io_aCachedRow[aFind->second.nPosition].isSigned()); + if ( io_aCachedRow[aFind->second.nPosition] != io_aRow[aFind->second.nPosition] ) + break; + ++aFind; + } + if ( aFind == m_pKeyColumnNames->end() ) + { + bRet = true; + SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin(); + SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end(); + for(sal_Int32 i = 1;aIter != aEnd;++aIter) + { + if ( aIter->second.sTableName == sTableName ) + { + io_aRow[aIter->second.nPosition] = io_aCachedRow[aIter->second.nPosition]; + io_aRow[aIter->second.nPosition].setModified(); + } + } + } + } + } + return bRet; +} +// ----------------------------------------------------------------------------- +bool OptimisticSet::columnValuesUpdated(ORowSetValueVector::Vector& o_aCachedRow,const ORowSetValueVector::Vector& i_aRow) +{ + bool bRet = false; + SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin(); + SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end(); + for(;aIter != aEnd;++aIter) + { + SelectColumnsMetaData::const_iterator aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),PositionFunctor(aIter->second.nPosition)); + if ( aFind != m_pKeyColumnNames->end() ) + { + const ::rtl::OUString sTableName = aFind->second.sTableName; + aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),TableNameFunctor(sTableName)); + while( aFind != m_pKeyColumnNames->end() ) + { + o_aCachedRow[aFind->second.nPosition].setSigned(i_aRow[aFind->second.nPosition].isSigned()); + if ( o_aCachedRow[aFind->second.nPosition] != i_aRow[aFind->second.nPosition] ) + break; + ++aFind; + } + if ( aFind == m_pKeyColumnNames->end() ) + { + bRet = true; + SelectColumnsMetaData::const_iterator aIter2 = m_pColumnNames->begin(); + SelectColumnsMetaData::const_iterator aEnd2 = m_pColumnNames->end(); + for(sal_Int32 i = 1;aIter2 != aEnd2;++aIter2) + { + if ( aIter2->second.sTableName == sTableName ) + { + o_aCachedRow[aIter2->second.nPosition] = i_aRow[aIter2->second.nPosition]; + o_aCachedRow[aIter2->second.nPosition].setModified(); + } + } + fillMissingValues(o_aCachedRow); + } + } + } + return bRet; +} +// ----------------------------------------------------------------------------- +void OptimisticSet::fillMissingValues(ORowSetValueVector::Vector& io_aRow) const +{ + TSQLStatements aSql; + TSQLStatements aKeyConditions; + ::std::map< ::rtl::OUString,bool > aResultSetChanged; + ::rtl::OUString aQuote = getIdentifierQuoteString(); + static ::rtl::OUString aAnd = ::rtl::OUString::createFromAscii(" AND "); + ::rtl::OUString sIsNull(RTL_CONSTASCII_USTRINGPARAM(" IS NULL")); + ::rtl::OUString sParam(RTL_CONSTASCII_USTRINGPARAM(" = ?")); + // here we build the condition part for the update statement + SelectColumnsMetaData::const_iterator aColIter = m_pColumnNames->begin(); + SelectColumnsMetaData::const_iterator aColEnd = m_pColumnNames->end(); + for(;aColIter != aColEnd;++aColIter) + { + const ::rtl::OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aColIter->second.sRealName); + if ( m_aJoinedKeyColumns.find(aColIter->second.nPosition) != m_aJoinedKeyColumns.end() ) + { + lcl_fillKeyCondition(aColIter->second.sTableName,sQuotedColumnName,io_aRow[aColIter->second.nPosition],aKeyConditions); + } + ::rtl::OUStringBuffer& rPart = aSql[aColIter->second.sTableName]; + if ( rPart.getLength() ) + rPart.appendAscii(", "); + rPart.append(sQuotedColumnName); + } + Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData(); + TSQLStatements::iterator aSqlIter = aSql.begin(); + TSQLStatements::iterator aSqlEnd = aSql.end(); + for(;aSqlIter != aSqlEnd ; ++aSqlIter) + { + if ( aSqlIter->second.getLength() ) + { + ::rtl::OUStringBuffer& rCondition = aKeyConditions[aSqlIter->first]; + if ( rCondition.getLength() ) + { + ::rtl::OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation); + ::rtl::OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ); + ::rtl::OUStringBuffer sQuery; + sQuery.appendAscii("SELECT "); + sQuery.append(aSqlIter->second); + sQuery.appendAscii(" FROM "); + sQuery.append(sComposedTableName); + sQuery.appendAscii(" WHERE "); + sQuery.append(rCondition.makeStringAndClear()); + + try + { + Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery.makeStringAndClear())); + Reference< XParameters > xParameter(xPrep,UNO_QUERY); + // and then the values of the where condition + SelectColumnsMetaData::iterator aKeyIter = m_pKeyColumnNames->begin(); + SelectColumnsMetaData::iterator aKeyEnd = m_pKeyColumnNames->end(); + sal_Int32 i = 1; + for(;aKeyIter != aKeyEnd;++aKeyIter) + { + if ( aKeyIter->second.sTableName == aSqlIter->first ) + { + setParameter(i++,xParameter,io_aRow[aKeyIter->second.nPosition],aKeyIter->second.nType,aKeyIter->second.nScale); + } + } + Reference<XResultSet> xRes = xPrep->executeQuery(); + Reference<XRow> xRow(xRes,UNO_QUERY); + if ( xRow.is() && xRes->next() ) + { + i = 1; + aColIter = m_pColumnNames->begin(); + for(;aColIter != aColEnd;++aColIter) + { + if ( aColIter->second.sTableName == aSqlIter->first ) + { + io_aRow[aColIter->second.nPosition].fill(i++,aColIter->second.nType,aColIter->second.bNullable,xRow); + io_aRow[aColIter->second.nPosition].setModified(); + } + } + } + } + catch(const SQLException&) + { + } + } + } + } +} +// ----------------------------------------------------------------------------- + diff --git a/dbaccess/source/core/api/OptimisticSet.hxx b/dbaccess/source/core/api/OptimisticSet.hxx new file mode 100644 index 000000000000..a3683aab0d12 --- /dev/null +++ b/dbaccess/source/core/api/OptimisticSet.hxx @@ -0,0 +1,196 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: KeySet.hxx,v $ + * $Revision: 1.30 $ + * + * 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. + * + ************************************************************************/ + +#ifndef DBACCESS_CORE_API_OPTIMISTICSET_HXX +#define DBACCESS_CORE_API_OPTIMISTICSET_HXX + +#include "CacheSet.hxx" +#include "KeySet.hxx" +#include <cppuhelper/implbase1.hxx> +#include <map> +#include <memory> +#include <connectivity/sqlparse.hxx> +#include <connectivity/sqliterator.hxx> + +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/sdb/XSingleSelectQueryAnalyzer.hpp> +#include <comphelper/stl_types.hxx> +#include <comphelper/componentcontext.hxx> + +namespace dbaccess +{ + // is used when the source supports keys + class OptimisticSet : public OCacheSet + { + ::connectivity::OSQLParser m_aSqlParser; + ::connectivity::OSQLParseTreeIterator m_aSqlIterator; + OKeySetMatrix m_aKeyMap; + OKeySetMatrix::iterator m_aKeyIter; + + ::std::vector< ::rtl::OUString > m_aAutoColumns; // contains all columns which are autoincrement ones + ::std::map<sal_Int32,sal_Int32> m_aJoinedColumns; + ::std::map<sal_Int32,sal_Int32> m_aJoinedKeyColumns; + + OUpdatedParameter m_aUpdatedParameter; // contains all parameter which have been updated and are needed for refetching + ORowSetValueVector m_aParameterValueForCache; + ::std::auto_ptr<SelectColumnsMetaData> m_pKeyColumnNames; // contains all key column names + ::std::auto_ptr<SelectColumnsMetaData> m_pColumnNames; // contains all column names + ::std::auto_ptr<SelectColumnsMetaData> m_pParameterNames; // contains all parameter names + connectivity::OSQLTable m_xTable; // reference to our table + ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XPreparedStatement> m_xStatement; + ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSet> m_xSet; + ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XRow> m_xRow; + ::com::sun::star::uno::Reference< ::com::sun::star::sdb::XSingleSelectQueryAnalyzer > m_xComposer; + + sal_Bool m_bRowCountFinal; + mutable bool m_bResultSetChanged; + + /** + getComposedTableName return the composed table name for the query + @param _sCatalog the catalogname may be empty + @param _sSchema the schemaname may be empty + @param _sTable the tablename + + @return the composed name + */ + ::rtl::OUString getComposedTableName( const ::rtl::OUString& _sCatalog, + const ::rtl::OUString& _sSchema, + const ::rtl::OUString& _sTable); + + /** copies the values from the insert row into the key row + * + * \param _rInsertRow the row which was inserted + * \param _rKeyRow The current key row of the row set. + + \param i_nBookmark The bookmark is used to update the parameter + */ + void copyRowValue(const ORowSetRow& _rInsertRow,ORowSetRow& _rKeyRow,sal_Int32 i_nBookmark); + + void fillAllRows(); + sal_Bool fetchRow(); + + void impl_convertValue_throw(const ORowSetRow& _rInsertRow,const SelectColumnDescription& i_aMetaData); + void findTableColumnsMatching_throw( const ::com::sun::star::uno::Any& i_aTable + ,const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XDatabaseMetaData>& i_xMeta + ,const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess>& i_xQueryColumns); + void executeUpdate(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOrginalRow,const ::rtl::OUString& i_sSQL,const ::rtl::OUString& i_sTableName); + void executeInsert( const ORowSetRow& _rInsertRow,const ::rtl::OUString& i_sSQL,const ::rtl::OUString& i_sTableName); + void executeDelete(const ORowSetRow& _rDeleteRow,const ::rtl::OUString& i_sSQL,const ::rtl::OUString& i_sTableName); + void fillJoinedColumns_throw(const ::std::vector< ::connectivity::TNodePair>& i_aJoinColumns); + void fillJoinedColumns_throw(const ::rtl::OUString& i_sLeftColumn,const ::rtl::OUString& i_sRightColumn); + protected: + virtual ~OptimisticSet(); + public: + OptimisticSet(const ::comphelper::ComponentContext& _rContext, + const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection>& i_xConnection, + const ::com::sun::star::uno::Reference< ::com::sun::star::sdb::XSingleSelectQueryAnalyzer >& _xComposer, + const ORowSetValueVector& _aParameterValueForCache); + + // late ctor which can throw exceptions + virtual void construct(const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSet>& _xDriverSet,const ::rtl::OUString& i_sRowSetFilter); + + // ::com::sun::star::sdbc::XRow + virtual sal_Bool SAL_CALL wasNull( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getString( sal_Int32 columnIndex ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >& typeMap ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + + + virtual sal_Bool SAL_CALL rowUpdated( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL rowInserted( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL rowDeleted( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + // ::com::sun::star::sdbc::XResultSet + virtual sal_Bool SAL_CALL next( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL isBeforeFirst( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL isAfterLast( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL isFirst( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL isLast( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL beforeFirst( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL afterLast( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL first( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL last( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getRow( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL previous( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL refreshRow( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + // ::com::sun::star::sdbcx::XRowLocate + virtual ::com::sun::star::uno::Any SAL_CALL getBookmark() throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + // ------------------------------------------------------------------------- + virtual sal_Bool SAL_CALL moveToBookmark( const ::com::sun::star::uno::Any& bookmark ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + // ------------------------------------------------------------------------- + virtual sal_Bool SAL_CALL moveRelativeToBookmark( const ::com::sun::star::uno::Any& bookmark, sal_Int32 rows ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + // ------------------------------------------------------------------------- + virtual sal_Int32 SAL_CALL compareBookmarks( const ::com::sun::star::uno::Any& first, const ::com::sun::star::uno::Any& second ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + // ------------------------------------------------------------------------- + virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + // ------------------------------------------------------------------------- + virtual sal_Int32 SAL_CALL hashBookmark( const ::com::sun::star::uno::Any& bookmark ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + // ------------------------------------------------------------------------- + // ::com::sun::star::sdbcx::XDeleteRows + virtual ::com::sun::star::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& rows ,const connectivity::OSQLTable& _xTable) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + // ::com::sun::star::sdbc::XResultSetUpdate + virtual void SAL_CALL updateRow(const ORowSetRow& _rInsertRow,const ORowSetRow& _rOrginalRow,const connectivity::OSQLTable& _xTable ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL deleteRow(const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL cancelRowUpdates( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL moveToInsertRow( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL moveToCurrentRow( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + + // CacheSet + virtual bool isResultSetChanged() const; + virtual void reset(const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSet>& _xDriverSet); + virtual void mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& io_aInsertRow,ORowSetValueVector::Vector& io_aRow,::std::vector<sal_Int32>& o_aChangedColumns); + virtual bool columnValuesUpdated(ORowSetValueVector::Vector& o_aCachedRow,const ORowSetValueVector::Vector& i_aRow); + virtual bool updateColumnValues(const ORowSetValueVector::Vector& io_aCachedRow,ORowSetValueVector::Vector& io_aRow,const ::std::vector<sal_Int32>& i_aChangedColumns); + virtual void fillMissingValues(ORowSetValueVector::Vector& io_aRow) const; + + bool isReadOnly() const { return m_aJoinedKeyColumns.empty(); } + const ::std::map<sal_Int32,sal_Int32>& getJoinedColumns() const { return m_aJoinedColumns; } + const ::std::map<sal_Int32,sal_Int32>& getJoinedKeyColumns() const { return m_aJoinedKeyColumns; } + }; +} +#endif // DBACCESS_CORE_API_OPTIMISTICSET_HXX + diff --git a/dbaccess/source/core/api/RowSet.cxx b/dbaccess/source/core/api/RowSet.cxx index 1531f232e5e7..a3d9d255986a 100644 --- a/dbaccess/source/core/api/RowSet.cxx +++ b/dbaccess/source/core/api/RowSet.cxx @@ -141,8 +141,6 @@ extern "C" void SAL_CALL createRegistryInfo_ORowSet() namespace dbaccess { //.................................................................. - - //-------------------------------------------------------------------------- Reference< XInterface > ORowSet_CreateInstance(const Reference< XMultiServiceFactory >& _rxFactory) { @@ -155,6 +153,7 @@ ORowSet::ORowSet( const Reference< ::com::sun::star::lang::XMultiServiceFactory ,m_pParameters( NULL ) ,m_aRowsetListeners(*m_pMutex) ,m_aApproveListeners(*m_pMutex) + ,m_aRowsChangeListener(*m_pMutex) ,m_pTables(NULL) ,m_nFetchDirection(FetchDirection::FORWARD) ,m_nFetchSize(50) @@ -532,6 +531,7 @@ void SAL_CALL ORowSet::disposing() aDisposeEvent.Source = static_cast< XComponent* >(this); m_aRowsetListeners.disposeAndClear( aDisposeEvent ); m_aApproveListeners.disposeAndClear( aDisposeEvent ); + m_aRowsChangeListener.disposeAndClear( aDisposeEvent ); freeResources( true ); @@ -704,12 +704,10 @@ void ORowSet::updateValue(sal_Int32 columnIndex,const ORowSetValue& x) checkUpdateConditions(columnIndex); checkUpdateIterator(); - ::connectivity::ORowSetValue aOldValue(((*m_aCurrentRow)->get())[columnIndex]); - m_pCache->updateValue(columnIndex,x); - // we have to notify all listeners - ((*m_aCurrentRow)->get())[columnIndex] = x; - firePropertyChange(columnIndex-1 ,aOldValue); - fireProperty(PROPERTY_ID_ISMODIFIED,sal_True,sal_False); + ORowSetValueVector::Vector& rRow = ((*m_aCurrentRow)->get()); + ORowSetNotifier aNotify(this,rRow); + m_pCache->updateValue(columnIndex,x,rRow,aNotify.getChangedColumns()); + aNotify.firePropertyChange(); } // ------------------------------------------------------------------------- // XRowUpdate @@ -721,12 +719,10 @@ void SAL_CALL ORowSet::updateNull( sal_Int32 columnIndex ) throw(SQLException, R checkUpdateConditions(columnIndex); checkUpdateIterator(); - ::connectivity::ORowSetValue aOldValue(((*m_aCurrentRow)->get())[columnIndex]); - m_pCache->updateNull(columnIndex); - // we have to notify all listeners - ((*m_aCurrentRow)->get())[columnIndex].setNull(); - firePropertyChange(columnIndex-1 ,aOldValue); - fireProperty(PROPERTY_ID_ISMODIFIED,sal_True,sal_False); + ORowSetValueVector::Vector& rRow = ((*m_aCurrentRow)->get()); + ORowSetNotifier aNotify(this,rRow); + m_pCache->updateNull(columnIndex,rRow,aNotify.getChangedColumns()); + aNotify.firePropertyChange(); } // ------------------------------------------------------------------------- void SAL_CALL ORowSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x ) throw(SQLException, RuntimeException) @@ -792,11 +788,8 @@ void SAL_CALL ORowSet::updateTimestamp( sal_Int32 columnIndex, const ::com::sun: void SAL_CALL ORowSet::updateBinaryStream( sal_Int32 columnIndex, const Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ) throw(SQLException, RuntimeException) { ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed); - ::osl::MutexGuard aGuard( *m_pMutex ); - checkUpdateConditions(columnIndex); - checkUpdateIterator(); //if(((*m_aCurrentRow)->get())[columnIndex].getTypeKind() == DataType::BLOB) @@ -820,26 +813,20 @@ void SAL_CALL ORowSet::updateBinaryStream( sal_Int32 columnIndex, const Referenc void SAL_CALL ORowSet::updateCharacterStream( sal_Int32 columnIndex, const Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ) throw(SQLException, RuntimeException) { ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed); - ::osl::MutexGuard aGuard( *m_pMutex ); checkUpdateConditions(columnIndex); - checkUpdateIterator(); - m_pCache->updateCharacterStream(columnIndex,x,length); - - ::connectivity::ORowSetValue aOldValue(((*m_aCurrentRow)->get())[columnIndex]); - ((*m_aCurrentRow)->get())[columnIndex] = makeAny(x); - firePropertyChange(columnIndex-1 ,aOldValue); - fireProperty(PROPERTY_ID_ISMODIFIED,sal_True,sal_False); + ORowSetValueVector::Vector& rRow = ((*m_aCurrentRow)->get()); + ORowSetNotifier aNotify(this,rRow); + m_pCache->updateCharacterStream(columnIndex,x,length,rRow,aNotify.getChangedColumns()); + aNotify.firePropertyChange(); } // ------------------------------------------------------------------------- void SAL_CALL ORowSet::updateObject( sal_Int32 columnIndex, const Any& x ) throw(SQLException, RuntimeException) { ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed); - ::osl::MutexGuard aGuard( *m_pMutex ); checkUpdateConditions(columnIndex); - checkUpdateIterator(); Any aNewValue = x; @@ -872,29 +859,23 @@ void SAL_CALL ORowSet::updateObject( sal_Int32 columnIndex, const Any& x ) throw if (!::dbtools::implUpdateObject(this, columnIndex, aNewValue)) { // there is no other updateXXX call which can handle the value in x - ::connectivity::ORowSetValue aOldValue(((*m_aCurrentRow)->get())[columnIndex]); - m_pCache->updateObject(columnIndex,aNewValue); - // we have to notify all listeners - ((*m_aCurrentRow)->get())[columnIndex] = aNewValue; - firePropertyChange(columnIndex-1 ,aOldValue); - fireProperty(PROPERTY_ID_ISMODIFIED,sal_True,sal_False); + ORowSetValueVector::Vector& rRow = ((*m_aCurrentRow)->get()); + ORowSetNotifier aNotify(this,rRow); + m_pCache->updateObject(columnIndex,aNewValue,rRow,aNotify.getChangedColumns()); + aNotify.firePropertyChange(); } } // ------------------------------------------------------------------------- void SAL_CALL ORowSet::updateNumericObject( sal_Int32 columnIndex, const Any& x, sal_Int32 scale ) throw(SQLException, RuntimeException) { ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed); - ::osl::MutexGuard aGuard( *m_pMutex ); checkUpdateConditions(columnIndex); - checkUpdateIterator(); - ::connectivity::ORowSetValue aOldValue(((*m_aCurrentRow)->get())[columnIndex]); - m_pCache->updateNumericObject(columnIndex,x,scale); - // we have to notify all listeners - ((*m_aCurrentRow)->get())[columnIndex] = x; - firePropertyChange(columnIndex-1 ,aOldValue); - fireProperty(PROPERTY_ID_ISMODIFIED,sal_True,sal_False); + ORowSetValueVector::Vector& rRow = ((*m_aCurrentRow)->get()); + ORowSetNotifier aNotify(this,rRow); + m_pCache->updateNumericObject(columnIndex,x,scale,rRow,aNotify.getChangedColumns()); + aNotify.firePropertyChange(); } // ------------------------------------------------------------------------- @@ -919,10 +900,12 @@ void SAL_CALL ORowSet::insertRow( ) throw(SQLException, RuntimeException) ORowSetRow aOldValues; if ( !m_aCurrentRow.isNull() ) aOldValues = new ORowSetValueVector( m_aCurrentRow->getBody() ); - RowChangeEvent aEvt(*this,RowChangeAction::INSERT,1); + Sequence<Any> aChangedBookmarks; + RowsChangeEvent aEvt(*this,RowChangeAction::INSERT,1,aChangedBookmarks); notifyAllListenersRowBeforeChange(aGuard,aEvt); - sal_Bool bInserted = m_pCache->insertRow(); + ::std::vector< Any > aBookmarks; + sal_Bool bInserted = m_pCache->insertRow(aBookmarks); // make sure that our row is set to the new inserted row before clearing the insert flags in the cache m_pCache->resetInsertRow(bInserted); @@ -931,9 +914,18 @@ void SAL_CALL ORowSet::insertRow( ) throw(SQLException, RuntimeException) // - column values setCurrentRow( sal_False, sal_True, aOldValues, aGuard ); // we don't move here + // read-only flag restored + impl_restoreDataColumnsWriteable_throw(); + // - rowChanged notifyAllListenersRowChanged(aGuard,aEvt); + if ( !aBookmarks.empty() ) + { + RowsChangeEvent aUpEvt(*this,RowChangeAction::UPDATE,aBookmarks.size(),Sequence<Any>(&(*aBookmarks.begin()),aBookmarks.size())); + notifyAllListenersRowChanged(aGuard,aUpEvt); + } + // - IsModified if(!m_bModified) fireProperty(PROPERTY_ID_ISMODIFIED,sal_False,sal_True); @@ -972,20 +964,31 @@ void SAL_CALL ORowSet::updateRow( ) throw(SQLException, RuntimeException) if ( !m_aCurrentRow.isNull() ) aOldValues = new ORowSetValueVector( m_aCurrentRow->getBody() ); - RowChangeEvent aEvt(*this,RowChangeAction::UPDATE,1); + Sequence<Any> aChangedBookmarks; + RowsChangeEvent aEvt(*this,RowChangeAction::UPDATE,1,aChangedBookmarks); notifyAllListenersRowBeforeChange(aGuard,aEvt); - m_pCache->updateRow(m_aCurrentRow.operator ->()); + ::std::vector< Any > aBookmarks; + m_pCache->updateRow(m_aCurrentRow.operator ->(),aBookmarks); + if ( !aBookmarks.empty() ) + aEvt.Bookmarks = Sequence<Any>(&(*aBookmarks.begin()),aBookmarks.size()); + aEvt.Rows += aBookmarks.size(); m_aBookmark = m_pCache->getBookmark(); m_aCurrentRow = m_pCache->m_aMatrixIter; - if ( m_pCache->m_aMatrixIter != m_pCache->getEnd() ) + if ( m_pCache->m_aMatrixIter != m_pCache->getEnd() && (*m_pCache->m_aMatrixIter).isValid() ) { - m_aOldRow->setRow(new ORowSetValueVector(m_aCurrentRow->getBody())); - - // notification order - // - column values - ORowSetBase::firePropertyChange(aOldValues); + if ( m_pCache->isResultSetChanged() ) + { + impl_rebuild_throw(aGuard); + } + else + { + m_aOldRow->setRow(new ORowSetValueVector(m_aCurrentRow->getBody())); + // notification order + // - column values + ORowSetBase::firePropertyChange(aOldValues); + } // - rowChanged notifyAllListenersRowChanged(aGuard,aEvt); @@ -993,6 +996,9 @@ void SAL_CALL ORowSet::updateRow( ) throw(SQLException, RuntimeException) if(!m_bModified) fireProperty(PROPERTY_ID_ISMODIFIED,sal_False,sal_True); OSL_ENSURE( !m_bModified, "ORowSet::updateRow: just updated, but _still_ modified?" ); + + // - RowCount/IsRowCountFinal + fireRowcount(); } else if ( !m_bAfterLast ) // the update went rong { @@ -1030,7 +1036,8 @@ void SAL_CALL ORowSet::deleteRow( ) throw(SQLException, RuntimeException) if ( m_pCache->m_aMatrixIter != m_pCache->getEnd() && m_pCache->m_aMatrixIter->isValid() ) aOldValues = new ORowSetValueVector( m_pCache->m_aMatrixIter->getBody() ); - RowChangeEvent aEvt(*this,RowChangeAction::DELETE,1); + Sequence<Any> aChangedBookmarks; + RowsChangeEvent aEvt(*this,RowChangeAction::DELETE,1,aChangedBookmarks); notifyAllListenersRowBeforeChange(aGuard,aEvt); m_pCache->deleteRow(); @@ -1129,10 +1136,11 @@ void ORowSet::notifyAllListenersCursorMoved(::osl::ResettableMutexGuard& _rGuard _rGuard.reset(); } // ------------------------------------------------------------------------- -void ORowSet::notifyAllListenersRowChanged(::osl::ResettableMutexGuard& _rGuard, const EventObject& aEvt) +void ORowSet::notifyAllListenersRowChanged(::osl::ResettableMutexGuard& _rGuard, const RowsChangeEvent& aEvt) { _rGuard.clear(); - m_aRowsetListeners.notifyEach( &XRowSetListener::rowChanged, aEvt ); + m_aRowsetListeners.notifyEach( &XRowSetListener::rowChanged, (EventObject)aEvt ); + m_aRowsChangeListener.notifyEach( &XRowsChangeListener::rowsChanged, aEvt ); _rGuard.reset(); } // ------------------------------------------------------------------------- @@ -1167,8 +1175,8 @@ void ORowSet::fireRowcount() { sal_Int32 nHandle = PROPERTY_ID_ISROWCOUNTFINAL; Any aNew,aOld; - aNew <<= bool2any( bCurrentRowCountFinal ); - aOld <<= bool2any( m_bLastKnownRowCountFinal ); + aNew <<= bCurrentRowCountFinal; + aOld <<= m_bLastKnownRowCountFinal; fire(&nHandle,&aNew,&aOld,1,sal_False); m_bLastKnownRowCountFinal = bCurrentRowCountFinal; } @@ -1210,6 +1218,9 @@ void SAL_CALL ORowSet::moveToInsertRow( ) throw(SQLException, RuntimeException) m_pCache->moveToInsertRow(); m_aCurrentRow = m_pCache->m_aInsertRow; + // set read-only flag to false + impl_setDataColumnsWriteable_throw(); + // notification order // - column values ORowSetBase::firePropertyChange(aOldValues); @@ -1230,6 +1241,33 @@ void SAL_CALL ORowSet::moveToInsertRow( ) throw(SQLException, RuntimeException) } } // ------------------------------------------------------------------------- +void ORowSet::impl_setDataColumnsWriteable_throw() +{ + impl_restoreDataColumnsWriteable_throw(); + TDataColumns::iterator aIter = m_aDataColumns.begin(); + m_aReadOnlyDataColumns.resize(m_aDataColumns.size(),false); + ::std::bit_vector::iterator aReadIter = m_aReadOnlyDataColumns.begin(); + for(;aIter != m_aDataColumns.end();++aIter,++aReadIter) + { + sal_Bool bReadOnly = sal_False; + (*aIter)->getPropertyValue(PROPERTY_ISREADONLY) >>= bReadOnly; + *aReadIter = bReadOnly; + + (*aIter)->setPropertyValue(PROPERTY_ISREADONLY,makeAny(sal_False)); + } +} +// ------------------------------------------------------------------------- +void ORowSet::impl_restoreDataColumnsWriteable_throw() +{ + TDataColumns::iterator aIter = m_aDataColumns.begin(); + ::std::bit_vector::iterator aReadIter = m_aReadOnlyDataColumns.begin(); + for(;aReadIter != m_aReadOnlyDataColumns.end();++aIter,++aReadIter) + { + (*aIter)->setPropertyValue(PROPERTY_ISREADONLY,makeAny((sal_Bool)*aReadIter )); + } + m_aReadOnlyDataColumns.clear(); +} +// ------------------------------------------------------------------------- void SAL_CALL ORowSet::moveToCurrentRow( ) throw(SQLException, RuntimeException) { ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed); @@ -1787,7 +1825,7 @@ void ORowSet::execute_NoApprove_NoNewConn(ResettableMutexGuard& _rClearForNotifi } m_pCache->setMaxRowSize(m_nFetchSize); m_aCurrentRow = m_pCache->createIterator(this); - m_aOldRow = m_pCache->registerOldRow(); + m_aOldRow = m_pCache->registerOldRow(); } // get the locale @@ -1807,6 +1845,7 @@ void ORowSet::execute_NoApprove_NoNewConn(ResettableMutexGuard& _rClearForNotifi ::rtl::OUString aDescription; sal_Int32 nFormatKey = 0; + const ::std::map<sal_Int32,sal_Int32>& rKeyColumns = m_pCache->getKeyColumns(); if(!m_xColumns.is()) { RTL_LOGFILE_CONTEXT_AUTHOR( aColumnCreateLog, "dbaccess", "frank.schoenheit@sun.com", "ORowSet::execute_NoApprove_NoNewConn::creating columns" ); @@ -1851,6 +1890,8 @@ void ORowSet::execute_NoApprove_NoNewConn(ResettableMutexGuard& _rClearForNotifi aNames.push_back(sName); m_aDataColumns.push_back(pColumn); + pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_ISREADONLY,makeAny(rKeyColumns.find(i+1) != rKeyColumns.end())); + try { nFormatKey = 0; @@ -1949,6 +1990,7 @@ void ORowSet::execute_NoApprove_NoNewConn(ResettableMutexGuard& _rClearForNotifi m_aCurrentRow); aColumns->get().push_back(pColumn); + pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_ISREADONLY,makeAny(rKeyColumns.find(i) != rKeyColumns.end())); if(!sColumnLabel.getLength()) { @@ -1999,6 +2041,24 @@ void SAL_CALL ORowSet::removeRowSetApproveListener( const Reference< XRowSetAppr m_aApproveListeners.removeInterface(listener); } +// XRowsChangeBroadcaster +void SAL_CALL ORowSet::addRowsChangeListener( const Reference< XRowsChangeListener >& listener ) throw(RuntimeException) +{ + ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed); + + ::osl::MutexGuard aGuard( m_aColumnsMutex ); + + m_aRowsChangeListener.addInterface(listener); +} +// ------------------------------------------------------------------------- +void SAL_CALL ORowSet::removeRowsChangeListener( const Reference< XRowsChangeListener >& listener ) throw(RuntimeException) +{ + ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed); + + ::osl::MutexGuard aGuard( m_aColumnsMutex ); + + m_aRowsChangeListener.removeInterface(listener); +} // ------------------------------------------------------------------------- // XResultSetAccess @@ -2034,7 +2094,8 @@ Sequence< sal_Int32 > SAL_CALL ORowSet::deleteRows( const Sequence< Any >& rows ::osl::ResettableMutexGuard aGuard( *m_pMutex ); - RowChangeEvent aEvt(*this,RowChangeAction::DELETE,rows.getLength()); + Sequence<Any> aChangedBookmarks; + RowsChangeEvent aEvt(*this,RowChangeAction::DELETE,rows.getLength(),aChangedBookmarks); // notify the rowset listeners notifyAllListenersRowBeforeChange(aGuard,aEvt); @@ -2640,20 +2701,16 @@ void SAL_CALL ORowSet::clearWarnings( ) throw (SQLException, RuntimeException) { m_aWarnings.clearWarnings(); } - -// ------------------------------------------------------------------------- -void ORowSet::firePropertyChange(sal_Int32 _nPos,const ::connectivity::ORowSetValue& _rOldValue) -{ - OSL_ENSURE(_nPos < (sal_Int32)m_aDataColumns.size(),"nPos is invalid!"); - m_aDataColumns[_nPos]->fireValueChange(_rOldValue); -} - // ----------------------------------------------------------------------------- void ORowSet::doCancelModification( ) { //OSL_ENSURE( isModification(), "ORowSet::doCancelModification: invalid call (no cache!)!" ); if ( isModification() ) + { + // read-only flag restored + impl_restoreDataColumnsWriteable_throw(); m_pCache->cancelRowModification(); + } m_bModified = sal_False; } @@ -2721,6 +2778,14 @@ void SAL_CALL ORowSet::refreshRow( ) throw(SQLException, RuntimeException) // - IsNew aNotifier.fire( ); } +// ----------------------------------------------------------------------------- +void ORowSet::impl_rebuild_throw(::osl::ResettableMutexGuard& _rGuard) +{ + Reference< XResultSet > xResultSet( m_xStatement->executeQuery() ); + m_aWarnings.setExternalWarnings( Reference< XWarningsSupplier >( xResultSet, UNO_QUERY ) ); + m_pCache->reset(xResultSet); + notifyAllListeners(_rGuard); +} // *********************************************************** // ORowSetClone // *********************************************************** diff --git a/dbaccess/source/core/api/RowSet.hxx b/dbaccess/source/core/api/RowSet.hxx index 25fa3a3415f6..854df5c3252b 100644 --- a/dbaccess/source/core/api/RowSet.hxx +++ b/dbaccess/source/core/api/RowSet.hxx @@ -35,68 +35,36 @@ #include "RowSetBase.hxx" /** === begin UNO includes === **/ -#ifndef _COM_SUN_STAR_SDBC_XPREPAREDSTATEMENT_HPP_ #include <com/sun/star/sdbc/XPreparedStatement.hpp> -#endif -#ifndef _COM_SUN_STAR_SDBC_XCONNECTION_HPP_ #include <com/sun/star/sdbc/XConnection.hpp> -#endif -#ifndef _COM_SUN_STAR_SDB_XSINGLESELECTQUERYCOMPOSER_HPP_ #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp> -#endif -#ifndef _COM_SUN_STAR_SDB_XRESULTSETACCESS_HPP_ #include <com/sun/star/sdb/XResultSetAccess.hpp> -#endif -#ifndef _COM_SUN_STAR_SDBC_XROWSETLISTENER_HPP_ #include <com/sun/star/sdbc/XRowSetListener.hpp> -#endif -#ifndef _COM_SUN_STAR_SDBC_XROWUPDATE_HPP_ #include <com/sun/star/sdbc/XRowUpdate.hpp> -#endif -#ifndef _COM_SUN_STAR_SDBC_XRESULTSETUPDATE_HPP_ #include <com/sun/star/sdbc/XResultSetUpdate.hpp> -#endif -#ifndef _COM_SUN_STAR_SDBC_XPARAMETERS_HPP_ #include <com/sun/star/sdbc/XParameters.hpp> -#endif -#ifndef _COM_SUN_STAR_SDB_XROWSETAPPROVEBROADCASTER_HPP_ #include <com/sun/star/sdb/XRowSetApproveBroadcaster.hpp> -#endif -#ifndef _COM_SUN_STAR_SDBC_RESULTSETTYPE_HPP_ #include <com/sun/star/sdbc/ResultSetType.hpp> -#endif -#ifndef _COM_SUN_STAR_UTIL_XCANCELLABLE_HPP_ #include <com/sun/star/util/XCancellable.hpp> -#endif -#ifndef _COM_SUN_STAR_SDBCX_XDELETEROWS_HPP_ #include <com/sun/star/sdbcx/XDeleteRows.hpp> -#endif -#ifndef _COM_SUN_STAR_SDB_XCOMPLETEDEXECUTION_HPP_ #include <com/sun/star/sdb/XCompletedExecution.hpp> -#endif -#ifndef _COM_SUN_STAR_SDB_ROWSETVETOEXCEPTION_HPP_ #include <com/sun/star/sdb/RowSetVetoException.hpp> -#endif -#ifndef _COM_SUN_STAR_SDB_XSINGLESELECTQUERYANALYZER_HPP_ #include <com/sun/star/sdb/XSingleSelectQueryAnalyzer.hpp> -#endif -#ifndef _COM_SUN_STAR_SDB_XSINGLESELECTQUERYCOMPOSER_HPP_ #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp> -#endif -#ifndef _COM_SUN_STAR_SDB_XPARAMETERSSUPPLIER_HPP_ #include <com/sun/star/sdb/XParametersSupplier.hpp> -#endif +#include <com/sun/star/sdb/XRowsChangeBroadcaster.hpp> /** === end UNO includes === **/ -#include <cppuhelper/compbase11.hxx> +#include <cppuhelper/compbase12.hxx> #include <connectivity/paramwrapper.hxx> #include <connectivity/FValue.hxx> #include <connectivity/warningscontainer.hxx> namespace dbaccess { - typedef ::cppu::WeakAggComponentImplHelper11 < ::com::sun::star::sdb::XResultSetAccess + typedef ::cppu::WeakAggComponentImplHelper12 < ::com::sun::star::sdb::XResultSetAccess , ::com::sun::star::sdb::XRowSetApproveBroadcaster + , ::com::sun::star::sdb::XRowsChangeBroadcaster , ::com::sun::star::sdbcx::XDeleteRows , ::com::sun::star::sdbc::XParameters , ::com::sun::star::lang::XEventListener @@ -135,9 +103,11 @@ namespace dbaccess ORowSetValueVector m_aPrematureParamValues; ORowSetValueVector m_aParameterValueForCache; ::std::bit_vector m_aParametersSet; + ::std::bit_vector m_aReadOnlyDataColumns; ::cppu::OInterfaceContainerHelper m_aRowsetListeners; ::cppu::OInterfaceContainerHelper m_aApproveListeners; + ::cppu::OInterfaceContainerHelper m_aRowsChangeListener; ::dbtools::WarningsContainer m_aWarnings; @@ -245,10 +215,6 @@ namespace dbaccess // free clones and ParseTree. Plus, if _bComplete is <TRUE/>, *all* other associated resources void freeResources( bool _bComplete ); - // fire a change for one column - // _nPos starts at zero - void firePropertyChange(sal_Int32 _nPos,const ::connectivity::ORowSetValue& _rNewValue); - /// informs the clones (and ourself) that we are going to delete a record with a given bookmark void notifyRowSetAndClonesRowDelete( const ::com::sun::star::uno::Any& _rBookmark ); @@ -263,6 +229,11 @@ namespace dbaccess void updateValue(sal_Int32 columnIndex,const connectivity::ORowSetValue& x); void checkUpdateConditions(sal_Int32 columnIndex); + void impl_rebuild_throw(::osl::ResettableMutexGuard& _rGuard); + // set all data columns to writeable + void impl_setDataColumnsWriteable_throw(); + // restore the old state of the data column read-only state + void impl_restoreDataColumnsWriteable_throw(); protected: virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const ::com::sun::star::uno::Any& rValue) throw (::com::sun::star::uno::Exception); @@ -271,7 +242,7 @@ namespace dbaccess virtual void fireRowcount(); void notifyAllListenersRowBeforeChange(::osl::ResettableMutexGuard& _rGuard,const ::com::sun::star::sdb::RowChangeEvent &rEvt); - void notifyAllListenersRowChanged(::osl::ResettableMutexGuard& _rGuard,const ::com::sun::star::lang::EventObject& rEvt); + void notifyAllListenersRowChanged(::osl::ResettableMutexGuard& _rGuard,const ::com::sun::star::sdb::RowsChangeEvent& rEvt); virtual sal_Bool notifyAllListenersCursorBeforeMove(::osl::ResettableMutexGuard& _rGuard); virtual void notifyAllListenersCursorMoved(::osl::ResettableMutexGuard& _rGuard); virtual void notifyAllListeners(::osl::ResettableMutexGuard& _rGuard); @@ -395,6 +366,10 @@ namespace dbaccess virtual void SAL_CALL addRowSetApproveListener( const ::com::sun::star::uno::Reference< ::com::sun::star::sdb::XRowSetApproveListener >& listener ) throw(::com::sun::star::uno::RuntimeException); virtual void SAL_CALL removeRowSetApproveListener( const ::com::sun::star::uno::Reference< ::com::sun::star::sdb::XRowSetApproveListener >& listener ) throw(::com::sun::star::uno::RuntimeException); + // ::com::sun::star::sdb::XRowsChangeBroadcaster + virtual void SAL_CALL addRowsChangeListener( const ::com::sun::star::uno::Reference< ::com::sun::star::sdb::XRowsChangeListener >& listener ) throw(::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeRowsChangeListener( const ::com::sun::star::uno::Reference< ::com::sun::star::sdb::XRowsChangeListener >& listener ) throw(::com::sun::star::uno::RuntimeException); + // ::com::sun::star::sdb::XResultSetAccess virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSet > SAL_CALL createResultSet( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); diff --git a/dbaccess/source/core/api/RowSetBase.cxx b/dbaccess/source/core/api/RowSetBase.cxx index c5811705570d..d367fb156f98 100644 --- a/dbaccess/source/core/api/RowSetBase.cxx +++ b/dbaccess/source/core/api/RowSetBase.cxx @@ -1297,7 +1297,12 @@ void ORowSetBase::firePropertyChange(const ORowSetRow& _rOldRow) } DBG_TRACE2("DBACCESS ORowSetBase::firePropertyChange() Clone = %i ID = %i\n",m_bClone,osl_getThreadIdentifier(NULL)); } - +// ------------------------------------------------------------------------- +void ORowSetBase::firePropertyChange(sal_Int32 _nPos,const ::connectivity::ORowSetValue& _rOldValue) +{ + OSL_ENSURE(_nPos < (sal_Int32)m_aDataColumns.size(),"nPos is invalid!"); + m_aDataColumns[_nPos]->fireValueChange(_rOldValue); +} // ----------------------------------------------------------------------------- void ORowSetBase::fireRowcount() { @@ -1475,6 +1480,13 @@ sal_Int32 ORowSetBase::impl_getRowCount() const return nRowCount; } // ============================================================================= +struct ORowSetNotifierImpl +{ + ::std::vector<sal_Int32> aChangedColumns; + ::std::vector<Any> aChangedBookmarks; + ORowSetValueVector::Vector aRow; + +}; DBG_NAME(ORowSetNotifier) // ----------------------------------------------------------------------------- ORowSetNotifier::ORowSetNotifier( ORowSetBase* _pRowSet ) @@ -1497,7 +1509,21 @@ ORowSetNotifier::ORowSetNotifier( ORowSetBase* _pRowSet ) if ( m_pRowSet->isModification( ORowSetBase::GrantNotifierAccess() ) ) m_pRowSet->doCancelModification( ORowSetBase::GrantNotifierAccess() ); } +// ----------------------------------------------------------------------------- +ORowSetNotifier::ORowSetNotifier( ORowSetBase* _pRowSet,const ORowSetValueVector::Vector& i_aRow ) + :m_pImpl(new ORowSetNotifierImpl) + ,m_pRowSet( _pRowSet ) + ,m_bWasNew( sal_False ) + ,m_bWasModified( sal_False ) +#ifdef DBG_UTIL + ,m_bNotifyCalled( sal_False ) +#endif +{ + DBG_CTOR(ORowSetNotifier,NULL); + OSL_ENSURE( m_pRowSet, "ORowSetNotifier::ORowSetNotifier: invalid row set. This wil crash." ); + m_pImpl->aRow = i_aRow; // yes, create a copy to store the old values +} // ----------------------------------------------------------------------------- ORowSetNotifier::~ORowSetNotifier( ) { @@ -1525,5 +1551,30 @@ void ORowSetNotifier::fire() m_bNotifyCalled = sal_True; #endif } - +// ----------------------------------------------------------------------------- +::std::vector<sal_Int32>& ORowSetNotifier::getChangedColumns() const +{ + OSL_ENSURE(m_pImpl.get(),"Illegal CTor call, use the other one!"); + return m_pImpl->aChangedColumns; +} +// ----------------------------------------------------------------------------- +::std::vector<Any>& ORowSetNotifier::getChangedBookmarks() const +{ + OSL_ENSURE(m_pImpl.get(),"Illegal CTor call, use the other one!"); + return m_pImpl->aChangedBookmarks; +} +// ----------------------------------------------------------------------------- +void ORowSetNotifier::firePropertyChange() +{ + OSL_ENSURE(m_pImpl.get(),"Illegal CTor call, use the other one!"); + if( m_pImpl.get() ) + { + ::std::vector<sal_Int32>::iterator aIter = m_pImpl->aChangedColumns.begin(); + for(;aIter != m_pImpl->aChangedColumns.end();++aIter) + { + m_pRowSet->firePropertyChange((*aIter)-1 ,m_pImpl->aRow[(*aIter)-1], ORowSetBase::GrantNotifierAccess()); + } + m_pRowSet->fireProperty(PROPERTY_ID_ISMODIFIED,sal_True,sal_False, ORowSetBase::GrantNotifierAccess()); + } +} } // namespace dbaccess diff --git a/dbaccess/source/core/api/RowSetBase.hxx b/dbaccess/source/core/api/RowSetBase.hxx index d55af88ee4d8..dc318b98bbe9 100644 --- a/dbaccess/source/core/api/RowSetBase.hxx +++ b/dbaccess/source/core/api/RowSetBase.hxx @@ -171,6 +171,9 @@ namespace dbaccess // fire a notification for all that are listening on column::VALUE property void firePropertyChange(const ORowSetRow& _rOldRow); + // fire a change for one column + // _nPos starts at zero + void firePropertyChange(sal_Int32 _nPos,const ::connectivity::ORowSetValue& _rNewValue); // fire if rowcount changed virtual void fireRowcount(); @@ -388,6 +391,10 @@ namespace dbaccess { fireProperty( _nProperty, _bNew, _bOld ); } + inline void firePropertyChange(sal_Int32 _nPos,const ::connectivity::ORowSetValue& _rNewValue, const GrantNotifierAccess& ) + { + firePropertyChange(_nPos,_rNewValue); + } using ::comphelper::OPropertyStateContainer::getFastPropertyValue; ::osl::Mutex* getMutex() const { return m_pMutex; } @@ -398,14 +405,17 @@ namespace dbaccess <p>The class can only be used on the stack, within a method of ORowSetBase (or derivees)</p> */ + struct ORowSetNotifierImpl; class ORowSetNotifier { private: + ::std::auto_ptr<ORowSetNotifierImpl> m_pImpl; ORowSetBase* m_pRowSet; // not aquired! This is not necessary because this class here is to be used on the stack within // a method of ORowSetBase (or derivees) sal_Bool m_bWasNew; sal_Bool m_bWasModified; + #ifdef DBG_UTIL sal_Bool m_bNotifyCalled; #endif @@ -417,6 +427,10 @@ namespace dbaccess */ ORowSetNotifier( ORowSetBase* m_pRowSet ); + /** use this one to consturct an vector for change value notification + */ + ORowSetNotifier( ORowSetBase* m_pRowSet,const ORowSetValueVector::Vector& i_aRow ); + // destructs the object. <member>fire</member> has to be called before. ~ORowSetNotifier( ); @@ -431,6 +445,19 @@ namespace dbaccess @see ORowSetBase::notifyCancelInsert */ void fire(); + + /** notifies value change events and notifies IsModified + @param i_aChangedColumns the index of the changed value columns + @param i_aRow the old values + @see ORowSetBase::notifyCancelInsert + */ + void firePropertyChange(); + + /** use this one to store the inde of the changed column values + */ + ::std::vector<sal_Int32>& getChangedColumns() const; + ::std::vector<com::sun::star::uno::Any>& getChangedBookmarks() const; + }; } // end of namespace diff --git a/dbaccess/source/core/api/RowSetCache.cxx b/dbaccess/source/core/api/RowSetCache.cxx index 924fd881346e..dba67c045f9d 100644 --- a/dbaccess/source/core/api/RowSetCache.cxx +++ b/dbaccess/source/core/api/RowSetCache.cxx @@ -70,18 +70,11 @@ #ifndef DBACCESS_CORE_API_ROWSETBASE_HXX #include "RowSetBase.hxx" #endif -#ifndef _DBHELPER_DBEXCEPTION_HXX_ #include <connectivity/dbexception.hxx> -#endif -#ifndef _CONNECTIVITY_SQLPARSE_HXX #include <connectivity/sqlparse.hxx> -#endif -#ifndef _CONNECTIVITY_SQLNODE_HXX #include <connectivity/sqlnode.hxx> -#endif -#ifndef _CONNECTIVITY_PARSE_SQLITERATOR_HXX_ +#include <connectivity/dbtools.hxx> #include <connectivity/sqliterator.hxx> -#endif #ifndef _COMPHELPER_PROPERTY_HXX_ #include <comphelper/property.hxx> #endif @@ -114,6 +107,8 @@ #ifndef DBACCESS_SHARED_DBASTRINGS_HRC #include "dbastrings.hrc" #endif +#include "WrappedResultSet.hxx" +#include "OptimisticSet.hxx" using namespace dbaccess; using namespace dbtools; @@ -162,10 +157,34 @@ ORowSetCache::ORowSetCache(const Reference< XResultSet >& _xRs, { 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); + 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&) + { + } + // 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; @@ -186,58 +205,54 @@ ORowSetCache::ORowSetCache(const Reference< XResultSet >& _xRs, Reference<XTablesSupplier> xTabSup(_xAnalyzer,UNO_QUERY); OSL_ENSURE(xTabSup.is(),"ORowSet::execute composer isn't a tablesupplier!"); Reference<XNameAccess> xTables = xTabSup->getTables(); - - - 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; + 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&) + { + } } - 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<XKeysSupplier> xKeys(m_aUpdateTable,UNO_QUERY); - if(xKeys.is()) + if(_rUpdateTableName.getLength() && xTables->hasByName(_rUpdateTableName)) + xTables->getByName(_rUpdateTableName) >>= m_aUpdateTable; + else if(xTables->getElementNames().getLength()) { - xUpdateTableKeys = xKeys->getKeys(); - if ( xUpdateTableKeys.is() ) - { - Reference<XColumnsSupplier> xColumnsSupplier; - // search the one and only primary key - const sal_Int32 nCount = xUpdateTableKeys->getCount(); - for(sal_Int32 i = 0 ; i < nCount ; ++i) - { - Reference<XPropertySet> xProp(xUpdateTableKeys->getByIndex(i),UNO_QUERY); - sal_Int32 nKeyType = 0; - xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType; - if(KeyType::PRIMARY == nKeyType) - { - xColumnsSupplier.set(xProp,UNO_QUERY); - break; - } - } + 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(xColumnsSupplier.is()) + 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> xColumns = xColumnsSupplier->getColumns(); - 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,xColumns->getElementNames(),aUpdateTableName,aColumnNames); - bAllKeysFound = !aColumnNames.empty() && sal_Int32(aColumnNames.size()) == xColumns->getElementNames().getLength(); - } + 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(); } } } @@ -247,12 +262,6 @@ ORowSetCache::ORowSetCache(const Reference< XResultSet >& _xRs, { } } - Reference< XPropertySet> xProp(_xRs,UNO_QUERY); - - sal_Bool bNeedKeySet = !(xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_ISBOOKMARKABLE) && - any2bool(xProp->getPropertyValue(PROPERTY_ISBOOKMARKABLE)) && Reference< XRowLocate >(_xRs, UNO_QUERY).is() ); - bNeedKeySet = bNeedKeySet || (xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_RESULTSETCONCURRENCY) && - ::comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY)) == ResultSetConcurrency::READ_ONLY); // first check if resultset is bookmarkable if(!bNeedKeySet) @@ -316,8 +325,7 @@ ORowSetCache::ORowSetCache(const Reference< XResultSet >& _xRs, const ::rtl::OUString* pEnd = pIter + aNames.getLength(); for(;pIter != pEnd;++pIter) { - Reference<XPropertySet> xColumn; - ::cppu::extractInterface(xColumn,xColumns->getByName(*pIter)); + Reference<XPropertySet> xColumn(xColumns->getByName(*pIter),UNO_QUERY); OSL_ENSURE(xColumn.is(),"Column in table is null!"); if(xColumn.is()) { @@ -473,6 +481,21 @@ 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( ) { @@ -485,17 +508,7 @@ Any ORowSetCache::getBookmark( ) return Any(); // this is allowed here because the rowset knowns what it is doing } - switch(((*m_aMatrixIter)->get())[0].getTypeKind()) - { - case DataType::TINYINT: - case DataType::SMALLINT: - case DataType::INTEGER: - return makeAny((sal_Int32)((*m_aMatrixIter)->get())[0]); - default: - if(((*m_aMatrixIter)->get())[0].isNull()) - ((*m_aMatrixIter)->get())[0] = m_pCacheSet->getBookmark(); - return ((*m_aMatrixIter)->get())[0].getAny(); - } + return lcl_getBookmark(((*m_aMatrixIter)->get())[0],m_pCacheSet); } // ------------------------------------------------------------------------- sal_Bool ORowSetCache::moveToBookmark( const Any& bookmark ) @@ -550,84 +563,106 @@ sal_Int32 ORowSetCache::compareBookmarks( const Any& _first, const Any& _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) +void ORowSetCache::updateNull(sal_Int32 columnIndex,ORowSetValueVector::Vector& io_aRow + ,::std::vector<sal_Int32>& o_ChangedColumns + ) { checkUpdateConditions(columnIndex); - ((*m_aInsertRow)->get())[columnIndex].setBound(sal_True); - ((*m_aInsertRow)->get())[columnIndex].setNull(); - ((*m_aInsertRow)->get())[columnIndex].setModified(); -} -// ----------------------------------------------------------------------------- -void ORowSetCache::updateValue(sal_Int32 columnIndex,const ORowSetValue& x) -{ - checkUpdateConditions(columnIndex); + ORowSetValueVector::Vector& rInsert = ((*m_aInsertRow)->get()); + rInsert[columnIndex].setBound(sal_True); + rInsert[columnIndex].setNull(); + rInsert[columnIndex].setModified(); + io_aRow[columnIndex].setNull(); - ((*m_aInsertRow)->get())[columnIndex].setBound(sal_True); - ((*m_aInsertRow)->get())[columnIndex] = x; - ((*m_aInsertRow)->get())[columnIndex].setModified(); + m_pCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns); + impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns); } -// ------------------------------------------------------------------------- -void ORowSetCache::updateBinaryStream( sal_Int32 columnIndex, const Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ) +// ----------------------------------------------------------------------------- +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]; - Sequence<sal_Int8> aSeq; - if(x.is()) - x->readBytes(aSeq,length); - updateValue(columnIndex,aSeq); + 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 ) +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); - updateValue(columnIndex,aSeq); + 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 ) +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_aInsertRow)->get())[columnIndex].setBound(sal_True); - ((*m_aInsertRow)->get())[columnIndex] = x; - ((*m_aInsertRow)->get())[columnIndex].setModified(); + 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*/ ) +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_aInsertRow)->get())[columnIndex].setBound(sal_True); - ((*m_aInsertRow)->get())[columnIndex] = x; - ((*m_aInsertRow)->get())[columnIndex].setModified(); + 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; @@ -1226,7 +1261,7 @@ sal_Bool ORowSetCache::rowInserted( ) } // ------------------------------------------------------------------------- // XResultSetUpdate -sal_Bool ORowSetCache::insertRow( ) +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() ); @@ -1240,7 +1275,19 @@ sal_Bool ORowSetCache::insertRow( ) 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!"); @@ -1270,7 +1317,7 @@ void ORowSetCache::cancelRowModification() resetInsertRow(sal_False); } // ------------------------------------------------------------------------- -void ORowSetCache::updateRow( ORowSetMatrix::iterator& _rUpdateRow ) +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() ); @@ -1281,16 +1328,23 @@ void ORowSetCache::updateRow( ORowSetMatrix::iterator& _rUpdateRow ) // the row was already fetched moveToBookmark(aBookmark); m_pCacheSet->updateRow(*_rUpdateRow,*m_aMatrixIter,m_aUpdateTable); - // *(*m_aMatrixIter) = *(*_rUpdateRow); // refetch the whole row (*m_aMatrixIter) = NULL; - moveToBookmark(aBookmark); - // moveToBookmark((*(*m_aInsertRow))[0].makeAny()); -// if(m_pCacheSet->rowUpdated()) -// *m_aMatrixIter = m_aInsertRow; + 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; - // refreshRow( ); } // ------------------------------------------------------------------------- bool ORowSetCache::deleteRow( ) @@ -1307,8 +1361,6 @@ bool ORowSetCache::deleteRow( ) OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!"); ORowSetMatrix::iterator aPos = calcPosition(); (*aPos) = NULL; - // (*m_pMatrix)[(m_nPosition - m_nStartPos)] = NULL; // set the deleted row to NULL - ORowSetMatrix::iterator aEnd = m_pMatrix->end(); for(++aPos;aPos != aEnd && aPos->isValid();++aPos) @@ -1625,8 +1677,39 @@ sal_Bool ORowSetCache::fill(ORowSetMatrix::iterator& _aIter,const ORowSetMatrix: 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); + } + } +} +// ----------------------------------------------------------------------------- diff --git a/dbaccess/source/core/api/RowSetCache.hxx b/dbaccess/source/core/api/RowSetCache.hxx index 268c32294824..851ac70149bc 100644 --- a/dbaccess/source/core/api/RowSetCache.hxx +++ b/dbaccess/source/core/api/RowSetCache.hxx @@ -122,6 +122,7 @@ namespace dbaccess typedef ::std::vector< TORowSetOldRowHelperRef > TOldRowSetRows; + ::std::map<sal_Int32,sal_Int32> m_aKeyColumns; //the set can be static, bookmarkable or keyset ::com::sun::star::uno::WeakReference< ::com::sun::star::sdbc::XResultSet> m_xSet; ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSetMetaData > m_xMetaData; // must be before m_aInsertRow @@ -169,7 +170,15 @@ namespace dbaccess void firePropertyChange(sal_Int32 _nColumnIndex,const ::connectivity::ORowSetValue& _rOldValue); void rotateCacheIterator(ORowSetMatrix::difference_type _nDist); - void updateValue(sal_Int32 columnIndex,const connectivity::ORowSetValue& x); + void updateValue(sal_Int32 columnIndex + ,const connectivity::ORowSetValue& x + ,ORowSetValueVector::Vector& io_aRow + ,::std::vector<sal_Int32>& o_ChangedColumns + ); + + void impl_updateRowFromCache_throw(ORowSetValueVector::Vector& io_aRow + ,::std::vector<sal_Int32>& o_ChangedColumns + ); // checks and set the flags isAfterLast isLast and position when afterlast is true void checkPositionFlags(); void checkUpdateConditions(sal_Int32 columnIndex); @@ -222,11 +231,14 @@ namespace dbaccess sal_Int32 hashBookmark( const ::com::sun::star::uno::Any& bookmark ); // ::com::sun::star::sdbc::XRowUpdate - void updateBinaryStream( sal_Int32 columnIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ); - void updateCharacterStream( sal_Int32 columnIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ); - void updateObject( sal_Int32 columnIndex, const ::com::sun::star::uno::Any& x ); - void updateNumericObject( sal_Int32 columnIndex, const ::com::sun::star::uno::Any& x, sal_Int32 scale ); - void updateNull(sal_Int32 columnIndex); + void updateCharacterStream( sal_Int32 columnIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length,ORowSetValueVector::Vector& io_aRow,::std::vector<sal_Int32>& o_ChangedColumns + ); + void updateObject( sal_Int32 columnIndex, const ::com::sun::star::uno::Any& x,ORowSetValueVector::Vector& io_aRow ,::std::vector<sal_Int32>& o_ChangedColumns); + void updateNumericObject( sal_Int32 columnIndex, const ::com::sun::star::uno::Any& x, sal_Int32 scale,ORowSetValueVector::Vector& io_aRow ,::std::vector<sal_Int32>& o_ChangedColumns); + void updateNull(sal_Int32 columnIndex + ,ORowSetValueVector::Vector& io_aRow + ,::std::vector<sal_Int32>& o_ChangedColumns + ); // ::com::sun::star::sdbc::XResultSet sal_Bool next( ); @@ -247,14 +259,17 @@ namespace dbaccess sal_Bool rowInserted( ); // ::com::sun::star::sdbc::XResultSetUpdate - sal_Bool insertRow(); + sal_Bool insertRow(::std::vector< ::com::sun::star::uno::Any >& o_aBookmarks); void resetInsertRow(sal_Bool _bClearInsertRow); - void updateRow(); - void updateRow( ORowSetMatrix::iterator& _rUpdateRow ); + void updateRow( ORowSetMatrix::iterator& _rUpdateRow,::std::vector< ::com::sun::star::uno::Any >& o_aBookmarks ); bool deleteRow(); void cancelRowUpdates( ); void moveToInsertRow( ); + + const ::std::map<sal_Int32,sal_Int32>& getKeyColumns() const { return m_aKeyColumns; } + bool isResultSetChanged() const; + void reset(const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSet>& _xDriverSet); }; } #endif diff --git a/dbaccess/source/core/api/SingleSelectQueryComposer.cxx b/dbaccess/source/core/api/SingleSelectQueryComposer.cxx index 1a1f9bc1d679..85de0b8bc463 100644 --- a/dbaccess/source/core/api/SingleSelectQueryComposer.cxx +++ b/dbaccess/source/core/api/SingleSelectQueryComposer.cxx @@ -1067,16 +1067,16 @@ sal_Bool OSingleSelectQueryComposer::setANDCriteria( OSQLParseNode * pCondition, aItem.Name = getColumnName(pCondition->getChild(0),_rIterator); aItem.Value <<= aValue; aItem.Handle = 0; // just to know that this is not one the known ones - if (SQL_ISRULE(pCondition,like_predicate)) + if ( SQL_ISRULE(pCondition,like_predicate) ) { - if (pCondition->count() == 5) + if ( SQL_ISTOKEN(pCondition->getChild(1)->getChild(0),NOT) ) aItem.Handle = SQLFilterOperator::NOT_LIKE; else aItem.Handle = SQLFilterOperator::LIKE; } else if (SQL_ISRULE(pCondition,test_for_null)) { - if (SQL_ISTOKEN(pCondition->getChild(2),NOT) ) + if (SQL_ISTOKEN(pCondition->getChild(1)->getChild(2),NOT) ) aItem.Handle = SQLFilterOperator::NOT_SQLNULL; else aItem.Handle = SQLFilterOperator::SQLNULL; @@ -1238,7 +1238,7 @@ sal_Bool OSingleSelectQueryComposer::setComparsionPredicate(OSQLParseNode * pCon aValue = aValue.copy(aColumnName.getLength()); aValue.trim(); - aItem.Name = UniString(getColumnName(pCondition->getChild(0),_rIterator)); + aItem.Name = getColumnName(pCondition->getChild(0),_rIterator); aItem.Value <<= aValue; aItem.Handle = pCondition->getNodeType(); rFilter.push_back(aItem); diff --git a/dbaccess/source/core/api/WrappedResultSet.cxx b/dbaccess/source/core/api/WrappedResultSet.cxx new file mode 100644 index 000000000000..074da2faf46e --- /dev/null +++ b/dbaccess/source/core/api/WrappedResultSet.cxx @@ -0,0 +1,256 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: BookmarkSet.cxx,v $ + * $Revision: 1.21 $ + * + * 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 "WrappedResultSet.hxx" +#include "core_resource.hxx" +#include "core_resource.hrc" +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <connectivity/dbexception.hxx> +#include <rtl/logfile.hxx> + +#include <limits> + +using namespace dbaccess; +using namespace ::connectivity; +using namespace ::dbtools; +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; + +void WrappedResultSet::construct(const Reference< XResultSet>& _xDriverSet,const ::rtl::OUString& i_sRowSetFilter) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::construct" ); + OCacheSet::construct(_xDriverSet,i_sRowSetFilter); + m_xUpd.set(_xDriverSet,UNO_QUERY_THROW); + m_xRowLocate.set(_xDriverSet,UNO_QUERY_THROW); + m_xUpdRow.set(_xDriverSet,UNO_QUERY_THROW); +} +// ----------------------------------------------------------------------------- +Any SAL_CALL WrappedResultSet::getBookmark() throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::getBookmark" ); + return makeAny(m_xDriverSet->getRow()); +} +// ------------------------------------------------------------------------- +sal_Bool SAL_CALL WrappedResultSet::moveToBookmark( const Any& bookmark ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::moveToBookmark" ); + sal_Int32 nPos = 1; + bookmark >>= nPos; + return m_xDriverSet->absolute(nPos); +} +// ------------------------------------------------------------------------- +sal_Bool SAL_CALL WrappedResultSet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::moveRelativeToBookmark" ); + sal_Int32 nPos = 1; + bookmark >>= nPos; + return m_xDriverSet->absolute(nPos + rows); +} +// ------------------------------------------------------------------------- +sal_Int32 SAL_CALL WrappedResultSet::compareBookmarks( const Any& _first, const Any& _second ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::compareBookmarks" ); + return _first != _second; +} +// ------------------------------------------------------------------------- +sal_Bool SAL_CALL WrappedResultSet::hasOrderedBookmarks( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::hasOrderedBookmarks" ); + return sal_True; +} +// ------------------------------------------------------------------------- +sal_Int32 SAL_CALL WrappedResultSet::hashBookmark( const Any& bookmark ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::hashBookmark" ); + sal_Int32 nPos = 1; + bookmark >>= nPos; + return nPos; +} +// ------------------------------------------------------------------------- +// ::com::sun::star::sdbcx::XDeleteRows +Sequence< sal_Int32 > SAL_CALL WrappedResultSet::deleteRows( const Sequence< Any >& rows ,const connectivity::OSQLTable& /*_xTable*/) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::deleteRows" ); + Reference< ::com::sun::star::sdbcx::XDeleteRows> xDeleteRow(m_xRowLocate,UNO_QUERY); + if(xDeleteRow.is()) + { + return xDeleteRow->deleteRows(rows); + } + return Sequence< sal_Int32 >(); +} +// ------------------------------------------------------------------------- +void SAL_CALL WrappedResultSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::insertRow" ); + + m_xUpd->moveToInsertRow(); + sal_Int32 i = 1; + connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->get().end(); + for(connectivity::ORowVector< ORowSetValue > ::Vector::iterator aIter = _rInsertRow->get().begin()+1;aIter != aEnd;++aIter,++i) + { + aIter->setSigned(m_aSignedFlags[i-1]); + updateColumn(i,m_xUpdRow,*aIter); + } + m_xUpd->insertRow(); + (*_rInsertRow->get().begin()) = m_xDriverSet->getRow(); +} +// ------------------------------------------------------------------------- +void SAL_CALL WrappedResultSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOrginalRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::updateRow" ); + sal_Int32 i = 1; + connectivity::ORowVector< ORowSetValue > ::Vector::const_iterator aOrgIter = _rOrginalRow->get().begin()+1; + connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->get().end(); + for(connectivity::ORowVector< ORowSetValue > ::Vector::iterator aIter = _rInsertRow->get().begin()+1;aIter != aEnd;++aIter,++i,++aOrgIter) + { + aIter->setSigned(aOrgIter->isSigned()); + updateColumn(i,m_xUpdRow,*aIter); + } + m_xUpd->updateRow(); +} +// ------------------------------------------------------------------------- +void SAL_CALL WrappedResultSet::deleteRow(const ORowSetRow& /*_rDeleteRow*/ ,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::deleteRow" ); + m_xUpd->deleteRow(); +} +// ------------------------------------------------------------------------- +void SAL_CALL WrappedResultSet::cancelRowUpdates( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::cancelRowUpdates" ); + m_xUpd->cancelRowUpdates(); +} +// ------------------------------------------------------------------------- +void SAL_CALL WrappedResultSet::moveToInsertRow( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::moveToInsertRow" ); + m_xUpd->moveToInsertRow(); +} +// ------------------------------------------------------------------------- +void SAL_CALL WrappedResultSet::moveToCurrentRow( ) throw(SQLException, RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::moveToCurrentRow" ); +} +// ------------------------------------------------------------------------- +void WrappedResultSet::fillValueRow(ORowSetRow& _rRow,sal_Int32 _nPosition) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::fillValueRow" ); + OCacheSet::fillValueRow(_rRow,_nPosition); +} +// ------------------------------------------------------------------------- +void WrappedResultSet::updateColumn(sal_Int32 nPos,Reference< XRowUpdate > _xParameter,const ORowSetValue& _rValue) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "WrappedResultSet::updateColumn" ); + if(_rValue.isBound() && _rValue.isModified()) + { + if(_rValue.isNull()) + _xParameter->updateNull(nPos); + else + { + + switch(_rValue.getTypeKind()) + { + case DataType::DECIMAL: + case DataType::NUMERIC: + _xParameter->updateNumericObject(nPos,_rValue.makeAny(),m_xSetMetaData->getScale(nPos)); + break; + case DataType::CHAR: + case DataType::VARCHAR: + //case DataType::DECIMAL: + //case DataType::NUMERIC: + _xParameter->updateString(nPos,_rValue); + break; + case DataType::BIGINT: + if ( _rValue.isSigned() ) + _xParameter->updateLong(nPos,_rValue); + else + _xParameter->updateString(nPos,_rValue); + break; + case DataType::BIT: + case DataType::BOOLEAN: + _xParameter->updateBoolean(nPos,_rValue); + break; + case DataType::TINYINT: + if ( _rValue.isSigned() ) + _xParameter->updateByte(nPos,_rValue); + else + _xParameter->updateShort(nPos,_rValue); + break; + case DataType::SMALLINT: + if ( _rValue.isSigned() ) + _xParameter->updateShort(nPos,_rValue); + else + _xParameter->updateInt(nPos,_rValue); + break; + case DataType::INTEGER: + if ( _rValue.isSigned() ) + _xParameter->updateInt(nPos,_rValue); + else + _xParameter->updateLong(nPos,_rValue); + break; + case DataType::FLOAT: + _xParameter->updateFloat(nPos,_rValue); + break; + case DataType::DOUBLE: + case DataType::REAL: + _xParameter->updateDouble(nPos,_rValue); + break; + case DataType::DATE: + _xParameter->updateDate(nPos,_rValue); + break; + case DataType::TIME: + _xParameter->updateTime(nPos,_rValue); + break; + case DataType::TIMESTAMP: + _xParameter->updateTimestamp(nPos,_rValue); + break; + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + _xParameter->updateBytes(nPos,_rValue); + break; + case DataType::BLOB: + case DataType::CLOB: + _xParameter->updateObject(nPos,_rValue.getAny()); + break; + } + } + } +} + diff --git a/dbaccess/source/core/api/WrappedResultSet.hxx b/dbaccess/source/core/api/WrappedResultSet.hxx new file mode 100644 index 000000000000..082811748e6a --- /dev/null +++ b/dbaccess/source/core/api/WrappedResultSet.hxx @@ -0,0 +1,79 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: BookmarkSet.hxx,v $ + * $Revision: 1.11 $ + * + * 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. + * + ************************************************************************/ + +#ifndef DBACCESS_CORE_API_WRAPPEDRESULTSET_HXX +#define DBACCESS_CORE_API_WRAPPEDRESULTSET_HXX + +#ifndef DBACCESS_CORE_API_CACHESET_HXX +#include "CacheSet.hxx" +#endif +#include <com/sun/star/sdbc/XRowUpdate.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> + +namespace dbaccess +{ + // this set is used when we have a bookmarkable set from the driver + class WrappedResultSet : public OCacheSet + { + ::com::sun::star::uno::Reference< ::com::sun::star::sdbcx::XRowLocate> m_xRowLocate; + ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSetUpdate> m_xUpd; + ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XRowUpdate> m_xUpdRow; + + void updateColumn(sal_Int32 nPos,::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XRowUpdate > _xParameter,const connectivity::ORowSetValue& _rValue); + public: + WrappedResultSet() + {} + ~WrappedResultSet() + { + m_xRowLocate = NULL; + } + + virtual void construct(const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSet>& _xDriverSet,const ::rtl::OUString& i_sRowSetFilter); + virtual void fillValueRow(ORowSetRow& _rRow,sal_Int32 _nPosition); + // ::com::sun::star::sdbcx::XRowLocate + virtual ::com::sun::star::uno::Any SAL_CALL getBookmark() throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL moveToBookmark( const ::com::sun::star::uno::Any& bookmark ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL moveRelativeToBookmark( const ::com::sun::star::uno::Any& bookmark, sal_Int32 rows ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL compareBookmarks( const ::com::sun::star::uno::Any& first, const ::com::sun::star::uno::Any& second ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL hashBookmark( const ::com::sun::star::uno::Any& bookmark ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + // ::com::sun::star::sdbcx::XDeleteRows + virtual ::com::sun::star::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& rows ,const connectivity::OSQLTable& _xTable) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + // ::com::sun::star::sdbc::XResultSetUpdate + virtual void SAL_CALL insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL updateRow(const ORowSetRow& _rInsertRow,const ORowSetRow& _rOrginalRow,const connectivity::OSQLTable& _xTable ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL deleteRow(const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL cancelRowUpdates( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL moveToInsertRow( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL moveToCurrentRow( ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException); + }; +} +#endif // DBACCESS_CORE_API_WRAPPEDRESULTSET_HXX + diff --git a/dbaccess/source/core/api/makefile.mk b/dbaccess/source/core/api/makefile.mk index df80f0423e14..af520ffec290 100644 --- a/dbaccess/source/core/api/makefile.mk +++ b/dbaccess/source/core/api/makefile.mk @@ -75,6 +75,8 @@ SLOFILES= \ $(SLO)$/HelperCollections.obj \ $(SLO)$/datasettings.obj \ $(SLO)$/View.obj \ + $(SLO)$/WrappedResultSet.obj \ + $(SLO)$/OptimisticSet.obj \ $(SLO)$/columnsettings.obj # --- Targets ---------------------------------- |