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