Fix GNU C++ version check
[LibreOffice.git] / dbaccess / source / core / api / OptimisticSet.cxx
bloba74ec45e41d774be52bf2e89b6199d8344af735b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <memory>
22 #include "OptimisticSet.hxx"
23 #include <core_resource.hxx>
24 #include <strings.hrc>
25 #include <strings.hxx>
26 #include <com/sun/star/beans/XPropertySet.hpp>
27 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
28 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
29 #include <com/sun/star/sdbc/XPreparedStatement.hpp>
30 #include <com/sun/star/sdbc/XParameters.hpp>
31 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
32 #include <comphelper/types.hxx>
33 #include <connectivity/dbtools.hxx>
34 #include <connectivity/dbexception.hxx>
35 #include <map>
36 #include <algorithm>
37 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
38 #include <composertools.hxx>
39 #include "PrivateRow.hxx"
41 using namespace dbaccess;
42 using namespace ::connectivity;
43 using namespace ::dbtools;
44 using namespace ::com::sun::star::uno;
45 using namespace ::com::sun::star::sdbc;
46 using namespace ::com::sun::star::sdb;
47 using namespace ::com::sun::star::sdbcx;
48 using namespace ::com::sun::star::container;
49 using namespace ::com::sun::star::lang;
50 using namespace ::com::sun::star::io;
51 using namespace ::com::sun::star;
53 typedef std::map<OUString, OUStringBuffer> TSQLStatements;
54 namespace
56 void lcl_fillKeyCondition(const OUString& i_sTableName,std::u16string_view i_sQuotedColumnName,const ORowSetValue& i_aValue,TSQLStatements& io_aKeyConditions)
58 OUStringBuffer& rKeyCondition = io_aKeyConditions[i_sTableName];
59 if ( !rKeyCondition.isEmpty() )
60 rKeyCondition.append(" AND ");
61 rKeyCondition.append(i_sQuotedColumnName);
62 if ( i_aValue.isNull() )
63 rKeyCondition.append(" IS NULL");
64 else
65 rKeyCondition.append(" = ?");
70 OptimisticSet::OptimisticSet(const Reference<XComponentContext>& _rContext,
71 const Reference< XConnection>& i_xConnection,
72 const Reference< XSingleSelectQueryAnalyzer >& _xComposer,
73 const ORowSetValueVector& _aParameterValueForCache,
74 sal_Int32 i_nMaxRows,
75 sal_Int32& o_nRowCount)
76 :OKeySet(nullptr,OUString(),_xComposer,_aParameterValueForCache,i_nMaxRows,o_nRowCount)
77 ,m_aSqlParser( _rContext )
78 ,m_aSqlIterator( i_xConnection, Reference<XTablesSupplier>(_xComposer,UNO_QUERY_THROW)->getTables(), m_aSqlParser )
79 ,m_bResultSetChanged(false)
83 OptimisticSet::~OptimisticSet()
87 void OptimisticSet::construct(const Reference< XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter)
89 OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
91 initColumns();
92 m_sRowSetFilter = i_sRowSetFilter;
94 Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
95 bool bCase = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers();
96 Reference<XColumnsSupplier> xQueryColSup(m_xComposer,UNO_QUERY);
97 const Reference<XNameAccess> xQueryColumns = xQueryColSup->getColumns();
98 const Reference<XTablesSupplier> xTabSup(m_xComposer,UNO_QUERY);
99 const Reference<XNameAccess> xTables = xTabSup->getTables();
100 for (auto& tableName : xTables->getElementNames())
102 std::unique_ptr<SelectColumnsMetaData> pKeyColumNames(new SelectColumnsMetaData(comphelper::UStringMixLess(bCase)));
103 findTableColumnsMatching_throw(xTables->getByName(tableName),tableName,xMeta,xQueryColumns,pKeyColumNames);
104 m_pKeyColumnNames->insert(pKeyColumNames->begin(),pKeyColumNames->end());
107 // the first row is empty because it's now easier for us to distinguish when we are beforefirst or first
108 // without extra variable to be set
109 OKeySetValue keySetValue{nullptr,0,nullptr};
110 m_aKeyMap.emplace(0,keySetValue);
111 m_aKeyIter = m_aKeyMap.begin();
113 Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
114 Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
115 Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
116 OUString sQuery = xSourceComposer->getQuery();
117 xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
118 // check for joins
119 OUString aErrorMsg;
120 std::unique_ptr<OSQLParseNode> pStatementNode( m_aSqlParser.parseTree( aErrorMsg, sQuery ) );
121 m_aSqlIterator.setParseTree( pStatementNode.get() );
122 m_aSqlIterator.traverseAll();
123 fillJoinedColumns_throw(m_aSqlIterator.getJoinConditions());
127 void OptimisticSet::makeNewStatement( )
129 OUStringBuffer aFilter = createKeyFilter();
131 Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
132 Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
133 Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
134 xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
136 const OUString sComposerFilter = m_xComposer->getFilter();
137 if ( !m_sRowSetFilter.isEmpty() || !sComposerFilter.isEmpty() )
139 FilterCreator aFilterCreator;
140 if ( !sComposerFilter.isEmpty() && sComposerFilter != m_sRowSetFilter )
141 aFilterCreator.append( sComposerFilter );
142 aFilterCreator.append( m_sRowSetFilter );
143 aFilterCreator.append( aFilter.makeStringAndClear() );
144 aFilter = aFilterCreator.getComposedAndClear();
146 xAnalyzer->setFilter(aFilter.makeStringAndClear());
147 m_xStatement = m_xConnection->prepareStatement(xAnalyzer->getQueryWithSubstitution());
148 ::comphelper::disposeComponent(xAnalyzer);
151 void OptimisticSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& /*_xTable*/ )
153 if ( m_aJoinedKeyColumns.empty() )
154 throw SQLException();
155 // list all columns that should be set
156 OUString aQuote = getIdentifierQuoteString();
158 std::map< OUString,bool > aResultSetChanged;
159 TSQLStatements aKeyConditions;
160 TSQLStatements aSql;
162 // here we build the condition part for the update statement
163 for (auto const& columnName : *m_pColumnNames)
165 aResultSetChanged.try_emplace(columnName.second.sTableName, false);
166 const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
167 if ( m_pKeyColumnNames->find(columnName.first) != m_pKeyColumnNames->end() )
169 aResultSetChanged[columnName.second.sTableName] = m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end();
170 lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,(*_rOriginalRow)[columnName.second.nPosition],aKeyConditions);
172 if((*_rInsertRow)[columnName.second.nPosition].isModified())
174 if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end() )
175 throw SQLException();
177 std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(columnName.second.nPosition);
178 if ( aJoinIter != m_aJoinedColumns.end() )
180 (*_rInsertRow)[aJoinIter->second] = (*_rInsertRow)[columnName.second.nPosition];
182 OUStringBuffer& rPart = aSql[columnName.second.sTableName];
183 if ( !rPart.isEmpty() )
184 rPart.append(", ");
185 rPart.append(sQuotedColumnName + " = ?");
189 if( aSql.empty() )
190 ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_VALUE_CHANGED ), StandardSQLState::GENERAL_ERROR, m_xConnection );
192 if( aKeyConditions.empty() )
193 ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_CONDITION_FOR_PK ), StandardSQLState::GENERAL_ERROR, m_xConnection );
195 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
197 for (auto const& elem : aSql)
199 if ( !elem.second.isEmpty() )
201 m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[elem.first];
202 OUString sCatalog,sSchema,sTable;
203 ::dbtools::qualifiedNameComponents(xMetaData,elem.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
204 OUStringBuffer sSql("UPDATE " + ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) +
205 " SET " + elem.second);
206 OUStringBuffer& rCondition = aKeyConditions[elem.first];
207 if ( !rCondition.isEmpty() )
208 sSql.append(" WHERE " + rCondition );
210 executeUpdate(_rInsertRow ,_rOriginalRow,sSql.makeStringAndClear(),elem.first);
215 void OptimisticSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ )
217 TSQLStatements aSql;
218 TSQLStatements aParameter;
219 TSQLStatements aKeyConditions;
220 std::map< OUString,bool > aResultSetChanged;
221 OUString aQuote = getIdentifierQuoteString();
223 // here we build the condition part for the update statement
224 for (auto const& columnName : *m_pColumnNames)
226 aResultSetChanged.try_emplace(columnName.second.sTableName, false);
228 const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
229 if ( (*_rInsertRow)[columnName.second.nPosition].isModified() )
231 if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end() )
233 lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,(*_rInsertRow)[columnName.second.nPosition],aKeyConditions);
234 aResultSetChanged[columnName.second.sTableName] = true;
236 std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(columnName.second.nPosition);
237 if ( aJoinIter != m_aJoinedColumns.end() )
239 (*_rInsertRow)[aJoinIter->second] = (*_rInsertRow)[columnName.second.nPosition];
241 OUStringBuffer& rPart = aSql[columnName.second.sTableName];
242 if ( !rPart.isEmpty() )
243 rPart.append(", ");
244 rPart.append(sQuotedColumnName);
245 OUStringBuffer& rParam = aParameter[columnName.second.sTableName];
246 if ( !rParam.isEmpty() )
247 rParam.append(", ");
248 rParam.append("?");
251 if ( aParameter.empty() )
252 ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_VALUE_CHANGED ), StandardSQLState::GENERAL_ERROR, m_xConnection );
254 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
255 for (auto const& elem : aSql)
257 if ( !elem.second.isEmpty() )
259 m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[elem.first];
260 OUString sCatalog,sSchema,sTable;
261 ::dbtools::qualifiedNameComponents(xMetaData,elem.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
262 OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
263 OUString sSql("INSERT INTO " + sComposedTableName + " ( " + elem.second +
264 ") VALUES ( " + aParameter[elem.first] + " )");
266 OUStringBuffer& rCondition = aKeyConditions[elem.first];
267 if ( !rCondition.isEmpty() )
269 OUString sQuery("SELECT " + elem.second + " FROM " + sComposedTableName +
270 " WHERE " + rCondition);
274 Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery));
275 Reference< XParameters > xParameter(xPrep,UNO_QUERY);
276 // and then the values of the where condition
277 sal_Int32 i = 1;
278 for (auto const& keyColumnName : *m_pKeyColumnNames)
280 if ( keyColumnName.second.sTableName == elem.first )
282 setParameter(i++,xParameter,(*_rInsertRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.second.nScale);
285 Reference<XResultSet> xRes = xPrep->executeQuery();
286 Reference<XRow> xRow(xRes,UNO_QUERY);
287 if ( xRow.is() && xRes->next() )
289 m_bResultSetChanged = true;
290 continue;
293 catch(const SQLException&)
298 executeInsert(_rInsertRow,sSql,elem.first);
303 void OptimisticSet::deleteRow(const ORowSetRow& _rDeleteRow,const connectivity::OSQLTable& /*_xTable*/ )
305 OUString aQuote = getIdentifierQuoteString();
306 TSQLStatements aKeyConditions;
308 // here we build the condition part for the update statement
309 for (auto const& columnName : *m_pColumnNames)
311 if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) == m_aJoinedKeyColumns.end() && m_pKeyColumnNames->find(columnName.first) != m_pKeyColumnNames->end() )
313 // only delete rows which aren't the key in the join
314 const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
315 lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,(*_rDeleteRow)[columnName.second.nPosition],aKeyConditions);
318 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
319 for (auto & keyCondition : aKeyConditions)
321 OUStringBuffer& rCondition = keyCondition.second;
322 if ( !rCondition.isEmpty() )
324 OUString sCatalog,sSchema,sTable;
325 ::dbtools::qualifiedNameComponents(xMetaData,keyCondition.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
326 OUString sSql("DELETE FROM " + ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) +
327 " WHERE " + rCondition );
328 executeDelete(_rDeleteRow, sSql, keyCondition.first);
333 void OptimisticSet::executeDelete(const ORowSetRow& _rDeleteRow,const OUString& i_sSQL,std::u16string_view i_sTableName)
335 // now create and execute the prepared statement
336 Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL));
337 Reference< XParameters > xParameter(xPrep,UNO_QUERY);
339 sal_Int32 i = 1;
340 for (auto const& keyColumnName : *m_pKeyColumnNames)
342 if ( keyColumnName.second.sTableName == i_sTableName )
343 setParameter(i++,xParameter,(*_rDeleteRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.second.nScale);
345 m_bDeleted = xPrep->executeUpdate() > 0;
347 if(m_bDeleted)
349 sal_Int32 nBookmark = ::comphelper::getINT32((*_rDeleteRow)[0].getAny());
350 const auto iter = m_aKeyMap.find(nBookmark);
351 assert(iter != m_aKeyMap.end());
352 if(m_aKeyIter == iter && m_aKeyIter != m_aKeyMap.end())
353 ++m_aKeyIter;
354 m_aKeyMap.erase(nBookmark);
355 m_bDeleted = true;
359 void OptimisticSet::fillJoinedColumns_throw(const std::vector< TNodePair >& i_aJoinColumns)
361 for (auto const& joinColumn : i_aJoinColumns)
363 OUString sColumnName,sTableName;
364 m_aSqlIterator.getColumnRange(joinColumn.first,sColumnName,sTableName);
365 OUString sLeft(sTableName + "." + sColumnName);
366 m_aSqlIterator.getColumnRange(joinColumn.second,sColumnName,sTableName);
367 OUString sRight(sTableName + "." + sColumnName);
368 fillJoinedColumns_throw(sLeft, sRight);
372 void OptimisticSet::fillJoinedColumns_throw(const OUString& i_sLeftColumn,const OUString& i_sRightColumn)
374 sal_Int32 nLeft = 0,nRight = 0;
375 SelectColumnsMetaData::const_iterator aLeftIter = m_pKeyColumnNames->find(i_sLeftColumn);
376 SelectColumnsMetaData::const_iterator aRightIter = m_pKeyColumnNames->find(i_sRightColumn);
378 bool bLeftKey = aLeftIter != m_pKeyColumnNames->end();
379 if ( bLeftKey )
381 nLeft = aLeftIter->second.nPosition;
383 else
385 aLeftIter = m_pColumnNames->find(i_sLeftColumn);
386 if ( aLeftIter != m_pColumnNames->end() )
387 nLeft = aLeftIter->second.nPosition;
390 bool bRightKey = aRightIter != m_pKeyColumnNames->end();
391 if ( bRightKey )
393 nRight = aRightIter->second.nPosition;
395 else
397 aRightIter = m_pColumnNames->find(i_sRightColumn);
398 if ( aRightIter != m_pColumnNames->end() )
399 nRight = aRightIter->second.nPosition;
402 if (bLeftKey)
403 m_aJoinedKeyColumns[nLeft] = nRight;
404 else
405 m_aJoinedColumns[nLeft] = nRight;
406 if (bRightKey)
407 m_aJoinedKeyColumns[nRight] = nLeft;
408 else
409 m_aJoinedColumns[nRight] = nLeft;
412 bool OptimisticSet::isResultSetChanged() const
414 bool bOld = m_bResultSetChanged;
415 m_bResultSetChanged = false;
416 return bOld;
419 void OptimisticSet::mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& io_aInsertRow,ORowSetValueVector::Vector& io_aRow,std::vector<sal_Int32>& o_aChangedColumns)
421 o_aChangedColumns.push_back(i_nColumnIndex);
422 std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(i_nColumnIndex);
423 if ( aJoinIter != m_aJoinedColumns.end() )
425 io_aRow[aJoinIter->second] = io_aRow[i_nColumnIndex];
426 io_aInsertRow[aJoinIter->second] = io_aInsertRow[i_nColumnIndex];
427 io_aRow[aJoinIter->second].setModified(true);
428 o_aChangedColumns.push_back(aJoinIter->second);
432 bool OptimisticSet::updateColumnValues(const ORowSetValueVector::Vector& io_aCachedRow,ORowSetValueVector::Vector& io_aRow,const std::vector<sal_Int32>& i_aChangedColumns)
434 bool bRet = false;
435 for( const auto& aColIdx : i_aChangedColumns )
437 SelectColumnsMetaData::const_iterator aFind = std::find_if(
438 m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
439 [&aColIdx]( const SelectColumnsMetaData::value_type& aType )
440 { return aType.second.nPosition == aColIdx; } );
441 if ( aFind != m_pKeyColumnNames->end() )
443 const OUString sTableName = aFind->second.sTableName;
444 aFind = std::find_if( m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
445 [&sTableName]
446 ( const SelectColumnsMetaData::value_type& rCurr )
447 { return rCurr.second.sTableName == sTableName; } );
448 while( aFind != m_pKeyColumnNames->end() )
450 io_aRow[aFind->second.nPosition].setSigned(io_aCachedRow[aFind->second.nPosition].isSigned());
451 if ( io_aCachedRow[aFind->second.nPosition] != io_aRow[aFind->second.nPosition] )
452 break;
453 ++aFind;
455 if ( aFind == m_pKeyColumnNames->end() )
457 bRet = true;
458 for( const auto& aCol : *m_pColumnNames )
460 if ( aCol.second.sTableName == sTableName )
462 io_aRow[aCol.second.nPosition] = io_aCachedRow[aCol.second.nPosition];
463 io_aRow[aCol.second.nPosition].setModified(true);
469 return bRet;
472 bool OptimisticSet::columnValuesUpdated(ORowSetValueVector::Vector& o_aCachedRow,const ORowSetValueVector::Vector& i_aRow)
474 bool bRet = false;
475 for( const auto& aCol : *m_pColumnNames )
477 sal_Int32 nPos = aCol.second.nPosition;
478 SelectColumnsMetaData::const_iterator aFind = std::find_if(
479 m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
480 [&nPos] ( const SelectColumnsMetaData::value_type& aType )
481 { return aType.second.nPosition == nPos; } );
482 if ( aFind != m_pKeyColumnNames->end() )
484 const OUString sTableName = aFind->second.sTableName;
485 aFind = std::find_if( m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
486 [&sTableName]
487 ( const SelectColumnsMetaData::value_type& rCurr )
488 { return rCurr.second.sTableName == sTableName; } );
489 while( aFind != m_pKeyColumnNames->end() )
491 o_aCachedRow[aFind->second.nPosition].setSigned(i_aRow[aFind->second.nPosition].isSigned());
492 if ( o_aCachedRow[aFind->second.nPosition] != i_aRow[aFind->second.nPosition] )
493 break;
494 ++aFind;
496 if ( aFind == m_pKeyColumnNames->end() )
498 bRet = true;
499 for( const auto& aCol2 : *m_pColumnNames )
501 if ( aCol2.second.sTableName == sTableName )
503 o_aCachedRow[aCol2.second.nPosition] = i_aRow[aCol2.second.nPosition];
504 o_aCachedRow[aCol2.second.nPosition].setModified(true);
507 fillMissingValues(o_aCachedRow);
511 return bRet;
514 void OptimisticSet::fillMissingValues(ORowSetValueVector::Vector& io_aRow) const
516 TSQLStatements aSql;
517 TSQLStatements aKeyConditions;
518 OUString aQuote = getIdentifierQuoteString();
519 // here we build the condition part for the update statement
520 for (auto const& columnName : *m_pColumnNames)
522 const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
523 if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end() )
525 lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,io_aRow[columnName.second.nPosition],aKeyConditions);
527 OUStringBuffer& rPart = aSql[columnName.second.sTableName];
528 if ( !rPart.isEmpty() )
529 rPart.append(", ");
530 rPart.append(sQuotedColumnName);
532 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
533 for (auto const& elem : aSql)
535 if ( !elem.second.isEmpty() )
537 OUStringBuffer& rCondition = aKeyConditions[elem.first];
538 if ( !rCondition.isEmpty() )
540 OUString sCatalog,sSchema,sTable;
541 ::dbtools::qualifiedNameComponents(xMetaData,elem.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
542 OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
543 OUString sQuery("SELECT " + elem.second + " FROM " + sComposedTableName + " WHERE " + rCondition);
544 rCondition.setLength(0);
548 Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery));
549 Reference< XParameters > xParameter(xPrep,UNO_QUERY);
550 // and then the values of the where condition
551 sal_Int32 i = 1;
552 for (auto const& keyColumn : *m_pKeyColumnNames)
554 if ( keyColumn.second.sTableName == elem.first )
556 setParameter(i++,xParameter,io_aRow[keyColumn.second.nPosition],keyColumn.second.nType,keyColumn.second.nScale);
559 Reference<XResultSet> xRes = xPrep->executeQuery();
560 Reference<XRow> xRow(xRes,UNO_QUERY);
561 if ( xRow.is() && xRes->next() )
563 i = 1;
564 for (auto const& columnName : *m_pColumnNames)
566 if ( columnName.second.sTableName == elem.first )
568 io_aRow[columnName.second.nPosition].fill(i++, columnName.second.nType, xRow);
569 io_aRow[columnName.second.nPosition].setModified(true);
574 catch(const SQLException&)
582 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */