1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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>
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
;
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");
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
,
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
);
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());
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
;
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() )
185 rPart
.append(sQuotedColumnName
+ " = ?");
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*/ )
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() )
244 rPart
.append(sQuotedColumnName
);
245 OUStringBuffer
& rParam
= aParameter
[columnName
.second
.sTableName
];
246 if ( !rParam
.isEmpty() )
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
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;
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
);
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;
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())
354 m_aKeyMap
.erase(nBookmark
);
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();
381 nLeft
= aLeftIter
->second
.nPosition
;
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();
393 nRight
= aRightIter
->second
.nPosition
;
397 aRightIter
= m_pColumnNames
->find(i_sRightColumn
);
398 if ( aRightIter
!= m_pColumnNames
->end() )
399 nRight
= aRightIter
->second
.nPosition
;
403 m_aJoinedKeyColumns
[nLeft
] = nRight
;
405 m_aJoinedColumns
[nLeft
] = nRight
;
407 m_aJoinedKeyColumns
[nRight
] = nLeft
;
409 m_aJoinedColumns
[nRight
] = nLeft
;
412 bool OptimisticSet::isResultSetChanged() const
414 bool bOld
= m_bResultSetChanged
;
415 m_bResultSetChanged
= false;
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
)
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(),
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
] )
455 if ( aFind
== m_pKeyColumnNames
->end() )
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);
472 bool OptimisticSet::columnValuesUpdated(ORowSetValueVector::Vector
& o_aCachedRow
,const ORowSetValueVector::Vector
& i_aRow
)
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(),
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
] )
496 if ( aFind
== m_pKeyColumnNames
->end() )
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
);
514 void OptimisticSet::fillMissingValues(ORowSetValueVector::Vector
& io_aRow
) const
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() )
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
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() )
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: */