LibreOffice Module dbaccess (master) 1
OptimisticSet.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
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>
35#include <map>
36#include <algorithm>
37#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
38#include <composertools.hxx>
39
40using namespace dbaccess;
41using namespace ::connectivity;
42using namespace ::dbtools;
43using namespace ::com::sun::star::uno;
44using namespace ::com::sun::star::beans;
45using namespace ::com::sun::star::sdbc;
46using namespace ::com::sun::star::sdb;
47using namespace ::com::sun::star::sdbcx;
48using namespace ::com::sun::star::container;
49using namespace ::com::sun::star::lang;
50using namespace ::com::sun::star::util;
51using namespace ::com::sun::star::io;
52using namespace ::com::sun::star;
53using namespace ::cppu;
54using namespace ::osl;
55
56typedef std::map<OUString, OUStringBuffer> TSQLStatements;
57namespace
58{
59 void lcl_fillKeyCondition(const OUString& i_sTableName,std::u16string_view i_sQuotedColumnName,const ORowSetValue& i_aValue,TSQLStatements& io_aKeyConditions)
60 {
61 OUStringBuffer& rKeyCondition = io_aKeyConditions[i_sTableName];
62 if ( !rKeyCondition.isEmpty() )
63 rKeyCondition.append(" AND ");
64 rKeyCondition.append(i_sQuotedColumnName);
65 if ( i_aValue.isNull() )
66 rKeyCondition.append(" IS NULL");
67 else
68 rKeyCondition.append(" = ?");
69 }
70}
71
72
73OptimisticSet::OptimisticSet(const Reference<XComponentContext>& _rContext,
74 const Reference< XConnection>& i_xConnection,
75 const Reference< XSingleSelectQueryAnalyzer >& _xComposer,
76 const ORowSetValueVector& _aParameterValueForCache,
77 sal_Int32 i_nMaxRows,
78 sal_Int32& o_nRowCount)
79 :OKeySet(nullptr,OUString(),_xComposer,_aParameterValueForCache,i_nMaxRows,o_nRowCount)
80 ,m_aSqlParser( _rContext )
81 ,m_aSqlIterator( i_xConnection, Reference<XTablesSupplier>(_xComposer,UNO_QUERY_THROW)->getTables(), m_aSqlParser )
82 ,m_bResultSetChanged(false)
83{
84}
85
87{
88}
89
90void OptimisticSet::construct(const Reference< XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter)
91{
92 OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
93
94 initColumns();
95 m_sRowSetFilter = i_sRowSetFilter;
96
97 Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
98 bool bCase = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers();
99 Reference<XColumnsSupplier> xQueryColSup(m_xComposer,UNO_QUERY);
100 const Reference<XNameAccess> xQueryColumns = xQueryColSup->getColumns();
101 const Reference<XTablesSupplier> xTabSup(m_xComposer,UNO_QUERY);
102 const Reference<XNameAccess> xTables = xTabSup->getTables();
103 const Sequence< OUString> aTableNames = xTables->getElementNames();
104 const OUString* pTableNameIter = aTableNames.getConstArray();
105 const OUString* pTableNameEnd = pTableNameIter + aTableNames.getLength();
106 for( ; pTableNameIter != pTableNameEnd ; ++pTableNameIter)
107 {
108 std::unique_ptr<SelectColumnsMetaData> pKeyColumNames(new SelectColumnsMetaData(bCase));
109 findTableColumnsMatching_throw(xTables->getByName(*pTableNameIter),*pTableNameIter,xMeta,xQueryColumns,pKeyColumNames);
110 m_pKeyColumnNames->insert(pKeyColumNames->begin(),pKeyColumNames->end());
111 }
112
113 // the first row is empty because it's now easier for us to distinguish when we are beforefirst or first
114 // without extra variable to be set
115 OKeySetValue keySetValue(nullptr,std::pair<sal_Int32,Reference<XRow> >(0,Reference<XRow>()));
116 m_aKeyMap.emplace(0,keySetValue);
117 m_aKeyIter = m_aKeyMap.begin();
118
119 Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
120 Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
121 Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
122 OUString sQuery = xSourceComposer->getQuery();
123 xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
124 // check for joins
125 OUString aErrorMsg;
126 std::unique_ptr<OSQLParseNode> pStatementNode( m_aSqlParser.parseTree( aErrorMsg, sQuery ) );
127 m_aSqlIterator.setParseTree( pStatementNode.get() );
130
131}
132
134{
135 OUStringBuffer aFilter = createKeyFilter();
136
137 Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
138 Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
139 Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
140 xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
141
142 const OUString sComposerFilter = m_xComposer->getFilter();
143 if ( !m_sRowSetFilter.isEmpty() || !sComposerFilter.isEmpty() )
144 {
145 FilterCreator aFilterCreator;
146 if ( !sComposerFilter.isEmpty() && sComposerFilter != m_sRowSetFilter )
147 aFilterCreator.append( sComposerFilter );
148 aFilterCreator.append( m_sRowSetFilter );
149 aFilterCreator.append( aFilter.makeStringAndClear() );
150 aFilter = aFilterCreator.getComposedAndClear();
151 }
152 xAnalyzer->setFilter(aFilter.makeStringAndClear());
153 m_xStatement = m_xConnection->prepareStatement(xAnalyzer->getQueryWithSubstitution());
154 ::comphelper::disposeComponent(xAnalyzer);
155}
156
157void OptimisticSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& /*_xTable*/ )
158{
159 if ( m_aJoinedKeyColumns.empty() )
160 throw SQLException();
161 // list all columns that should be set
162 OUString aQuote = getIdentifierQuoteString();
163
164 std::map< OUString,bool > aResultSetChanged;
165 TSQLStatements aKeyConditions;
166 TSQLStatements aSql;
167
168 // here we build the condition part for the update statement
169 for (auto const& columnName : *m_pColumnNames)
170 {
171 aResultSetChanged.try_emplace(columnName.second.sTableName, false);
172 const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
173 if ( m_pKeyColumnNames->find(columnName.first) != m_pKeyColumnNames->end() )
174 {
175 aResultSetChanged[columnName.second.sTableName] = m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end();
176 lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,(*_rOriginalRow)[columnName.second.nPosition],aKeyConditions);
177 }
178 if((*_rInsertRow)[columnName.second.nPosition].isModified())
179 {
180 if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end() )
181 throw SQLException();
182
183 std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(columnName.second.nPosition);
184 if ( aJoinIter != m_aJoinedColumns.end() )
185 {
186 (*_rInsertRow)[aJoinIter->second] = (*_rInsertRow)[columnName.second.nPosition];
187 }
188 OUStringBuffer& rPart = aSql[columnName.second.sTableName];
189 if ( !rPart.isEmpty() )
190 rPart.append(", ");
191 rPart.append(sQuotedColumnName + " = ?");
192 }
193 }
194
195 if( aSql.empty() )
196 ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_VALUE_CHANGED ), StandardSQLState::GENERAL_ERROR, m_xConnection );
197
198 if( aKeyConditions.empty() )
199 ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_CONDITION_FOR_PK ), StandardSQLState::GENERAL_ERROR, m_xConnection );
200
201 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
202
203 for (auto const& elem : aSql)
204 {
205 if ( !elem.second.isEmpty() )
206 {
207 m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[elem.first];
208 OUString sCatalog,sSchema,sTable;
209 ::dbtools::qualifiedNameComponents(xMetaData,elem.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
210 OUStringBuffer sSql("UPDATE " + ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) +
211 " SET " + elem.second);
212 OUStringBuffer& rCondition = aKeyConditions[elem.first];
213 if ( !rCondition.isEmpty() )
214 sSql.append(" WHERE " + rCondition );
215
216 executeUpdate(_rInsertRow ,_rOriginalRow,sSql.makeStringAndClear(),elem.first);
217 }
218 }
219}
220
221void OptimisticSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ )
222{
223 TSQLStatements aSql;
224 TSQLStatements aParameter;
225 TSQLStatements aKeyConditions;
226 std::map< OUString,bool > aResultSetChanged;
227 OUString aQuote = getIdentifierQuoteString();
228
229 // here we build the condition part for the update statement
230 for (auto const& columnName : *m_pColumnNames)
231 {
232 aResultSetChanged.try_emplace(columnName.second.sTableName, false);
233
234 const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
235 if ( (*_rInsertRow)[columnName.second.nPosition].isModified() )
236 {
237 if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end() )
238 {
239 lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,(*_rInsertRow)[columnName.second.nPosition],aKeyConditions);
240 aResultSetChanged[columnName.second.sTableName] = true;
241 }
242 std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(columnName.second.nPosition);
243 if ( aJoinIter != m_aJoinedColumns.end() )
244 {
245 (*_rInsertRow)[aJoinIter->second] = (*_rInsertRow)[columnName.second.nPosition];
246 }
247 OUStringBuffer& rPart = aSql[columnName.second.sTableName];
248 if ( !rPart.isEmpty() )
249 rPart.append(", ");
250 rPart.append(sQuotedColumnName);
251 OUStringBuffer& rParam = aParameter[columnName.second.sTableName];
252 if ( !rParam.isEmpty() )
253 rParam.append(", ");
254 rParam.append("?");
255 }
256 }
257 if ( aParameter.empty() )
258 ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_VALUE_CHANGED ), StandardSQLState::GENERAL_ERROR, m_xConnection );
259
260 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
261 for (auto const& elem : aSql)
262 {
263 if ( !elem.second.isEmpty() )
264 {
265 m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[elem.first];
266 OUString sCatalog,sSchema,sTable;
267 ::dbtools::qualifiedNameComponents(xMetaData,elem.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
268 OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
269 OUString sSql("INSERT INTO " + sComposedTableName + " ( " + elem.second +
270 ") VALUES ( " + aParameter[elem.first] + " )");
271
272 OUStringBuffer& rCondition = aKeyConditions[elem.first];
273 if ( !rCondition.isEmpty() )
274 {
275 OUString sQuery("SELECT " + elem.second + " FROM " + sComposedTableName +
276 " WHERE " + rCondition);
277
278 try
279 {
280 Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery));
281 Reference< XParameters > xParameter(xPrep,UNO_QUERY);
282 // and then the values of the where condition
283 sal_Int32 i = 1;
284 for (auto const& keyColumnName : *m_pKeyColumnNames)
285 {
286 if ( keyColumnName.second.sTableName == elem.first )
287 {
288 setParameter(i++,xParameter,(*_rInsertRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.second.nScale);
289 }
290 }
291 Reference<XResultSet> xRes = xPrep->executeQuery();
292 Reference<XRow> xRow(xRes,UNO_QUERY);
293 if ( xRow.is() && xRes->next() )
294 {
295 m_bResultSetChanged = true;
296 continue;
297 }
298 }
299 catch(const SQLException&)
300 {
301 }
302 }
303
304 executeInsert(_rInsertRow,sSql,elem.first);
305 }
306 }
307}
308
309void OptimisticSet::deleteRow(const ORowSetRow& _rDeleteRow,const connectivity::OSQLTable& /*_xTable*/ )
310{
311 OUString aQuote = getIdentifierQuoteString();
312 TSQLStatements aKeyConditions;
313
314 // here we build the condition part for the update statement
315 for (auto const& columnName : *m_pColumnNames)
316 {
317 if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) == m_aJoinedKeyColumns.end() && m_pKeyColumnNames->find(columnName.first) != m_pKeyColumnNames->end() )
318 {
319 // only delete rows which aren't the key in the join
320 const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
321 lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,(*_rDeleteRow)[columnName.second.nPosition],aKeyConditions);
322 }
323 }
324 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
325 for (auto & keyCondition : aKeyConditions)
326 {
327 OUStringBuffer& rCondition = keyCondition.second;
328 if ( !rCondition.isEmpty() )
329 {
330 OUString sCatalog,sSchema,sTable;
331 ::dbtools::qualifiedNameComponents(xMetaData,keyCondition.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
332 OUString sSql("DELETE FROM " + ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) +
333 " WHERE " + rCondition );
334 executeDelete(_rDeleteRow, sSql, keyCondition.first);
335 }
336 }
337}
338
339void OptimisticSet::executeDelete(const ORowSetRow& _rDeleteRow,const OUString& i_sSQL,std::u16string_view i_sTableName)
340{
341 // now create and execute the prepared statement
342 Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL));
343 Reference< XParameters > xParameter(xPrep,UNO_QUERY);
344
345 sal_Int32 i = 1;
346 for (auto const& keyColumnName : *m_pKeyColumnNames)
347 {
348 if ( keyColumnName.second.sTableName == i_sTableName )
349 setParameter(i++,xParameter,(*_rDeleteRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.second.nScale);
350 }
351 m_bDeleted = xPrep->executeUpdate() > 0;
352
353 if(m_bDeleted)
354 {
355 sal_Int32 nBookmark = ::comphelper::getINT32((*_rDeleteRow)[0].getAny());
356 if(m_aKeyIter == m_aKeyMap.find(nBookmark) && m_aKeyIter != m_aKeyMap.end())
357 ++m_aKeyIter;
358 m_aKeyMap.erase(nBookmark);
359 m_bDeleted = true;
360 }
361}
362
363void OptimisticSet::fillJoinedColumns_throw(const std::vector< TNodePair >& i_aJoinColumns)
364{
365 for (auto const& joinColumn : i_aJoinColumns)
366 {
367 OUString sColumnName,sTableName;
368 m_aSqlIterator.getColumnRange(joinColumn.first,sColumnName,sTableName);
369 OUString sLeft(sTableName + "." + sColumnName);
370 m_aSqlIterator.getColumnRange(joinColumn.second,sColumnName,sTableName);
371 OUString sRight(sTableName + "." + sColumnName);
372 fillJoinedColumns_throw(sLeft, sRight);
373 }
374}
375
376void OptimisticSet::fillJoinedColumns_throw(const OUString& i_sLeftColumn,const OUString& i_sRightColumn)
377{
378 sal_Int32 nLeft = 0,nRight = 0;
379 SelectColumnsMetaData::const_iterator aLeftIter = m_pKeyColumnNames->find(i_sLeftColumn);
380 SelectColumnsMetaData::const_iterator aRightIter = m_pKeyColumnNames->find(i_sRightColumn);
381
382 bool bLeftKey = aLeftIter != m_pKeyColumnNames->end();
383 if ( bLeftKey )
384 {
385 nLeft = aLeftIter->second.nPosition;
386 }
387 else
388 {
389 aLeftIter = m_pColumnNames->find(i_sLeftColumn);
390 if ( aLeftIter != m_pColumnNames->end() )
391 nLeft = aLeftIter->second.nPosition;
392 }
393
394 bool bRightKey = aRightIter != m_pKeyColumnNames->end();
395 if ( bRightKey )
396 {
397 nRight = aRightIter->second.nPosition;
398 }
399 else
400 {
401 aRightIter = m_pColumnNames->find(i_sRightColumn);
402 if ( aRightIter != m_pColumnNames->end() )
403 nRight = aRightIter->second.nPosition;
404 }
405
406 if (bLeftKey)
407 m_aJoinedKeyColumns[nLeft] = nRight;
408 else
409 m_aJoinedColumns[nLeft] = nRight;
410 if (bRightKey)
411 m_aJoinedKeyColumns[nRight] = nLeft;
412 else
413 m_aJoinedColumns[nRight] = nLeft;
414}
415
417{
418 bool bOld = m_bResultSetChanged;
419 m_bResultSetChanged = false;
420 return bOld;
421}
422
423void OptimisticSet::mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& io_aInsertRow,ORowSetValueVector::Vector& io_aRow,std::vector<sal_Int32>& o_aChangedColumns)
424{
425 o_aChangedColumns.push_back(i_nColumnIndex);
426 std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(i_nColumnIndex);
427 if ( aJoinIter != m_aJoinedColumns.end() )
428 {
429 io_aRow[aJoinIter->second] = io_aRow[i_nColumnIndex];
430 io_aInsertRow[aJoinIter->second] = io_aInsertRow[i_nColumnIndex];
431 io_aRow[aJoinIter->second].setModified(true);
432 o_aChangedColumns.push_back(aJoinIter->second);
433 }
434}
435
436bool OptimisticSet::updateColumnValues(const ORowSetValueVector::Vector& io_aCachedRow,ORowSetValueVector::Vector& io_aRow,const std::vector<sal_Int32>& i_aChangedColumns)
437{
438 bool bRet = false;
439 for( const auto& aColIdx : i_aChangedColumns )
440 {
441 SelectColumnsMetaData::const_iterator aFind = std::find_if(
442 m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
443 [&aColIdx]( const SelectColumnsMetaData::value_type& aType )
444 { return aType.second.nPosition == aColIdx; } );
445 if ( aFind != m_pKeyColumnNames->end() )
446 {
447 const OUString sTableName = aFind->second.sTableName;
448 aFind = std::find_if( m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
449 [&sTableName]
450 ( const SelectColumnsMetaData::value_type& rCurr )
451 { return rCurr.second.sTableName == sTableName; } );
452 while( aFind != m_pKeyColumnNames->end() )
453 {
454 io_aRow[aFind->second.nPosition].setSigned(io_aCachedRow[aFind->second.nPosition].isSigned());
455 if ( io_aCachedRow[aFind->second.nPosition] != io_aRow[aFind->second.nPosition] )
456 break;
457 ++aFind;
458 }
459 if ( aFind == m_pKeyColumnNames->end() )
460 {
461 bRet = true;
462 for( const auto& aCol : *m_pColumnNames )
463 {
464 if ( aCol.second.sTableName == sTableName )
465 {
466 io_aRow[aCol.second.nPosition] = io_aCachedRow[aCol.second.nPosition];
467 io_aRow[aCol.second.nPosition].setModified(true);
468 }
469 }
470 }
471 }
472 }
473 return bRet;
474}
475
477{
478 bool bRet = false;
479 for( const auto& aCol : *m_pColumnNames )
480 {
481 sal_Int32 nPos = aCol.second.nPosition;
482 SelectColumnsMetaData::const_iterator aFind = std::find_if(
483 m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
484 [&nPos] ( const SelectColumnsMetaData::value_type& aType )
485 { return aType.second.nPosition == nPos; } );
486 if ( aFind != m_pKeyColumnNames->end() )
487 {
488 const OUString sTableName = aFind->second.sTableName;
489 aFind = std::find_if( m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
490 [&sTableName]
491 ( const SelectColumnsMetaData::value_type& rCurr )
492 { return rCurr.second.sTableName == sTableName; } );
493 while( aFind != m_pKeyColumnNames->end() )
494 {
495 o_aCachedRow[aFind->second.nPosition].setSigned(i_aRow[aFind->second.nPosition].isSigned());
496 if ( o_aCachedRow[aFind->second.nPosition] != i_aRow[aFind->second.nPosition] )
497 break;
498 ++aFind;
499 }
500 if ( aFind == m_pKeyColumnNames->end() )
501 {
502 bRet = true;
503 for( const auto& aCol2 : *m_pColumnNames )
504 {
505 if ( aCol2.second.sTableName == sTableName )
506 {
507 o_aCachedRow[aCol2.second.nPosition] = i_aRow[aCol2.second.nPosition];
508 o_aCachedRow[aCol2.second.nPosition].setModified(true);
509 }
510 }
511 fillMissingValues(o_aCachedRow);
512 }
513 }
514 }
515 return bRet;
516}
517
519{
520 TSQLStatements aSql;
521 TSQLStatements aKeyConditions;
522 OUString aQuote = getIdentifierQuoteString();
523 // here we build the condition part for the update statement
524 for (auto const& columnName : *m_pColumnNames)
525 {
526 const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
527 if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end() )
528 {
529 lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,io_aRow[columnName.second.nPosition],aKeyConditions);
530 }
531 OUStringBuffer& rPart = aSql[columnName.second.sTableName];
532 if ( !rPart.isEmpty() )
533 rPart.append(", ");
534 rPart.append(sQuotedColumnName);
535 }
536 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
537 for (auto const& elem : aSql)
538 {
539 if ( !elem.second.isEmpty() )
540 {
541 OUStringBuffer& rCondition = aKeyConditions[elem.first];
542 if ( !rCondition.isEmpty() )
543 {
544 OUString sCatalog,sSchema,sTable;
545 ::dbtools::qualifiedNameComponents(xMetaData,elem.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
546 OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
547 OUString sQuery("SELECT " + elem.second + " FROM " + sComposedTableName + " WHERE " + rCondition);
548 rCondition.setLength(0);
549
550 try
551 {
552 Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery));
553 Reference< XParameters > xParameter(xPrep,UNO_QUERY);
554 // and then the values of the where condition
555 sal_Int32 i = 1;
556 for (auto const& keyColumn : *m_pKeyColumnNames)
557 {
558 if ( keyColumn.second.sTableName == elem.first )
559 {
560 setParameter(i++,xParameter,io_aRow[keyColumn.second.nPosition],keyColumn.second.nType,keyColumn.second.nScale);
561 }
562 }
563 Reference<XResultSet> xRes = xPrep->executeQuery();
564 Reference<XRow> xRow(xRes,UNO_QUERY);
565 if ( xRow.is() && xRes->next() )
566 {
567 i = 1;
568 for (auto const& columnName : *m_pColumnNames)
569 {
570 if ( columnName.second.sTableName == elem.first )
571 {
572 io_aRow[columnName.second.nPosition].fill(i++, columnName.second.nType, xRow);
573 io_aRow[columnName.second.nPosition].setModified(true);
574 }
575 }
576 }
577 }
578 catch(const SQLException&)
579 {
580 }
581 }
582 }
583 }
584}
585
586/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OptionalString sSchema
OptionalString sCatalog
std::map< OUString, OUStringBuffer > TSQLStatements
std::vector< VectorVal > Vector
void getColumnRange(const OSQLParseNode *_pColumnRef, OUString &_rColumnName, OUString &_rTableRange) const
void setParseTree(const OSQLParseNode *pNewParseTree)
::std::vector< TNodePair > & getJoinConditions() const
std::unique_ptr< OSQLParseNode > parseTree(OUString &rErrorMessage, const OUString &rStatement, bool bInternational=false)
virtual void construct(const css::uno::Reference< css::sdbc::XResultSet > &_xDriverSet, const OUString &i_sRowSetFilter)
Definition: CacheSet.cxx:74
virtual void deleteRow(const ORowSetRow &_rInsertRow, const connectivity::OSQLTable &_xTable) override
virtual void updateRow(const ORowSetRow &_rInsertRow, const ORowSetRow &_rOriginalRow, const connectivity::OSQLTable &_xTable) override
virtual void construct(const css::uno::Reference< css::sdbc::XResultSet > &_xDriverSet, const OUString &i_sRowSetFilter) override
virtual void makeNewStatement() override
virtual ~OptimisticSet() override
void fillJoinedColumns_throw(const std::vector< ::connectivity::TNodePair > &i_aJoinColumns)
void executeDelete(const ORowSetRow &_rDeleteRow, const OUString &i_sSQL, std::u16string_view i_sTableName)
virtual bool updateColumnValues(const ORowSetValueVector::Vector &io_aCachedRow, ORowSetValueVector::Vector &io_aRow, const std::vector< sal_Int32 > &i_aChangedColumns) override
::connectivity::OSQLParser m_aSqlParser
virtual void fillMissingValues(ORowSetValueVector::Vector &io_aRow) const override
virtual bool isResultSetChanged() const override
std::map< sal_Int32, sal_Int32 > m_aJoinedKeyColumns
virtual void mergeColumnValues(sal_Int32 i_nColumnIndex, ORowSetValueVector::Vector &io_aInsertRow, ORowSetValueVector::Vector &io_aRow, std::vector< sal_Int32 > &o_aChangedColumns) override
virtual bool columnValuesUpdated(ORowSetValueVector::Vector &o_aCachedRow, const ORowSetValueVector::Vector &i_aRow) override
virtual void insertRow(const ORowSetRow &_rInsertRow, const connectivity::OSQLTable &_xTable) override
std::map< sal_Int32, sal_Int32 > m_aJoinedColumns
::connectivity::OSQLParseTreeIterator m_aSqlIterator
#define DBA_RES(id)
Reference< XSingleServiceFactory > xFactory
sal_uInt16 nPos
css::uno::Reference< css::sdbcx::XColumnsSupplier > OSQLTable
std::map< OUString, SelectColumnDescription, ::comphelper::UStringMixLess > SelectColumnsMetaData
Definition: KeySet.hxx:62
std::pair< ORowSetRow, std::pair< sal_Int32, css::uno::Reference< css::sdbc::XRow > > > OKeySetValue
Definition: KeySet.hxx:71
Reference
int i
Reference< XConnection > m_xConnection
Definition: objectnames.cxx:79
const char * columnName
constexpr OUStringLiteral SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
Definition: strings.hxx:201
void append(const OUString &lhs)