summaryrefslogtreecommitdiffstats
path: root/dbaccess/source/core/api/OptimisticSet.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'dbaccess/source/core/api/OptimisticSet.cxx')
-rw-r--r--dbaccess/source/core/api/OptimisticSet.cxx586
1 files changed, 586 insertions, 0 deletions
diff --git a/dbaccess/source/core/api/OptimisticSet.cxx b/dbaccess/source/core/api/OptimisticSet.cxx
new file mode 100644
index 000000000..d1d70955f
--- /dev/null
+++ b/dbaccess/source/core/api/OptimisticSet.cxx
@@ -0,0 +1,586 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <memory>
+#include "OptimisticSet.hxx"
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <map>
+#include <algorithm>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <composertools.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;
+
+typedef std::map<OUString, OUStringBuffer> TSQLStatements;
+namespace
+{
+ void lcl_fillKeyCondition(const OUString& i_sTableName,std::u16string_view i_sQuotedColumnName,const ORowSetValue& i_aValue,TSQLStatements& io_aKeyConditions)
+ {
+ OUStringBuffer& rKeyCondition = io_aKeyConditions[i_sTableName];
+ if ( !rKeyCondition.isEmpty() )
+ rKeyCondition.append(" AND ");
+ rKeyCondition.append(i_sQuotedColumnName);
+ if ( i_aValue.isNull() )
+ rKeyCondition.append(" IS NULL");
+ else
+ rKeyCondition.append(" = ?");
+ }
+}
+
+
+OptimisticSet::OptimisticSet(const Reference<XComponentContext>& _rContext,
+ const Reference< XConnection>& i_xConnection,
+ const Reference< XSingleSelectQueryAnalyzer >& _xComposer,
+ const ORowSetValueVector& _aParameterValueForCache,
+ sal_Int32 i_nMaxRows,
+ sal_Int32& o_nRowCount)
+ :OKeySet(nullptr,OUString(),_xComposer,_aParameterValueForCache,i_nMaxRows,o_nRowCount)
+ ,m_aSqlParser( _rContext )
+ ,m_aSqlIterator( i_xConnection, Reference<XTablesSupplier>(_xComposer,UNO_QUERY_THROW)->getTables(), m_aSqlParser )
+ ,m_bResultSetChanged(false)
+{
+}
+
+OptimisticSet::~OptimisticSet()
+{
+}
+
+void OptimisticSet::construct(const Reference< XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter)
+{
+ OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
+
+ initColumns();
+ m_sRowSetFilter = i_sRowSetFilter;
+
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ bool bCase = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers();
+ 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< OUString> aTableNames = xTables->getElementNames();
+ const OUString* pTableNameIter = aTableNames.getConstArray();
+ const OUString* pTableNameEnd = pTableNameIter + aTableNames.getLength();
+ for( ; pTableNameIter != pTableNameEnd ; ++pTableNameIter)
+ {
+ std::unique_ptr<SelectColumnsMetaData> 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
+ OKeySetValue keySetValue(nullptr,std::pair<sal_Int32,Reference<XRow> >(0,Reference<XRow>()));
+ m_aKeyMap.emplace(0,keySetValue);
+ m_aKeyIter = m_aKeyMap.begin();
+
+ Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
+ Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
+ Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
+ OUString sQuery = xSourceComposer->getQuery();
+ xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
+ // check for joins
+ OUString aErrorMsg;
+ std::unique_ptr<OSQLParseNode> pStatementNode( m_aSqlParser.parseTree( aErrorMsg, sQuery ) );
+ m_aSqlIterator.setParseTree( pStatementNode.get() );
+ m_aSqlIterator.traverseAll();
+ fillJoinedColumns_throw(m_aSqlIterator.getJoinConditions());
+
+}
+
+void OptimisticSet::makeNewStatement( )
+{
+ OUStringBuffer aFilter = createKeyFilter();
+
+ Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
+ Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
+ Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
+ xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
+
+ const OUString sComposerFilter = m_xComposer->getFilter();
+ if ( !m_sRowSetFilter.isEmpty() || !sComposerFilter.isEmpty() )
+ {
+ FilterCreator aFilterCreator;
+ if ( !sComposerFilter.isEmpty() && sComposerFilter != m_sRowSetFilter )
+ aFilterCreator.append( sComposerFilter );
+ aFilterCreator.append( m_sRowSetFilter );
+ aFilterCreator.append( aFilter.makeStringAndClear() );
+ aFilter = aFilterCreator.getComposedAndClear();
+ }
+ xAnalyzer->setFilter(aFilter.makeStringAndClear());
+ m_xStatement = m_xConnection->prepareStatement(xAnalyzer->getQueryWithSubstitution());
+ ::comphelper::disposeComponent(xAnalyzer);
+}
+
+void OptimisticSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ if ( m_aJoinedKeyColumns.empty() )
+ throw SQLException();
+ // list all columns that should be set
+ OUString aQuote = getIdentifierQuoteString();
+
+ std::map< OUString,bool > aResultSetChanged;
+ TSQLStatements aKeyConditions;
+ TSQLStatements aSql;
+
+ // here we build the condition part for the update statement
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ aResultSetChanged.try_emplace(columnName.second.sTableName, false);
+ const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
+ if ( m_pKeyColumnNames->find(columnName.first) != m_pKeyColumnNames->end() )
+ {
+ aResultSetChanged[columnName.second.sTableName] = m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end();
+ lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,(*_rOriginalRow)[columnName.second.nPosition],aKeyConditions);
+ }
+ if((*_rInsertRow)[columnName.second.nPosition].isModified())
+ {
+ if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end() )
+ throw SQLException();
+
+ std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(columnName.second.nPosition);
+ if ( aJoinIter != m_aJoinedColumns.end() )
+ {
+ (*_rInsertRow)[aJoinIter->second] = (*_rInsertRow)[columnName.second.nPosition];
+ }
+ OUStringBuffer& rPart = aSql[columnName.second.sTableName];
+ if ( !rPart.isEmpty() )
+ rPart.append(", ");
+ rPart.append(sQuotedColumnName + " = ?");
+ }
+ }
+
+ if( aSql.empty() )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_VALUE_CHANGED ), StandardSQLState::GENERAL_ERROR, m_xConnection );
+
+ if( aKeyConditions.empty() )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_CONDITION_FOR_PK ), StandardSQLState::GENERAL_ERROR, m_xConnection );
+
+ Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
+
+ for (auto const& elem : aSql)
+ {
+ if ( !elem.second.isEmpty() )
+ {
+ m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[elem.first];
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(xMetaData,elem.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+ OUStringBuffer sSql("UPDATE " + ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) +
+ " SET " + elem.second);
+ OUStringBuffer& rCondition = aKeyConditions[elem.first];
+ if ( !rCondition.isEmpty() )
+ sSql.append(" WHERE " + rCondition );
+
+ executeUpdate(_rInsertRow ,_rOriginalRow,sSql.makeStringAndClear(),elem.first);
+ }
+ }
+}
+
+void OptimisticSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ TSQLStatements aSql;
+ TSQLStatements aParameter;
+ TSQLStatements aKeyConditions;
+ std::map< OUString,bool > aResultSetChanged;
+ OUString aQuote = getIdentifierQuoteString();
+
+ // here we build the condition part for the update statement
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ aResultSetChanged.try_emplace(columnName.second.sTableName, false);
+
+ const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
+ if ( (*_rInsertRow)[columnName.second.nPosition].isModified() )
+ {
+ if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end() )
+ {
+ lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,(*_rInsertRow)[columnName.second.nPosition],aKeyConditions);
+ aResultSetChanged[columnName.second.sTableName] = true;
+ }
+ std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(columnName.second.nPosition);
+ if ( aJoinIter != m_aJoinedColumns.end() )
+ {
+ (*_rInsertRow)[aJoinIter->second] = (*_rInsertRow)[columnName.second.nPosition];
+ }
+ OUStringBuffer& rPart = aSql[columnName.second.sTableName];
+ if ( !rPart.isEmpty() )
+ rPart.append(", ");
+ rPart.append(sQuotedColumnName);
+ OUStringBuffer& rParam = aParameter[columnName.second.sTableName];
+ if ( !rParam.isEmpty() )
+ rParam.append(", ");
+ rParam.append("?");
+ }
+ }
+ if ( aParameter.empty() )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_VALUE_CHANGED ), StandardSQLState::GENERAL_ERROR, m_xConnection );
+
+ Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
+ for (auto const& elem : aSql)
+ {
+ if ( !elem.second.isEmpty() )
+ {
+ m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[elem.first];
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(xMetaData,elem.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+ OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
+ OUString sSql("INSERT INTO " + sComposedTableName + " ( " + elem.second +
+ ") VALUES ( " + aParameter[elem.first] + " )");
+
+ OUStringBuffer& rCondition = aKeyConditions[elem.first];
+ if ( !rCondition.isEmpty() )
+ {
+ OUString sQuery("SELECT " + elem.second + " FROM " + sComposedTableName +
+ " WHERE " + rCondition);
+
+ try
+ {
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+ // and then the values of the where condition
+ sal_Int32 i = 1;
+ for (auto const& keyColumnName : *m_pKeyColumnNames)
+ {
+ if ( keyColumnName.second.sTableName == elem.first )
+ {
+ setParameter(i++,xParameter,(*_rInsertRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.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,elem.first);
+ }
+ }
+}
+
+void OptimisticSet::deleteRow(const ORowSetRow& _rDeleteRow,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ OUString aQuote = getIdentifierQuoteString();
+ TSQLStatements aKeyConditions;
+
+ // here we build the condition part for the update statement
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) == m_aJoinedKeyColumns.end() && m_pKeyColumnNames->find(columnName.first) != m_pKeyColumnNames->end() )
+ {
+ // only delete rows which aren't the key in the join
+ const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
+ lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,(*_rDeleteRow)[columnName.second.nPosition],aKeyConditions);
+ }
+ }
+ Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
+ for (auto & keyCondition : aKeyConditions)
+ {
+ OUStringBuffer& rCondition = keyCondition.second;
+ if ( !rCondition.isEmpty() )
+ {
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(xMetaData,keyCondition.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+ OUString sSql("DELETE FROM " + ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) +
+ " WHERE " + rCondition );
+ executeDelete(_rDeleteRow, sSql, keyCondition.first);
+ }
+ }
+}
+
+void OptimisticSet::executeDelete(const ORowSetRow& _rDeleteRow,const OUString& i_sSQL,std::u16string_view i_sTableName)
+{
+ // now create and execute the prepared statement
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+
+ sal_Int32 i = 1;
+ for (auto const& keyColumnName : *m_pKeyColumnNames)
+ {
+ if ( keyColumnName.second.sTableName == i_sTableName )
+ setParameter(i++,xParameter,(*_rDeleteRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.second.nScale);
+ }
+ m_bDeleted = xPrep->executeUpdate() > 0;
+
+ if(m_bDeleted)
+ {
+ sal_Int32 nBookmark = ::comphelper::getINT32((*_rDeleteRow)[0].getAny());
+ if(m_aKeyIter == m_aKeyMap.find(nBookmark) && m_aKeyIter != m_aKeyMap.end())
+ ++m_aKeyIter;
+ m_aKeyMap.erase(nBookmark);
+ m_bDeleted = true;
+ }
+}
+
+void OptimisticSet::fillJoinedColumns_throw(const std::vector< TNodePair >& i_aJoinColumns)
+{
+ for (auto const& joinColumn : i_aJoinColumns)
+ {
+ OUString sColumnName,sTableName;
+ m_aSqlIterator.getColumnRange(joinColumn.first,sColumnName,sTableName);
+ OUString sLeft(sTableName + "." + sColumnName);
+ m_aSqlIterator.getColumnRange(joinColumn.second,sColumnName,sTableName);
+ OUString sRight(sTableName + "." + sColumnName);
+ fillJoinedColumns_throw(sLeft, sRight);
+ }
+}
+
+void OptimisticSet::fillJoinedColumns_throw(const OUString& i_sLeftColumn,const 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::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(true);
+ o_aChangedColumns.push_back(aJoinIter->second);
+ }
+}
+
+bool OptimisticSet::updateColumnValues(const ORowSetValueVector::Vector& io_aCachedRow,ORowSetValueVector::Vector& io_aRow,const std::vector<sal_Int32>& i_aChangedColumns)
+{
+ bool bRet = false;
+ for( const auto& aColIdx : i_aChangedColumns )
+ {
+ SelectColumnsMetaData::const_iterator aFind = std::find_if(
+ m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
+ [&aColIdx]( const SelectColumnsMetaData::value_type& aType )
+ { return aType.second.nPosition == aColIdx; } );
+ if ( aFind != m_pKeyColumnNames->end() )
+ {
+ const OUString sTableName = aFind->second.sTableName;
+ aFind = std::find_if( m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
+ [&sTableName]
+ ( const SelectColumnsMetaData::value_type& rCurr )
+ { return rCurr.second.sTableName == 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;
+ for( const auto& aCol : *m_pColumnNames )
+ {
+ if ( aCol.second.sTableName == sTableName )
+ {
+ io_aRow[aCol.second.nPosition] = io_aCachedRow[aCol.second.nPosition];
+ io_aRow[aCol.second.nPosition].setModified(true);
+ }
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+bool OptimisticSet::columnValuesUpdated(ORowSetValueVector::Vector& o_aCachedRow,const ORowSetValueVector::Vector& i_aRow)
+{
+ bool bRet = false;
+ for( const auto& aCol : *m_pColumnNames )
+ {
+ sal_Int32 nPos = aCol.second.nPosition;
+ SelectColumnsMetaData::const_iterator aFind = std::find_if(
+ m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
+ [&nPos] ( const SelectColumnsMetaData::value_type& aType )
+ { return aType.second.nPosition == nPos; } );
+ if ( aFind != m_pKeyColumnNames->end() )
+ {
+ const OUString sTableName = aFind->second.sTableName;
+ aFind = std::find_if( m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
+ [&sTableName]
+ ( const SelectColumnsMetaData::value_type& rCurr )
+ { return rCurr.second.sTableName == 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;
+ for( const auto& aCol2 : *m_pColumnNames )
+ {
+ if ( aCol2.second.sTableName == sTableName )
+ {
+ o_aCachedRow[aCol2.second.nPosition] = i_aRow[aCol2.second.nPosition];
+ o_aCachedRow[aCol2.second.nPosition].setModified(true);
+ }
+ }
+ fillMissingValues(o_aCachedRow);
+ }
+ }
+ }
+ return bRet;
+}
+
+void OptimisticSet::fillMissingValues(ORowSetValueVector::Vector& io_aRow) const
+{
+ TSQLStatements aSql;
+ TSQLStatements aKeyConditions;
+ OUString aQuote = getIdentifierQuoteString();
+ // here we build the condition part for the update statement
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
+ if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end() )
+ {
+ lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,io_aRow[columnName.second.nPosition],aKeyConditions);
+ }
+ OUStringBuffer& rPart = aSql[columnName.second.sTableName];
+ if ( !rPart.isEmpty() )
+ rPart.append(", ");
+ rPart.append(sQuotedColumnName);
+ }
+ Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
+ for (auto const& elem : aSql)
+ {
+ if ( !elem.second.isEmpty() )
+ {
+ OUStringBuffer& rCondition = aKeyConditions[elem.first];
+ if ( !rCondition.isEmpty() )
+ {
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(xMetaData,elem.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+ OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
+ OUString sQuery("SELECT " + elem.second + " FROM " + sComposedTableName + " WHERE " + rCondition);
+ rCondition.setLength(0);
+
+ try
+ {
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+ // and then the values of the where condition
+ sal_Int32 i = 1;
+ for (auto const& keyColumn : *m_pKeyColumnNames)
+ {
+ if ( keyColumn.second.sTableName == elem.first )
+ {
+ setParameter(i++,xParameter,io_aRow[keyColumn.second.nPosition],keyColumn.second.nType,keyColumn.second.nScale);
+ }
+ }
+ Reference<XResultSet> xRes = xPrep->executeQuery();
+ Reference<XRow> xRow(xRes,UNO_QUERY);
+ if ( xRow.is() && xRes->next() )
+ {
+ i = 1;
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ if ( columnName.second.sTableName == elem.first )
+ {
+ io_aRow[columnName.second.nPosition].fill(i++, columnName.second.nType, xRow);
+ io_aRow[columnName.second.nPosition].setModified(true);
+ }
+ }
+ }
+ }
+ catch(const SQLException&)
+ {
+ }
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */