Version 4.0.0.1, tag libreoffice-4.0.0.1
[LibreOffice.git] / dbaccess / source / core / api / OptimisticSet.cxx
blobca6f1b59cf332c0d20bd7ac1f334ed859b4f8716
2 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4 * This file is part of the LibreOffice project.
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 * This file incorporates work covered by the following license notice:
12 * Licensed to the Apache Software Foundation (ASF) under one or more
13 * contributor license agreements. See the NOTICE file distributed
14 * with this work for additional information regarding copyright
15 * ownership. The ASF licenses this file to you under the Apache
16 * License, Version 2.0 (the "License"); you may not use this file
17 * except in compliance with the License. You may obtain a copy of
18 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include "OptimisticSet.hxx"
23 #include "core_resource.hxx"
24 #include "core_resource.hrc"
25 #include <com/sun/star/beans/XPropertySet.hpp>
26 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
27 #include <com/sun/star/sdbc/ColumnValue.hpp>
28 #include <com/sun/star/sdbc/XPreparedStatement.hpp>
29 #include <com/sun/star/sdbc/XParameters.hpp>
30 #include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
31 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
32 #include <com/sun/star/sdb/SQLFilterOperator.hpp>
33 #include <com/sun/star/sdbc/XColumnLocate.hpp>
34 #include <com/sun/star/container/XIndexAccess.hpp>
35 #include "dbastrings.hrc"
36 #include "apitools.hxx"
37 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
38 #include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
39 #include <cppuhelper/typeprovider.hxx>
40 #include <comphelper/types.hxx>
41 #include <com/sun/star/sdbcx/KeyType.hpp>
42 #include <connectivity/dbtools.hxx>
43 #include <connectivity/dbexception.hxx>
44 #include <list>
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>
52 #include <rtl/logfile.hxx>
54 using namespace dbaccess;
55 using namespace ::connectivity;
56 using namespace ::dbtools;
57 using namespace ::com::sun::star::uno;
58 using namespace ::com::sun::star::beans;
59 using namespace ::com::sun::star::sdbc;
60 using namespace ::com::sun::star::sdb;
61 using namespace ::com::sun::star::sdbcx;
62 using namespace ::com::sun::star::container;
63 using namespace ::com::sun::star::lang;
64 using namespace ::com::sun::star::util;
65 using namespace ::com::sun::star::io;
66 using namespace ::com::sun::star;
67 using namespace ::cppu;
68 using namespace ::osl;
70 DECLARE_STL_USTRINGACCESS_MAP(::rtl::OUStringBuffer,TSQLStatements);
71 namespace
73 void lcl_fillKeyCondition(const ::rtl::OUString& i_sTableName,const ::rtl::OUString& i_sQuotedColumnName,const ORowSetValue& i_aValue,TSQLStatements& io_aKeyConditions)
75 ::rtl::OUStringBuffer& rKeyCondition = io_aKeyConditions[i_sTableName];
76 if ( rKeyCondition.getLength() )
77 rKeyCondition.appendAscii(" AND ");
78 rKeyCondition.append(i_sQuotedColumnName);
79 if ( i_aValue.isNull() )
80 rKeyCondition.appendAscii(" IS NULL");
81 else
82 rKeyCondition.appendAscii(" = ?");
86 DBG_NAME(OptimisticSet)
88 OptimisticSet::OptimisticSet(const ::comphelper::ComponentContext& _rContext,
89 const Reference< XConnection>& i_xConnection,
90 const Reference< XSingleSelectQueryAnalyzer >& _xComposer,
91 const ORowSetValueVector& _aParameterValueForCache,
92 sal_Int32 i_nMaxRows,
93 sal_Int32& o_nRowCount)
94 :OKeySet(NULL,NULL,::rtl::OUString(),_xComposer,_aParameterValueForCache,i_nMaxRows,o_nRowCount)
95 ,m_aSqlParser( _rContext.getUNOContext() )
96 ,m_aSqlIterator( i_xConnection, Reference<XTablesSupplier>(_xComposer,UNO_QUERY)->getTables(), m_aSqlParser, NULL )
97 ,m_bResultSetChanged(false)
99 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::OptimisticSet" );
100 DBG_CTOR(OptimisticSet,NULL);
103 OptimisticSet::~OptimisticSet()
105 DBG_DTOR(OptimisticSet,NULL);
108 void OptimisticSet::construct(const Reference< XResultSet>& _xDriverSet,const ::rtl::OUString& i_sRowSetFilter)
110 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::construct" );
111 OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
112 initColumns();
114 Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
115 bool bCase = (xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers()) ? true : false;
116 Reference<XColumnsSupplier> xQueryColSup(m_xComposer,UNO_QUERY);
117 const Reference<XNameAccess> xQueryColumns = xQueryColSup->getColumns();
118 const Reference<XTablesSupplier> xTabSup(m_xComposer,UNO_QUERY);
119 const Reference<XNameAccess> xTables = xTabSup->getTables();
120 const Sequence< ::rtl::OUString> aTableNames = xTables->getElementNames();
121 const ::rtl::OUString* pTableNameIter = aTableNames.getConstArray();
122 const ::rtl::OUString* pTableNameEnd = pTableNameIter + aTableNames.getLength();
123 for( ; pTableNameIter != pTableNameEnd ; ++pTableNameIter)
125 SAL_WNODEPRECATED_DECLARATIONS_PUSH
126 ::std::auto_ptr<SelectColumnsMetaData> pKeyColumNames(new SelectColumnsMetaData(bCase));
127 SAL_WNODEPRECATED_DECLARATIONS_POP
128 findTableColumnsMatching_throw(xTables->getByName(*pTableNameIter),*pTableNameIter,xMeta,xQueryColumns,pKeyColumNames);
129 m_pKeyColumnNames->insert(pKeyColumNames->begin(),pKeyColumNames->end());
132 // the first row is empty because it's now easier for us to distinguish when we are beforefirst or first
133 // without extra variable to be set
134 OKeySetValue keySetValue((ORowSetValueVector *)NULL,::std::pair<sal_Int32,Reference<XRow> >(0,(Reference<XRow>)NULL));
135 m_aKeyMap.insert(OKeySetMatrix::value_type(0,keySetValue));
136 m_aKeyIter = m_aKeyMap.begin();
138 ::rtl::OUStringBuffer aFilter = createKeyFilter();
140 Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
141 Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
142 Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
143 ::rtl::OUString sQuery = xSourceComposer->getQuery();
144 xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
145 // check for joins
146 ::rtl::OUString aErrorMsg;
147 SAL_WNODEPRECATED_DECLARATIONS_PUSH
148 ::std::auto_ptr<OSQLParseNode> pStatementNode( m_aSqlParser.parseTree( aErrorMsg, sQuery ) );
149 SAL_WNODEPRECATED_DECLARATIONS_POP
150 m_aSqlIterator.setParseTree( pStatementNode.get() );
151 m_aSqlIterator.traverseAll();
152 fillJoinedColumns_throw(m_aSqlIterator.getJoinConditions());
154 const ::rtl::OUString sComposerFilter = m_xComposer->getFilter();
155 if ( !i_sRowSetFilter.isEmpty() || (!sComposerFilter.isEmpty() && sComposerFilter != i_sRowSetFilter) )
157 FilterCreator aFilterCreator;
158 if ( !sComposerFilter.isEmpty() && sComposerFilter != i_sRowSetFilter )
159 aFilterCreator.append( sComposerFilter );
160 aFilterCreator.append( i_sRowSetFilter );
161 aFilterCreator.append( aFilter.makeStringAndClear() );
162 aFilter = aFilterCreator.getComposedAndClear();
164 xAnalyzer->setFilter(aFilter.makeStringAndClear());
165 m_xStatement = m_xConnection->prepareStatement(xAnalyzer->getQueryWithSubstitution());
166 ::comphelper::disposeComponent(xAnalyzer);
169 // ::com::sun::star::sdbcx::XDeleteRows
170 Sequence< sal_Int32 > SAL_CALL OptimisticSet::deleteRows( const Sequence< Any >& /*rows*/ ,const connectivity::OSQLTable& /*_xTable*/) throw(SQLException, RuntimeException)
172 Sequence< sal_Int32 > aRet;
173 return aRet;
176 void SAL_CALL OptimisticSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOrginalRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException)
178 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::updateRow" );
179 if ( m_aJoinedKeyColumns.empty() )
180 throw SQLException();
181 // list all cloumns that should be set
182 static ::rtl::OUString s_sPara(" = ?");
183 ::rtl::OUString aQuote = getIdentifierQuoteString();
185 ::rtl::OUString aColumnName;
186 ::rtl::OUStringBuffer sKeyCondition;
187 ::std::map< ::rtl::OUString,bool > aResultSetChanged;
188 TSQLStatements aKeyConditions;
189 TSQLStatements aIndexConditions;
190 TSQLStatements aSql;
192 // here we build the condition part for the update statement
193 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
194 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
195 for(;aIter != aEnd;++aIter)
197 if ( aResultSetChanged.find( aIter->second.sTableName ) == aResultSetChanged.end() )
198 aResultSetChanged[aIter->second.sTableName] = false;
199 const ::rtl::OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aIter->second.sRealName);
200 if ( m_pKeyColumnNames->find(aIter->first) != m_pKeyColumnNames->end() )
202 aResultSetChanged[aIter->second.sTableName] = m_aJoinedKeyColumns.find(aIter->second.nPosition) != m_aJoinedKeyColumns.end();
203 lcl_fillKeyCondition(aIter->second.sTableName,sQuotedColumnName,(_rOrginalRow->get())[aIter->second.nPosition],aKeyConditions);
205 if((_rInsertRow->get())[aIter->second.nPosition].isModified())
207 if ( m_aJoinedKeyColumns.find(aIter->second.nPosition) != m_aJoinedKeyColumns.end() )
208 throw SQLException();
210 ::std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(aIter->second.nPosition);
211 if ( aJoinIter != m_aJoinedColumns.end() )
213 (_rInsertRow->get())[aJoinIter->second] = (_rInsertRow->get())[aIter->second.nPosition];
215 ::rtl::OUStringBuffer& rPart = aSql[aIter->second.sTableName];
216 if ( rPart.getLength() )
217 rPart.appendAscii(", ");
218 rPart.append(sQuotedColumnName);
219 rPart.append(s_sPara);
223 if( aSql.empty() )
224 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED ), SQL_GENERAL_ERROR, m_xConnection );
226 if( aKeyConditions.empty() )
227 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_CONDITION_FOR_PK ), SQL_GENERAL_ERROR, m_xConnection );
229 static const ::rtl::OUString s_sUPDATE("UPDATE ");
230 static const ::rtl::OUString s_sSET(" SET ");
232 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
234 TSQLStatements::iterator aSqlIter = aSql.begin();
235 TSQLStatements::iterator aSqlEnd = aSql.end();
236 for(;aSqlIter != aSqlEnd ; ++aSqlIter)
238 if ( aSqlIter->second.getLength() )
240 m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[aSqlIter->first];
241 ::rtl::OUStringBuffer sSql(s_sUPDATE);
242 ::rtl::OUString sCatalog,sSchema,sTable;
243 ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
244 sSql.append( ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) );
245 sSql.append(s_sSET);
246 sSql.append(aSqlIter->second.toString());
247 ::rtl::OUStringBuffer& rCondition = aKeyConditions[aSqlIter->first];
248 if ( rCondition.getLength() )
250 sSql.appendAscii(" WHERE ");
251 sSql.append( rCondition.toString() );
253 executeUpdate(_rInsertRow ,_rOrginalRow,sSql.makeStringAndClear(),aSqlIter->first);
258 void SAL_CALL OptimisticSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException)
260 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::insertRow" );
261 TSQLStatements aSql;
262 TSQLStatements aParameter;
263 TSQLStatements aKeyConditions;
264 ::std::map< ::rtl::OUString,bool > aResultSetChanged;
265 ::rtl::OUString aQuote = getIdentifierQuoteString();
267 // here we build the condition part for the update statement
268 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
269 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
270 for(;aIter != aEnd;++aIter)
272 if ( aResultSetChanged.find( aIter->second.sTableName ) == aResultSetChanged.end() )
273 aResultSetChanged[aIter->second.sTableName] = false;
275 const ::rtl::OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aIter->second.sRealName);
276 if ( (_rInsertRow->get())[aIter->second.nPosition].isModified() )
278 if ( m_aJoinedKeyColumns.find(aIter->second.nPosition) != m_aJoinedKeyColumns.end() )
280 lcl_fillKeyCondition(aIter->second.sTableName,sQuotedColumnName,(_rInsertRow->get())[aIter->second.nPosition],aKeyConditions);
281 aResultSetChanged[aIter->second.sTableName] = true;
283 ::std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(aIter->second.nPosition);
284 if ( aJoinIter != m_aJoinedColumns.end() )
286 (_rInsertRow->get())[aJoinIter->second] = (_rInsertRow->get())[aIter->second.nPosition];
288 ::rtl::OUStringBuffer& rPart = aSql[aIter->second.sTableName];
289 if ( rPart.getLength() )
290 rPart.appendAscii(", ");
291 rPart.append(sQuotedColumnName);
292 ::rtl::OUStringBuffer& rParam = aParameter[aIter->second.sTableName];
293 if ( rParam.getLength() )
294 rParam.appendAscii(", ");
295 rParam.appendAscii("?");
298 if ( aParameter.empty() )
299 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED ), SQL_GENERAL_ERROR, m_xConnection );
301 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
302 static const ::rtl::OUString s_sINSERT("INSERT INTO ");
303 static const ::rtl::OUString s_sVALUES(") VALUES ( ");
304 TSQLStatements::iterator aSqlIter = aSql.begin();
305 TSQLStatements::iterator aSqlEnd = aSql.end();
306 for(;aSqlIter != aSqlEnd ; ++aSqlIter)
308 if ( aSqlIter->second.getLength() )
310 m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[aSqlIter->first];
311 ::rtl::OUStringBuffer sSql(s_sINSERT);
312 ::rtl::OUString sCatalog,sSchema,sTable;
313 ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
314 ::rtl::OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
315 sSql.append(sComposedTableName);
316 sSql.appendAscii(" ( ");
317 sSql.append(aSqlIter->second.toString());
318 sSql.append(s_sVALUES);
319 sSql.append(aParameter[aSqlIter->first].toString());
320 sSql.appendAscii(" )");
322 ::rtl::OUStringBuffer& rCondition = aKeyConditions[aSqlIter->first];
323 if ( rCondition.getLength() )
325 ::rtl::OUStringBuffer sQuery;
326 sQuery.appendAscii("SELECT ");
327 sQuery.append(aSqlIter->second.toString());
328 sQuery.appendAscii(" FROM ");
329 sQuery.append(sComposedTableName);
330 sQuery.appendAscii(" WHERE ");
331 sQuery.append(rCondition.toString());
335 Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery.makeStringAndClear()));
336 Reference< XParameters > xParameter(xPrep,UNO_QUERY);
337 // and then the values of the where condition
338 SelectColumnsMetaData::iterator aKeyCol = m_pKeyColumnNames->begin();
339 SelectColumnsMetaData::iterator aKeysEnd = m_pKeyColumnNames->end();
340 sal_Int32 i = 1;
341 for(;aKeyCol != aKeysEnd;++aKeyCol)
343 if ( aKeyCol->second.sTableName == aSqlIter->first )
345 setParameter(i++,xParameter,(_rInsertRow->get())[aKeyCol->second.nPosition],aKeyCol->second.nType,aKeyCol->second.nScale);
348 Reference<XResultSet> xRes = xPrep->executeQuery();
349 Reference<XRow> xRow(xRes,UNO_QUERY);
350 if ( xRow.is() && xRes->next() )
352 m_bResultSetChanged = true;
353 continue;
356 catch(const SQLException&)
361 executeInsert(_rInsertRow,sSql.makeStringAndClear(),aSqlIter->first);
366 void SAL_CALL OptimisticSet::deleteRow(const ORowSetRow& _rDeleteRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException)
368 ::rtl::OUString aQuote = getIdentifierQuoteString();
369 ::rtl::OUString aColumnName;
370 ::rtl::OUStringBuffer sKeyCondition,sIndexCondition;
371 ::std::vector<sal_Int32> aIndexColumnPositions;
372 TSQLStatements aKeyConditions;
373 TSQLStatements aIndexConditions;
374 TSQLStatements aSql;
376 // here we build the condition part for the update statement
377 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
378 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
379 for(;aIter != aEnd;++aIter)
381 if ( m_aJoinedKeyColumns.find(aIter->second.nPosition) == m_aJoinedKeyColumns.end() && m_pKeyColumnNames->find(aIter->first) != m_pKeyColumnNames->end() )
383 // only delete rows which aren't the key in the join
384 const ::rtl::OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aIter->second.sRealName);
385 lcl_fillKeyCondition(aIter->second.sTableName,sQuotedColumnName,(_rDeleteRow->get())[aIter->second.nPosition],aKeyConditions);
388 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
389 TSQLStatements::iterator aSqlIter = aKeyConditions.begin();
390 TSQLStatements::iterator aSqlEnd = aKeyConditions.end();
391 for(;aSqlIter != aSqlEnd ; ++aSqlIter)
393 ::rtl::OUStringBuffer& rCondition = aSqlIter->second;
394 if ( rCondition.getLength() )
396 ::rtl::OUStringBuffer sSql;
397 sSql.appendAscii("DELETE FROM ");
398 ::rtl::OUString sCatalog,sSchema,sTable;
399 ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
400 sSql.append( ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) );
401 sSql.appendAscii(" WHERE ");
402 sSql.append( rCondition.toString() );
403 executeDelete(_rDeleteRow,sSql.makeStringAndClear(),aSqlIter->first);
408 void OptimisticSet::executeDelete(const ORowSetRow& _rDeleteRow,const ::rtl::OUString& i_sSQL,const ::rtl::OUString& i_sTableName)
410 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::executeDelete" );
412 // now create and execute the prepared statement
413 Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL));
414 Reference< XParameters > xParameter(xPrep,UNO_QUERY);
416 SelectColumnsMetaData::const_iterator aIter = m_pKeyColumnNames->begin();
417 SelectColumnsMetaData::const_iterator aEnd = m_pKeyColumnNames->end();
418 sal_Int32 i = 1;
419 for(;aIter != aEnd;++aIter)
421 if ( aIter->second.sTableName == i_sTableName )
422 setParameter(i++,xParameter,(_rDeleteRow->get())[aIter->second.nPosition],aIter->second.nType,aIter->second.nScale);
424 m_bDeleted = xPrep->executeUpdate() > 0;
426 if(m_bDeleted)
428 sal_Int32 nBookmark = ::comphelper::getINT32((_rDeleteRow->get())[0].getAny());
429 if(m_aKeyIter == m_aKeyMap.find(nBookmark) && m_aKeyIter != m_aKeyMap.end())
430 ++m_aKeyIter;
431 m_aKeyMap.erase(nBookmark);
432 m_bDeleted = sal_True;
436 void OptimisticSet::fillJoinedColumns_throw(const ::std::vector< TNodePair >& i_aJoinColumns)
438 ::std::vector< TNodePair >::const_iterator aIter = i_aJoinColumns.begin();
439 for(;aIter != i_aJoinColumns.end();++aIter)
441 ::rtl::OUString sColumnName,sTableName;
442 m_aSqlIterator.getColumnRange(aIter->first,sColumnName,sTableName);
443 ::rtl::OUStringBuffer sLeft,sRight;
444 sLeft.append(sTableName);
445 sLeft.appendAscii(".");
446 sLeft.append(sColumnName);
447 m_aSqlIterator.getColumnRange(aIter->second,sColumnName,sTableName);
448 sRight.append(sTableName);
449 sRight.appendAscii(".");
450 sRight.append(sColumnName);
451 fillJoinedColumns_throw(sLeft.makeStringAndClear(),sRight.makeStringAndClear());
455 void OptimisticSet::fillJoinedColumns_throw(const ::rtl::OUString& i_sLeftColumn,const ::rtl::OUString& i_sRightColumn)
457 sal_Int32 nLeft = 0,nRight = 0;
458 SelectColumnsMetaData::const_iterator aLeftIter = m_pKeyColumnNames->find(i_sLeftColumn);
459 SelectColumnsMetaData::const_iterator aRightIter = m_pKeyColumnNames->find(i_sRightColumn);
461 bool bLeftKey = aLeftIter != m_pKeyColumnNames->end();
462 if ( bLeftKey )
464 nLeft = aLeftIter->second.nPosition;
466 else
468 aLeftIter = m_pColumnNames->find(i_sLeftColumn);
469 if ( aLeftIter != m_pColumnNames->end() )
470 nLeft = aLeftIter->second.nPosition;
473 bool bRightKey = aRightIter != m_pKeyColumnNames->end();
474 if ( bRightKey )
476 nRight = aRightIter->second.nPosition;
478 else
480 aRightIter = m_pColumnNames->find(i_sRightColumn);
481 if ( aRightIter != m_pColumnNames->end() )
482 nRight = aRightIter->second.nPosition;
485 if (bLeftKey)
486 m_aJoinedKeyColumns[nLeft] = nRight;
487 else
488 m_aJoinedColumns[nLeft] = nRight;
489 if (bRightKey)
490 m_aJoinedKeyColumns[nRight] = nLeft;
491 else
492 m_aJoinedColumns[nRight] = nLeft;
495 bool OptimisticSet::isResultSetChanged() const
497 bool bOld = m_bResultSetChanged;
498 m_bResultSetChanged = false;
499 return bOld;
502 void OptimisticSet::reset(const Reference< XResultSet>& _xDriverSet)
504 OCacheSet::construct(_xDriverSet,::rtl::OUString());
505 m_bRowCountFinal = sal_False;
506 m_aKeyMap.clear();
507 OKeySetValue keySetValue((ORowSetValueVector *)NULL,::std::pair<sal_Int32,Reference<XRow> >(0,(Reference<XRow>)NULL));
508 m_aKeyMap.insert(OKeySetMatrix::value_type(0,keySetValue));
509 m_aKeyIter = m_aKeyMap.begin();
512 void OptimisticSet::mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& io_aInsertRow,ORowSetValueVector::Vector& io_aRow,::std::vector<sal_Int32>& o_aChangedColumns)
514 o_aChangedColumns.push_back(i_nColumnIndex);
515 ::std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(i_nColumnIndex);
516 if ( aJoinIter != m_aJoinedColumns.end() )
518 io_aRow[aJoinIter->second] = io_aRow[i_nColumnIndex];
519 io_aInsertRow[aJoinIter->second] = io_aInsertRow[i_nColumnIndex];
520 io_aRow[aJoinIter->second].setModified();
521 o_aChangedColumns.push_back(aJoinIter->second);
524 namespace
526 struct PositionFunctor : ::std::unary_function<SelectColumnsMetaData::value_type,bool>
528 sal_Int32 m_nPos;
529 PositionFunctor(sal_Int32 i_nPos)
530 : m_nPos(i_nPos)
534 inline bool operator()(const SelectColumnsMetaData::value_type& _aType)
536 return m_nPos == _aType.second.nPosition;
539 struct TableNameFunctor : ::std::unary_function<SelectColumnsMetaData::value_type,bool>
541 ::rtl::OUString m_sTableName;
542 TableNameFunctor(const ::rtl::OUString& i_sTableName)
543 : m_sTableName(i_sTableName)
547 inline bool operator()(const SelectColumnsMetaData::value_type& _aType)
549 return m_sTableName == _aType.second.sTableName;
554 bool OptimisticSet::updateColumnValues(const ORowSetValueVector::Vector& io_aCachedRow,ORowSetValueVector::Vector& io_aRow,const ::std::vector<sal_Int32>& i_aChangedColumns)
556 bool bRet = false;
557 ::std::vector<sal_Int32>::const_iterator aColIdxIter = i_aChangedColumns.begin();
558 for(;aColIdxIter != i_aChangedColumns.end();++aColIdxIter)
560 SelectColumnsMetaData::const_iterator aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),PositionFunctor(*aColIdxIter));
561 if ( aFind != m_pKeyColumnNames->end() )
563 const ::rtl::OUString sTableName = aFind->second.sTableName;
564 aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),TableNameFunctor(sTableName));
565 while( aFind != m_pKeyColumnNames->end() )
567 io_aRow[aFind->second.nPosition].setSigned(io_aCachedRow[aFind->second.nPosition].isSigned());
568 if ( io_aCachedRow[aFind->second.nPosition] != io_aRow[aFind->second.nPosition] )
569 break;
570 ++aFind;
572 if ( aFind == m_pKeyColumnNames->end() )
574 bRet = true;
575 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
576 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
577 for ( ;aIter != aEnd;++aIter )
579 if ( aIter->second.sTableName == sTableName )
581 io_aRow[aIter->second.nPosition] = io_aCachedRow[aIter->second.nPosition];
582 io_aRow[aIter->second.nPosition].setModified();
588 return bRet;
591 bool OptimisticSet::columnValuesUpdated(ORowSetValueVector::Vector& o_aCachedRow,const ORowSetValueVector::Vector& i_aRow)
593 bool bRet = false;
594 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
595 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
596 for(;aIter != aEnd;++aIter)
598 SelectColumnsMetaData::const_iterator aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),PositionFunctor(aIter->second.nPosition));
599 if ( aFind != m_pKeyColumnNames->end() )
601 const ::rtl::OUString sTableName = aFind->second.sTableName;
602 aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),TableNameFunctor(sTableName));
603 while( aFind != m_pKeyColumnNames->end() )
605 o_aCachedRow[aFind->second.nPosition].setSigned(i_aRow[aFind->second.nPosition].isSigned());
606 if ( o_aCachedRow[aFind->second.nPosition] != i_aRow[aFind->second.nPosition] )
607 break;
608 ++aFind;
610 if ( aFind == m_pKeyColumnNames->end() )
612 bRet = true;
613 SelectColumnsMetaData::const_iterator aIter2 = m_pColumnNames->begin();
614 SelectColumnsMetaData::const_iterator aEnd2 = m_pColumnNames->end();
615 for ( ;aIter2 != aEnd2;++aIter2 )
617 if ( aIter2->second.sTableName == sTableName )
619 o_aCachedRow[aIter2->second.nPosition] = i_aRow[aIter2->second.nPosition];
620 o_aCachedRow[aIter2->second.nPosition].setModified();
623 fillMissingValues(o_aCachedRow);
627 return bRet;
630 void OptimisticSet::fillMissingValues(ORowSetValueVector::Vector& io_aRow) const
632 TSQLStatements aSql;
633 TSQLStatements aKeyConditions;
634 ::std::map< ::rtl::OUString,bool > aResultSetChanged;
635 ::rtl::OUString aQuote = getIdentifierQuoteString();
636 // here we build the condition part for the update statement
637 SelectColumnsMetaData::const_iterator aColIter = m_pColumnNames->begin();
638 SelectColumnsMetaData::const_iterator aColEnd = m_pColumnNames->end();
639 for(;aColIter != aColEnd;++aColIter)
641 const ::rtl::OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aColIter->second.sRealName);
642 if ( m_aJoinedKeyColumns.find(aColIter->second.nPosition) != m_aJoinedKeyColumns.end() )
644 lcl_fillKeyCondition(aColIter->second.sTableName,sQuotedColumnName,io_aRow[aColIter->second.nPosition],aKeyConditions);
646 ::rtl::OUStringBuffer& rPart = aSql[aColIter->second.sTableName];
647 if ( rPart.getLength() )
648 rPart.appendAscii(", ");
649 rPart.append(sQuotedColumnName);
651 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
652 TSQLStatements::iterator aSqlIter = aSql.begin();
653 TSQLStatements::iterator aSqlEnd = aSql.end();
654 for(;aSqlIter != aSqlEnd ; ++aSqlIter)
656 if ( aSqlIter->second.getLength() )
658 ::rtl::OUStringBuffer& rCondition = aKeyConditions[aSqlIter->first];
659 if ( rCondition.getLength() )
661 ::rtl::OUString sCatalog,sSchema,sTable;
662 ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
663 ::rtl::OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
664 ::rtl::OUStringBuffer sQuery;
665 sQuery.appendAscii("SELECT ");
666 sQuery.append(aSqlIter->second.toString());
667 sQuery.appendAscii(" FROM ");
668 sQuery.append(sComposedTableName);
669 sQuery.appendAscii(" WHERE ");
670 sQuery.append(rCondition.makeStringAndClear());
674 Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery.makeStringAndClear()));
675 Reference< XParameters > xParameter(xPrep,UNO_QUERY);
676 // and then the values of the where condition
677 SelectColumnsMetaData::iterator aKeyIter = m_pKeyColumnNames->begin();
678 SelectColumnsMetaData::iterator aKeyEnd = m_pKeyColumnNames->end();
679 sal_Int32 i = 1;
680 for(;aKeyIter != aKeyEnd;++aKeyIter)
682 if ( aKeyIter->second.sTableName == aSqlIter->first )
684 setParameter(i++,xParameter,io_aRow[aKeyIter->second.nPosition],aKeyIter->second.nType,aKeyIter->second.nScale);
687 Reference<XResultSet> xRes = xPrep->executeQuery();
688 Reference<XRow> xRow(xRes,UNO_QUERY);
689 if ( xRow.is() && xRes->next() )
691 i = 1;
692 aColIter = m_pColumnNames->begin();
693 for(;aColIter != aColEnd;++aColIter)
695 if ( aColIter->second.sTableName == aSqlIter->first )
697 io_aRow[aColIter->second.nPosition].fill(i++, aColIter->second.nType, xRow);
698 io_aRow[aColIter->second.nPosition].setModified();
703 catch(const SQLException&)
710 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */