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