/************************************************************************* * * 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 * * 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 #include #include #include #include #include #include #include #include #include #include "dbastrings.hrc" #include "apitools.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "querycomposer.hxx" #include "composertools.hxx" #include #include #include 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_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, sal_Int32 i_nMaxRows, sal_Int32& o_nRowCount) :OKeySet(NULL,NULL,::rtl::OUString(),_xComposer,_aParameterValueForCache,i_nMaxRows,o_nRowCount) ,m_aSqlParser( _rContext.getLegacyServiceFactory() ) ,m_aSqlIterator( i_xConnection, Reference(_xComposer,UNO_QUERY)->getTables(), m_aSqlParser, NULL ) ,m_bResultSetChanged(false) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::OptimisticSet" ); DBG_CTOR(OptimisticSet,NULL); } // ----------------------------------------------------------------------------- OptimisticSet::~OptimisticSet() { 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); initColumns(); Reference xMeta = m_xConnection->getMetaData(); bool bCase = (xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers()) ? true : false; Reference xQueryColSup(m_xComposer,UNO_QUERY); const Reference xQueryColumns = xQueryColSup->getColumns(); const Reference xTabSup(m_xComposer,UNO_QUERY); const Reference 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) { ::std::auto_ptr pKeyColumNames(new SelectColumnsMetaData(bCase)); findTableColumnsMatching_throw(xTables->getByName(*pTableNameIter),*pTableNameIter,xMeta,xQueryColumns,pKeyColumNames); m_pKeyColumnNames->insert(pKeyColumNames->begin(),pKeyColumNames->end()); } // 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,::std::pair >(0,NULL)))); m_aKeyIter = m_aKeyMap.begin(); ::rtl::OUStringBuffer aFilter = createKeyFilter(); Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY); Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW); Reference xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY); ::rtl::OUString sQuery = xSourceComposer->getQuery(); xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery()); // check for joins ::rtl::OUString aErrorMsg; ::std::auto_ptr 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); } // ------------------------------------------------------------------------- // ::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::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 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::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 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 aKeyCol = m_pKeyColumnNames->begin(); SelectColumnsMetaData::iterator aKeysEnd = m_pKeyColumnNames->end(); sal_Int32 i = 1; for(;aKeyCol != aKeysEnd;++aKeyCol) { if ( aKeyCol->second.sTableName == aSqlIter->first ) { setParameter(i++,xParameter,(_rInsertRow->get())[aKeyCol->second.nPosition],aKeyCol->second.nType,aKeyCol->second.nScale); } } Reference xRes = xPrep->executeQuery(); Reference xRow(xRes,UNO_QUERY); if ( xRow.is() && xRes->next() ) { m_bResultSetChanged = true; continue; } } catch(const SQLException&) { } } executeInsert(_rInsertRow,sSql.makeStringAndClear(),aSqlIter->first); } } } // ------------------------------------------------------------------------- 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 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 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; } } // ----------------------------------------------------------------------------- ::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 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 xTabSup(m_xComposer,UNO_QUERY); Reference 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; } // ----------------------------------------------------------------------------- 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,::std::pair >(0,NULL)))); m_aKeyIter = m_aKeyMap.begin(); } // ----------------------------------------------------------------------------- void OptimisticSet::mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& io_aInsertRow,ORowSetValueVector::Vector& io_aRow,::std::vector& o_aChangedColumns) { o_aChangedColumns.push_back(i_nColumnIndex); ::std::map::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 { 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 { ::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& i_aChangedColumns) { bool bRet = false; ::std::vector::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 ( ;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 ( ;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 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 xRes = xPrep->executeQuery(); Reference 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&) { } } } } } // -----------------------------------------------------------------------------