Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include "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>
52 :
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;
68 :
69 : typedef std::map<OUString, OUStringBuffer> TSQLStatements;
70 : namespace
71 : {
72 0 : void lcl_fillKeyCondition(const OUString& i_sTableName,const OUString& i_sQuotedColumnName,const ORowSetValue& i_aValue,TSQLStatements& io_aKeyConditions)
73 : {
74 0 : OUStringBuffer& rKeyCondition = io_aKeyConditions[i_sTableName];
75 0 : if ( !rKeyCondition.isEmpty() )
76 0 : rKeyCondition.append(" AND ");
77 0 : rKeyCondition.append(i_sQuotedColumnName);
78 0 : if ( i_aValue.isNull() )
79 0 : rKeyCondition.append(" IS NULL");
80 : else
81 0 : rKeyCondition.append(" = ?");
82 0 : }
83 : }
84 :
85 :
86 0 : 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 0 : ,m_aSqlIterator( i_xConnection, Reference<XTablesSupplier>(_xComposer,UNO_QUERY)->getTables(), m_aSqlParser, NULL )
95 0 : ,m_bResultSetChanged(false)
96 : {
97 : SAL_INFO("dbaccess", "OptimisticSet::OptimisticSet" );
98 0 : }
99 :
100 0 : OptimisticSet::~OptimisticSet()
101 : {
102 0 : }
103 :
104 0 : void OptimisticSet::construct(const Reference< XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter)
105 : {
106 : SAL_INFO("dbaccess", "OptimisticSet::construct" );
107 :
108 0 : OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
109 :
110 0 : initColumns();
111 0 : m_sRowSetFilter = i_sRowSetFilter;
112 :
113 0 : Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
114 0 : bool bCase = (xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers()) ? true : false;
115 0 : Reference<XColumnsSupplier> xQueryColSup(m_xComposer,UNO_QUERY);
116 0 : const Reference<XNameAccess> xQueryColumns = xQueryColSup->getColumns();
117 0 : const Reference<XTablesSupplier> xTabSup(m_xComposer,UNO_QUERY);
118 0 : const Reference<XNameAccess> xTables = xTabSup->getTables();
119 0 : const Sequence< OUString> aTableNames = xTables->getElementNames();
120 0 : const OUString* pTableNameIter = aTableNames.getConstArray();
121 0 : const OUString* pTableNameEnd = pTableNameIter + aTableNames.getLength();
122 0 : for( ; pTableNameIter != pTableNameEnd ; ++pTableNameIter)
123 : {
124 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
125 0 : ::std::auto_ptr<SelectColumnsMetaData> pKeyColumNames(new SelectColumnsMetaData(bCase));
126 : SAL_WNODEPRECATED_DECLARATIONS_POP
127 0 : findTableColumnsMatching_throw(xTables->getByName(*pTableNameIter),*pTableNameIter,xMeta,xQueryColumns,pKeyColumNames);
128 0 : m_pKeyColumnNames->insert(pKeyColumNames->begin(),pKeyColumNames->end());
129 0 : }
130 :
131 : // the first row is empty because it's now easier for us to distinguish when we are beforefirst or first
132 : // without extra variable to be set
133 0 : OKeySetValue keySetValue((ORowSetValueVector *)NULL,::std::pair<sal_Int32,Reference<XRow> >(0,(Reference<XRow>)NULL));
134 0 : m_aKeyMap.insert(OKeySetMatrix::value_type(0,keySetValue));
135 0 : m_aKeyIter = m_aKeyMap.begin();
136 :
137 0 : Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
138 0 : Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
139 0 : Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
140 0 : OUString sQuery = xSourceComposer->getQuery();
141 0 : xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
142 : // check for joins
143 0 : OUString aErrorMsg;
144 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
145 0 : ::std::auto_ptr<OSQLParseNode> pStatementNode( m_aSqlParser.parseTree( aErrorMsg, sQuery ) );
146 : SAL_WNODEPRECATED_DECLARATIONS_POP
147 0 : m_aSqlIterator.setParseTree( pStatementNode.get() );
148 0 : m_aSqlIterator.traverseAll();
149 0 : fillJoinedColumns_throw(m_aSqlIterator.getJoinConditions());
150 :
151 0 : }
152 :
153 0 : void OptimisticSet::makeNewStatement( )
154 : {
155 0 : OUStringBuffer aFilter = createKeyFilter();
156 :
157 0 : Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
158 0 : Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
159 0 : Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
160 0 : xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
161 :
162 0 : const OUString sComposerFilter = m_xComposer->getFilter();
163 0 : if ( !m_sRowSetFilter.isEmpty() || !sComposerFilter.isEmpty() )
164 : {
165 0 : FilterCreator aFilterCreator;
166 0 : if ( !sComposerFilter.isEmpty() && sComposerFilter != m_sRowSetFilter )
167 0 : aFilterCreator.append( sComposerFilter );
168 0 : aFilterCreator.append( m_sRowSetFilter );
169 0 : aFilterCreator.append( aFilter.makeStringAndClear() );
170 0 : aFilter = aFilterCreator.getComposedAndClear();
171 : }
172 0 : xAnalyzer->setFilter(aFilter.makeStringAndClear());
173 0 : m_xStatement = m_xConnection->prepareStatement(xAnalyzer->getQueryWithSubstitution());
174 0 : ::comphelper::disposeComponent(xAnalyzer);
175 0 : }
176 :
177 : // ::com::sun::star::sdbcx::XDeleteRows
178 0 : Sequence< sal_Int32 > SAL_CALL OptimisticSet::deleteRows( const Sequence< Any >& /*rows*/ ,const connectivity::OSQLTable& /*_xTable*/) throw(SQLException, RuntimeException)
179 : {
180 0 : Sequence< sal_Int32 > aRet;
181 0 : return aRet;
182 : }
183 :
184 0 : void SAL_CALL OptimisticSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException)
185 : {
186 : SAL_INFO("dbaccess", "OptimisticSet::updateRow" );
187 0 : if ( m_aJoinedKeyColumns.empty() )
188 0 : throw SQLException();
189 : // list all cloumns that should be set
190 0 : static OUString s_sPara(" = ?");
191 0 : OUString aQuote = getIdentifierQuoteString();
192 :
193 0 : ::std::map< OUString,bool > aResultSetChanged;
194 0 : TSQLStatements aKeyConditions;
195 0 : TSQLStatements aIndexConditions;
196 0 : TSQLStatements aSql;
197 :
198 : // here we build the condition part for the update statement
199 0 : SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
200 0 : SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
201 0 : for(;aIter != aEnd;++aIter)
202 : {
203 0 : if ( aResultSetChanged.find( aIter->second.sTableName ) == aResultSetChanged.end() )
204 0 : aResultSetChanged[aIter->second.sTableName] = false;
205 0 : const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aIter->second.sRealName);
206 0 : if ( m_pKeyColumnNames->find(aIter->first) != m_pKeyColumnNames->end() )
207 : {
208 0 : aResultSetChanged[aIter->second.sTableName] = m_aJoinedKeyColumns.find(aIter->second.nPosition) != m_aJoinedKeyColumns.end();
209 0 : lcl_fillKeyCondition(aIter->second.sTableName,sQuotedColumnName,(_rOriginalRow->get())[aIter->second.nPosition],aKeyConditions);
210 : }
211 0 : if((_rInsertRow->get())[aIter->second.nPosition].isModified())
212 : {
213 0 : if ( m_aJoinedKeyColumns.find(aIter->second.nPosition) != m_aJoinedKeyColumns.end() )
214 0 : throw SQLException();
215 :
216 0 : ::std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(aIter->second.nPosition);
217 0 : if ( aJoinIter != m_aJoinedColumns.end() )
218 : {
219 0 : (_rInsertRow->get())[aJoinIter->second] = (_rInsertRow->get())[aIter->second.nPosition];
220 : }
221 0 : OUStringBuffer& rPart = aSql[aIter->second.sTableName];
222 0 : if ( !rPart.isEmpty() )
223 0 : rPart.append(", ");
224 0 : rPart.append(sQuotedColumnName + s_sPara);
225 : }
226 0 : }
227 :
228 0 : if( aSql.empty() )
229 0 : ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED ), SQL_GENERAL_ERROR, m_xConnection );
230 :
231 0 : if( aKeyConditions.empty() )
232 0 : ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_CONDITION_FOR_PK ), SQL_GENERAL_ERROR, m_xConnection );
233 :
234 0 : static const OUString s_sUPDATE("UPDATE ");
235 0 : static const OUString s_sSET(" SET ");
236 :
237 0 : Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
238 :
239 0 : TSQLStatements::iterator aSqlIter = aSql.begin();
240 0 : TSQLStatements::iterator aSqlEnd = aSql.end();
241 0 : for(;aSqlIter != aSqlEnd ; ++aSqlIter)
242 : {
243 0 : if ( !aSqlIter->second.isEmpty() )
244 : {
245 0 : m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[aSqlIter->first];
246 0 : OUString sCatalog,sSchema,sTable;
247 0 : ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
248 0 : OUStringBuffer sSql(s_sUPDATE + ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) +
249 0 : s_sSET + aSqlIter->second.toString());
250 0 : OUStringBuffer& rCondition = aKeyConditions[aSqlIter->first];
251 0 : if ( !rCondition.isEmpty() )
252 0 : sSql.append(" WHERE " + rCondition.toString() );
253 :
254 0 : executeUpdate(_rInsertRow ,_rOriginalRow,sSql.makeStringAndClear(),aSqlIter->first);
255 : }
256 0 : }
257 0 : }
258 :
259 0 : void SAL_CALL OptimisticSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException)
260 : {
261 : SAL_INFO("dbaccess", "OptimisticSet::insertRow" );
262 0 : TSQLStatements aSql;
263 0 : TSQLStatements aParameter;
264 0 : TSQLStatements aKeyConditions;
265 0 : ::std::map< OUString,bool > aResultSetChanged;
266 0 : OUString aQuote = getIdentifierQuoteString();
267 :
268 : // here we build the condition part for the update statement
269 0 : SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
270 0 : SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
271 0 : for(;aIter != aEnd;++aIter)
272 : {
273 0 : if ( aResultSetChanged.find( aIter->second.sTableName ) == aResultSetChanged.end() )
274 0 : aResultSetChanged[aIter->second.sTableName] = false;
275 :
276 0 : const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aIter->second.sRealName);
277 0 : if ( (_rInsertRow->get())[aIter->second.nPosition].isModified() )
278 : {
279 0 : if ( m_aJoinedKeyColumns.find(aIter->second.nPosition) != m_aJoinedKeyColumns.end() )
280 : {
281 0 : lcl_fillKeyCondition(aIter->second.sTableName,sQuotedColumnName,(_rInsertRow->get())[aIter->second.nPosition],aKeyConditions);
282 0 : aResultSetChanged[aIter->second.sTableName] = true;
283 : }
284 0 : ::std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(aIter->second.nPosition);
285 0 : if ( aJoinIter != m_aJoinedColumns.end() )
286 : {
287 0 : (_rInsertRow->get())[aJoinIter->second] = (_rInsertRow->get())[aIter->second.nPosition];
288 : }
289 0 : OUStringBuffer& rPart = aSql[aIter->second.sTableName];
290 0 : if ( !rPart.isEmpty() )
291 0 : rPart.append(", ");
292 0 : rPart.append(sQuotedColumnName);
293 0 : OUStringBuffer& rParam = aParameter[aIter->second.sTableName];
294 0 : if ( !rParam.isEmpty() )
295 0 : rParam.append(", ");
296 0 : rParam.append("?");
297 : }
298 0 : }
299 0 : if ( aParameter.empty() )
300 0 : ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED ), SQL_GENERAL_ERROR, m_xConnection );
301 :
302 0 : Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
303 0 : static const OUString s_sINSERT("INSERT INTO ");
304 0 : static const OUString s_sVALUES(") VALUES ( ");
305 0 : TSQLStatements::iterator aSqlIter = aSql.begin();
306 0 : TSQLStatements::iterator aSqlEnd = aSql.end();
307 0 : for(;aSqlIter != aSqlEnd ; ++aSqlIter)
308 : {
309 0 : if ( !aSqlIter->second.isEmpty() )
310 : {
311 0 : m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[aSqlIter->first];
312 0 : OUString sCatalog,sSchema,sTable;
313 0 : ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
314 0 : OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
315 0 : OUString sSql(s_sINSERT + sComposedTableName + " ( " + aSqlIter->second.toString() +
316 0 : s_sVALUES + aParameter[aSqlIter->first].toString() + " )");
317 :
318 0 : OUStringBuffer& rCondition = aKeyConditions[aSqlIter->first];
319 0 : if ( !rCondition.isEmpty() )
320 : {
321 0 : OUString sQuery("SELECT " + aSqlIter->second.toString() + " FROM " + sComposedTableName +
322 0 : " WHERE " + rCondition.toString());
323 :
324 : try
325 : {
326 0 : Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery));
327 0 : Reference< XParameters > xParameter(xPrep,UNO_QUERY);
328 : // and then the values of the where condition
329 0 : SelectColumnsMetaData::iterator aKeyCol = m_pKeyColumnNames->begin();
330 0 : SelectColumnsMetaData::iterator aKeysEnd = m_pKeyColumnNames->end();
331 0 : sal_Int32 i = 1;
332 0 : for(;aKeyCol != aKeysEnd;++aKeyCol)
333 : {
334 0 : if ( aKeyCol->second.sTableName == aSqlIter->first )
335 : {
336 0 : setParameter(i++,xParameter,(_rInsertRow->get())[aKeyCol->second.nPosition],aKeyCol->second.nType,aKeyCol->second.nScale);
337 : }
338 : }
339 0 : Reference<XResultSet> xRes = xPrep->executeQuery();
340 0 : Reference<XRow> xRow(xRes,UNO_QUERY);
341 0 : if ( xRow.is() && xRes->next() )
342 : {
343 0 : m_bResultSetChanged = true;
344 0 : continue;
345 0 : }
346 : }
347 0 : catch(const SQLException&)
348 : {
349 0 : }
350 : }
351 :
352 0 : executeInsert(_rInsertRow,sSql,aSqlIter->first);
353 : }
354 0 : }
355 0 : }
356 :
357 0 : void SAL_CALL OptimisticSet::deleteRow(const ORowSetRow& _rDeleteRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException)
358 : {
359 0 : OUString aQuote = getIdentifierQuoteString();
360 0 : TSQLStatements aKeyConditions;
361 0 : TSQLStatements aIndexConditions;
362 0 : TSQLStatements aSql;
363 :
364 : // here we build the condition part for the update statement
365 0 : SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
366 0 : SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
367 0 : for(;aIter != aEnd;++aIter)
368 : {
369 0 : if ( m_aJoinedKeyColumns.find(aIter->second.nPosition) == m_aJoinedKeyColumns.end() && m_pKeyColumnNames->find(aIter->first) != m_pKeyColumnNames->end() )
370 : {
371 : // only delete rows which aren't the key in the join
372 0 : const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aIter->second.sRealName);
373 0 : lcl_fillKeyCondition(aIter->second.sTableName,sQuotedColumnName,(_rDeleteRow->get())[aIter->second.nPosition],aKeyConditions);
374 : }
375 : }
376 0 : Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
377 0 : TSQLStatements::iterator aSqlIter = aKeyConditions.begin();
378 0 : TSQLStatements::iterator aSqlEnd = aKeyConditions.end();
379 0 : for(;aSqlIter != aSqlEnd ; ++aSqlIter)
380 : {
381 0 : OUStringBuffer& rCondition = aSqlIter->second;
382 0 : if ( !rCondition.isEmpty() )
383 : {
384 0 : OUString sCatalog,sSchema,sTable;
385 0 : ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
386 0 : OUString sSql("DELETE FROM " + ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) +
387 0 : " WHERE " + rCondition.toString() );
388 0 : executeDelete(_rDeleteRow, sSql, aSqlIter->first);
389 : }
390 0 : }
391 0 : }
392 :
393 0 : void OptimisticSet::executeDelete(const ORowSetRow& _rDeleteRow,const OUString& i_sSQL,const OUString& i_sTableName)
394 : {
395 : SAL_INFO("dbaccess", "OptimisticSet::executeDelete" );
396 :
397 : // now create and execute the prepared statement
398 0 : Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL));
399 0 : Reference< XParameters > xParameter(xPrep,UNO_QUERY);
400 :
401 0 : SelectColumnsMetaData::const_iterator aIter = m_pKeyColumnNames->begin();
402 0 : SelectColumnsMetaData::const_iterator aEnd = m_pKeyColumnNames->end();
403 0 : sal_Int32 i = 1;
404 0 : for(;aIter != aEnd;++aIter)
405 : {
406 0 : if ( aIter->second.sTableName == i_sTableName )
407 0 : setParameter(i++,xParameter,(_rDeleteRow->get())[aIter->second.nPosition],aIter->second.nType,aIter->second.nScale);
408 : }
409 0 : m_bDeleted = xPrep->executeUpdate() > 0;
410 :
411 0 : if(m_bDeleted)
412 : {
413 0 : sal_Int32 nBookmark = ::comphelper::getINT32((_rDeleteRow->get())[0].getAny());
414 0 : if(m_aKeyIter == m_aKeyMap.find(nBookmark) && m_aKeyIter != m_aKeyMap.end())
415 0 : ++m_aKeyIter;
416 0 : m_aKeyMap.erase(nBookmark);
417 0 : m_bDeleted = sal_True;
418 0 : }
419 0 : }
420 :
421 0 : void OptimisticSet::fillJoinedColumns_throw(const ::std::vector< TNodePair >& i_aJoinColumns)
422 : {
423 0 : ::std::vector< TNodePair >::const_iterator aIter = i_aJoinColumns.begin();
424 0 : for(;aIter != i_aJoinColumns.end();++aIter)
425 : {
426 0 : OUString sColumnName,sTableName;
427 0 : m_aSqlIterator.getColumnRange(aIter->first,sColumnName,sTableName);
428 0 : OUString sLeft(sTableName + "." + sColumnName);
429 0 : m_aSqlIterator.getColumnRange(aIter->second,sColumnName,sTableName);
430 0 : OUString sRight(sTableName + "." + sColumnName);
431 0 : fillJoinedColumns_throw(sLeft, sRight);
432 0 : }
433 0 : }
434 :
435 0 : void OptimisticSet::fillJoinedColumns_throw(const OUString& i_sLeftColumn,const OUString& i_sRightColumn)
436 : {
437 0 : sal_Int32 nLeft = 0,nRight = 0;
438 0 : SelectColumnsMetaData::const_iterator aLeftIter = m_pKeyColumnNames->find(i_sLeftColumn);
439 0 : SelectColumnsMetaData::const_iterator aRightIter = m_pKeyColumnNames->find(i_sRightColumn);
440 :
441 0 : bool bLeftKey = aLeftIter != m_pKeyColumnNames->end();
442 0 : if ( bLeftKey )
443 : {
444 0 : nLeft = aLeftIter->second.nPosition;
445 : }
446 : else
447 : {
448 0 : aLeftIter = m_pColumnNames->find(i_sLeftColumn);
449 0 : if ( aLeftIter != m_pColumnNames->end() )
450 0 : nLeft = aLeftIter->second.nPosition;
451 : }
452 :
453 0 : bool bRightKey = aRightIter != m_pKeyColumnNames->end();
454 0 : if ( bRightKey )
455 : {
456 0 : nRight = aRightIter->second.nPosition;
457 : }
458 : else
459 : {
460 0 : aRightIter = m_pColumnNames->find(i_sRightColumn);
461 0 : if ( aRightIter != m_pColumnNames->end() )
462 0 : nRight = aRightIter->second.nPosition;
463 : }
464 :
465 0 : if (bLeftKey)
466 0 : m_aJoinedKeyColumns[nLeft] = nRight;
467 : else
468 0 : m_aJoinedColumns[nLeft] = nRight;
469 0 : if (bRightKey)
470 0 : m_aJoinedKeyColumns[nRight] = nLeft;
471 : else
472 0 : m_aJoinedColumns[nRight] = nLeft;
473 0 : }
474 :
475 0 : bool OptimisticSet::isResultSetChanged() const
476 : {
477 0 : bool bOld = m_bResultSetChanged;
478 0 : m_bResultSetChanged = false;
479 0 : return bOld;
480 : }
481 :
482 0 : void OptimisticSet::mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& io_aInsertRow,ORowSetValueVector::Vector& io_aRow,::std::vector<sal_Int32>& o_aChangedColumns)
483 : {
484 0 : o_aChangedColumns.push_back(i_nColumnIndex);
485 0 : ::std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(i_nColumnIndex);
486 0 : if ( aJoinIter != m_aJoinedColumns.end() )
487 : {
488 0 : io_aRow[aJoinIter->second] = io_aRow[i_nColumnIndex];
489 0 : io_aInsertRow[aJoinIter->second] = io_aInsertRow[i_nColumnIndex];
490 0 : io_aRow[aJoinIter->second].setModified();
491 0 : o_aChangedColumns.push_back(aJoinIter->second);
492 : }
493 0 : }
494 :
495 : namespace
496 : {
497 : struct PositionFunctor : ::std::unary_function<SelectColumnsMetaData::value_type,bool>
498 : {
499 : sal_Int32 m_nPos;
500 0 : PositionFunctor(sal_Int32 i_nPos)
501 0 : : m_nPos(i_nPos)
502 : {
503 0 : }
504 :
505 0 : inline bool operator()(const SelectColumnsMetaData::value_type& _aType)
506 : {
507 0 : return m_nPos == _aType.second.nPosition;
508 : }
509 : };
510 0 : struct TableNameFunctor : ::std::unary_function<SelectColumnsMetaData::value_type,bool>
511 : {
512 : OUString m_sTableName;
513 0 : TableNameFunctor(const OUString& i_sTableName)
514 0 : : m_sTableName(i_sTableName)
515 : {
516 0 : }
517 :
518 0 : inline bool operator()(const SelectColumnsMetaData::value_type& _aType)
519 : {
520 0 : return m_sTableName == _aType.second.sTableName;
521 : }
522 : };
523 : }
524 :
525 0 : bool OptimisticSet::updateColumnValues(const ORowSetValueVector::Vector& io_aCachedRow,ORowSetValueVector::Vector& io_aRow,const ::std::vector<sal_Int32>& i_aChangedColumns)
526 : {
527 0 : bool bRet = false;
528 0 : ::std::vector<sal_Int32>::const_iterator aColIdxIter = i_aChangedColumns.begin();
529 0 : for(;aColIdxIter != i_aChangedColumns.end();++aColIdxIter)
530 : {
531 0 : SelectColumnsMetaData::const_iterator aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),PositionFunctor(*aColIdxIter));
532 0 : if ( aFind != m_pKeyColumnNames->end() )
533 : {
534 0 : const OUString sTableName = aFind->second.sTableName;
535 0 : aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),TableNameFunctor(sTableName));
536 0 : while( aFind != m_pKeyColumnNames->end() )
537 : {
538 0 : io_aRow[aFind->second.nPosition].setSigned(io_aCachedRow[aFind->second.nPosition].isSigned());
539 0 : if ( io_aCachedRow[aFind->second.nPosition] != io_aRow[aFind->second.nPosition] )
540 0 : break;
541 0 : ++aFind;
542 : }
543 0 : if ( aFind == m_pKeyColumnNames->end() )
544 : {
545 0 : bRet = true;
546 0 : SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
547 0 : SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
548 0 : for ( ;aIter != aEnd;++aIter )
549 : {
550 0 : if ( aIter->second.sTableName == sTableName )
551 : {
552 0 : io_aRow[aIter->second.nPosition] = io_aCachedRow[aIter->second.nPosition];
553 0 : io_aRow[aIter->second.nPosition].setModified();
554 : }
555 : }
556 0 : }
557 : }
558 : }
559 0 : return bRet;
560 : }
561 :
562 0 : bool OptimisticSet::columnValuesUpdated(ORowSetValueVector::Vector& o_aCachedRow,const ORowSetValueVector::Vector& i_aRow)
563 : {
564 0 : bool bRet = false;
565 0 : SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
566 0 : SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
567 0 : for(;aIter != aEnd;++aIter)
568 : {
569 0 : SelectColumnsMetaData::const_iterator aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),PositionFunctor(aIter->second.nPosition));
570 0 : if ( aFind != m_pKeyColumnNames->end() )
571 : {
572 0 : const OUString sTableName = aFind->second.sTableName;
573 0 : aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),TableNameFunctor(sTableName));
574 0 : while( aFind != m_pKeyColumnNames->end() )
575 : {
576 0 : o_aCachedRow[aFind->second.nPosition].setSigned(i_aRow[aFind->second.nPosition].isSigned());
577 0 : if ( o_aCachedRow[aFind->second.nPosition] != i_aRow[aFind->second.nPosition] )
578 0 : break;
579 0 : ++aFind;
580 : }
581 0 : if ( aFind == m_pKeyColumnNames->end() )
582 : {
583 0 : bRet = true;
584 0 : SelectColumnsMetaData::const_iterator aIter2 = m_pColumnNames->begin();
585 0 : SelectColumnsMetaData::const_iterator aEnd2 = m_pColumnNames->end();
586 0 : for ( ;aIter2 != aEnd2;++aIter2 )
587 : {
588 0 : if ( aIter2->second.sTableName == sTableName )
589 : {
590 0 : o_aCachedRow[aIter2->second.nPosition] = i_aRow[aIter2->second.nPosition];
591 0 : o_aCachedRow[aIter2->second.nPosition].setModified();
592 : }
593 : }
594 0 : fillMissingValues(o_aCachedRow);
595 0 : }
596 : }
597 : }
598 0 : return bRet;
599 : }
600 :
601 0 : void OptimisticSet::fillMissingValues(ORowSetValueVector::Vector& io_aRow) const
602 : {
603 0 : TSQLStatements aSql;
604 0 : TSQLStatements aKeyConditions;
605 0 : ::std::map< OUString,bool > aResultSetChanged;
606 0 : OUString aQuote = getIdentifierQuoteString();
607 : // here we build the condition part for the update statement
608 0 : SelectColumnsMetaData::const_iterator aColIter = m_pColumnNames->begin();
609 0 : SelectColumnsMetaData::const_iterator aColEnd = m_pColumnNames->end();
610 0 : for(;aColIter != aColEnd;++aColIter)
611 : {
612 0 : const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aColIter->second.sRealName);
613 0 : if ( m_aJoinedKeyColumns.find(aColIter->second.nPosition) != m_aJoinedKeyColumns.end() )
614 : {
615 0 : lcl_fillKeyCondition(aColIter->second.sTableName,sQuotedColumnName,io_aRow[aColIter->second.nPosition],aKeyConditions);
616 : }
617 0 : OUStringBuffer& rPart = aSql[aColIter->second.sTableName];
618 0 : if ( !rPart.isEmpty() )
619 0 : rPart.append(", ");
620 0 : rPart.append(sQuotedColumnName);
621 0 : }
622 0 : Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
623 0 : TSQLStatements::iterator aSqlIter = aSql.begin();
624 0 : TSQLStatements::iterator aSqlEnd = aSql.end();
625 0 : for(;aSqlIter != aSqlEnd ; ++aSqlIter)
626 : {
627 0 : if ( !aSqlIter->second.isEmpty() )
628 : {
629 0 : OUStringBuffer& rCondition = aKeyConditions[aSqlIter->first];
630 0 : if ( !rCondition.isEmpty() )
631 : {
632 0 : OUString sCatalog,sSchema,sTable;
633 0 : ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
634 0 : OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
635 0 : OUString sQuery("SELECT " + aSqlIter->second.toString() + " FROM " + sComposedTableName + " WHERE " +
636 0 : rCondition.makeStringAndClear());
637 :
638 : try
639 : {
640 0 : Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery));
641 0 : Reference< XParameters > xParameter(xPrep,UNO_QUERY);
642 : // and then the values of the where condition
643 0 : SelectColumnsMetaData::iterator aKeyIter = m_pKeyColumnNames->begin();
644 0 : SelectColumnsMetaData::iterator aKeyEnd = m_pKeyColumnNames->end();
645 0 : sal_Int32 i = 1;
646 0 : for(;aKeyIter != aKeyEnd;++aKeyIter)
647 : {
648 0 : if ( aKeyIter->second.sTableName == aSqlIter->first )
649 : {
650 0 : setParameter(i++,xParameter,io_aRow[aKeyIter->second.nPosition],aKeyIter->second.nType,aKeyIter->second.nScale);
651 : }
652 : }
653 0 : Reference<XResultSet> xRes = xPrep->executeQuery();
654 0 : Reference<XRow> xRow(xRes,UNO_QUERY);
655 0 : if ( xRow.is() && xRes->next() )
656 : {
657 0 : i = 1;
658 0 : aColIter = m_pColumnNames->begin();
659 0 : for(;aColIter != aColEnd;++aColIter)
660 : {
661 0 : if ( aColIter->second.sTableName == aSqlIter->first )
662 : {
663 0 : io_aRow[aColIter->second.nPosition].fill(i++, aColIter->second.nType, xRow);
664 0 : io_aRow[aColIter->second.nPosition].setModified();
665 : }
666 : }
667 0 : }
668 : }
669 0 : catch(const SQLException&)
670 : {
671 0 : }
672 : }
673 : }
674 0 : }
675 0 : }
676 :
677 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|