1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "OptimisticSet.hxx"
22 #include "core_resource.hxx"
23 #include "core_resource.hrc"
24 #include <com/sun/star/beans/XPropertySet.hpp>
25 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
26 #include <com/sun/star/sdbc/ColumnValue.hpp>
27 #include <com/sun/star/sdbc/XPreparedStatement.hpp>
28 #include <com/sun/star/sdbc/XParameters.hpp>
29 #include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
30 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
31 #include <com/sun/star/sdb/SQLFilterOperator.hpp>
32 #include <com/sun/star/sdbc/XColumnLocate.hpp>
33 #include <com/sun/star/container/XIndexAccess.hpp>
34 #include "dbastrings.hrc"
35 #include "apitools.hxx"
36 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
37 #include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
38 #include <cppuhelper/typeprovider.hxx>
39 #include <comphelper/types.hxx>
40 #include <com/sun/star/sdbcx/KeyType.hpp>
41 #include <connectivity/dbtools.hxx>
42 #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>
53 using namespace dbaccess
;
54 using namespace ::connectivity
;
55 using namespace ::dbtools
;
56 using namespace ::com::sun::star::uno
;
57 using namespace ::com::sun::star::beans
;
58 using namespace ::com::sun::star::sdbc
;
59 using namespace ::com::sun::star::sdb
;
60 using namespace ::com::sun::star::sdbcx
;
61 using namespace ::com::sun::star::container
;
62 using namespace ::com::sun::star::lang
;
63 using namespace ::com::sun::star::util
;
64 using namespace ::com::sun::star::io
;
65 using namespace ::com::sun::star
;
66 using namespace ::cppu
;
67 using namespace ::osl
;
69 typedef std::map
<OUString
, OUStringBuffer
> TSQLStatements
;
72 void lcl_fillKeyCondition(const OUString
& i_sTableName
,const OUString
& i_sQuotedColumnName
,const ORowSetValue
& i_aValue
,TSQLStatements
& io_aKeyConditions
)
74 OUStringBuffer
& rKeyCondition
= io_aKeyConditions
[i_sTableName
];
75 if ( !rKeyCondition
.isEmpty() )
76 rKeyCondition
.append(" AND ");
77 rKeyCondition
.append(i_sQuotedColumnName
);
78 if ( i_aValue
.isNull() )
79 rKeyCondition
.append(" IS NULL");
81 rKeyCondition
.append(" = ?");
86 OptimisticSet::OptimisticSet(const Reference
<XComponentContext
>& _rContext
,
87 const Reference
< XConnection
>& i_xConnection
,
88 const Reference
< XSingleSelectQueryAnalyzer
>& _xComposer
,
89 const ORowSetValueVector
& _aParameterValueForCache
,
91 sal_Int32
& o_nRowCount
)
92 :OKeySet(NULL
,NULL
,OUString(),_xComposer
,_aParameterValueForCache
,i_nMaxRows
,o_nRowCount
)
93 ,m_aSqlParser( _rContext
)
94 ,m_aSqlIterator( i_xConnection
, Reference
<XTablesSupplier
>(_xComposer
,UNO_QUERY
)->getTables(), m_aSqlParser
, NULL
)
95 ,m_bResultSetChanged(false)
99 OptimisticSet::~OptimisticSet()
103 void OptimisticSet::construct(const Reference
< XResultSet
>& _xDriverSet
,const OUString
& i_sRowSetFilter
)
105 OCacheSet::construct(_xDriverSet
,i_sRowSetFilter
);
108 m_sRowSetFilter
= i_sRowSetFilter
;
110 Reference
<XDatabaseMetaData
> xMeta
= m_xConnection
->getMetaData();
111 bool bCase
= xMeta
.is() && xMeta
->supportsMixedCaseQuotedIdentifiers();
112 Reference
<XColumnsSupplier
> xQueryColSup(m_xComposer
,UNO_QUERY
);
113 const Reference
<XNameAccess
> xQueryColumns
= xQueryColSup
->getColumns();
114 const Reference
<XTablesSupplier
> xTabSup(m_xComposer
,UNO_QUERY
);
115 const Reference
<XNameAccess
> xTables
= xTabSup
->getTables();
116 const Sequence
< OUString
> aTableNames
= xTables
->getElementNames();
117 const OUString
* pTableNameIter
= aTableNames
.getConstArray();
118 const OUString
* pTableNameEnd
= pTableNameIter
+ aTableNames
.getLength();
119 for( ; pTableNameIter
!= pTableNameEnd
; ++pTableNameIter
)
121 ::std::unique_ptr
<SelectColumnsMetaData
> pKeyColumNames(new SelectColumnsMetaData(bCase
));
122 findTableColumnsMatching_throw(xTables
->getByName(*pTableNameIter
),*pTableNameIter
,xMeta
,xQueryColumns
,pKeyColumNames
);
123 m_pKeyColumnNames
->insert(pKeyColumNames
->begin(),pKeyColumNames
->end());
126 // the first row is empty because it's now easier for us to distinguish when we are beforefirst or first
127 // without extra variable to be set
128 OKeySetValue
keySetValue((ORowSetValueVector
*)NULL
,::std::pair
<sal_Int32
,Reference
<XRow
> >(0,Reference
<XRow
>()));
129 m_aKeyMap
.insert(OKeySetMatrix::value_type(0,keySetValue
));
130 m_aKeyIter
= m_aKeyMap
.begin();
132 Reference
< XSingleSelectQueryComposer
> xSourceComposer(m_xComposer
,UNO_QUERY
);
133 Reference
< XMultiServiceFactory
> xFactory(m_xConnection
, UNO_QUERY_THROW
);
134 Reference
<XSingleSelectQueryComposer
> xAnalyzer(xFactory
->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
),UNO_QUERY
);
135 OUString sQuery
= xSourceComposer
->getQuery();
136 xAnalyzer
->setElementaryQuery(xSourceComposer
->getElementaryQuery());
139 ::std::unique_ptr
<OSQLParseNode
> pStatementNode( m_aSqlParser
.parseTree( aErrorMsg
, sQuery
) );
140 m_aSqlIterator
.setParseTree( pStatementNode
.get() );
141 m_aSqlIterator
.traverseAll();
142 fillJoinedColumns_throw(m_aSqlIterator
.getJoinConditions());
146 void OptimisticSet::makeNewStatement( )
148 OUStringBuffer aFilter
= createKeyFilter();
150 Reference
< XSingleSelectQueryComposer
> xSourceComposer(m_xComposer
,UNO_QUERY
);
151 Reference
< XMultiServiceFactory
> xFactory(m_xConnection
, UNO_QUERY_THROW
);
152 Reference
<XSingleSelectQueryComposer
> xAnalyzer(xFactory
->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
),UNO_QUERY
);
153 xAnalyzer
->setElementaryQuery(xSourceComposer
->getElementaryQuery());
155 const OUString sComposerFilter
= m_xComposer
->getFilter();
156 if ( !m_sRowSetFilter
.isEmpty() || !sComposerFilter
.isEmpty() )
158 FilterCreator aFilterCreator
;
159 if ( !sComposerFilter
.isEmpty() && sComposerFilter
!= m_sRowSetFilter
)
160 aFilterCreator
.append( sComposerFilter
);
161 aFilterCreator
.append( m_sRowSetFilter
);
162 aFilterCreator
.append( aFilter
.makeStringAndClear() );
163 aFilter
= aFilterCreator
.getComposedAndClear();
165 xAnalyzer
->setFilter(aFilter
.makeStringAndClear());
166 m_xStatement
= m_xConnection
->prepareStatement(xAnalyzer
->getQueryWithSubstitution());
167 ::comphelper::disposeComponent(xAnalyzer
);
170 // ::com::sun::star::sdbcx::XDeleteRows
171 Sequence
< sal_Int32
> SAL_CALL
OptimisticSet::deleteRows( const Sequence
< Any
>& /*rows*/ ,const connectivity::OSQLTable
& /*_xTable*/) throw(SQLException
, RuntimeException
)
173 Sequence
< sal_Int32
> aRet
;
177 void SAL_CALL
OptimisticSet::updateRow(const ORowSetRow
& _rInsertRow
,const ORowSetRow
& _rOriginalRow
,const connectivity::OSQLTable
& /*_xTable*/ ) throw(SQLException
, RuntimeException
)
179 if ( m_aJoinedKeyColumns
.empty() )
180 throw SQLException();
181 // list all columns that should be set
182 static const char s_sPara
[] = " = ?";
183 OUString aQuote
= getIdentifierQuoteString();
185 ::std::map
< OUString
,bool > aResultSetChanged
;
186 TSQLStatements aKeyConditions
;
189 // here we build the condition part for the update statement
190 SelectColumnsMetaData::const_iterator aIter
= m_pColumnNames
->begin();
191 SelectColumnsMetaData::const_iterator aEnd
= m_pColumnNames
->end();
192 for(;aIter
!= aEnd
;++aIter
)
194 if ( aResultSetChanged
.find( aIter
->second
.sTableName
) == aResultSetChanged
.end() )
195 aResultSetChanged
[aIter
->second
.sTableName
] = false;
196 const OUString sQuotedColumnName
= ::dbtools::quoteName( aQuote
,aIter
->second
.sRealName
);
197 if ( m_pKeyColumnNames
->find(aIter
->first
) != m_pKeyColumnNames
->end() )
199 aResultSetChanged
[aIter
->second
.sTableName
] = m_aJoinedKeyColumns
.find(aIter
->second
.nPosition
) != m_aJoinedKeyColumns
.end();
200 lcl_fillKeyCondition(aIter
->second
.sTableName
,sQuotedColumnName
,(_rOriginalRow
->get())[aIter
->second
.nPosition
],aKeyConditions
);
202 if((_rInsertRow
->get())[aIter
->second
.nPosition
].isModified())
204 if ( m_aJoinedKeyColumns
.find(aIter
->second
.nPosition
) != m_aJoinedKeyColumns
.end() )
205 throw SQLException();
207 ::std::map
<sal_Int32
,sal_Int32
>::const_iterator aJoinIter
= m_aJoinedColumns
.find(aIter
->second
.nPosition
);
208 if ( aJoinIter
!= m_aJoinedColumns
.end() )
210 (_rInsertRow
->get())[aJoinIter
->second
] = (_rInsertRow
->get())[aIter
->second
.nPosition
];
212 OUStringBuffer
& rPart
= aSql
[aIter
->second
.sTableName
];
213 if ( !rPart
.isEmpty() )
215 rPart
.append(sQuotedColumnName
+ s_sPara
);
220 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED
), SQL_GENERAL_ERROR
, m_xConnection
);
222 if( aKeyConditions
.empty() )
223 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_CONDITION_FOR_PK
), SQL_GENERAL_ERROR
, m_xConnection
);
225 static const char s_sUPDATE
[] = "UPDATE ";
226 static const char s_sSET
[] = " SET ";
228 Reference
<XDatabaseMetaData
> xMetaData
= m_xConnection
->getMetaData();
230 TSQLStatements::iterator aSqlIter
= aSql
.begin();
231 TSQLStatements::iterator aSqlEnd
= aSql
.end();
232 for(;aSqlIter
!= aSqlEnd
; ++aSqlIter
)
234 if ( !aSqlIter
->second
.isEmpty() )
236 m_bResultSetChanged
= m_bResultSetChanged
|| aResultSetChanged
[aSqlIter
->first
];
237 OUString sCatalog
,sSchema
,sTable
;
238 ::dbtools::qualifiedNameComponents(xMetaData
,aSqlIter
->first
,sCatalog
,sSchema
,sTable
,::dbtools::eInDataManipulation
);
239 OUStringBuffer
sSql(s_sUPDATE
+ ::dbtools::composeTableNameForSelect( m_xConnection
, sCatalog
, sSchema
, sTable
) +
240 s_sSET
+ aSqlIter
->second
.toString());
241 OUStringBuffer
& rCondition
= aKeyConditions
[aSqlIter
->first
];
242 if ( !rCondition
.isEmpty() )
243 sSql
.append(" WHERE " + rCondition
.toString() );
245 executeUpdate(_rInsertRow
,_rOriginalRow
,sSql
.makeStringAndClear(),aSqlIter
->first
);
250 void SAL_CALL
OptimisticSet::insertRow( const ORowSetRow
& _rInsertRow
,const connectivity::OSQLTable
& /*_xTable*/ ) throw(SQLException
, RuntimeException
)
253 TSQLStatements aParameter
;
254 TSQLStatements aKeyConditions
;
255 ::std::map
< OUString
,bool > aResultSetChanged
;
256 OUString aQuote
= getIdentifierQuoteString();
258 // here we build the condition part for the update statement
259 SelectColumnsMetaData::const_iterator aIter
= m_pColumnNames
->begin();
260 SelectColumnsMetaData::const_iterator aEnd
= m_pColumnNames
->end();
261 for(;aIter
!= aEnd
;++aIter
)
263 if ( aResultSetChanged
.find( aIter
->second
.sTableName
) == aResultSetChanged
.end() )
264 aResultSetChanged
[aIter
->second
.sTableName
] = false;
266 const OUString sQuotedColumnName
= ::dbtools::quoteName( aQuote
,aIter
->second
.sRealName
);
267 if ( (_rInsertRow
->get())[aIter
->second
.nPosition
].isModified() )
269 if ( m_aJoinedKeyColumns
.find(aIter
->second
.nPosition
) != m_aJoinedKeyColumns
.end() )
271 lcl_fillKeyCondition(aIter
->second
.sTableName
,sQuotedColumnName
,(_rInsertRow
->get())[aIter
->second
.nPosition
],aKeyConditions
);
272 aResultSetChanged
[aIter
->second
.sTableName
] = true;
274 ::std::map
<sal_Int32
,sal_Int32
>::const_iterator aJoinIter
= m_aJoinedColumns
.find(aIter
->second
.nPosition
);
275 if ( aJoinIter
!= m_aJoinedColumns
.end() )
277 (_rInsertRow
->get())[aJoinIter
->second
] = (_rInsertRow
->get())[aIter
->second
.nPosition
];
279 OUStringBuffer
& rPart
= aSql
[aIter
->second
.sTableName
];
280 if ( !rPart
.isEmpty() )
282 rPart
.append(sQuotedColumnName
);
283 OUStringBuffer
& rParam
= aParameter
[aIter
->second
.sTableName
];
284 if ( !rParam
.isEmpty() )
289 if ( aParameter
.empty() )
290 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED
), SQL_GENERAL_ERROR
, m_xConnection
);
292 Reference
<XDatabaseMetaData
> xMetaData
= m_xConnection
->getMetaData();
293 static const char s_sINSERT
[] = "INSERT INTO ";
294 static const char s_sVALUES
[] = ") VALUES ( ";
295 TSQLStatements::iterator aSqlIter
= aSql
.begin();
296 TSQLStatements::iterator aSqlEnd
= aSql
.end();
297 for(;aSqlIter
!= aSqlEnd
; ++aSqlIter
)
299 if ( !aSqlIter
->second
.isEmpty() )
301 m_bResultSetChanged
= m_bResultSetChanged
|| aResultSetChanged
[aSqlIter
->first
];
302 OUString sCatalog
,sSchema
,sTable
;
303 ::dbtools::qualifiedNameComponents(xMetaData
,aSqlIter
->first
,sCatalog
,sSchema
,sTable
,::dbtools::eInDataManipulation
);
304 OUString sComposedTableName
= ::dbtools::composeTableNameForSelect( m_xConnection
, sCatalog
, sSchema
, sTable
);
305 OUString
sSql(s_sINSERT
+ sComposedTableName
+ " ( " + aSqlIter
->second
.toString() +
306 s_sVALUES
+ aParameter
[aSqlIter
->first
].toString() + " )");
308 OUStringBuffer
& rCondition
= aKeyConditions
[aSqlIter
->first
];
309 if ( !rCondition
.isEmpty() )
311 OUString
sQuery("SELECT " + aSqlIter
->second
.toString() + " FROM " + sComposedTableName
+
312 " WHERE " + rCondition
.toString());
316 Reference
< XPreparedStatement
> xPrep(m_xConnection
->prepareStatement(sQuery
));
317 Reference
< XParameters
> xParameter(xPrep
,UNO_QUERY
);
318 // and then the values of the where condition
319 SelectColumnsMetaData::iterator aKeyCol
= m_pKeyColumnNames
->begin();
320 SelectColumnsMetaData::iterator aKeysEnd
= m_pKeyColumnNames
->end();
322 for(;aKeyCol
!= aKeysEnd
;++aKeyCol
)
324 if ( aKeyCol
->second
.sTableName
== aSqlIter
->first
)
326 setParameter(i
++,xParameter
,(_rInsertRow
->get())[aKeyCol
->second
.nPosition
],aKeyCol
->second
.nType
,aKeyCol
->second
.nScale
);
329 Reference
<XResultSet
> xRes
= xPrep
->executeQuery();
330 Reference
<XRow
> xRow(xRes
,UNO_QUERY
);
331 if ( xRow
.is() && xRes
->next() )
333 m_bResultSetChanged
= true;
337 catch(const SQLException
&)
342 executeInsert(_rInsertRow
,sSql
,aSqlIter
->first
);
347 void SAL_CALL
OptimisticSet::deleteRow(const ORowSetRow
& _rDeleteRow
,const connectivity::OSQLTable
& /*_xTable*/ ) throw(SQLException
, RuntimeException
)
349 OUString aQuote
= getIdentifierQuoteString();
350 TSQLStatements aKeyConditions
;
352 // here we build the condition part for the update statement
353 SelectColumnsMetaData::const_iterator aIter
= m_pColumnNames
->begin();
354 SelectColumnsMetaData::const_iterator aEnd
= m_pColumnNames
->end();
355 for(;aIter
!= aEnd
;++aIter
)
357 if ( m_aJoinedKeyColumns
.find(aIter
->second
.nPosition
) == m_aJoinedKeyColumns
.end() && m_pKeyColumnNames
->find(aIter
->first
) != m_pKeyColumnNames
->end() )
359 // only delete rows which aren't the key in the join
360 const OUString sQuotedColumnName
= ::dbtools::quoteName( aQuote
,aIter
->second
.sRealName
);
361 lcl_fillKeyCondition(aIter
->second
.sTableName
,sQuotedColumnName
,(_rDeleteRow
->get())[aIter
->second
.nPosition
],aKeyConditions
);
364 Reference
<XDatabaseMetaData
> xMetaData
= m_xConnection
->getMetaData();
365 TSQLStatements::iterator aSqlIter
= aKeyConditions
.begin();
366 TSQLStatements::iterator aSqlEnd
= aKeyConditions
.end();
367 for(;aSqlIter
!= aSqlEnd
; ++aSqlIter
)
369 OUStringBuffer
& rCondition
= aSqlIter
->second
;
370 if ( !rCondition
.isEmpty() )
372 OUString sCatalog
,sSchema
,sTable
;
373 ::dbtools::qualifiedNameComponents(xMetaData
,aSqlIter
->first
,sCatalog
,sSchema
,sTable
,::dbtools::eInDataManipulation
);
374 OUString
sSql("DELETE FROM " + ::dbtools::composeTableNameForSelect( m_xConnection
, sCatalog
, sSchema
, sTable
) +
375 " WHERE " + rCondition
.toString() );
376 executeDelete(_rDeleteRow
, sSql
, aSqlIter
->first
);
381 void OptimisticSet::executeDelete(const ORowSetRow
& _rDeleteRow
,const OUString
& i_sSQL
,const OUString
& i_sTableName
)
383 // now create and execute the prepared statement
384 Reference
< XPreparedStatement
> xPrep(m_xConnection
->prepareStatement(i_sSQL
));
385 Reference
< XParameters
> xParameter(xPrep
,UNO_QUERY
);
387 SelectColumnsMetaData::const_iterator aIter
= m_pKeyColumnNames
->begin();
388 SelectColumnsMetaData::const_iterator aEnd
= m_pKeyColumnNames
->end();
390 for(;aIter
!= aEnd
;++aIter
)
392 if ( aIter
->second
.sTableName
== i_sTableName
)
393 setParameter(i
++,xParameter
,(_rDeleteRow
->get())[aIter
->second
.nPosition
],aIter
->second
.nType
,aIter
->second
.nScale
);
395 m_bDeleted
= xPrep
->executeUpdate() > 0;
399 sal_Int32 nBookmark
= ::comphelper::getINT32((_rDeleteRow
->get())[0].getAny());
400 if(m_aKeyIter
== m_aKeyMap
.find(nBookmark
) && m_aKeyIter
!= m_aKeyMap
.end())
402 m_aKeyMap
.erase(nBookmark
);
407 void OptimisticSet::fillJoinedColumns_throw(const ::std::vector
< TNodePair
>& i_aJoinColumns
)
409 ::std::vector
< TNodePair
>::const_iterator aIter
= i_aJoinColumns
.begin();
410 for(;aIter
!= i_aJoinColumns
.end();++aIter
)
412 OUString sColumnName
,sTableName
;
413 m_aSqlIterator
.getColumnRange(aIter
->first
,sColumnName
,sTableName
);
414 OUString
sLeft(sTableName
+ "." + sColumnName
);
415 m_aSqlIterator
.getColumnRange(aIter
->second
,sColumnName
,sTableName
);
416 OUString
sRight(sTableName
+ "." + sColumnName
);
417 fillJoinedColumns_throw(sLeft
, sRight
);
421 void OptimisticSet::fillJoinedColumns_throw(const OUString
& i_sLeftColumn
,const OUString
& i_sRightColumn
)
423 sal_Int32 nLeft
= 0,nRight
= 0;
424 SelectColumnsMetaData::const_iterator aLeftIter
= m_pKeyColumnNames
->find(i_sLeftColumn
);
425 SelectColumnsMetaData::const_iterator aRightIter
= m_pKeyColumnNames
->find(i_sRightColumn
);
427 bool bLeftKey
= aLeftIter
!= m_pKeyColumnNames
->end();
430 nLeft
= aLeftIter
->second
.nPosition
;
434 aLeftIter
= m_pColumnNames
->find(i_sLeftColumn
);
435 if ( aLeftIter
!= m_pColumnNames
->end() )
436 nLeft
= aLeftIter
->second
.nPosition
;
439 bool bRightKey
= aRightIter
!= m_pKeyColumnNames
->end();
442 nRight
= aRightIter
->second
.nPosition
;
446 aRightIter
= m_pColumnNames
->find(i_sRightColumn
);
447 if ( aRightIter
!= m_pColumnNames
->end() )
448 nRight
= aRightIter
->second
.nPosition
;
452 m_aJoinedKeyColumns
[nLeft
] = nRight
;
454 m_aJoinedColumns
[nLeft
] = nRight
;
456 m_aJoinedKeyColumns
[nRight
] = nLeft
;
458 m_aJoinedColumns
[nRight
] = nLeft
;
461 bool OptimisticSet::isResultSetChanged() const
463 bool bOld
= m_bResultSetChanged
;
464 m_bResultSetChanged
= false;
468 void OptimisticSet::mergeColumnValues(sal_Int32 i_nColumnIndex
,ORowSetValueVector::Vector
& io_aInsertRow
,ORowSetValueVector::Vector
& io_aRow
,::std::vector
<sal_Int32
>& o_aChangedColumns
)
470 o_aChangedColumns
.push_back(i_nColumnIndex
);
471 ::std::map
<sal_Int32
,sal_Int32
>::const_iterator aJoinIter
= m_aJoinedColumns
.find(i_nColumnIndex
);
472 if ( aJoinIter
!= m_aJoinedColumns
.end() )
474 io_aRow
[aJoinIter
->second
] = io_aRow
[i_nColumnIndex
];
475 io_aInsertRow
[aJoinIter
->second
] = io_aInsertRow
[i_nColumnIndex
];
476 io_aRow
[aJoinIter
->second
].setModified();
477 o_aChangedColumns
.push_back(aJoinIter
->second
);
483 struct PositionFunctor
: ::std::unary_function
<SelectColumnsMetaData::value_type
,bool>
486 PositionFunctor(sal_Int32 i_nPos
)
491 inline bool operator()(const SelectColumnsMetaData::value_type
& _aType
)
493 return m_nPos
== _aType
.second
.nPosition
;
496 struct TableNameFunctor
: ::std::unary_function
<SelectColumnsMetaData::value_type
,bool>
498 OUString m_sTableName
;
499 TableNameFunctor(const OUString
& i_sTableName
)
500 : m_sTableName(i_sTableName
)
504 inline bool operator()(const SelectColumnsMetaData::value_type
& _aType
)
506 return m_sTableName
== _aType
.second
.sTableName
;
511 bool OptimisticSet::updateColumnValues(const ORowSetValueVector::Vector
& io_aCachedRow
,ORowSetValueVector::Vector
& io_aRow
,const ::std::vector
<sal_Int32
>& i_aChangedColumns
)
514 ::std::vector
<sal_Int32
>::const_iterator aColIdxIter
= i_aChangedColumns
.begin();
515 for(;aColIdxIter
!= i_aChangedColumns
.end();++aColIdxIter
)
517 SelectColumnsMetaData::const_iterator aFind
= ::std::find_if(m_pKeyColumnNames
->begin(),m_pKeyColumnNames
->end(),PositionFunctor(*aColIdxIter
));
518 if ( aFind
!= m_pKeyColumnNames
->end() )
520 const OUString sTableName
= aFind
->second
.sTableName
;
521 aFind
= ::std::find_if(m_pKeyColumnNames
->begin(),m_pKeyColumnNames
->end(),TableNameFunctor(sTableName
));
522 while( aFind
!= m_pKeyColumnNames
->end() )
524 io_aRow
[aFind
->second
.nPosition
].setSigned(io_aCachedRow
[aFind
->second
.nPosition
].isSigned());
525 if ( io_aCachedRow
[aFind
->second
.nPosition
] != io_aRow
[aFind
->second
.nPosition
] )
529 if ( aFind
== m_pKeyColumnNames
->end() )
532 SelectColumnsMetaData::const_iterator aIter
= m_pColumnNames
->begin();
533 SelectColumnsMetaData::const_iterator aEnd
= m_pColumnNames
->end();
534 for ( ;aIter
!= aEnd
;++aIter
)
536 if ( aIter
->second
.sTableName
== sTableName
)
538 io_aRow
[aIter
->second
.nPosition
] = io_aCachedRow
[aIter
->second
.nPosition
];
539 io_aRow
[aIter
->second
.nPosition
].setModified();
548 bool OptimisticSet::columnValuesUpdated(ORowSetValueVector::Vector
& o_aCachedRow
,const ORowSetValueVector::Vector
& i_aRow
)
551 SelectColumnsMetaData::const_iterator aIter
= m_pColumnNames
->begin();
552 SelectColumnsMetaData::const_iterator aEnd
= m_pColumnNames
->end();
553 for(;aIter
!= aEnd
;++aIter
)
555 SelectColumnsMetaData::const_iterator aFind
= ::std::find_if(m_pKeyColumnNames
->begin(),m_pKeyColumnNames
->end(),PositionFunctor(aIter
->second
.nPosition
));
556 if ( aFind
!= m_pKeyColumnNames
->end() )
558 const OUString sTableName
= aFind
->second
.sTableName
;
559 aFind
= ::std::find_if(m_pKeyColumnNames
->begin(),m_pKeyColumnNames
->end(),TableNameFunctor(sTableName
));
560 while( aFind
!= m_pKeyColumnNames
->end() )
562 o_aCachedRow
[aFind
->second
.nPosition
].setSigned(i_aRow
[aFind
->second
.nPosition
].isSigned());
563 if ( o_aCachedRow
[aFind
->second
.nPosition
] != i_aRow
[aFind
->second
.nPosition
] )
567 if ( aFind
== m_pKeyColumnNames
->end() )
570 SelectColumnsMetaData::const_iterator aIter2
= m_pColumnNames
->begin();
571 SelectColumnsMetaData::const_iterator aEnd2
= m_pColumnNames
->end();
572 for ( ;aIter2
!= aEnd2
;++aIter2
)
574 if ( aIter2
->second
.sTableName
== sTableName
)
576 o_aCachedRow
[aIter2
->second
.nPosition
] = i_aRow
[aIter2
->second
.nPosition
];
577 o_aCachedRow
[aIter2
->second
.nPosition
].setModified();
580 fillMissingValues(o_aCachedRow
);
587 void OptimisticSet::fillMissingValues(ORowSetValueVector::Vector
& io_aRow
) const
590 TSQLStatements aKeyConditions
;
591 ::std::map
< OUString
,bool > aResultSetChanged
;
592 OUString aQuote
= getIdentifierQuoteString();
593 // here we build the condition part for the update statement
594 SelectColumnsMetaData::const_iterator aColIter
= m_pColumnNames
->begin();
595 SelectColumnsMetaData::const_iterator aColEnd
= m_pColumnNames
->end();
596 for(;aColIter
!= aColEnd
;++aColIter
)
598 const OUString sQuotedColumnName
= ::dbtools::quoteName( aQuote
,aColIter
->second
.sRealName
);
599 if ( m_aJoinedKeyColumns
.find(aColIter
->second
.nPosition
) != m_aJoinedKeyColumns
.end() )
601 lcl_fillKeyCondition(aColIter
->second
.sTableName
,sQuotedColumnName
,io_aRow
[aColIter
->second
.nPosition
],aKeyConditions
);
603 OUStringBuffer
& rPart
= aSql
[aColIter
->second
.sTableName
];
604 if ( !rPart
.isEmpty() )
606 rPart
.append(sQuotedColumnName
);
608 Reference
<XDatabaseMetaData
> xMetaData
= m_xConnection
->getMetaData();
609 TSQLStatements::iterator aSqlIter
= aSql
.begin();
610 TSQLStatements::iterator aSqlEnd
= aSql
.end();
611 for(;aSqlIter
!= aSqlEnd
; ++aSqlIter
)
613 if ( !aSqlIter
->second
.isEmpty() )
615 OUStringBuffer
& rCondition
= aKeyConditions
[aSqlIter
->first
];
616 if ( !rCondition
.isEmpty() )
618 OUString sCatalog
,sSchema
,sTable
;
619 ::dbtools::qualifiedNameComponents(xMetaData
,aSqlIter
->first
,sCatalog
,sSchema
,sTable
,::dbtools::eInDataManipulation
);
620 OUString sComposedTableName
= ::dbtools::composeTableNameForSelect( m_xConnection
, sCatalog
, sSchema
, sTable
);
621 OUString
sQuery("SELECT " + aSqlIter
->second
.toString() + " FROM " + sComposedTableName
+ " WHERE " +
622 rCondition
.makeStringAndClear());
626 Reference
< XPreparedStatement
> xPrep(m_xConnection
->prepareStatement(sQuery
));
627 Reference
< XParameters
> xParameter(xPrep
,UNO_QUERY
);
628 // and then the values of the where condition
629 SelectColumnsMetaData::iterator aKeyIter
= m_pKeyColumnNames
->begin();
630 SelectColumnsMetaData::iterator aKeyEnd
= m_pKeyColumnNames
->end();
632 for(;aKeyIter
!= aKeyEnd
;++aKeyIter
)
634 if ( aKeyIter
->second
.sTableName
== aSqlIter
->first
)
636 setParameter(i
++,xParameter
,io_aRow
[aKeyIter
->second
.nPosition
],aKeyIter
->second
.nType
,aKeyIter
->second
.nScale
);
639 Reference
<XResultSet
> xRes
= xPrep
->executeQuery();
640 Reference
<XRow
> xRow(xRes
,UNO_QUERY
);
641 if ( xRow
.is() && xRes
->next() )
644 aColIter
= m_pColumnNames
->begin();
645 for(;aColIter
!= aColEnd
;++aColIter
)
647 if ( aColIter
->second
.sTableName
== aSqlIter
->first
)
649 io_aRow
[aColIter
->second
.nPosition
].fill(i
++, aColIter
->second
.nType
, xRow
);
650 io_aRow
[aColIter
->second
.nPosition
].setModified();
655 catch(const SQLException
&)
663 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */