Bump version to 5.0-14
[LibreOffice.git] / dbaccess / source / core / api / OptimisticSet.cxx
blobf48c0b101d7a457166b8e47cd623960d547d7afb
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 "OptimisticSet.hxx"
22 #include "core_resource.hxx"
23 #include "core_resource.hrc"
24 #include <com/sun/star/beans/XPropertySet.hpp>
25 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
26 #include <com/sun/star/sdbc/ColumnValue.hpp>
27 #include <com/sun/star/sdbc/XPreparedStatement.hpp>
28 #include <com/sun/star/sdbc/XParameters.hpp>
29 #include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
30 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
31 #include <com/sun/star/sdb/SQLFilterOperator.hpp>
32 #include <com/sun/star/sdbc/XColumnLocate.hpp>
33 #include <com/sun/star/container/XIndexAccess.hpp>
34 #include "dbastrings.hrc"
35 #include "apitools.hxx"
36 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
37 #include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
38 #include <cppuhelper/typeprovider.hxx>
39 #include <comphelper/types.hxx>
40 #include <com/sun/star/sdbcx/KeyType.hpp>
41 #include <connectivity/dbtools.hxx>
42 #include <connectivity/dbexception.hxx>
43 #include <list>
44 #include <map>
45 #include <algorithm>
46 #include <string.h>
47 #include <com/sun/star/io/XInputStream.hpp>
48 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
49 #include "querycomposer.hxx"
50 #include "composertools.hxx"
51 #include <tools/debug.hxx>
53 using namespace dbaccess;
54 using namespace ::connectivity;
55 using namespace ::dbtools;
56 using namespace ::com::sun::star::uno;
57 using namespace ::com::sun::star::beans;
58 using namespace ::com::sun::star::sdbc;
59 using namespace ::com::sun::star::sdb;
60 using namespace ::com::sun::star::sdbcx;
61 using namespace ::com::sun::star::container;
62 using namespace ::com::sun::star::lang;
63 using namespace ::com::sun::star::util;
64 using namespace ::com::sun::star::io;
65 using namespace ::com::sun::star;
66 using namespace ::cppu;
67 using namespace ::osl;
69 typedef std::map<OUString, OUStringBuffer> TSQLStatements;
70 namespace
72 void lcl_fillKeyCondition(const OUString& i_sTableName,const OUString& i_sQuotedColumnName,const ORowSetValue& i_aValue,TSQLStatements& io_aKeyConditions)
74 OUStringBuffer& rKeyCondition = io_aKeyConditions[i_sTableName];
75 if ( !rKeyCondition.isEmpty() )
76 rKeyCondition.append(" AND ");
77 rKeyCondition.append(i_sQuotedColumnName);
78 if ( i_aValue.isNull() )
79 rKeyCondition.append(" IS NULL");
80 else
81 rKeyCondition.append(" = ?");
86 OptimisticSet::OptimisticSet(const Reference<XComponentContext>& _rContext,
87 const Reference< XConnection>& i_xConnection,
88 const Reference< XSingleSelectQueryAnalyzer >& _xComposer,
89 const ORowSetValueVector& _aParameterValueForCache,
90 sal_Int32 i_nMaxRows,
91 sal_Int32& o_nRowCount)
92 :OKeySet(NULL,NULL,OUString(),_xComposer,_aParameterValueForCache,i_nMaxRows,o_nRowCount)
93 ,m_aSqlParser( _rContext )
94 ,m_aSqlIterator( i_xConnection, Reference<XTablesSupplier>(_xComposer,UNO_QUERY)->getTables(), m_aSqlParser, NULL )
95 ,m_bResultSetChanged(false)
99 OptimisticSet::~OptimisticSet()
103 void OptimisticSet::construct(const Reference< XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter)
105 OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
107 initColumns();
108 m_sRowSetFilter = i_sRowSetFilter;
110 Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
111 bool bCase = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers();
112 Reference<XColumnsSupplier> xQueryColSup(m_xComposer,UNO_QUERY);
113 const Reference<XNameAccess> xQueryColumns = xQueryColSup->getColumns();
114 const Reference<XTablesSupplier> xTabSup(m_xComposer,UNO_QUERY);
115 const Reference<XNameAccess> xTables = xTabSup->getTables();
116 const Sequence< OUString> aTableNames = xTables->getElementNames();
117 const OUString* pTableNameIter = aTableNames.getConstArray();
118 const OUString* pTableNameEnd = pTableNameIter + aTableNames.getLength();
119 for( ; pTableNameIter != pTableNameEnd ; ++pTableNameIter)
121 ::std::unique_ptr<SelectColumnsMetaData> pKeyColumNames(new SelectColumnsMetaData(bCase));
122 findTableColumnsMatching_throw(xTables->getByName(*pTableNameIter),*pTableNameIter,xMeta,xQueryColumns,pKeyColumNames);
123 m_pKeyColumnNames->insert(pKeyColumNames->begin(),pKeyColumNames->end());
126 // the first row is empty because it's now easier for us to distinguish when we are beforefirst or first
127 // without extra variable to be set
128 OKeySetValue keySetValue((ORowSetValueVector *)NULL,::std::pair<sal_Int32,Reference<XRow> >(0,Reference<XRow>()));
129 m_aKeyMap.insert(OKeySetMatrix::value_type(0,keySetValue));
130 m_aKeyIter = m_aKeyMap.begin();
132 Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
133 Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
134 Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
135 OUString sQuery = xSourceComposer->getQuery();
136 xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
137 // check for joins
138 OUString aErrorMsg;
139 ::std::unique_ptr<OSQLParseNode> pStatementNode( m_aSqlParser.parseTree( aErrorMsg, sQuery ) );
140 m_aSqlIterator.setParseTree( pStatementNode.get() );
141 m_aSqlIterator.traverseAll();
142 fillJoinedColumns_throw(m_aSqlIterator.getJoinConditions());
146 void OptimisticSet::makeNewStatement( )
148 OUStringBuffer aFilter = createKeyFilter();
150 Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
151 Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
152 Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
153 xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
155 const OUString sComposerFilter = m_xComposer->getFilter();
156 if ( !m_sRowSetFilter.isEmpty() || !sComposerFilter.isEmpty() )
158 FilterCreator aFilterCreator;
159 if ( !sComposerFilter.isEmpty() && sComposerFilter != m_sRowSetFilter )
160 aFilterCreator.append( sComposerFilter );
161 aFilterCreator.append( m_sRowSetFilter );
162 aFilterCreator.append( aFilter.makeStringAndClear() );
163 aFilter = aFilterCreator.getComposedAndClear();
165 xAnalyzer->setFilter(aFilter.makeStringAndClear());
166 m_xStatement = m_xConnection->prepareStatement(xAnalyzer->getQueryWithSubstitution());
167 ::comphelper::disposeComponent(xAnalyzer);
170 // ::com::sun::star::sdbcx::XDeleteRows
171 Sequence< sal_Int32 > SAL_CALL OptimisticSet::deleteRows( const Sequence< Any >& /*rows*/ ,const connectivity::OSQLTable& /*_xTable*/) throw(SQLException, RuntimeException)
173 Sequence< sal_Int32 > aRet;
174 return aRet;
177 void SAL_CALL OptimisticSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException)
179 if ( m_aJoinedKeyColumns.empty() )
180 throw SQLException();
181 // list all columns that should be set
182 static const char s_sPara[] = " = ?";
183 OUString aQuote = getIdentifierQuoteString();
185 ::std::map< OUString,bool > aResultSetChanged;
186 TSQLStatements aKeyConditions;
187 TSQLStatements aSql;
189 // here we build the condition part for the update statement
190 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
191 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
192 for(;aIter != aEnd;++aIter)
194 if ( aResultSetChanged.find( aIter->second.sTableName ) == aResultSetChanged.end() )
195 aResultSetChanged[aIter->second.sTableName] = false;
196 const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aIter->second.sRealName);
197 if ( m_pKeyColumnNames->find(aIter->first) != m_pKeyColumnNames->end() )
199 aResultSetChanged[aIter->second.sTableName] = m_aJoinedKeyColumns.find(aIter->second.nPosition) != m_aJoinedKeyColumns.end();
200 lcl_fillKeyCondition(aIter->second.sTableName,sQuotedColumnName,(_rOriginalRow->get())[aIter->second.nPosition],aKeyConditions);
202 if((_rInsertRow->get())[aIter->second.nPosition].isModified())
204 if ( m_aJoinedKeyColumns.find(aIter->second.nPosition) != m_aJoinedKeyColumns.end() )
205 throw SQLException();
207 ::std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(aIter->second.nPosition);
208 if ( aJoinIter != m_aJoinedColumns.end() )
210 (_rInsertRow->get())[aJoinIter->second] = (_rInsertRow->get())[aIter->second.nPosition];
212 OUStringBuffer& rPart = aSql[aIter->second.sTableName];
213 if ( !rPart.isEmpty() )
214 rPart.append(", ");
215 rPart.append(sQuotedColumnName + s_sPara);
219 if( aSql.empty() )
220 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED ), SQL_GENERAL_ERROR, m_xConnection );
222 if( aKeyConditions.empty() )
223 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_CONDITION_FOR_PK ), SQL_GENERAL_ERROR, m_xConnection );
225 static const char s_sUPDATE[] = "UPDATE ";
226 static const char s_sSET[] = " SET ";
228 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
230 TSQLStatements::iterator aSqlIter = aSql.begin();
231 TSQLStatements::iterator aSqlEnd = aSql.end();
232 for(;aSqlIter != aSqlEnd ; ++aSqlIter)
234 if ( !aSqlIter->second.isEmpty() )
236 m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[aSqlIter->first];
237 OUString sCatalog,sSchema,sTable;
238 ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
239 OUStringBuffer sSql(s_sUPDATE + ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) +
240 s_sSET + aSqlIter->second.toString());
241 OUStringBuffer& rCondition = aKeyConditions[aSqlIter->first];
242 if ( !rCondition.isEmpty() )
243 sSql.append(" WHERE " + rCondition.toString() );
245 executeUpdate(_rInsertRow ,_rOriginalRow,sSql.makeStringAndClear(),aSqlIter->first);
250 void SAL_CALL OptimisticSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException)
252 TSQLStatements aSql;
253 TSQLStatements aParameter;
254 TSQLStatements aKeyConditions;
255 ::std::map< OUString,bool > aResultSetChanged;
256 OUString aQuote = getIdentifierQuoteString();
258 // here we build the condition part for the update statement
259 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
260 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
261 for(;aIter != aEnd;++aIter)
263 if ( aResultSetChanged.find( aIter->second.sTableName ) == aResultSetChanged.end() )
264 aResultSetChanged[aIter->second.sTableName] = false;
266 const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aIter->second.sRealName);
267 if ( (_rInsertRow->get())[aIter->second.nPosition].isModified() )
269 if ( m_aJoinedKeyColumns.find(aIter->second.nPosition) != m_aJoinedKeyColumns.end() )
271 lcl_fillKeyCondition(aIter->second.sTableName,sQuotedColumnName,(_rInsertRow->get())[aIter->second.nPosition],aKeyConditions);
272 aResultSetChanged[aIter->second.sTableName] = true;
274 ::std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(aIter->second.nPosition);
275 if ( aJoinIter != m_aJoinedColumns.end() )
277 (_rInsertRow->get())[aJoinIter->second] = (_rInsertRow->get())[aIter->second.nPosition];
279 OUStringBuffer& rPart = aSql[aIter->second.sTableName];
280 if ( !rPart.isEmpty() )
281 rPart.append(", ");
282 rPart.append(sQuotedColumnName);
283 OUStringBuffer& rParam = aParameter[aIter->second.sTableName];
284 if ( !rParam.isEmpty() )
285 rParam.append(", ");
286 rParam.append("?");
289 if ( aParameter.empty() )
290 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED ), SQL_GENERAL_ERROR, m_xConnection );
292 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
293 static const char s_sINSERT[] = "INSERT INTO ";
294 static const char s_sVALUES[] = ") VALUES ( ";
295 TSQLStatements::iterator aSqlIter = aSql.begin();
296 TSQLStatements::iterator aSqlEnd = aSql.end();
297 for(;aSqlIter != aSqlEnd ; ++aSqlIter)
299 if ( !aSqlIter->second.isEmpty() )
301 m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[aSqlIter->first];
302 OUString sCatalog,sSchema,sTable;
303 ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
304 OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
305 OUString sSql(s_sINSERT + sComposedTableName + " ( " + aSqlIter->second.toString() +
306 s_sVALUES + aParameter[aSqlIter->first].toString() + " )");
308 OUStringBuffer& rCondition = aKeyConditions[aSqlIter->first];
309 if ( !rCondition.isEmpty() )
311 OUString sQuery("SELECT " + aSqlIter->second.toString() + " FROM " + sComposedTableName +
312 " WHERE " + rCondition.toString());
316 Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery));
317 Reference< XParameters > xParameter(xPrep,UNO_QUERY);
318 // and then the values of the where condition
319 SelectColumnsMetaData::iterator aKeyCol = m_pKeyColumnNames->begin();
320 SelectColumnsMetaData::iterator aKeysEnd = m_pKeyColumnNames->end();
321 sal_Int32 i = 1;
322 for(;aKeyCol != aKeysEnd;++aKeyCol)
324 if ( aKeyCol->second.sTableName == aSqlIter->first )
326 setParameter(i++,xParameter,(_rInsertRow->get())[aKeyCol->second.nPosition],aKeyCol->second.nType,aKeyCol->second.nScale);
329 Reference<XResultSet> xRes = xPrep->executeQuery();
330 Reference<XRow> xRow(xRes,UNO_QUERY);
331 if ( xRow.is() && xRes->next() )
333 m_bResultSetChanged = true;
334 continue;
337 catch(const SQLException&)
342 executeInsert(_rInsertRow,sSql,aSqlIter->first);
347 void SAL_CALL OptimisticSet::deleteRow(const ORowSetRow& _rDeleteRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException)
349 OUString aQuote = getIdentifierQuoteString();
350 TSQLStatements aKeyConditions;
352 // here we build the condition part for the update statement
353 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
354 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
355 for(;aIter != aEnd;++aIter)
357 if ( m_aJoinedKeyColumns.find(aIter->second.nPosition) == m_aJoinedKeyColumns.end() && m_pKeyColumnNames->find(aIter->first) != m_pKeyColumnNames->end() )
359 // only delete rows which aren't the key in the join
360 const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aIter->second.sRealName);
361 lcl_fillKeyCondition(aIter->second.sTableName,sQuotedColumnName,(_rDeleteRow->get())[aIter->second.nPosition],aKeyConditions);
364 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
365 TSQLStatements::iterator aSqlIter = aKeyConditions.begin();
366 TSQLStatements::iterator aSqlEnd = aKeyConditions.end();
367 for(;aSqlIter != aSqlEnd ; ++aSqlIter)
369 OUStringBuffer& rCondition = aSqlIter->second;
370 if ( !rCondition.isEmpty() )
372 OUString sCatalog,sSchema,sTable;
373 ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
374 OUString sSql("DELETE FROM " + ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) +
375 " WHERE " + rCondition.toString() );
376 executeDelete(_rDeleteRow, sSql, aSqlIter->first);
381 void OptimisticSet::executeDelete(const ORowSetRow& _rDeleteRow,const OUString& i_sSQL,const OUString& i_sTableName)
383 // now create and execute the prepared statement
384 Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL));
385 Reference< XParameters > xParameter(xPrep,UNO_QUERY);
387 SelectColumnsMetaData::const_iterator aIter = m_pKeyColumnNames->begin();
388 SelectColumnsMetaData::const_iterator aEnd = m_pKeyColumnNames->end();
389 sal_Int32 i = 1;
390 for(;aIter != aEnd;++aIter)
392 if ( aIter->second.sTableName == i_sTableName )
393 setParameter(i++,xParameter,(_rDeleteRow->get())[aIter->second.nPosition],aIter->second.nType,aIter->second.nScale);
395 m_bDeleted = xPrep->executeUpdate() > 0;
397 if(m_bDeleted)
399 sal_Int32 nBookmark = ::comphelper::getINT32((_rDeleteRow->get())[0].getAny());
400 if(m_aKeyIter == m_aKeyMap.find(nBookmark) && m_aKeyIter != m_aKeyMap.end())
401 ++m_aKeyIter;
402 m_aKeyMap.erase(nBookmark);
403 m_bDeleted = true;
407 void OptimisticSet::fillJoinedColumns_throw(const ::std::vector< TNodePair >& i_aJoinColumns)
409 ::std::vector< TNodePair >::const_iterator aIter = i_aJoinColumns.begin();
410 for(;aIter != i_aJoinColumns.end();++aIter)
412 OUString sColumnName,sTableName;
413 m_aSqlIterator.getColumnRange(aIter->first,sColumnName,sTableName);
414 OUString sLeft(sTableName + "." + sColumnName);
415 m_aSqlIterator.getColumnRange(aIter->second,sColumnName,sTableName);
416 OUString sRight(sTableName + "." + sColumnName);
417 fillJoinedColumns_throw(sLeft, sRight);
421 void OptimisticSet::fillJoinedColumns_throw(const OUString& i_sLeftColumn,const OUString& i_sRightColumn)
423 sal_Int32 nLeft = 0,nRight = 0;
424 SelectColumnsMetaData::const_iterator aLeftIter = m_pKeyColumnNames->find(i_sLeftColumn);
425 SelectColumnsMetaData::const_iterator aRightIter = m_pKeyColumnNames->find(i_sRightColumn);
427 bool bLeftKey = aLeftIter != m_pKeyColumnNames->end();
428 if ( bLeftKey )
430 nLeft = aLeftIter->second.nPosition;
432 else
434 aLeftIter = m_pColumnNames->find(i_sLeftColumn);
435 if ( aLeftIter != m_pColumnNames->end() )
436 nLeft = aLeftIter->second.nPosition;
439 bool bRightKey = aRightIter != m_pKeyColumnNames->end();
440 if ( bRightKey )
442 nRight = aRightIter->second.nPosition;
444 else
446 aRightIter = m_pColumnNames->find(i_sRightColumn);
447 if ( aRightIter != m_pColumnNames->end() )
448 nRight = aRightIter->second.nPosition;
451 if (bLeftKey)
452 m_aJoinedKeyColumns[nLeft] = nRight;
453 else
454 m_aJoinedColumns[nLeft] = nRight;
455 if (bRightKey)
456 m_aJoinedKeyColumns[nRight] = nLeft;
457 else
458 m_aJoinedColumns[nRight] = nLeft;
461 bool OptimisticSet::isResultSetChanged() const
463 bool bOld = m_bResultSetChanged;
464 m_bResultSetChanged = false;
465 return bOld;
468 void OptimisticSet::mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& io_aInsertRow,ORowSetValueVector::Vector& io_aRow,::std::vector<sal_Int32>& o_aChangedColumns)
470 o_aChangedColumns.push_back(i_nColumnIndex);
471 ::std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(i_nColumnIndex);
472 if ( aJoinIter != m_aJoinedColumns.end() )
474 io_aRow[aJoinIter->second] = io_aRow[i_nColumnIndex];
475 io_aInsertRow[aJoinIter->second] = io_aInsertRow[i_nColumnIndex];
476 io_aRow[aJoinIter->second].setModified();
477 o_aChangedColumns.push_back(aJoinIter->second);
481 namespace
483 struct PositionFunctor : ::std::unary_function<SelectColumnsMetaData::value_type,bool>
485 sal_Int32 m_nPos;
486 PositionFunctor(sal_Int32 i_nPos)
487 : m_nPos(i_nPos)
491 inline bool operator()(const SelectColumnsMetaData::value_type& _aType)
493 return m_nPos == _aType.second.nPosition;
496 struct TableNameFunctor : ::std::unary_function<SelectColumnsMetaData::value_type,bool>
498 OUString m_sTableName;
499 TableNameFunctor(const OUString& i_sTableName)
500 : m_sTableName(i_sTableName)
504 inline bool operator()(const SelectColumnsMetaData::value_type& _aType)
506 return m_sTableName == _aType.second.sTableName;
511 bool OptimisticSet::updateColumnValues(const ORowSetValueVector::Vector& io_aCachedRow,ORowSetValueVector::Vector& io_aRow,const ::std::vector<sal_Int32>& i_aChangedColumns)
513 bool bRet = false;
514 ::std::vector<sal_Int32>::const_iterator aColIdxIter = i_aChangedColumns.begin();
515 for(;aColIdxIter != i_aChangedColumns.end();++aColIdxIter)
517 SelectColumnsMetaData::const_iterator aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),PositionFunctor(*aColIdxIter));
518 if ( aFind != m_pKeyColumnNames->end() )
520 const OUString sTableName = aFind->second.sTableName;
521 aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),TableNameFunctor(sTableName));
522 while( aFind != m_pKeyColumnNames->end() )
524 io_aRow[aFind->second.nPosition].setSigned(io_aCachedRow[aFind->second.nPosition].isSigned());
525 if ( io_aCachedRow[aFind->second.nPosition] != io_aRow[aFind->second.nPosition] )
526 break;
527 ++aFind;
529 if ( aFind == m_pKeyColumnNames->end() )
531 bRet = true;
532 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
533 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
534 for ( ;aIter != aEnd;++aIter )
536 if ( aIter->second.sTableName == sTableName )
538 io_aRow[aIter->second.nPosition] = io_aCachedRow[aIter->second.nPosition];
539 io_aRow[aIter->second.nPosition].setModified();
545 return bRet;
548 bool OptimisticSet::columnValuesUpdated(ORowSetValueVector::Vector& o_aCachedRow,const ORowSetValueVector::Vector& i_aRow)
550 bool bRet = false;
551 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
552 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
553 for(;aIter != aEnd;++aIter)
555 SelectColumnsMetaData::const_iterator aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),PositionFunctor(aIter->second.nPosition));
556 if ( aFind != m_pKeyColumnNames->end() )
558 const OUString sTableName = aFind->second.sTableName;
559 aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),TableNameFunctor(sTableName));
560 while( aFind != m_pKeyColumnNames->end() )
562 o_aCachedRow[aFind->second.nPosition].setSigned(i_aRow[aFind->second.nPosition].isSigned());
563 if ( o_aCachedRow[aFind->second.nPosition] != i_aRow[aFind->second.nPosition] )
564 break;
565 ++aFind;
567 if ( aFind == m_pKeyColumnNames->end() )
569 bRet = true;
570 SelectColumnsMetaData::const_iterator aIter2 = m_pColumnNames->begin();
571 SelectColumnsMetaData::const_iterator aEnd2 = m_pColumnNames->end();
572 for ( ;aIter2 != aEnd2;++aIter2 )
574 if ( aIter2->second.sTableName == sTableName )
576 o_aCachedRow[aIter2->second.nPosition] = i_aRow[aIter2->second.nPosition];
577 o_aCachedRow[aIter2->second.nPosition].setModified();
580 fillMissingValues(o_aCachedRow);
584 return bRet;
587 void OptimisticSet::fillMissingValues(ORowSetValueVector::Vector& io_aRow) const
589 TSQLStatements aSql;
590 TSQLStatements aKeyConditions;
591 ::std::map< OUString,bool > aResultSetChanged;
592 OUString aQuote = getIdentifierQuoteString();
593 // here we build the condition part for the update statement
594 SelectColumnsMetaData::const_iterator aColIter = m_pColumnNames->begin();
595 SelectColumnsMetaData::const_iterator aColEnd = m_pColumnNames->end();
596 for(;aColIter != aColEnd;++aColIter)
598 const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aColIter->second.sRealName);
599 if ( m_aJoinedKeyColumns.find(aColIter->second.nPosition) != m_aJoinedKeyColumns.end() )
601 lcl_fillKeyCondition(aColIter->second.sTableName,sQuotedColumnName,io_aRow[aColIter->second.nPosition],aKeyConditions);
603 OUStringBuffer& rPart = aSql[aColIter->second.sTableName];
604 if ( !rPart.isEmpty() )
605 rPart.append(", ");
606 rPart.append(sQuotedColumnName);
608 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
609 TSQLStatements::iterator aSqlIter = aSql.begin();
610 TSQLStatements::iterator aSqlEnd = aSql.end();
611 for(;aSqlIter != aSqlEnd ; ++aSqlIter)
613 if ( !aSqlIter->second.isEmpty() )
615 OUStringBuffer& rCondition = aKeyConditions[aSqlIter->first];
616 if ( !rCondition.isEmpty() )
618 OUString sCatalog,sSchema,sTable;
619 ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
620 OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
621 OUString sQuery("SELECT " + aSqlIter->second.toString() + " FROM " + sComposedTableName + " WHERE " +
622 rCondition.makeStringAndClear());
626 Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery));
627 Reference< XParameters > xParameter(xPrep,UNO_QUERY);
628 // and then the values of the where condition
629 SelectColumnsMetaData::iterator aKeyIter = m_pKeyColumnNames->begin();
630 SelectColumnsMetaData::iterator aKeyEnd = m_pKeyColumnNames->end();
631 sal_Int32 i = 1;
632 for(;aKeyIter != aKeyEnd;++aKeyIter)
634 if ( aKeyIter->second.sTableName == aSqlIter->first )
636 setParameter(i++,xParameter,io_aRow[aKeyIter->second.nPosition],aKeyIter->second.nType,aKeyIter->second.nScale);
639 Reference<XResultSet> xRes = xPrep->executeQuery();
640 Reference<XRow> xRow(xRes,UNO_QUERY);
641 if ( xRow.is() && xRes->next() )
643 i = 1;
644 aColIter = m_pColumnNames->begin();
645 for(;aColIter != aColEnd;++aColIter)
647 if ( aColIter->second.sTableName == aSqlIter->first )
649 io_aRow[aColIter->second.nPosition].fill(i++, aColIter->second.nType, xRow);
650 io_aRow[aColIter->second.nPosition].setModified();
655 catch(const SQLException&)
663 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */