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