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