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