2 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4 * This file is part of the LibreOffice project.
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 * This file incorporates work covered by the following license notice:
12 * Licensed to the Apache Software Foundation (ASF) under one or more
13 * contributor license agreements. See the NOTICE file distributed
14 * with this work for additional information regarding copyright
15 * ownership. The ASF licenses this file to you under the Apache
16 * License, Version 2.0 (the "License"); you may not use this file
17 * except in compliance with the License. You may obtain a copy of
18 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include "OptimisticSet.hxx"
23 #include "core_resource.hxx"
24 #include "core_resource.hrc"
25 #include <com/sun/star/beans/XPropertySet.hpp>
26 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
27 #include <com/sun/star/sdbc/ColumnValue.hpp>
28 #include <com/sun/star/sdbc/XPreparedStatement.hpp>
29 #include <com/sun/star/sdbc/XParameters.hpp>
30 #include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
31 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
32 #include <com/sun/star/sdb/SQLFilterOperator.hpp>
33 #include <com/sun/star/sdbc/XColumnLocate.hpp>
34 #include <com/sun/star/container/XIndexAccess.hpp>
35 #include "dbastrings.hrc"
36 #include "apitools.hxx"
37 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
38 #include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
39 #include <cppuhelper/typeprovider.hxx>
40 #include <comphelper/types.hxx>
41 #include <com/sun/star/sdbcx/KeyType.hpp>
42 #include <connectivity/dbtools.hxx>
43 #include <connectivity/dbexception.hxx>
47 #include <com/sun/star/io/XInputStream.hpp>
48 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
49 #include "querycomposer.hxx"
50 #include "composertools.hxx"
51 #include <tools/debug.hxx>
52 #include <rtl/logfile.hxx>
54 using namespace dbaccess
;
55 using namespace ::connectivity
;
56 using namespace ::dbtools
;
57 using namespace ::com::sun::star::uno
;
58 using namespace ::com::sun::star::beans
;
59 using namespace ::com::sun::star::sdbc
;
60 using namespace ::com::sun::star::sdb
;
61 using namespace ::com::sun::star::sdbcx
;
62 using namespace ::com::sun::star::container
;
63 using namespace ::com::sun::star::lang
;
64 using namespace ::com::sun::star::util
;
65 using namespace ::com::sun::star::io
;
66 using namespace ::com::sun::star
;
67 using namespace ::cppu
;
68 using namespace ::osl
;
70 DECLARE_STL_USTRINGACCESS_MAP(::rtl::OUStringBuffer
,TSQLStatements
);
73 void lcl_fillKeyCondition(const ::rtl::OUString
& i_sTableName
,const ::rtl::OUString
& i_sQuotedColumnName
,const ORowSetValue
& i_aValue
,TSQLStatements
& io_aKeyConditions
)
75 ::rtl::OUStringBuffer
& rKeyCondition
= io_aKeyConditions
[i_sTableName
];
76 if ( rKeyCondition
.getLength() )
77 rKeyCondition
.appendAscii(" AND ");
78 rKeyCondition
.append(i_sQuotedColumnName
);
79 if ( i_aValue
.isNull() )
80 rKeyCondition
.appendAscii(" IS NULL");
82 rKeyCondition
.appendAscii(" = ?");
86 DBG_NAME(OptimisticSet
)
88 OptimisticSet::OptimisticSet(const ::comphelper::ComponentContext
& _rContext
,
89 const Reference
< XConnection
>& i_xConnection
,
90 const Reference
< XSingleSelectQueryAnalyzer
>& _xComposer
,
91 const ORowSetValueVector
& _aParameterValueForCache
,
93 sal_Int32
& o_nRowCount
)
94 :OKeySet(NULL
,NULL
,::rtl::OUString(),_xComposer
,_aParameterValueForCache
,i_nMaxRows
,o_nRowCount
)
95 ,m_aSqlParser( _rContext
.getUNOContext() )
96 ,m_aSqlIterator( i_xConnection
, Reference
<XTablesSupplier
>(_xComposer
,UNO_QUERY
)->getTables(), m_aSqlParser
, NULL
)
97 ,m_bResultSetChanged(false)
99 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::OptimisticSet" );
100 DBG_CTOR(OptimisticSet
,NULL
);
103 OptimisticSet::~OptimisticSet()
105 DBG_DTOR(OptimisticSet
,NULL
);
108 void OptimisticSet::construct(const Reference
< XResultSet
>& _xDriverSet
,const ::rtl::OUString
& i_sRowSetFilter
)
110 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::construct" );
111 OCacheSet::construct(_xDriverSet
,i_sRowSetFilter
);
114 Reference
<XDatabaseMetaData
> xMeta
= m_xConnection
->getMetaData();
115 bool bCase
= (xMeta
.is() && xMeta
->supportsMixedCaseQuotedIdentifiers()) ? true : false;
116 Reference
<XColumnsSupplier
> xQueryColSup(m_xComposer
,UNO_QUERY
);
117 const Reference
<XNameAccess
> xQueryColumns
= xQueryColSup
->getColumns();
118 const Reference
<XTablesSupplier
> xTabSup(m_xComposer
,UNO_QUERY
);
119 const Reference
<XNameAccess
> xTables
= xTabSup
->getTables();
120 const Sequence
< ::rtl::OUString
> aTableNames
= xTables
->getElementNames();
121 const ::rtl::OUString
* pTableNameIter
= aTableNames
.getConstArray();
122 const ::rtl::OUString
* pTableNameEnd
= pTableNameIter
+ aTableNames
.getLength();
123 for( ; pTableNameIter
!= pTableNameEnd
; ++pTableNameIter
)
125 SAL_WNODEPRECATED_DECLARATIONS_PUSH
126 ::std::auto_ptr
<SelectColumnsMetaData
> pKeyColumNames(new SelectColumnsMetaData(bCase
));
127 SAL_WNODEPRECATED_DECLARATIONS_POP
128 findTableColumnsMatching_throw(xTables
->getByName(*pTableNameIter
),*pTableNameIter
,xMeta
,xQueryColumns
,pKeyColumNames
);
129 m_pKeyColumnNames
->insert(pKeyColumNames
->begin(),pKeyColumNames
->end());
132 // the first row is empty because it's now easier for us to distinguish when we are beforefirst or first
133 // without extra variable to be set
134 OKeySetValue
keySetValue((ORowSetValueVector
*)NULL
,::std::pair
<sal_Int32
,Reference
<XRow
> >(0,(Reference
<XRow
>)NULL
));
135 m_aKeyMap
.insert(OKeySetMatrix::value_type(0,keySetValue
));
136 m_aKeyIter
= m_aKeyMap
.begin();
138 ::rtl::OUStringBuffer aFilter
= createKeyFilter();
140 Reference
< XSingleSelectQueryComposer
> xSourceComposer(m_xComposer
,UNO_QUERY
);
141 Reference
< XMultiServiceFactory
> xFactory(m_xConnection
, UNO_QUERY_THROW
);
142 Reference
<XSingleSelectQueryComposer
> xAnalyzer(xFactory
->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
),UNO_QUERY
);
143 ::rtl::OUString sQuery
= xSourceComposer
->getQuery();
144 xAnalyzer
->setElementaryQuery(xSourceComposer
->getElementaryQuery());
146 ::rtl::OUString aErrorMsg
;
147 SAL_WNODEPRECATED_DECLARATIONS_PUSH
148 ::std::auto_ptr
<OSQLParseNode
> pStatementNode( m_aSqlParser
.parseTree( aErrorMsg
, sQuery
) );
149 SAL_WNODEPRECATED_DECLARATIONS_POP
150 m_aSqlIterator
.setParseTree( pStatementNode
.get() );
151 m_aSqlIterator
.traverseAll();
152 fillJoinedColumns_throw(m_aSqlIterator
.getJoinConditions());
154 const ::rtl::OUString sComposerFilter
= m_xComposer
->getFilter();
155 if ( !i_sRowSetFilter
.isEmpty() || (!sComposerFilter
.isEmpty() && sComposerFilter
!= i_sRowSetFilter
) )
157 FilterCreator aFilterCreator
;
158 if ( !sComposerFilter
.isEmpty() && sComposerFilter
!= i_sRowSetFilter
)
159 aFilterCreator
.append( sComposerFilter
);
160 aFilterCreator
.append( i_sRowSetFilter
);
161 aFilterCreator
.append( aFilter
.makeStringAndClear() );
162 aFilter
= aFilterCreator
.getComposedAndClear();
164 xAnalyzer
->setFilter(aFilter
.makeStringAndClear());
165 m_xStatement
= m_xConnection
->prepareStatement(xAnalyzer
->getQueryWithSubstitution());
166 ::comphelper::disposeComponent(xAnalyzer
);
169 // ::com::sun::star::sdbcx::XDeleteRows
170 Sequence
< sal_Int32
> SAL_CALL
OptimisticSet::deleteRows( const Sequence
< Any
>& /*rows*/ ,const connectivity::OSQLTable
& /*_xTable*/) throw(SQLException
, RuntimeException
)
172 Sequence
< sal_Int32
> aRet
;
176 void SAL_CALL
OptimisticSet::updateRow(const ORowSetRow
& _rInsertRow
,const ORowSetRow
& _rOrginalRow
,const connectivity::OSQLTable
& /*_xTable*/ ) throw(SQLException
, RuntimeException
)
178 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::updateRow" );
179 if ( m_aJoinedKeyColumns
.empty() )
180 throw SQLException();
181 // list all cloumns that should be set
182 static ::rtl::OUString
s_sPara(" = ?");
183 ::rtl::OUString aQuote
= getIdentifierQuoteString();
185 ::rtl::OUString aColumnName
;
186 ::rtl::OUStringBuffer sKeyCondition
;
187 ::std::map
< ::rtl::OUString
,bool > aResultSetChanged
;
188 TSQLStatements aKeyConditions
;
189 TSQLStatements aIndexConditions
;
192 // here we build the condition part for the update statement
193 SelectColumnsMetaData::const_iterator aIter
= m_pColumnNames
->begin();
194 SelectColumnsMetaData::const_iterator aEnd
= m_pColumnNames
->end();
195 for(;aIter
!= aEnd
;++aIter
)
197 if ( aResultSetChanged
.find( aIter
->second
.sTableName
) == aResultSetChanged
.end() )
198 aResultSetChanged
[aIter
->second
.sTableName
] = false;
199 const ::rtl::OUString sQuotedColumnName
= ::dbtools::quoteName( aQuote
,aIter
->second
.sRealName
);
200 if ( m_pKeyColumnNames
->find(aIter
->first
) != m_pKeyColumnNames
->end() )
202 aResultSetChanged
[aIter
->second
.sTableName
] = m_aJoinedKeyColumns
.find(aIter
->second
.nPosition
) != m_aJoinedKeyColumns
.end();
203 lcl_fillKeyCondition(aIter
->second
.sTableName
,sQuotedColumnName
,(_rOrginalRow
->get())[aIter
->second
.nPosition
],aKeyConditions
);
205 if((_rInsertRow
->get())[aIter
->second
.nPosition
].isModified())
207 if ( m_aJoinedKeyColumns
.find(aIter
->second
.nPosition
) != m_aJoinedKeyColumns
.end() )
208 throw SQLException();
210 ::std::map
<sal_Int32
,sal_Int32
>::const_iterator aJoinIter
= m_aJoinedColumns
.find(aIter
->second
.nPosition
);
211 if ( aJoinIter
!= m_aJoinedColumns
.end() )
213 (_rInsertRow
->get())[aJoinIter
->second
] = (_rInsertRow
->get())[aIter
->second
.nPosition
];
215 ::rtl::OUStringBuffer
& rPart
= aSql
[aIter
->second
.sTableName
];
216 if ( rPart
.getLength() )
217 rPart
.appendAscii(", ");
218 rPart
.append(sQuotedColumnName
);
219 rPart
.append(s_sPara
);
224 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED
), SQL_GENERAL_ERROR
, m_xConnection
);
226 if( aKeyConditions
.empty() )
227 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_CONDITION_FOR_PK
), SQL_GENERAL_ERROR
, m_xConnection
);
229 static const ::rtl::OUString
s_sUPDATE("UPDATE ");
230 static const ::rtl::OUString
s_sSET(" SET ");
232 Reference
<XDatabaseMetaData
> xMetaData
= m_xConnection
->getMetaData();
234 TSQLStatements::iterator aSqlIter
= aSql
.begin();
235 TSQLStatements::iterator aSqlEnd
= aSql
.end();
236 for(;aSqlIter
!= aSqlEnd
; ++aSqlIter
)
238 if ( aSqlIter
->second
.getLength() )
240 m_bResultSetChanged
= m_bResultSetChanged
|| aResultSetChanged
[aSqlIter
->first
];
241 ::rtl::OUStringBuffer
sSql(s_sUPDATE
);
242 ::rtl::OUString sCatalog
,sSchema
,sTable
;
243 ::dbtools::qualifiedNameComponents(xMetaData
,aSqlIter
->first
,sCatalog
,sSchema
,sTable
,::dbtools::eInDataManipulation
);
244 sSql
.append( ::dbtools::composeTableNameForSelect( m_xConnection
, sCatalog
, sSchema
, sTable
) );
246 sSql
.append(aSqlIter
->second
.toString());
247 ::rtl::OUStringBuffer
& rCondition
= aKeyConditions
[aSqlIter
->first
];
248 if ( rCondition
.getLength() )
250 sSql
.appendAscii(" WHERE ");
251 sSql
.append( rCondition
.toString() );
253 executeUpdate(_rInsertRow
,_rOrginalRow
,sSql
.makeStringAndClear(),aSqlIter
->first
);
258 void SAL_CALL
OptimisticSet::insertRow( const ORowSetRow
& _rInsertRow
,const connectivity::OSQLTable
& /*_xTable*/ ) throw(SQLException
, RuntimeException
)
260 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::insertRow" );
262 TSQLStatements aParameter
;
263 TSQLStatements aKeyConditions
;
264 ::std::map
< ::rtl::OUString
,bool > aResultSetChanged
;
265 ::rtl::OUString aQuote
= getIdentifierQuoteString();
267 // here we build the condition part for the update statement
268 SelectColumnsMetaData::const_iterator aIter
= m_pColumnNames
->begin();
269 SelectColumnsMetaData::const_iterator aEnd
= m_pColumnNames
->end();
270 for(;aIter
!= aEnd
;++aIter
)
272 if ( aResultSetChanged
.find( aIter
->second
.sTableName
) == aResultSetChanged
.end() )
273 aResultSetChanged
[aIter
->second
.sTableName
] = false;
275 const ::rtl::OUString sQuotedColumnName
= ::dbtools::quoteName( aQuote
,aIter
->second
.sRealName
);
276 if ( (_rInsertRow
->get())[aIter
->second
.nPosition
].isModified() )
278 if ( m_aJoinedKeyColumns
.find(aIter
->second
.nPosition
) != m_aJoinedKeyColumns
.end() )
280 lcl_fillKeyCondition(aIter
->second
.sTableName
,sQuotedColumnName
,(_rInsertRow
->get())[aIter
->second
.nPosition
],aKeyConditions
);
281 aResultSetChanged
[aIter
->second
.sTableName
] = true;
283 ::std::map
<sal_Int32
,sal_Int32
>::const_iterator aJoinIter
= m_aJoinedColumns
.find(aIter
->second
.nPosition
);
284 if ( aJoinIter
!= m_aJoinedColumns
.end() )
286 (_rInsertRow
->get())[aJoinIter
->second
] = (_rInsertRow
->get())[aIter
->second
.nPosition
];
288 ::rtl::OUStringBuffer
& rPart
= aSql
[aIter
->second
.sTableName
];
289 if ( rPart
.getLength() )
290 rPart
.appendAscii(", ");
291 rPart
.append(sQuotedColumnName
);
292 ::rtl::OUStringBuffer
& rParam
= aParameter
[aIter
->second
.sTableName
];
293 if ( rParam
.getLength() )
294 rParam
.appendAscii(", ");
295 rParam
.appendAscii("?");
298 if ( aParameter
.empty() )
299 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED
), SQL_GENERAL_ERROR
, m_xConnection
);
301 Reference
<XDatabaseMetaData
> xMetaData
= m_xConnection
->getMetaData();
302 static const ::rtl::OUString
s_sINSERT("INSERT INTO ");
303 static const ::rtl::OUString
s_sVALUES(") VALUES ( ");
304 TSQLStatements::iterator aSqlIter
= aSql
.begin();
305 TSQLStatements::iterator aSqlEnd
= aSql
.end();
306 for(;aSqlIter
!= aSqlEnd
; ++aSqlIter
)
308 if ( aSqlIter
->second
.getLength() )
310 m_bResultSetChanged
= m_bResultSetChanged
|| aResultSetChanged
[aSqlIter
->first
];
311 ::rtl::OUStringBuffer
sSql(s_sINSERT
);
312 ::rtl::OUString sCatalog
,sSchema
,sTable
;
313 ::dbtools::qualifiedNameComponents(xMetaData
,aSqlIter
->first
,sCatalog
,sSchema
,sTable
,::dbtools::eInDataManipulation
);
314 ::rtl::OUString sComposedTableName
= ::dbtools::composeTableNameForSelect( m_xConnection
, sCatalog
, sSchema
, sTable
);
315 sSql
.append(sComposedTableName
);
316 sSql
.appendAscii(" ( ");
317 sSql
.append(aSqlIter
->second
.toString());
318 sSql
.append(s_sVALUES
);
319 sSql
.append(aParameter
[aSqlIter
->first
].toString());
320 sSql
.appendAscii(" )");
322 ::rtl::OUStringBuffer
& rCondition
= aKeyConditions
[aSqlIter
->first
];
323 if ( rCondition
.getLength() )
325 ::rtl::OUStringBuffer sQuery
;
326 sQuery
.appendAscii("SELECT ");
327 sQuery
.append(aSqlIter
->second
.toString());
328 sQuery
.appendAscii(" FROM ");
329 sQuery
.append(sComposedTableName
);
330 sQuery
.appendAscii(" WHERE ");
331 sQuery
.append(rCondition
.toString());
335 Reference
< XPreparedStatement
> xPrep(m_xConnection
->prepareStatement(sQuery
.makeStringAndClear()));
336 Reference
< XParameters
> xParameter(xPrep
,UNO_QUERY
);
337 // and then the values of the where condition
338 SelectColumnsMetaData::iterator aKeyCol
= m_pKeyColumnNames
->begin();
339 SelectColumnsMetaData::iterator aKeysEnd
= m_pKeyColumnNames
->end();
341 for(;aKeyCol
!= aKeysEnd
;++aKeyCol
)
343 if ( aKeyCol
->second
.sTableName
== aSqlIter
->first
)
345 setParameter(i
++,xParameter
,(_rInsertRow
->get())[aKeyCol
->second
.nPosition
],aKeyCol
->second
.nType
,aKeyCol
->second
.nScale
);
348 Reference
<XResultSet
> xRes
= xPrep
->executeQuery();
349 Reference
<XRow
> xRow(xRes
,UNO_QUERY
);
350 if ( xRow
.is() && xRes
->next() )
352 m_bResultSetChanged
= true;
356 catch(const SQLException
&)
361 executeInsert(_rInsertRow
,sSql
.makeStringAndClear(),aSqlIter
->first
);
366 void SAL_CALL
OptimisticSet::deleteRow(const ORowSetRow
& _rDeleteRow
,const connectivity::OSQLTable
& /*_xTable*/ ) throw(SQLException
, RuntimeException
)
368 ::rtl::OUString aQuote
= getIdentifierQuoteString();
369 ::rtl::OUString aColumnName
;
370 ::rtl::OUStringBuffer sKeyCondition
,sIndexCondition
;
371 ::std::vector
<sal_Int32
> aIndexColumnPositions
;
372 TSQLStatements aKeyConditions
;
373 TSQLStatements aIndexConditions
;
376 // here we build the condition part for the update statement
377 SelectColumnsMetaData::const_iterator aIter
= m_pColumnNames
->begin();
378 SelectColumnsMetaData::const_iterator aEnd
= m_pColumnNames
->end();
379 for(;aIter
!= aEnd
;++aIter
)
381 if ( m_aJoinedKeyColumns
.find(aIter
->second
.nPosition
) == m_aJoinedKeyColumns
.end() && m_pKeyColumnNames
->find(aIter
->first
) != m_pKeyColumnNames
->end() )
383 // only delete rows which aren't the key in the join
384 const ::rtl::OUString sQuotedColumnName
= ::dbtools::quoteName( aQuote
,aIter
->second
.sRealName
);
385 lcl_fillKeyCondition(aIter
->second
.sTableName
,sQuotedColumnName
,(_rDeleteRow
->get())[aIter
->second
.nPosition
],aKeyConditions
);
388 Reference
<XDatabaseMetaData
> xMetaData
= m_xConnection
->getMetaData();
389 TSQLStatements::iterator aSqlIter
= aKeyConditions
.begin();
390 TSQLStatements::iterator aSqlEnd
= aKeyConditions
.end();
391 for(;aSqlIter
!= aSqlEnd
; ++aSqlIter
)
393 ::rtl::OUStringBuffer
& rCondition
= aSqlIter
->second
;
394 if ( rCondition
.getLength() )
396 ::rtl::OUStringBuffer sSql
;
397 sSql
.appendAscii("DELETE FROM ");
398 ::rtl::OUString sCatalog
,sSchema
,sTable
;
399 ::dbtools::qualifiedNameComponents(xMetaData
,aSqlIter
->first
,sCatalog
,sSchema
,sTable
,::dbtools::eInDataManipulation
);
400 sSql
.append( ::dbtools::composeTableNameForSelect( m_xConnection
, sCatalog
, sSchema
, sTable
) );
401 sSql
.appendAscii(" WHERE ");
402 sSql
.append( rCondition
.toString() );
403 executeDelete(_rDeleteRow
,sSql
.makeStringAndClear(),aSqlIter
->first
);
408 void OptimisticSet::executeDelete(const ORowSetRow
& _rDeleteRow
,const ::rtl::OUString
& i_sSQL
,const ::rtl::OUString
& i_sTableName
)
410 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbaccess", "Ocke.Janssen@sun.com", "OptimisticSet::executeDelete" );
412 // now create and execute the prepared statement
413 Reference
< XPreparedStatement
> xPrep(m_xConnection
->prepareStatement(i_sSQL
));
414 Reference
< XParameters
> xParameter(xPrep
,UNO_QUERY
);
416 SelectColumnsMetaData::const_iterator aIter
= m_pKeyColumnNames
->begin();
417 SelectColumnsMetaData::const_iterator aEnd
= m_pKeyColumnNames
->end();
419 for(;aIter
!= aEnd
;++aIter
)
421 if ( aIter
->second
.sTableName
== i_sTableName
)
422 setParameter(i
++,xParameter
,(_rDeleteRow
->get())[aIter
->second
.nPosition
],aIter
->second
.nType
,aIter
->second
.nScale
);
424 m_bDeleted
= xPrep
->executeUpdate() > 0;
428 sal_Int32 nBookmark
= ::comphelper::getINT32((_rDeleteRow
->get())[0].getAny());
429 if(m_aKeyIter
== m_aKeyMap
.find(nBookmark
) && m_aKeyIter
!= m_aKeyMap
.end())
431 m_aKeyMap
.erase(nBookmark
);
432 m_bDeleted
= sal_True
;
436 void OptimisticSet::fillJoinedColumns_throw(const ::std::vector
< TNodePair
>& i_aJoinColumns
)
438 ::std::vector
< TNodePair
>::const_iterator aIter
= i_aJoinColumns
.begin();
439 for(;aIter
!= i_aJoinColumns
.end();++aIter
)
441 ::rtl::OUString sColumnName
,sTableName
;
442 m_aSqlIterator
.getColumnRange(aIter
->first
,sColumnName
,sTableName
);
443 ::rtl::OUStringBuffer sLeft
,sRight
;
444 sLeft
.append(sTableName
);
445 sLeft
.appendAscii(".");
446 sLeft
.append(sColumnName
);
447 m_aSqlIterator
.getColumnRange(aIter
->second
,sColumnName
,sTableName
);
448 sRight
.append(sTableName
);
449 sRight
.appendAscii(".");
450 sRight
.append(sColumnName
);
451 fillJoinedColumns_throw(sLeft
.makeStringAndClear(),sRight
.makeStringAndClear());
455 void OptimisticSet::fillJoinedColumns_throw(const ::rtl::OUString
& i_sLeftColumn
,const ::rtl::OUString
& i_sRightColumn
)
457 sal_Int32 nLeft
= 0,nRight
= 0;
458 SelectColumnsMetaData::const_iterator aLeftIter
= m_pKeyColumnNames
->find(i_sLeftColumn
);
459 SelectColumnsMetaData::const_iterator aRightIter
= m_pKeyColumnNames
->find(i_sRightColumn
);
461 bool bLeftKey
= aLeftIter
!= m_pKeyColumnNames
->end();
464 nLeft
= aLeftIter
->second
.nPosition
;
468 aLeftIter
= m_pColumnNames
->find(i_sLeftColumn
);
469 if ( aLeftIter
!= m_pColumnNames
->end() )
470 nLeft
= aLeftIter
->second
.nPosition
;
473 bool bRightKey
= aRightIter
!= m_pKeyColumnNames
->end();
476 nRight
= aRightIter
->second
.nPosition
;
480 aRightIter
= m_pColumnNames
->find(i_sRightColumn
);
481 if ( aRightIter
!= m_pColumnNames
->end() )
482 nRight
= aRightIter
->second
.nPosition
;
486 m_aJoinedKeyColumns
[nLeft
] = nRight
;
488 m_aJoinedColumns
[nLeft
] = nRight
;
490 m_aJoinedKeyColumns
[nRight
] = nLeft
;
492 m_aJoinedColumns
[nRight
] = nLeft
;
495 bool OptimisticSet::isResultSetChanged() const
497 bool bOld
= m_bResultSetChanged
;
498 m_bResultSetChanged
= false;
502 void OptimisticSet::reset(const Reference
< XResultSet
>& _xDriverSet
)
504 OCacheSet::construct(_xDriverSet
,::rtl::OUString());
505 m_bRowCountFinal
= sal_False
;
507 OKeySetValue
keySetValue((ORowSetValueVector
*)NULL
,::std::pair
<sal_Int32
,Reference
<XRow
> >(0,(Reference
<XRow
>)NULL
));
508 m_aKeyMap
.insert(OKeySetMatrix::value_type(0,keySetValue
));
509 m_aKeyIter
= m_aKeyMap
.begin();
512 void OptimisticSet::mergeColumnValues(sal_Int32 i_nColumnIndex
,ORowSetValueVector::Vector
& io_aInsertRow
,ORowSetValueVector::Vector
& io_aRow
,::std::vector
<sal_Int32
>& o_aChangedColumns
)
514 o_aChangedColumns
.push_back(i_nColumnIndex
);
515 ::std::map
<sal_Int32
,sal_Int32
>::const_iterator aJoinIter
= m_aJoinedColumns
.find(i_nColumnIndex
);
516 if ( aJoinIter
!= m_aJoinedColumns
.end() )
518 io_aRow
[aJoinIter
->second
] = io_aRow
[i_nColumnIndex
];
519 io_aInsertRow
[aJoinIter
->second
] = io_aInsertRow
[i_nColumnIndex
];
520 io_aRow
[aJoinIter
->second
].setModified();
521 o_aChangedColumns
.push_back(aJoinIter
->second
);
526 struct PositionFunctor
: ::std::unary_function
<SelectColumnsMetaData::value_type
,bool>
529 PositionFunctor(sal_Int32 i_nPos
)
534 inline bool operator()(const SelectColumnsMetaData::value_type
& _aType
)
536 return m_nPos
== _aType
.second
.nPosition
;
539 struct TableNameFunctor
: ::std::unary_function
<SelectColumnsMetaData::value_type
,bool>
541 ::rtl::OUString m_sTableName
;
542 TableNameFunctor(const ::rtl::OUString
& i_sTableName
)
543 : m_sTableName(i_sTableName
)
547 inline bool operator()(const SelectColumnsMetaData::value_type
& _aType
)
549 return m_sTableName
== _aType
.second
.sTableName
;
554 bool OptimisticSet::updateColumnValues(const ORowSetValueVector::Vector
& io_aCachedRow
,ORowSetValueVector::Vector
& io_aRow
,const ::std::vector
<sal_Int32
>& i_aChangedColumns
)
557 ::std::vector
<sal_Int32
>::const_iterator aColIdxIter
= i_aChangedColumns
.begin();
558 for(;aColIdxIter
!= i_aChangedColumns
.end();++aColIdxIter
)
560 SelectColumnsMetaData::const_iterator aFind
= ::std::find_if(m_pKeyColumnNames
->begin(),m_pKeyColumnNames
->end(),PositionFunctor(*aColIdxIter
));
561 if ( aFind
!= m_pKeyColumnNames
->end() )
563 const ::rtl::OUString sTableName
= aFind
->second
.sTableName
;
564 aFind
= ::std::find_if(m_pKeyColumnNames
->begin(),m_pKeyColumnNames
->end(),TableNameFunctor(sTableName
));
565 while( aFind
!= m_pKeyColumnNames
->end() )
567 io_aRow
[aFind
->second
.nPosition
].setSigned(io_aCachedRow
[aFind
->second
.nPosition
].isSigned());
568 if ( io_aCachedRow
[aFind
->second
.nPosition
] != io_aRow
[aFind
->second
.nPosition
] )
572 if ( aFind
== m_pKeyColumnNames
->end() )
575 SelectColumnsMetaData::const_iterator aIter
= m_pColumnNames
->begin();
576 SelectColumnsMetaData::const_iterator aEnd
= m_pColumnNames
->end();
577 for ( ;aIter
!= aEnd
;++aIter
)
579 if ( aIter
->second
.sTableName
== sTableName
)
581 io_aRow
[aIter
->second
.nPosition
] = io_aCachedRow
[aIter
->second
.nPosition
];
582 io_aRow
[aIter
->second
.nPosition
].setModified();
591 bool OptimisticSet::columnValuesUpdated(ORowSetValueVector::Vector
& o_aCachedRow
,const ORowSetValueVector::Vector
& i_aRow
)
594 SelectColumnsMetaData::const_iterator aIter
= m_pColumnNames
->begin();
595 SelectColumnsMetaData::const_iterator aEnd
= m_pColumnNames
->end();
596 for(;aIter
!= aEnd
;++aIter
)
598 SelectColumnsMetaData::const_iterator aFind
= ::std::find_if(m_pKeyColumnNames
->begin(),m_pKeyColumnNames
->end(),PositionFunctor(aIter
->second
.nPosition
));
599 if ( aFind
!= m_pKeyColumnNames
->end() )
601 const ::rtl::OUString sTableName
= aFind
->second
.sTableName
;
602 aFind
= ::std::find_if(m_pKeyColumnNames
->begin(),m_pKeyColumnNames
->end(),TableNameFunctor(sTableName
));
603 while( aFind
!= m_pKeyColumnNames
->end() )
605 o_aCachedRow
[aFind
->second
.nPosition
].setSigned(i_aRow
[aFind
->second
.nPosition
].isSigned());
606 if ( o_aCachedRow
[aFind
->second
.nPosition
] != i_aRow
[aFind
->second
.nPosition
] )
610 if ( aFind
== m_pKeyColumnNames
->end() )
613 SelectColumnsMetaData::const_iterator aIter2
= m_pColumnNames
->begin();
614 SelectColumnsMetaData::const_iterator aEnd2
= m_pColumnNames
->end();
615 for ( ;aIter2
!= aEnd2
;++aIter2
)
617 if ( aIter2
->second
.sTableName
== sTableName
)
619 o_aCachedRow
[aIter2
->second
.nPosition
] = i_aRow
[aIter2
->second
.nPosition
];
620 o_aCachedRow
[aIter2
->second
.nPosition
].setModified();
623 fillMissingValues(o_aCachedRow
);
630 void OptimisticSet::fillMissingValues(ORowSetValueVector::Vector
& io_aRow
) const
633 TSQLStatements aKeyConditions
;
634 ::std::map
< ::rtl::OUString
,bool > aResultSetChanged
;
635 ::rtl::OUString aQuote
= getIdentifierQuoteString();
636 // here we build the condition part for the update statement
637 SelectColumnsMetaData::const_iterator aColIter
= m_pColumnNames
->begin();
638 SelectColumnsMetaData::const_iterator aColEnd
= m_pColumnNames
->end();
639 for(;aColIter
!= aColEnd
;++aColIter
)
641 const ::rtl::OUString sQuotedColumnName
= ::dbtools::quoteName( aQuote
,aColIter
->second
.sRealName
);
642 if ( m_aJoinedKeyColumns
.find(aColIter
->second
.nPosition
) != m_aJoinedKeyColumns
.end() )
644 lcl_fillKeyCondition(aColIter
->second
.sTableName
,sQuotedColumnName
,io_aRow
[aColIter
->second
.nPosition
],aKeyConditions
);
646 ::rtl::OUStringBuffer
& rPart
= aSql
[aColIter
->second
.sTableName
];
647 if ( rPart
.getLength() )
648 rPart
.appendAscii(", ");
649 rPart
.append(sQuotedColumnName
);
651 Reference
<XDatabaseMetaData
> xMetaData
= m_xConnection
->getMetaData();
652 TSQLStatements::iterator aSqlIter
= aSql
.begin();
653 TSQLStatements::iterator aSqlEnd
= aSql
.end();
654 for(;aSqlIter
!= aSqlEnd
; ++aSqlIter
)
656 if ( aSqlIter
->second
.getLength() )
658 ::rtl::OUStringBuffer
& rCondition
= aKeyConditions
[aSqlIter
->first
];
659 if ( rCondition
.getLength() )
661 ::rtl::OUString sCatalog
,sSchema
,sTable
;
662 ::dbtools::qualifiedNameComponents(xMetaData
,aSqlIter
->first
,sCatalog
,sSchema
,sTable
,::dbtools::eInDataManipulation
);
663 ::rtl::OUString sComposedTableName
= ::dbtools::composeTableNameForSelect( m_xConnection
, sCatalog
, sSchema
, sTable
);
664 ::rtl::OUStringBuffer sQuery
;
665 sQuery
.appendAscii("SELECT ");
666 sQuery
.append(aSqlIter
->second
.toString());
667 sQuery
.appendAscii(" FROM ");
668 sQuery
.append(sComposedTableName
);
669 sQuery
.appendAscii(" WHERE ");
670 sQuery
.append(rCondition
.makeStringAndClear());
674 Reference
< XPreparedStatement
> xPrep(m_xConnection
->prepareStatement(sQuery
.makeStringAndClear()));
675 Reference
< XParameters
> xParameter(xPrep
,UNO_QUERY
);
676 // and then the values of the where condition
677 SelectColumnsMetaData::iterator aKeyIter
= m_pKeyColumnNames
->begin();
678 SelectColumnsMetaData::iterator aKeyEnd
= m_pKeyColumnNames
->end();
680 for(;aKeyIter
!= aKeyEnd
;++aKeyIter
)
682 if ( aKeyIter
->second
.sTableName
== aSqlIter
->first
)
684 setParameter(i
++,xParameter
,io_aRow
[aKeyIter
->second
.nPosition
],aKeyIter
->second
.nType
,aKeyIter
->second
.nScale
);
687 Reference
<XResultSet
> xRes
= xPrep
->executeQuery();
688 Reference
<XRow
> xRow(xRes
,UNO_QUERY
);
689 if ( xRow
.is() && xRes
->next() )
692 aColIter
= m_pColumnNames
->begin();
693 for(;aColIter
!= aColEnd
;++aColIter
)
695 if ( aColIter
->second
.sTableName
== aSqlIter
->first
)
697 io_aRow
[aColIter
->second
.nPosition
].fill(i
++, aColIter
->second
.nType
, xRow
);
698 io_aRow
[aColIter
->second
.nPosition
].setModified();
703 catch(const SQLException
&)
710 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */