1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_dbaccess.hxx"
26
27 #include "OptimisticSet.hxx"
28 #include "core_resource.hxx"
29 #include "core_resource.hrc"
30 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
32 #include <com/sun/star/sdbc/ColumnValue.hpp>
33 #include <com/sun/star/sdbc/XPreparedStatement.hpp>
34 #include <com/sun/star/sdbc/XParameters.hpp>
35 #include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
36 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
37 #include <com/sun/star/sdb/SQLFilterOperator.hpp>
38 #include <com/sun/star/sdbc/XColumnLocate.hpp>
39 #include <com/sun/star/container/XIndexAccess.hpp>
40 #include "dbastrings.hrc"
41 #include "apitools.hxx"
42 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
43 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
44 #include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
45 #include <cppuhelper/typeprovider.hxx>
46 #include <comphelper/types.hxx>
47 #include <com/sun/star/sdbcx/KeyType.hpp>
48 #include <connectivity/dbtools.hxx>
49 #include <connectivity/dbexception.hxx>
50 #include <list>
51 #include <algorithm>
52 #include <string.h>
53 #include <com/sun/star/io/XInputStream.hpp>
54 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
55 #include "querycomposer.hxx"
56 #include "composertools.hxx"
57 #include <tools/debug.hxx>
58 #include <string.h>
59 #include <rtl/logfile.hxx>
60
61 using namespace dbaccess;
62 using namespace ::connectivity;
63 using namespace ::dbtools;
64 using namespace ::com::sun::star::uno;
65 using namespace ::com::sun::star::beans;
66 using namespace ::com::sun::star::sdbc;
67 using namespace ::com::sun::star::sdb;
68 using namespace ::com::sun::star::sdbcx;
69 using namespace ::com::sun::star::container;
70 using namespace ::com::sun::star::lang;
71 using namespace ::com::sun::star::util;
72 using namespace ::com::sun::star::io;
73 using namespace ::com::sun::star;
74 using namespace ::cppu;
75 using namespace ::osl;
76
77 DECLARE_STL_USTRINGACCESS_MAP(::rtl::OUStringBuffer,TSQLStatements);
78 namespace
79 {
lcl_fillKeyCondition(const::rtl::OUString & i_sTableName,const::rtl::OUString & i_sQuotedColumnName,const ORowSetValue & i_aValue,TSQLStatements & io_aKeyConditions)80 void lcl_fillKeyCondition(const ::rtl::OUString& i_sTableName,const ::rtl::OUString& i_sQuotedColumnName,const ORowSetValue& i_aValue,TSQLStatements& io_aKeyConditions)
81 {
82 ::rtl::OUStringBuffer& rKeyCondition = io_aKeyConditions[i_sTableName];
83 if ( rKeyCondition.getLength() )
84 rKeyCondition.appendAscii(" AND ");
85 rKeyCondition.append(i_sQuotedColumnName);
86 if ( i_aValue.isNull() )
87 rKeyCondition.appendAscii(" IS NULL");
88 else
89 rKeyCondition.appendAscii(" = ?");
90 }
91 }
92
DBG_NAME(OptimisticSet)93 DBG_NAME(OptimisticSet)
94 // -------------------------------------------------------------------------
95 OptimisticSet::OptimisticSet(const ::comphelper::ComponentContext& _rContext,
96 const Reference< XConnection>& i_xConnection,
97 const Reference< XSingleSelectQueryAnalyzer >& _xComposer,
98 const ORowSetValueVector& _aParameterValueForCache,
99 sal_Int32 i_nMaxRows,
100 sal_Int32& o_nRowCount)
101 :OKeySet(NULL,NULL,::rtl::OUString(),_xComposer,_aParameterValueForCache,i_nMaxRows,o_nRowCount)
102 ,m_aSqlParser( _rContext.getLegacyServiceFactory() )
103 ,m_aSqlIterator( i_xConnection, Reference<XTablesSupplier>(_xComposer,UNO_QUERY)->getTables(), m_aSqlParser, NULL )
104 ,m_bResultSetChanged(false)
105 {
106 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::OptimisticSet" );
107 DBG_CTOR(OptimisticSet,NULL);
108 }
109 // -----------------------------------------------------------------------------
~OptimisticSet()110 OptimisticSet::~OptimisticSet()
111 {
112 DBG_DTOR(OptimisticSet,NULL);
113 }
114 // -----------------------------------------------------------------------------
construct(const Reference<XResultSet> & _xDriverSet,const::rtl::OUString & i_sRowSetFilter)115 void OptimisticSet::construct(const Reference< XResultSet>& _xDriverSet,const ::rtl::OUString& i_sRowSetFilter)
116 {
117 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::construct" );
118 OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
119 initColumns();
120
121 Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
122 bool bCase = (xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers()) ? true : false;
123 Reference<XColumnsSupplier> xQueryColSup(m_xComposer,UNO_QUERY);
124 const Reference<XNameAccess> xQueryColumns = xQueryColSup->getColumns();
125 const Reference<XTablesSupplier> xTabSup(m_xComposer,UNO_QUERY);
126 const Reference<XNameAccess> xTables = xTabSup->getTables();
127 const Sequence< ::rtl::OUString> aTableNames = xTables->getElementNames();
128 const ::rtl::OUString* pTableNameIter = aTableNames.getConstArray();
129 const ::rtl::OUString* pTableNameEnd = pTableNameIter + aTableNames.getLength();
130 for( ; pTableNameIter != pTableNameEnd ; ++pTableNameIter)
131 {
132 ::std::auto_ptr<SelectColumnsMetaData> pKeyColumNames(new SelectColumnsMetaData(bCase));
133 findTableColumnsMatching_throw(xTables->getByName(*pTableNameIter),*pTableNameIter,xMeta,xQueryColumns,pKeyColumNames);
134 m_pKeyColumnNames->insert(pKeyColumNames->begin(),pKeyColumNames->end());
135 }
136
137 // the first row is empty because it's now easier for us to distinguish when we are beforefirst or first
138 // without extra variable to be set
139 m_aKeyMap.insert(OKeySetMatrix::value_type(0,OKeySetValue(NULL,::std::pair<sal_Int32,Reference<XRow> >(0,NULL))));
140 m_aKeyIter = m_aKeyMap.begin();
141
142 ::rtl::OUStringBuffer aFilter = createKeyFilter();
143
144 Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
145 Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
146 Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
147 ::rtl::OUString sQuery = xSourceComposer->getQuery();
148 xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
149 // check for joins
150 ::rtl::OUString aErrorMsg;
151 ::std::auto_ptr<OSQLParseNode> pStatementNode( m_aSqlParser.parseTree( aErrorMsg, sQuery ) );
152 m_aSqlIterator.setParseTree( pStatementNode.get() );
153 m_aSqlIterator.traverseAll();
154 fillJoinedColumns_throw(m_aSqlIterator.getJoinConditions());
155
156 const ::rtl::OUString sComposerFilter = m_xComposer->getFilter();
157 if ( i_sRowSetFilter.getLength() || (sComposerFilter.getLength() && sComposerFilter != i_sRowSetFilter) )
158 {
159 FilterCreator aFilterCreator;
160 if ( sComposerFilter.getLength() && sComposerFilter != i_sRowSetFilter )
161 aFilterCreator.append( sComposerFilter );
162 aFilterCreator.append( i_sRowSetFilter );
163 aFilterCreator.append( aFilter.makeStringAndClear() );
164 aFilter = aFilterCreator.getComposedAndClear();
165 }
166 xAnalyzer->setFilter(aFilter.makeStringAndClear());
167 m_xStatement = m_xConnection->prepareStatement(xAnalyzer->getQueryWithSubstitution());
168 ::comphelper::disposeComponent(xAnalyzer);
169 }
170 // -------------------------------------------------------------------------
171 // ::com::sun::star::sdbcx::XDeleteRows
deleteRows(const Sequence<Any> &,const connectivity::OSQLTable &)172 Sequence< sal_Int32 > SAL_CALL OptimisticSet::deleteRows( const Sequence< Any >& /*rows*/ ,const connectivity::OSQLTable& /*_xTable*/) throw(SQLException, RuntimeException)
173 {
174 Sequence< sal_Int32 > aRet;
175 return aRet;
176 }
177 // -------------------------------------------------------------------------
updateRow(const ORowSetRow & _rInsertRow,const ORowSetRow & _rOrginalRow,const connectivity::OSQLTable &)178 void SAL_CALL OptimisticSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOrginalRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException)
179 {
180 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::updateRow" );
181 if ( m_aJoinedKeyColumns.empty() )
182 throw SQLException();
183 // list all cloumns that should be set
184 static ::rtl::OUString s_sPara = ::rtl::OUString::createFromAscii(" = ?");
185 ::rtl::OUString aQuote = getIdentifierQuoteString();
186 static ::rtl::OUString aAnd = ::rtl::OUString::createFromAscii(" AND ");
187 ::rtl::OUString sIsNull(RTL_CONSTASCII_USTRINGPARAM(" IS NULL"));
188 ::rtl::OUString sParam(RTL_CONSTASCII_USTRINGPARAM(" = ?"));
189
190 ::rtl::OUString aColumnName;
191 ::rtl::OUStringBuffer sKeyCondition;
192 ::std::map< ::rtl::OUString,bool > aResultSetChanged;
193 TSQLStatements aKeyConditions;
194 TSQLStatements aIndexConditions;
195 TSQLStatements aSql;
196
197 // sal_Int32 i = 1;
198 // here we build the condition part for the update statement
199 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
200 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
201 for(;aIter != aEnd;++aIter)
202 {
203 if ( aResultSetChanged.find( aIter->second.sTableName ) == aResultSetChanged.end() )
204 aResultSetChanged[aIter->second.sTableName] = false;
205 const ::rtl::OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aIter->second.sRealName);
206 if ( m_pKeyColumnNames->find(aIter->first) != m_pKeyColumnNames->end() )
207 {
208 aResultSetChanged[aIter->second.sTableName] = m_aJoinedKeyColumns.find(aIter->second.nPosition) != m_aJoinedKeyColumns.end();
209 lcl_fillKeyCondition(aIter->second.sTableName,sQuotedColumnName,(_rOrginalRow->get())[aIter->second.nPosition],aKeyConditions);
210 }
211 if((_rInsertRow->get())[aIter->second.nPosition].isModified())
212 {
213 if ( m_aJoinedKeyColumns.find(aIter->second.nPosition) != m_aJoinedKeyColumns.end() )
214 throw SQLException();
215
216 ::std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(aIter->second.nPosition);
217 if ( aJoinIter != m_aJoinedColumns.end() )
218 {
219 (_rInsertRow->get())[aJoinIter->second] = (_rInsertRow->get())[aIter->second.nPosition];
220 }
221 ::rtl::OUStringBuffer& rPart = aSql[aIter->second.sTableName];
222 if ( rPart.getLength() )
223 rPart.appendAscii(", ");
224 rPart.append(sQuotedColumnName);
225 rPart.append(s_sPara);
226 }
227 }
228
229 if( aSql.empty() )
230 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED ), SQL_GENERAL_ERROR, m_xConnection );
231
232 if( aKeyConditions.empty() )
233 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_CONDITION_FOR_PK ), SQL_GENERAL_ERROR, m_xConnection );
234
235 static const ::rtl::OUString s_sUPDATE(RTL_CONSTASCII_USTRINGPARAM("UPDATE "));
236 static const ::rtl::OUString s_sSET(RTL_CONSTASCII_USTRINGPARAM(" SET "));
237
238 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
239
240 TSQLStatements::iterator aSqlIter = aSql.begin();
241 TSQLStatements::iterator aSqlEnd = aSql.end();
242 for(;aSqlIter != aSqlEnd ; ++aSqlIter)
243 {
244 if ( aSqlIter->second.getLength() )
245 {
246 m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[aSqlIter->first];
247 ::rtl::OUStringBuffer sSql(s_sUPDATE);
248 ::rtl::OUString sCatalog,sSchema,sTable;
249 ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
250 sSql.append( ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) );
251 sSql.append(s_sSET);
252 sSql.append(aSqlIter->second);
253 ::rtl::OUStringBuffer& rCondition = aKeyConditions[aSqlIter->first];
254 bool bAddWhere = true;
255 if ( rCondition.getLength() )
256 {
257 bAddWhere = false;
258 sSql.appendAscii(" WHERE ");
259 sSql.append( rCondition );
260 }
261 executeUpdate(_rInsertRow ,_rOrginalRow,sSql.makeStringAndClear(),aSqlIter->first);
262 }
263 }
264 }
265 // -------------------------------------------------------------------------
insertRow(const ORowSetRow & _rInsertRow,const connectivity::OSQLTable &)266 void SAL_CALL OptimisticSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException)
267 {
268 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::insertRow" );
269 TSQLStatements aSql;
270 TSQLStatements aParameter;
271 TSQLStatements aKeyConditions;
272 ::std::map< ::rtl::OUString,bool > aResultSetChanged;
273 ::rtl::OUString aQuote = getIdentifierQuoteString();
274 static ::rtl::OUString aAnd = ::rtl::OUString::createFromAscii(" AND ");
275 ::rtl::OUString sIsNull(RTL_CONSTASCII_USTRINGPARAM(" IS NULL"));
276 ::rtl::OUString sParam(RTL_CONSTASCII_USTRINGPARAM(" = ?"));
277
278 // here we build the condition part for the update statement
279 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
280 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
281 for(;aIter != aEnd;++aIter)
282 {
283 if ( aResultSetChanged.find( aIter->second.sTableName ) == aResultSetChanged.end() )
284 aResultSetChanged[aIter->second.sTableName] = false;
285
286 const ::rtl::OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aIter->second.sRealName);
287 if ( (_rInsertRow->get())[aIter->second.nPosition].isModified() )
288 {
289 if ( m_aJoinedKeyColumns.find(aIter->second.nPosition) != m_aJoinedKeyColumns.end() )
290 {
291 lcl_fillKeyCondition(aIter->second.sTableName,sQuotedColumnName,(_rInsertRow->get())[aIter->second.nPosition],aKeyConditions);
292 aResultSetChanged[aIter->second.sTableName] = true;
293 }
294 ::std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(aIter->second.nPosition);
295 if ( aJoinIter != m_aJoinedColumns.end() )
296 {
297 (_rInsertRow->get())[aJoinIter->second] = (_rInsertRow->get())[aIter->second.nPosition];
298 }
299 ::rtl::OUStringBuffer& rPart = aSql[aIter->second.sTableName];
300 if ( rPart.getLength() )
301 rPart.appendAscii(", ");
302 rPart.append(sQuotedColumnName);
303 ::rtl::OUStringBuffer& rParam = aParameter[aIter->second.sTableName];
304 if ( rParam.getLength() )
305 rParam.appendAscii(", ");
306 rParam.appendAscii("?");
307 }
308 }
309 if ( aParameter.empty() )
310 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED ), SQL_GENERAL_ERROR, m_xConnection );
311
312 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
313 static const ::rtl::OUString s_sINSERT(RTL_CONSTASCII_USTRINGPARAM("INSERT INTO "));
314 static const ::rtl::OUString s_sVALUES(RTL_CONSTASCII_USTRINGPARAM(") VALUES ( "));
315 TSQLStatements::iterator aSqlIter = aSql.begin();
316 TSQLStatements::iterator aSqlEnd = aSql.end();
317 for(;aSqlIter != aSqlEnd ; ++aSqlIter)
318 {
319 if ( aSqlIter->second.getLength() )
320 {
321 m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[aSqlIter->first];
322 ::rtl::OUStringBuffer sSql(s_sINSERT);
323 ::rtl::OUString sCatalog,sSchema,sTable;
324 ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
325 ::rtl::OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
326 sSql.append(sComposedTableName);
327 sSql.appendAscii(" ( ");
328 sSql.append(aSqlIter->second);
329 sSql.append(s_sVALUES);
330 sSql.append(aParameter[aSqlIter->first]);
331 sSql.appendAscii(" )");
332
333 ::rtl::OUStringBuffer& rCondition = aKeyConditions[aSqlIter->first];
334 if ( rCondition.getLength() )
335 {
336 ::rtl::OUStringBuffer sQuery;
337 sQuery.appendAscii("SELECT ");
338 sQuery.append(aSqlIter->second);
339 sQuery.appendAscii(" FROM ");
340 sQuery.append(sComposedTableName);
341 sQuery.appendAscii(" WHERE ");
342 sQuery.append(rCondition);
343
344 try
345 {
346 Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery.makeStringAndClear()));
347 Reference< XParameters > xParameter(xPrep,UNO_QUERY);
348 // and then the values of the where condition
349 SelectColumnsMetaData::iterator aKeyCol = m_pKeyColumnNames->begin();
350 SelectColumnsMetaData::iterator aKeysEnd = m_pKeyColumnNames->end();
351 sal_Int32 i = 1;
352 for(;aKeyCol != aKeysEnd;++aKeyCol)
353 {
354 if ( aKeyCol->second.sTableName == aSqlIter->first )
355 {
356 setParameter(i++,xParameter,(_rInsertRow->get())[aKeyCol->second.nPosition],aKeyCol->second.nType,aKeyCol->second.nScale);
357 }
358 }
359 Reference<XResultSet> xRes = xPrep->executeQuery();
360 Reference<XRow> xRow(xRes,UNO_QUERY);
361 if ( xRow.is() && xRes->next() )
362 {
363 m_bResultSetChanged = true;
364 continue;
365 }
366 }
367 catch(const SQLException&)
368 {
369 }
370 }
371
372 executeInsert(_rInsertRow,sSql.makeStringAndClear(),aSqlIter->first);
373 }
374 }
375 }
376 // -------------------------------------------------------------------------
deleteRow(const ORowSetRow & _rDeleteRow,const connectivity::OSQLTable &)377 void SAL_CALL OptimisticSet::deleteRow(const ORowSetRow& _rDeleteRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException)
378 {
379 ::rtl::OUString sParam(RTL_CONSTASCII_USTRINGPARAM(" = ?"));
380 ::rtl::OUString sIsNull(RTL_CONSTASCII_USTRINGPARAM(" IS NULL"));
381 static const ::rtl::OUString s_sAnd(RTL_CONSTASCII_USTRINGPARAM(" AND "));
382 ::rtl::OUString aQuote = getIdentifierQuoteString();
383 ::rtl::OUString aColumnName;
384 ::rtl::OUStringBuffer sKeyCondition,sIndexCondition;
385 ::std::vector<sal_Int32> aIndexColumnPositions;
386 TSQLStatements aKeyConditions;
387 TSQLStatements aIndexConditions;
388 TSQLStatements aSql;
389
390 // sal_Int32 i = 1;
391 // here we build the condition part for the update statement
392 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
393 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
394 for(;aIter != aEnd;++aIter)
395 {
396 if ( m_aJoinedKeyColumns.find(aIter->second.nPosition) == m_aJoinedKeyColumns.end() && m_pKeyColumnNames->find(aIter->first) != m_pKeyColumnNames->end() )
397 {
398 // only delete rows which aren't the key in the join
399 const ::rtl::OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aIter->second.sRealName);
400 lcl_fillKeyCondition(aIter->second.sTableName,sQuotedColumnName,(_rDeleteRow->get())[aIter->second.nPosition],aKeyConditions);
401 }
402 }
403 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
404 TSQLStatements::iterator aSqlIter = aKeyConditions.begin();
405 TSQLStatements::iterator aSqlEnd = aKeyConditions.end();
406 for(;aSqlIter != aSqlEnd ; ++aSqlIter)
407 {
408 ::rtl::OUStringBuffer& rCondition = aSqlIter->second;
409 if ( rCondition.getLength() )
410 {
411 ::rtl::OUStringBuffer sSql;
412 sSql.appendAscii("DELETE FROM ");
413 ::rtl::OUString sCatalog,sSchema,sTable;
414 ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
415 sSql.append( ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) );
416 sSql.appendAscii(" WHERE ");
417 sSql.append( rCondition );
418 executeDelete(_rDeleteRow,sSql.makeStringAndClear(),aSqlIter->first);
419 }
420 }
421 }
422 // -------------------------------------------------------------------------
executeDelete(const ORowSetRow & _rDeleteRow,const::rtl::OUString & i_sSQL,const::rtl::OUString & i_sTableName)423 void OptimisticSet::executeDelete(const ORowSetRow& _rDeleteRow,const ::rtl::OUString& i_sSQL,const ::rtl::OUString& i_sTableName)
424 {
425 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::executeDelete" );
426
427 // now create end execute the prepared statement
428 Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL));
429 Reference< XParameters > xParameter(xPrep,UNO_QUERY);
430
431 SelectColumnsMetaData::const_iterator aIter = m_pKeyColumnNames->begin();
432 SelectColumnsMetaData::const_iterator aEnd = m_pKeyColumnNames->end();
433 sal_Int32 i = 1;
434 for(;aIter != aEnd;++aIter)
435 {
436 if ( aIter->second.sTableName == i_sTableName )
437 setParameter(i++,xParameter,(_rDeleteRow->get())[aIter->second.nPosition],aIter->second.nType,aIter->second.nScale);
438 }
439 m_bDeleted = xPrep->executeUpdate() > 0;
440
441 if(m_bDeleted)
442 {
443 sal_Int32 nBookmark = ::comphelper::getINT32((_rDeleteRow->get())[0].getAny());
444 if(m_aKeyIter == m_aKeyMap.find(nBookmark) && m_aKeyIter != m_aKeyMap.end())
445 ++m_aKeyIter;
446 m_aKeyMap.erase(nBookmark);
447 m_bDeleted = sal_True;
448 }
449 }
450 // -----------------------------------------------------------------------------
getComposedTableName(const::rtl::OUString &,const::rtl::OUString &,const::rtl::OUString &)451 ::rtl::OUString OptimisticSet::getComposedTableName(const ::rtl::OUString& /*_sCatalog*/,
452 const ::rtl::OUString& /*_sSchema*/,
453 const ::rtl::OUString& /*_sTable*/)
454 {
455 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::getComposedTableName" );
456 ::rtl::OUString aComposedName;
457 /*
458 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
459
460 if( xMetaData.is() && xMetaData->supportsTableCorrelationNames() )
461 {
462 aComposedName = ::dbtools::composeTableName( xMetaData, _sCatalog, _sSchema, _sTable, sal_False, ::dbtools::eInDataManipulation );
463 // first we have to check if the composed tablename is in the select clause or if an alias is used
464 Reference<XTablesSupplier> xTabSup(m_xComposer,UNO_QUERY);
465 Reference<XNameAccess> xSelectTables = xTabSup->getTables();
466 OSL_ENSURE(xSelectTables.is(),"No Select tables!");
467 if(xSelectTables.is())
468 {
469 if(!xSelectTables->hasByName(aComposedName))
470 { // the composed name isn't used in the select clause so we have to find out which name is used instead
471 ::rtl::OUString sCatalog,sSchema,sTable;
472 ::dbtools::qualifiedNameComponents(xMetaData,m_sUpdateTableName,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
473 aComposedName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
474 }
475 else
476 aComposedName = ::dbtools::composeTableNameForSelect( m_xConnection, _sCatalog, _sSchema, _sTable );
477 }
478 }
479 else
480 aComposedName = ::dbtools::composeTableNameForSelect( m_xConnection, _sCatalog, _sSchema, _sTable );
481 */
482 return aComposedName;
483 }
484 // -----------------------------------------------------------------------------
fillJoinedColumns_throw(const::std::vector<TNodePair> & i_aJoinColumns)485 void OptimisticSet::fillJoinedColumns_throw(const ::std::vector< TNodePair >& i_aJoinColumns)
486 {
487 ::std::vector< TNodePair >::const_iterator aIter = i_aJoinColumns.begin();
488 for(;aIter != i_aJoinColumns.end();++aIter)
489 {
490 ::rtl::OUString sColumnName,sTableName;
491 m_aSqlIterator.getColumnRange(aIter->first,sColumnName,sTableName);
492 ::rtl::OUStringBuffer sLeft,sRight;
493 sLeft.append(sTableName);
494 sLeft.appendAscii(".");
495 sLeft.append(sColumnName);
496 m_aSqlIterator.getColumnRange(aIter->second,sColumnName,sTableName);
497 sRight.append(sTableName);
498 sRight.appendAscii(".");
499 sRight.append(sColumnName);
500 fillJoinedColumns_throw(sLeft.makeStringAndClear(),sRight.makeStringAndClear());
501 }
502 }
503 // -----------------------------------------------------------------------------
fillJoinedColumns_throw(const::rtl::OUString & i_sLeftColumn,const::rtl::OUString & i_sRightColumn)504 void OptimisticSet::fillJoinedColumns_throw(const ::rtl::OUString& i_sLeftColumn,const ::rtl::OUString& i_sRightColumn)
505 {
506 sal_Int32 nLeft = 0,nRight = 0;
507 SelectColumnsMetaData::const_iterator aLeftIter = m_pKeyColumnNames->find(i_sLeftColumn);
508 SelectColumnsMetaData::const_iterator aRightIter = m_pKeyColumnNames->find(i_sRightColumn);
509
510 bool bLeftKey = aLeftIter != m_pKeyColumnNames->end();
511 if ( bLeftKey )
512 {
513 nLeft = aLeftIter->second.nPosition;
514 }
515 else
516 {
517 aLeftIter = m_pColumnNames->find(i_sLeftColumn);
518 if ( aLeftIter != m_pColumnNames->end() )
519 nLeft = aLeftIter->second.nPosition;
520 }
521
522 bool bRightKey = aRightIter != m_pKeyColumnNames->end();
523 if ( bRightKey )
524 {
525 nRight = aRightIter->second.nPosition;
526 }
527 else
528 {
529 aRightIter = m_pColumnNames->find(i_sRightColumn);
530 if ( aRightIter != m_pColumnNames->end() )
531 nRight = aRightIter->second.nPosition;
532 }
533
534 if (bLeftKey)
535 m_aJoinedKeyColumns[nLeft] = nRight;
536 else
537 m_aJoinedColumns[nLeft] = nRight;
538 if (bRightKey)
539 m_aJoinedKeyColumns[nRight] = nLeft;
540 else
541 m_aJoinedColumns[nRight] = nLeft;
542 }
543 // -----------------------------------------------------------------------------
isResultSetChanged() const544 bool OptimisticSet::isResultSetChanged() const
545 {
546 bool bOld = m_bResultSetChanged;
547 m_bResultSetChanged = false;
548 return bOld;
549 }
550 // -----------------------------------------------------------------------------
reset(const Reference<XResultSet> & _xDriverSet)551 void OptimisticSet::reset(const Reference< XResultSet>& _xDriverSet)
552 {
553 OCacheSet::construct(_xDriverSet,::rtl::OUString());
554 m_bRowCountFinal = sal_False;
555 m_aKeyMap.clear();
556 m_aKeyMap.insert(OKeySetMatrix::value_type(0,OKeySetValue(NULL,::std::pair<sal_Int32,Reference<XRow> >(0,NULL))));
557 m_aKeyIter = m_aKeyMap.begin();
558 }
559 // -----------------------------------------------------------------------------
mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector & io_aInsertRow,ORowSetValueVector::Vector & io_aRow,::std::vector<sal_Int32> & o_aChangedColumns)560 void OptimisticSet::mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& io_aInsertRow,ORowSetValueVector::Vector& io_aRow,::std::vector<sal_Int32>& o_aChangedColumns)
561 {
562 o_aChangedColumns.push_back(i_nColumnIndex);
563 ::std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(i_nColumnIndex);
564 if ( aJoinIter != m_aJoinedColumns.end() )
565 {
566 io_aRow[aJoinIter->second] = io_aRow[i_nColumnIndex];
567 io_aInsertRow[aJoinIter->second] = io_aInsertRow[i_nColumnIndex];
568 io_aRow[aJoinIter->second].setModified();
569 o_aChangedColumns.push_back(aJoinIter->second);
570 }
571 }
572 namespace
573 {
574 struct PositionFunctor : ::std::unary_function<SelectColumnsMetaData::value_type,bool>
575 {
576 sal_Int32 m_nPos;
PositionFunctor__anonbd6925a80211::PositionFunctor577 PositionFunctor(sal_Int32 i_nPos)
578 : m_nPos(i_nPos)
579 {
580 }
581
operator ()__anonbd6925a80211::PositionFunctor582 inline bool operator()(const SelectColumnsMetaData::value_type& _aType)
583 {
584 return m_nPos == _aType.second.nPosition;
585 }
586 };
587 struct TableNameFunctor : ::std::unary_function<SelectColumnsMetaData::value_type,bool>
588 {
589 ::rtl::OUString m_sTableName;
TableNameFunctor__anonbd6925a80211::TableNameFunctor590 TableNameFunctor(const ::rtl::OUString& i_sTableName)
591 : m_sTableName(i_sTableName)
592 {
593 }
594
operator ()__anonbd6925a80211::TableNameFunctor595 inline bool operator()(const SelectColumnsMetaData::value_type& _aType)
596 {
597 return m_sTableName == _aType.second.sTableName;
598 }
599 };
600 }
601 // -----------------------------------------------------------------------------
updateColumnValues(const ORowSetValueVector::Vector & io_aCachedRow,ORowSetValueVector::Vector & io_aRow,const::std::vector<sal_Int32> & i_aChangedColumns)602 bool OptimisticSet::updateColumnValues(const ORowSetValueVector::Vector& io_aCachedRow,ORowSetValueVector::Vector& io_aRow,const ::std::vector<sal_Int32>& i_aChangedColumns)
603 {
604 bool bRet = false;
605 ::std::vector<sal_Int32>::const_iterator aColIdxIter = i_aChangedColumns.begin();
606 for(;aColIdxIter != i_aChangedColumns.end();++aColIdxIter)
607 {
608 SelectColumnsMetaData::const_iterator aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),PositionFunctor(*aColIdxIter));
609 if ( aFind != m_pKeyColumnNames->end() )
610 {
611 const ::rtl::OUString sTableName = aFind->second.sTableName;
612 aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),TableNameFunctor(sTableName));
613 while( aFind != m_pKeyColumnNames->end() )
614 {
615 io_aRow[aFind->second.nPosition].setSigned(io_aCachedRow[aFind->second.nPosition].isSigned());
616 if ( io_aCachedRow[aFind->second.nPosition] != io_aRow[aFind->second.nPosition] )
617 break;
618 ++aFind;
619 }
620 if ( aFind == m_pKeyColumnNames->end() )
621 {
622 bRet = true;
623 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
624 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
625 for ( ;aIter != aEnd;++aIter )
626 {
627 if ( aIter->second.sTableName == sTableName )
628 {
629 io_aRow[aIter->second.nPosition] = io_aCachedRow[aIter->second.nPosition];
630 io_aRow[aIter->second.nPosition].setModified();
631 }
632 }
633 }
634 }
635 }
636 return bRet;
637 }
638 // -----------------------------------------------------------------------------
columnValuesUpdated(ORowSetValueVector::Vector & o_aCachedRow,const ORowSetValueVector::Vector & i_aRow)639 bool OptimisticSet::columnValuesUpdated(ORowSetValueVector::Vector& o_aCachedRow,const ORowSetValueVector::Vector& i_aRow)
640 {
641 bool bRet = false;
642 SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
643 SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
644 for(;aIter != aEnd;++aIter)
645 {
646 SelectColumnsMetaData::const_iterator aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),PositionFunctor(aIter->second.nPosition));
647 if ( aFind != m_pKeyColumnNames->end() )
648 {
649 const ::rtl::OUString sTableName = aFind->second.sTableName;
650 aFind = ::std::find_if(m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),TableNameFunctor(sTableName));
651 while( aFind != m_pKeyColumnNames->end() )
652 {
653 o_aCachedRow[aFind->second.nPosition].setSigned(i_aRow[aFind->second.nPosition].isSigned());
654 if ( o_aCachedRow[aFind->second.nPosition] != i_aRow[aFind->second.nPosition] )
655 break;
656 ++aFind;
657 }
658 if ( aFind == m_pKeyColumnNames->end() )
659 {
660 bRet = true;
661 SelectColumnsMetaData::const_iterator aIter2 = m_pColumnNames->begin();
662 SelectColumnsMetaData::const_iterator aEnd2 = m_pColumnNames->end();
663 for ( ;aIter2 != aEnd2;++aIter2 )
664 {
665 if ( aIter2->second.sTableName == sTableName )
666 {
667 o_aCachedRow[aIter2->second.nPosition] = i_aRow[aIter2->second.nPosition];
668 o_aCachedRow[aIter2->second.nPosition].setModified();
669 }
670 }
671 fillMissingValues(o_aCachedRow);
672 }
673 }
674 }
675 return bRet;
676 }
677 // -----------------------------------------------------------------------------
fillMissingValues(ORowSetValueVector::Vector & io_aRow) const678 void OptimisticSet::fillMissingValues(ORowSetValueVector::Vector& io_aRow) const
679 {
680 TSQLStatements aSql;
681 TSQLStatements aKeyConditions;
682 ::std::map< ::rtl::OUString,bool > aResultSetChanged;
683 ::rtl::OUString aQuote = getIdentifierQuoteString();
684 static ::rtl::OUString aAnd = ::rtl::OUString::createFromAscii(" AND ");
685 ::rtl::OUString sIsNull(RTL_CONSTASCII_USTRINGPARAM(" IS NULL"));
686 ::rtl::OUString sParam(RTL_CONSTASCII_USTRINGPARAM(" = ?"));
687 // here we build the condition part for the update statement
688 SelectColumnsMetaData::const_iterator aColIter = m_pColumnNames->begin();
689 SelectColumnsMetaData::const_iterator aColEnd = m_pColumnNames->end();
690 for(;aColIter != aColEnd;++aColIter)
691 {
692 const ::rtl::OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,aColIter->second.sRealName);
693 if ( m_aJoinedKeyColumns.find(aColIter->second.nPosition) != m_aJoinedKeyColumns.end() )
694 {
695 lcl_fillKeyCondition(aColIter->second.sTableName,sQuotedColumnName,io_aRow[aColIter->second.nPosition],aKeyConditions);
696 }
697 ::rtl::OUStringBuffer& rPart = aSql[aColIter->second.sTableName];
698 if ( rPart.getLength() )
699 rPart.appendAscii(", ");
700 rPart.append(sQuotedColumnName);
701 }
702 Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
703 TSQLStatements::iterator aSqlIter = aSql.begin();
704 TSQLStatements::iterator aSqlEnd = aSql.end();
705 for(;aSqlIter != aSqlEnd ; ++aSqlIter)
706 {
707 if ( aSqlIter->second.getLength() )
708 {
709 ::rtl::OUStringBuffer& rCondition = aKeyConditions[aSqlIter->first];
710 if ( rCondition.getLength() )
711 {
712 ::rtl::OUString sCatalog,sSchema,sTable;
713 ::dbtools::qualifiedNameComponents(xMetaData,aSqlIter->first,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
714 ::rtl::OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
715 ::rtl::OUStringBuffer sQuery;
716 sQuery.appendAscii("SELECT ");
717 sQuery.append(aSqlIter->second);
718 sQuery.appendAscii(" FROM ");
719 sQuery.append(sComposedTableName);
720 sQuery.appendAscii(" WHERE ");
721 sQuery.append(rCondition.makeStringAndClear());
722
723 try
724 {
725 Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery.makeStringAndClear()));
726 Reference< XParameters > xParameter(xPrep,UNO_QUERY);
727 // and then the values of the where condition
728 SelectColumnsMetaData::iterator aKeyIter = m_pKeyColumnNames->begin();
729 SelectColumnsMetaData::iterator aKeyEnd = m_pKeyColumnNames->end();
730 sal_Int32 i = 1;
731 for(;aKeyIter != aKeyEnd;++aKeyIter)
732 {
733 if ( aKeyIter->second.sTableName == aSqlIter->first )
734 {
735 setParameter(i++,xParameter,io_aRow[aKeyIter->second.nPosition],aKeyIter->second.nType,aKeyIter->second.nScale);
736 }
737 }
738 Reference<XResultSet> xRes = xPrep->executeQuery();
739 Reference<XRow> xRow(xRes,UNO_QUERY);
740 if ( xRow.is() && xRes->next() )
741 {
742 i = 1;
743 aColIter = m_pColumnNames->begin();
744 for(;aColIter != aColEnd;++aColIter)
745 {
746 if ( aColIter->second.sTableName == aSqlIter->first )
747 {
748 io_aRow[aColIter->second.nPosition].fill(i++,aColIter->second.nType,aColIter->second.bNullable,xRow);
749 io_aRow[aColIter->second.nPosition].setModified();
750 }
751 }
752 }
753 }
754 catch(const SQLException&)
755 {
756 }
757 }
758 }
759 }
760 }
761 // -----------------------------------------------------------------------------
762
763