23#include <core_resource.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>
37#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
53using namespace ::
cppu;
59 void lcl_fillKeyCondition(
const OUString& i_sTableName,std::u16string_view i_sQuotedColumnName,
const ORowSetValue& i_aValue,
TSQLStatements& io_aKeyConditions)
61 OUStringBuffer& rKeyCondition = io_aKeyConditions[i_sTableName];
62 if ( !rKeyCondition.isEmpty() )
63 rKeyCondition.append(
" AND ");
64 rKeyCondition.append(i_sQuotedColumnName);
66 rKeyCondition.append(
" IS NULL");
68 rKeyCondition.append(
" = ?");
73OptimisticSet::OptimisticSet(
const Reference<XComponentContext>& _rContext,
74 const Reference< XConnection>& i_xConnection,
75 const Reference< XSingleSelectQueryAnalyzer >& _xComposer,
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)
95 m_sRowSetFilter = i_sRowSetFilter;
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)
109 findTableColumnsMatching_throw(xTables->getByName(*pTableNameIter),*pTableNameIter,xMeta,xQueryColumns,pKeyColumNames);
110 m_pKeyColumnNames->insert(pKeyColumNames->begin(),pKeyColumNames->end());
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();
119 Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
122 OUString sQuery = xSourceComposer->getQuery();
123 xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
135 OUStringBuffer aFilter = createKeyFilter();
137 Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
140 xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
142 const OUString sComposerFilter = m_xComposer->getFilter();
143 if ( !m_sRowSetFilter.isEmpty() || !sComposerFilter.isEmpty() )
146 if ( !sComposerFilter.isEmpty() && sComposerFilter != m_sRowSetFilter )
147 aFilterCreator.
append( sComposerFilter );
148 aFilterCreator.
append( m_sRowSetFilter );
149 aFilterCreator.
append( aFilter.makeStringAndClear() );
152 xAnalyzer->setFilter(aFilter.makeStringAndClear());
153 m_xStatement =
m_xConnection->prepareStatement(xAnalyzer->getQueryWithSubstitution());
154 ::comphelper::disposeComponent(xAnalyzer);
160 throw SQLException();
162 OUString aQuote = getIdentifierQuoteString();
164 std::map< OUString,bool > aResultSetChanged;
169 for (
auto const&
columnName : *m_pColumnNames)
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() )
176 lcl_fillKeyCondition(
columnName.second.sTableName,sQuotedColumnName,(*_rOriginalRow)[
columnName.second.nPosition],aKeyConditions);
178 if((*_rInsertRow)[
columnName.second.nPosition].isModified())
181 throw SQLException();
186 (*_rInsertRow)[aJoinIter->second] = (*_rInsertRow)[
columnName.second.nPosition];
188 OUStringBuffer& rPart = aSql[
columnName.second.sTableName];
189 if ( !rPart.isEmpty() )
191 rPart.append(sQuotedColumnName +
" = ?");
196 ::dbtools::throwSQLException(
DBA_RES( RID_STR_NO_VALUE_CHANGED ), StandardSQLState::GENERAL_ERROR,
m_xConnection );
198 if( aKeyConditions.empty() )
199 ::dbtools::throwSQLException(
DBA_RES( RID_STR_NO_CONDITION_FOR_PK ), StandardSQLState::GENERAL_ERROR,
m_xConnection );
201 Reference<XDatabaseMetaData> xMetaData =
m_xConnection->getMetaData();
203 for (
auto const& elem : aSql)
205 if ( !elem.second.isEmpty() )
209 ::dbtools::qualifiedNameComponents(xMetaData,elem.first,
sCatalog,
sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
211 " SET " + elem.second);
212 OUStringBuffer& rCondition = aKeyConditions[elem.first];
213 if ( !rCondition.isEmpty() )
214 sSql.append(
" WHERE " + rCondition );
216 executeUpdate(_rInsertRow ,_rOriginalRow,sSql.makeStringAndClear(),elem.first);
226 std::map< OUString,bool > aResultSetChanged;
227 OUString aQuote = getIdentifierQuoteString();
230 for (
auto const&
columnName : *m_pColumnNames)
232 aResultSetChanged.try_emplace(
columnName.second.sTableName,
false);
234 const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,
columnName.second.sRealName);
235 if ( (*_rInsertRow)[
columnName.second.nPosition].isModified() )
239 lcl_fillKeyCondition(
columnName.second.sTableName,sQuotedColumnName,(*_rInsertRow)[
columnName.second.nPosition],aKeyConditions);
240 aResultSetChanged[
columnName.second.sTableName] =
true;
245 (*_rInsertRow)[aJoinIter->second] = (*_rInsertRow)[
columnName.second.nPosition];
247 OUStringBuffer& rPart = aSql[
columnName.second.sTableName];
248 if ( !rPart.isEmpty() )
250 rPart.append(sQuotedColumnName);
251 OUStringBuffer& rParam = aParameter[
columnName.second.sTableName];
252 if ( !rParam.isEmpty() )
257 if ( aParameter.empty() )
258 ::dbtools::throwSQLException(
DBA_RES( RID_STR_NO_VALUE_CHANGED ), StandardSQLState::GENERAL_ERROR,
m_xConnection );
260 Reference<XDatabaseMetaData> xMetaData =
m_xConnection->getMetaData();
261 for (
auto const& elem : aSql)
263 if ( !elem.second.isEmpty() )
267 ::dbtools::qualifiedNameComponents(xMetaData,elem.first,
sCatalog,
sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
269 OUString sSql(
"INSERT INTO " + sComposedTableName +
" ( " + elem.second +
270 ") VALUES ( " + aParameter[elem.first] +
" )");
272 OUStringBuffer& rCondition = aKeyConditions[elem.first];
273 if ( !rCondition.isEmpty() )
275 OUString sQuery(
"SELECT " + elem.second +
" FROM " + sComposedTableName +
276 " WHERE " + rCondition);
280 Reference< XPreparedStatement > xPrep(
m_xConnection->prepareStatement(sQuery));
281 Reference< XParameters > xParameter(xPrep,UNO_QUERY);
284 for (
auto const& keyColumnName : *m_pKeyColumnNames)
286 if ( keyColumnName.second.sTableName == elem.first )
288 setParameter(
i++,xParameter,(*_rInsertRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.second.nScale);
291 Reference<XResultSet> xRes = xPrep->executeQuery();
292 Reference<XRow> xRow(xRes,UNO_QUERY);
293 if ( xRow.is() && xRes->next() )
299 catch(
const SQLException&)
304 executeInsert(_rInsertRow,sSql,elem.first);
311 OUString aQuote = getIdentifierQuoteString();
315 for (
auto const&
columnName : *m_pColumnNames)
320 const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,
columnName.second.sRealName);
321 lcl_fillKeyCondition(
columnName.second.sTableName,sQuotedColumnName,(*_rDeleteRow)[
columnName.second.nPosition],aKeyConditions);
324 Reference<XDatabaseMetaData> xMetaData =
m_xConnection->getMetaData();
325 for (
auto & keyCondition : aKeyConditions)
327 OUStringBuffer& rCondition = keyCondition.second;
328 if ( !rCondition.isEmpty() )
331 ::dbtools::qualifiedNameComponents(xMetaData,keyCondition.first,
sCatalog,
sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
333 " WHERE " + rCondition );
342 Reference< XPreparedStatement > xPrep(
m_xConnection->prepareStatement(i_sSQL));
343 Reference< XParameters > xParameter(xPrep,UNO_QUERY);
346 for (
auto const& keyColumnName : *m_pKeyColumnNames)
348 if ( keyColumnName.second.sTableName == i_sTableName )
349 setParameter(
i++,xParameter,(*_rDeleteRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.second.nScale);
351 m_bDeleted = xPrep->executeUpdate() > 0;
355 sal_Int32 nBookmark = ::comphelper::getINT32((*_rDeleteRow)[0].getAny());
356 if(m_aKeyIter == m_aKeyMap.find(nBookmark) && m_aKeyIter != m_aKeyMap.end())
358 m_aKeyMap.erase(nBookmark);
365 for (
auto const& joinColumn : i_aJoinColumns)
367 OUString sColumnName,sTableName;
369 OUString sLeft(sTableName +
"." + sColumnName);
371 OUString sRight(sTableName +
"." + sColumnName);
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);
382 bool bLeftKey = aLeftIter != m_pKeyColumnNames->end();
385 nLeft = aLeftIter->second.nPosition;
389 aLeftIter = m_pColumnNames->find(i_sLeftColumn);
390 if ( aLeftIter != m_pColumnNames->end() )
391 nLeft = aLeftIter->second.nPosition;
394 bool bRightKey = aRightIter != m_pKeyColumnNames->end();
397 nRight = aRightIter->second.nPosition;
401 aRightIter = m_pColumnNames->find(i_sRightColumn);
402 if ( aRightIter != m_pColumnNames->end() )
403 nRight = aRightIter->second.nPosition;
425 o_aChangedColumns.push_back(i_nColumnIndex);
426 std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter =
m_aJoinedColumns.find(i_nColumnIndex);
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);
439 for(
const auto& aColIdx : i_aChangedColumns )
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() )
447 const OUString sTableName = aFind->second.sTableName;
448 aFind = std::find_if( m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
450 (
const SelectColumnsMetaData::value_type& rCurr )
451 { return rCurr.second.sTableName == sTableName; } );
452 while( aFind != m_pKeyColumnNames->end() )
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] )
459 if ( aFind == m_pKeyColumnNames->end() )
462 for(
const auto& aCol : *m_pColumnNames )
464 if ( aCol.second.sTableName == sTableName )
466 io_aRow[aCol.second.nPosition] = io_aCachedRow[aCol.second.nPosition];
467 io_aRow[aCol.second.nPosition].setModified(
true);
479 for(
const auto& aCol : *m_pColumnNames )
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() )
488 const OUString sTableName = aFind->second.sTableName;
489 aFind = std::find_if( m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
491 (
const SelectColumnsMetaData::value_type& rCurr )
492 { return rCurr.second.sTableName == sTableName; } );
493 while( aFind != m_pKeyColumnNames->end() )
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] )
500 if ( aFind == m_pKeyColumnNames->end() )
503 for(
const auto& aCol2 : *m_pColumnNames )
505 if ( aCol2.second.sTableName == sTableName )
507 o_aCachedRow[aCol2.second.nPosition] = i_aRow[aCol2.second.nPosition];
508 o_aCachedRow[aCol2.second.nPosition].setModified(
true);
522 OUString aQuote = getIdentifierQuoteString();
524 for (
auto const&
columnName : *m_pColumnNames)
526 const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,
columnName.second.sRealName);
529 lcl_fillKeyCondition(
columnName.second.sTableName,sQuotedColumnName,io_aRow[
columnName.second.nPosition],aKeyConditions);
531 OUStringBuffer& rPart = aSql[
columnName.second.sTableName];
532 if ( !rPart.isEmpty() )
534 rPart.append(sQuotedColumnName);
536 Reference<XDatabaseMetaData> xMetaData =
m_xConnection->getMetaData();
537 for (
auto const& elem : aSql)
539 if ( !elem.second.isEmpty() )
541 OUStringBuffer& rCondition = aKeyConditions[elem.first];
542 if ( !rCondition.isEmpty() )
545 ::dbtools::qualifiedNameComponents(xMetaData,elem.first,
sCatalog,
sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
547 OUString sQuery(
"SELECT " + elem.second +
" FROM " + sComposedTableName +
" WHERE " + rCondition);
548 rCondition.setLength(0);
552 Reference< XPreparedStatement > xPrep(
m_xConnection->prepareStatement(sQuery));
553 Reference< XParameters > xParameter(xPrep,UNO_QUERY);
556 for (
auto const& keyColumn : *m_pKeyColumnNames)
558 if ( keyColumn.second.sTableName == elem.first )
560 setParameter(
i++,xParameter,io_aRow[keyColumn.second.nPosition],keyColumn.second.nType,keyColumn.second.nScale);
563 Reference<XResultSet> xRes = xPrep->executeQuery();
564 Reference<XRow> xRow(xRes,UNO_QUERY);
565 if ( xRow.is() && xRes->next() )
568 for (
auto const&
columnName : *m_pColumnNames)
570 if (
columnName.second.sTableName == elem.first )
573 io_aRow[
columnName.second.nPosition].setModified(
true);
578 catch(
const SQLException&)
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)
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
Reference< XSingleServiceFactory > xFactory
css::uno::Reference< css::sdbcx::XColumnsSupplier > OSQLTable
std::map< OUString, SelectColumnDescription, ::comphelper::UStringMixLess > SelectColumnsMetaData
std::pair< ORowSetRow, std::pair< sal_Int32, css::uno::Reference< css::sdbc::XRow > > > OKeySetValue
Reference< XConnection > m_xConnection
constexpr OUStringLiteral SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
OUString getComposedAndClear()
void append(const OUString &lhs)