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 "core_resource.hxx"
22 #include "core_resource.hrc"
23 #include <com/sun/star/beans/XPropertySet.hpp>
24 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
25 #include <com/sun/star/sdbc/ColumnValue.hpp>
26 #include <com/sun/star/sdbc/XPreparedStatement.hpp>
27 #include <com/sun/star/sdbc/XParameters.hpp>
28 #include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
29 #include <com/sun/star/sdbc/XColumnLocate.hpp>
30 #include <com/sun/star/container/XIndexAccess.hpp>
31 #include "dbastrings.hrc"
32 #include "apitools.hxx"
33 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
34 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
35 #include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
36 #include <cppuhelper/typeprovider.hxx>
37 #include <comphelper/types.hxx>
38 #include <com/sun/star/sdbcx/KeyType.hpp>
39 #include <connectivity/dbtools.hxx>
40 #include <connectivity/dbexception.hxx>
44 #include <com/sun/star/io/XInputStream.hpp>
45 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
46 #include "querycomposer.hxx"
47 #include "composertools.hxx"
48 #include <tools/debug.hxx>
49 #include "PrivateRow.hxx"
51 using namespace dbaccess
;
52 using namespace ::connectivity
;
53 using namespace ::dbtools
;
54 using namespace ::com::sun::star::uno
;
55 using namespace ::com::sun::star::beans
;
56 using namespace ::com::sun::star::sdbc
;
57 using namespace ::com::sun::star::sdb
;
58 using namespace ::com::sun::star::sdbcx
;
59 using namespace ::com::sun::star::container
;
60 using namespace ::com::sun::star::lang
;
61 using namespace ::com::sun::star::util
;
62 using namespace ::com::sun::star::io
;
63 using namespace ::com::sun::star
;
64 using namespace ::cppu
;
65 using namespace ::osl
;
70 void lcl_fillIndexColumns(const Reference
<XIndexAccess
>& _xIndexes
, ::std::vector
< Reference
<XNameAccess
> >& _rAllIndexColumns
)
74 Reference
<XPropertySet
> xIndexColsSup
;
75 sal_Int32 nCount
= _xIndexes
->getCount();
76 for(sal_Int32 j
= 0 ; j
< nCount
; ++j
)
78 xIndexColsSup
.set(_xIndexes
->getByIndex(j
),UNO_QUERY
);
79 if( xIndexColsSup
.is()
80 && comphelper::getBOOL(xIndexColsSup
->getPropertyValue(PROPERTY_ISUNIQUE
))
81 && !comphelper::getBOOL(xIndexColsSup
->getPropertyValue(PROPERTY_ISPRIMARYKEYINDEX
))
83 _rAllIndexColumns
.push_back(Reference
<XColumnsSupplier
>(xIndexColsSup
,UNO_QUERY
)->getColumns());
88 template < typename T
> inline void tryDispose( Reference
<T
> &r
)
92 ::comphelper::disposeComponent(r
);
94 catch(const Exception
&)
100 SAL_WARN("dbaccess", "Unknown Exception occurred");
106 OKeySet::OKeySet(const connectivity::OSQLTable
& _xTable
,
107 const Reference
< XIndexAccess
>& _xTableKeys
,
108 const OUString
& _rUpdateTableName
, // this can be the alias or the full qualified name
109 const Reference
< XSingleSelectQueryAnalyzer
>& _xComposer
,
110 const ORowSetValueVector
& _aParameterValueForCache
,
111 sal_Int32 i_nMaxRows
,
112 sal_Int32
& o_nRowCount
)
113 :OCacheSet(i_nMaxRows
)
114 ,m_aParameterValueForCache(_aParameterValueForCache
)
116 ,m_xTableKeys(_xTableKeys
)
117 ,m_xComposer(_xComposer
)
118 ,m_sUpdateTableName(_rUpdateTableName
)
119 ,m_rRowCount(o_nRowCount
)
120 ,m_bRowCountFinal(false)
127 // m_xStatement is necessarily one of those
128 const vStatements_t::const_iterator
end(m_vStatements
.end());
129 for(vStatements_t::iterator
i(m_vStatements
.begin());
133 tryDispose(i
->second
);
140 void OKeySet::initColumns()
142 Reference
<XDatabaseMetaData
> xMeta
= m_xConnection
->getMetaData();
143 bool bCase
= xMeta
.is() && xMeta
->supportsMixedCaseQuotedIdentifiers();
144 m_pKeyColumnNames
.reset( new SelectColumnsMetaData(bCase
) );
145 m_pColumnNames
.reset( new SelectColumnsMetaData(bCase
) );
146 m_pParameterNames
.reset( new SelectColumnsMetaData(bCase
) );
147 m_pForeignColumnNames
.reset( new SelectColumnsMetaData(bCase
) );
150 void OKeySet::findTableColumnsMatching_throw( const Any
& i_aTable
,
151 const OUString
& i_rUpdateTableName
,
152 const Reference
<XDatabaseMetaData
>& i_xMeta
,
153 const Reference
<XNameAccess
>& i_xQueryColumns
,
154 ::std::unique_ptr
<SelectColumnsMetaData
>& o_pKeyColumnNames
)
156 // first ask the database itself for the best columns which can be used
157 Sequence
< OUString
> aBestColumnNames
;
158 Reference
<XNameAccess
> xKeyColumns
= getPrimaryKeyColumns_throw(i_aTable
);
159 if ( xKeyColumns
.is() )
160 aBestColumnNames
= xKeyColumns
->getElementNames();
162 const Reference
<XColumnsSupplier
> xTblColSup(i_aTable
,UNO_QUERY_THROW
);
163 const Reference
<XNameAccess
> xTblColumns
= xTblColSup
->getColumns();
164 // locate parameter in select columns
165 Reference
<XParametersSupplier
> xParaSup(m_xComposer
,UNO_QUERY
);
166 Reference
<XIndexAccess
> xQueryParameters
= xParaSup
->getParameters();
167 const sal_Int32 nParaCount
= xQueryParameters
->getCount();
168 Sequence
< OUString
> aParameterColumns(nParaCount
);
169 for(sal_Int32 i
= 0; i
< nParaCount
;++i
)
171 Reference
<XPropertySet
> xPara(xQueryParameters
->getByIndex(i
),UNO_QUERY_THROW
);
172 xPara
->getPropertyValue(PROPERTY_REALNAME
) >>= aParameterColumns
[i
];
175 OUString
sUpdateTableName( i_rUpdateTableName
);
176 if ( sUpdateTableName
.isEmpty() )
178 SAL_WARN("dbaccess", "OKeySet::findTableColumnsMatching_throw: This is a fallback only - it won't work when the table has an alias name." );
179 // If i_aTable originates from a query composer, and is a table which appears with an alias in the SELECT statement,
180 // then the below code will not produce correct results.
181 // For instance, imagine a "SELECT alias.col FROM table AS alias". Now i_aTable would be the table named
182 // "table", so our sUpdateTableName would be "table" as well - not the information about the "alias" is
183 // already lost here.
184 // now getColumnPositions would traverse the columns, and check which of them belong to the table denoted
185 // by sUpdateTableName. Since the latter is "table", but the columns only know that they belong to a table
186 // named "alias", there will be no matching - so getColumnPositions wouldn't find anything.
188 OUString sCatalog
, sSchema
, sTable
;
189 Reference
<XPropertySet
> xTableProp( i_aTable
, UNO_QUERY_THROW
);
190 xTableProp
->getPropertyValue( PROPERTY_CATALOGNAME
)>>= sCatalog
;
191 xTableProp
->getPropertyValue( PROPERTY_SCHEMANAME
) >>= sSchema
;
192 xTableProp
->getPropertyValue( PROPERTY_NAME
) >>= sTable
;
193 sUpdateTableName
= dbtools::composeTableName( i_xMeta
, sCatalog
, sSchema
, sTable
, false, ::dbtools::eInDataManipulation
);
196 ::dbaccess::getColumnPositions(i_xQueryColumns
,aBestColumnNames
,sUpdateTableName
,(*o_pKeyColumnNames
),true);
197 ::dbaccess::getColumnPositions(i_xQueryColumns
,xTblColumns
->getElementNames(),sUpdateTableName
,(*m_pColumnNames
),true);
198 ::dbaccess::getColumnPositions(i_xQueryColumns
,aParameterColumns
,sUpdateTableName
,(*m_pParameterNames
),true);
200 if ( o_pKeyColumnNames
->empty() )
202 ::dbtools::throwGenericSQLException("Could not find any key column.", *this );
205 for ( SelectColumnsMetaData::const_iterator keyColumn
= o_pKeyColumnNames
->begin();
206 keyColumn
!= o_pKeyColumnNames
->end();
210 if ( !xTblColumns
->hasByName( keyColumn
->second
.sRealName
) )
213 Reference
<XPropertySet
> xProp( xTblColumns
->getByName( keyColumn
->second
.sRealName
), UNO_QUERY
);
215 if ( ( xProp
->getPropertyValue( PROPERTY_ISAUTOINCREMENT
) >>= bAuto
) && bAuto
)
216 m_aAutoColumns
.push_back( keyColumn
->first
);
222 void appendOneKeyColumnClause( const OUString
&tblName
, const OUString
&colName
, const connectivity::ORowSetValue
&_rValue
, OUStringBuffer
&o_buf
)
224 static const char s_sDot
[] = ".";
226 if (tblName
.isEmpty())
229 fullName
= tblName
+ s_sDot
+ colName
;
230 if ( _rValue
.isNull() )
232 o_buf
.append(fullName
+ " IS NULL ");
236 o_buf
.append(fullName
+ " = ? ");
241 void OKeySet::setOneKeyColumnParameter( sal_Int32
&nPos
, const Reference
< XParameters
> &_xParameter
, const connectivity::ORowSetValue
&_rValue
, sal_Int32 _nType
, sal_Int32 _nScale
)
243 if ( _rValue
.isNull() )
245 // Nothing to do, appendOneKeyColumnClause took care of it,
246 // the "IS NULL" is hardcoded in the query
250 setParameter( nPos
++, _xParameter
, _rValue
, _nType
, _nScale
);
254 OUStringBuffer
OKeySet::createKeyFilter()
256 connectivity::ORowVector
< ORowSetValue
>::Vector::const_iterator aIter
= m_aKeyIter
->second
.first
->get().begin();
258 static const char aAnd
[] = " AND ";
259 const OUString aQuote
= getIdentifierQuoteString();
260 OUStringBuffer aFilter
;
261 // create the where clause
262 Reference
<XDatabaseMetaData
> xMeta
= m_xConnection
->getMetaData();
263 SelectColumnsMetaData::const_iterator aPosEnd
= m_pKeyColumnNames
->end();
264 for(SelectColumnsMetaData::const_iterator aPosIter
= m_pKeyColumnNames
->begin();aPosIter
!= aPosEnd
; ++aPosIter
)
266 if ( ! aFilter
.isEmpty() )
267 aFilter
.append(aAnd
);
268 appendOneKeyColumnClause(::dbtools::quoteTableName(xMeta
, aPosIter
->second
.sTableName
, ::dbtools::eInDataManipulation
),
269 ::dbtools::quoteName(aQuote
, aPosIter
->second
.sRealName
),
273 aPosEnd
= m_pForeignColumnNames
->end();
274 for(SelectColumnsMetaData::const_iterator aPosIter
= m_pForeignColumnNames
->begin(); aPosIter
!= aPosEnd
; ++aPosIter
)
276 if ( ! aFilter
.isEmpty() )
277 aFilter
.append(aAnd
);
278 appendOneKeyColumnClause(::dbtools::quoteTableName(xMeta
, aPosIter
->second
.sTableName
, ::dbtools::eInDataManipulation
),
279 ::dbtools::quoteName(aQuote
, aPosIter
->second
.sRealName
),
286 void OKeySet::construct(const Reference
< XResultSet
>& _xDriverSet
, const OUString
& i_sRowSetFilter
)
288 OCacheSet::construct(_xDriverSet
,i_sRowSetFilter
);
292 Reference
<XDatabaseMetaData
> xMeta
= m_xConnection
->getMetaData();
293 Reference
<XColumnsSupplier
> xQueryColSup(m_xComposer
, UNO_QUERY
);
294 const Reference
<XNameAccess
> xQueryColumns
= xQueryColSup
->getColumns();
295 findTableColumnsMatching_throw( makeAny(m_xTable
), m_sUpdateTableName
, xMeta
, xQueryColumns
, m_pKeyColumnNames
);
297 Reference
< XSingleSelectQueryComposer
> xSourceComposer(m_xComposer
,UNO_QUERY
);
298 Reference
< XMultiServiceFactory
> xFactory(m_xConnection
, UNO_QUERY_THROW
);
299 Reference
<XSingleSelectQueryComposer
> xAnalyzer(xFactory
->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
),UNO_QUERY
);
300 xAnalyzer
->setElementaryQuery(xSourceComposer
->getElementaryQuery());
301 Reference
<XTablesSupplier
> xTabSup(xAnalyzer
,uno::UNO_QUERY
);
302 Reference
<XNameAccess
> xSelectTables(xTabSup
->getTables(),uno::UNO_QUERY
);
303 const Sequence
< OUString
> aSeq
= xSelectTables
->getElementNames();
304 if ( aSeq
.getLength() > 1 ) // special handling for join
306 const OUString
* pIter
= aSeq
.getConstArray();
307 const OUString
* const pEnd
= pIter
+ aSeq
.getLength();
308 for(;pIter
!= pEnd
;++pIter
)
310 if ( *pIter
!= m_sUpdateTableName
)
312 connectivity::OSQLTable
xSelColSup(xSelectTables
->getByName(*pIter
),uno::UNO_QUERY
);
313 Reference
<XPropertySet
> xProp(xSelColSup
,uno::UNO_QUERY
);
314 OUString sSelectTableName
= ::dbtools::composeTableName( xMeta
, xProp
, ::dbtools::eInDataManipulation
, false, false, false );
316 ::dbaccess::getColumnPositions(xQueryColumns
, xSelColSup
->getColumns()->getElementNames(), sSelectTableName
, (*m_pForeignColumnNames
), true);
318 // LEM: there used to be a break here; however, I see no reason to stop
319 // at first non-updateTable, so I removed it. (think of multiple joins...)
324 // the first row is empty because it's now easier for us to distinguish when we are beforefirst or first
325 // without extra variable to be set
326 OKeySetValue
keySetValue((ORowSetValueVector
*)NULL
,::std::pair
<sal_Int32
,Reference
<XRow
> >(0,Reference
<XRow
>()));
327 m_aKeyMap
.insert(OKeySetMatrix::value_type(0, keySetValue
));
328 m_aKeyIter
= m_aKeyMap
.begin();
331 void OKeySet::reset(const Reference
< XResultSet
>& _xDriverSet
)
333 OCacheSet::construct(_xDriverSet
, m_sRowSetFilter
);
334 m_bRowCountFinal
= false;
336 OKeySetValue
keySetValue((ORowSetValueVector
*)NULL
,::std::pair
<sal_Int32
,Reference
<XRow
> >(0,Reference
<XRow
>()));
337 m_aKeyMap
.insert(OKeySetMatrix::value_type(0,keySetValue
));
338 m_aKeyIter
= m_aKeyMap
.begin();
341 void OKeySet::ensureStatement( )
343 // do we already have a statement for the current combination of NULLness
344 // of key & foreign columns?
345 FilterColumnsNULL_t FilterColumnsNULL
;
346 FilterColumnsNULL
.reserve(m_aKeyIter
->second
.first
->get().size());
347 connectivity::ORowVector
< ORowSetValue
>::Vector::const_iterator aIter
= m_aKeyIter
->second
.first
->get().begin();
348 const connectivity::ORowVector
< ORowSetValue
>::Vector::const_iterator aEnd
= m_aKeyIter
->second
.first
->get().end();
349 for( ; aIter
!= aEnd
; ++aIter
)
350 FilterColumnsNULL
.push_back(aIter
->isNull());
351 vStatements_t::iterator
pNewStatement(m_vStatements
.find(FilterColumnsNULL
));
352 if(pNewStatement
== m_vStatements
.end())
354 // no: make a new one
356 std::pair
< vStatements_t::iterator
, bool > insert_result
357 (m_vStatements
.insert(vStatements_t::value_type(FilterColumnsNULL
, m_xStatement
)));
358 (void) insert_result
; // WaE: unused variable
359 assert(insert_result
.second
);
363 m_xStatement
= pNewStatement
->second
;
366 void OKeySet::makeNewStatement()
368 Reference
< XSingleSelectQueryComposer
> xSourceComposer(m_xComposer
,UNO_QUERY
);
369 Reference
< XMultiServiceFactory
> xFactory(m_xConnection
, UNO_QUERY_THROW
);
370 Reference
<XSingleSelectQueryComposer
> xAnalyzer(xFactory
->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
),UNO_QUERY
);
371 xAnalyzer
->setElementaryQuery(xSourceComposer
->getElementaryQuery());
373 OUStringBuffer
aFilter(createKeyFilter());
374 executeStatement(aFilter
, xAnalyzer
);
377 void OKeySet::executeStatement(OUStringBuffer
& io_aFilter
, Reference
<XSingleSelectQueryComposer
>& io_xAnalyzer
)
379 bool bFilterSet
= !m_sRowSetFilter
.isEmpty();
382 FilterCreator aFilterCreator
;
383 aFilterCreator
.append( m_sRowSetFilter
);
384 aFilterCreator
.append( io_aFilter
.makeStringAndClear() );
385 io_aFilter
= aFilterCreator
.getComposedAndClear();
387 io_xAnalyzer
->setFilter(io_aFilter
.makeStringAndClear());
390 Sequence
< Sequence
< PropertyValue
> > aFilter2
= io_xAnalyzer
->getStructuredFilter();
391 const Sequence
< PropertyValue
>* pOr
= aFilter2
.getConstArray();
392 const Sequence
< PropertyValue
>* pOrEnd
= pOr
+ aFilter2
.getLength();
393 for(;pOr
!= pOrEnd
;++pOr
)
395 const PropertyValue
* pAnd
= pOr
->getConstArray();
396 const PropertyValue
* pAndEnd
= pAnd
+ pOr
->getLength();
397 for(;pAnd
!= pAndEnd
;++pAnd
)
400 if ( !(pAnd
->Value
>>= sValue
) || !( sValue
== "?" || sValue
.startsWith( ":" ) ) )
401 { // we have a criteria which has to be taken into account for updates
402 m_aFilterColumns
.push_back(pAnd
->Name
);
407 m_xStatement
= m_xConnection
->prepareStatement(io_xAnalyzer
->getQueryWithSubstitution());
408 ::comphelper::disposeComponent(io_xAnalyzer
);
411 void OKeySet::invalidateRow()
414 ::comphelper::disposeComponent(m_xSet
);
417 Any SAL_CALL
OKeySet::getBookmark() throw(SQLException
, RuntimeException
)
419 OSL_ENSURE(m_aKeyIter
!= m_aKeyMap
.end() && m_aKeyIter
!= m_aKeyMap
.begin(),
420 "getBookmark is only possible when we stand on a valid row!");
421 return makeAny(m_aKeyIter
->first
);
424 bool SAL_CALL
OKeySet::moveToBookmark( const Any
& bookmark
) throw(SQLException
, RuntimeException
)
426 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
427 m_aKeyIter
= m_aKeyMap
.find(::comphelper::getINT32(bookmark
));
429 return m_aKeyIter
!= m_aKeyMap
.end();
432 bool SAL_CALL
OKeySet::moveRelativeToBookmark( const Any
& bookmark
, sal_Int32 rows
) throw(SQLException
, RuntimeException
)
434 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
435 m_aKeyIter
= m_aKeyMap
.find(::comphelper::getINT32(bookmark
));
436 if(m_aKeyIter
!= m_aKeyMap
.end())
438 return relative(rows
);
445 sal_Int32 SAL_CALL
OKeySet::compareBookmarks( const Any
& _first
, const Any
& _second
) throw(SQLException
, RuntimeException
)
447 sal_Int32 nFirst
= 0, nSecond
= 0;
451 return (nFirst
!= nSecond
) ? CompareBookmark::NOT_EQUAL
: CompareBookmark::EQUAL
;
454 bool SAL_CALL
OKeySet::hasOrderedBookmarks( ) throw(SQLException
, RuntimeException
)
459 sal_Int32 SAL_CALL
OKeySet::hashBookmark( const Any
& bookmark
) throw(SQLException
, RuntimeException
)
461 return ::comphelper::getINT32(bookmark
);
464 // ::com::sun::star::sdbcx::XDeleteRows
465 Sequence
< sal_Int32
> SAL_CALL
OKeySet::deleteRows( const Sequence
< Any
>& rows
,const connectivity::OSQLTable
& _xTable
) throw(SQLException
, RuntimeException
)
467 Reference
<XPropertySet
> xSet(_xTable
,UNO_QUERY
);
470 OUStringBuffer
aSql("DELETE FROM " + m_aComposedTableName
+ " WHERE ");
472 // list all columns that should be set
473 const OUString aQuote
= getIdentifierQuoteString();
474 static const char aAnd
[] = " AND ";
475 static const char aOr
[] = " OR ";
476 static const char aEqual
[] = " = ?";
478 // use keys for exact positioning
479 Reference
<XNameAccess
> xKeyColumns
= getKeyColumns();
481 OUStringBuffer
aCondition("( ");
483 SelectColumnsMetaData::const_iterator aIter
= (*m_pKeyColumnNames
).begin();
484 const SelectColumnsMetaData::const_iterator aPosEnd
= (*m_pKeyColumnNames
).end();
485 for(;aIter
!= aPosEnd
;++aIter
)
487 aCondition
.append(::dbtools::quoteName( aQuote
,aIter
->second
.sRealName
) + aEqual
+ aAnd
);
489 aCondition
.setLength(aCondition
.getLength() - strlen(aAnd
));
490 // sCon is (parenthesised) the condition to locate ONE row
491 // e.g. ( colName1 = ? AND colName2 = ? AND colName3 = ? )
492 const OUString
sCon( aCondition
.makeStringAndClear() );
494 // since we need to delete all rows in "rows",
495 // we need to OR as many row locators.
496 const Any
* pBegin
= rows
.getConstArray();
497 const Any
* const pEnd
= pBegin
+ rows
.getLength();
498 for(;pBegin
!= pEnd
;++pBegin
)
500 aSql
.append(sCon
+ aOr
);
502 aSql
.setLength(aSql
.getLength()-3);
504 // now create end execute the prepared statement
506 Reference
< XPreparedStatement
> xPrep(m_xConnection
->prepareStatement(aSql
.makeStringAndClear()));
507 Reference
< XParameters
> xParameter(xPrep
,UNO_QUERY
);
509 // now, fill in the parameters in the row locators
510 pBegin
= rows
.getConstArray();
512 for(;pBegin
!= pEnd
;++pBegin
)
514 m_aKeyIter
= m_aKeyMap
.find(::comphelper::getINT32(*pBegin
));
515 // LEM FIXME: what happens if m_aKeyIter == m_aKeyMap.end() ?
516 // the whole operation fails because there are unfilled parameters
517 // the remaining rows *are* deleted?
518 // check what happens vs what is supposed to happen
519 // (cf documentation of ::com::sun::star::sdbcx::XDeleteRows)
520 if(m_aKeyIter
!= m_aKeyMap
.end())
522 connectivity::ORowVector
< ORowSetValue
>::Vector::iterator aKeyIter
= m_aKeyIter
->second
.first
->get().begin();
523 connectivity::ORowVector
< ORowSetValue
>::Vector::iterator aKeyEnd
= m_aKeyIter
->second
.first
->get().end();
524 SelectColumnsMetaData::const_iterator aPosIter
= (*m_pKeyColumnNames
).begin();
525 for(sal_uInt16 j
= 0;aKeyIter
!= aKeyEnd
;++aKeyIter
,++j
,++aPosIter
)
527 setParameter(i
++,xParameter
,*aKeyIter
,aPosIter
->second
.nType
,aPosIter
->second
.nScale
);
532 bool bOk
= xPrep
->executeUpdate() > 0;
533 Sequence
< sal_Int32
> aRet(rows
.getLength());
534 memset(aRet
.getArray(),bOk
,sizeof(sal_Int32
)*aRet
.getLength());
537 pBegin
= rows
.getConstArray();
539 for(;pBegin
!= pEnd
;++pBegin
)
543 if(m_aKeyIter
== m_aKeyMap
.find(nPos
) && m_aKeyIter
!= m_aKeyMap
.end())
545 m_aKeyMap
.erase(nPos
);
552 void SAL_CALL
OKeySet::updateRow(const ORowSetRow
& _rInsertRow
,const ORowSetRow
& _rOriginalRow
,const connectivity::OSQLTable
& _xTable
) throw(SQLException
, RuntimeException
)
554 Reference
<XPropertySet
> xSet(_xTable
,UNO_QUERY
);
557 OUStringBuffer aSql
= "UPDATE " + m_aComposedTableName
+ " SET ";
558 // list all columns that should be set
559 static OUString
aPara(" = ?,");
560 OUString aQuote
= getIdentifierQuoteString();
561 static OUString
aAnd(" AND ");
562 OUString
sIsNull(" IS NULL");
563 OUString
sParam(" = ?");
565 // use keys and indexes for exact positioning
567 Reference
<XNameAccess
> xKeyColumns
= getKeyColumns();
569 // second the indexes
570 Reference
<XIndexesSupplier
> xIndexSup(_xTable
,UNO_QUERY
);
571 Reference
<XIndexAccess
> xIndexes
;
572 if ( xIndexSup
.is() )
573 xIndexes
.set(xIndexSup
->getIndexes(),UNO_QUERY
);
575 ::std::vector
< Reference
<XNameAccess
> > aAllIndexColumns
;
576 lcl_fillIndexColumns(xIndexes
,aAllIndexColumns
);
578 OUStringBuffer sKeyCondition
,sIndexCondition
;
579 ::std::vector
<sal_Int32
> aIndexColumnPositions
;
581 const sal_Int32 nOldLength
= aSql
.getLength();
583 // here we build the condition part for the update statement
584 SelectColumnsMetaData::const_iterator aIter
= m_pColumnNames
->begin();
585 SelectColumnsMetaData::const_iterator aEnd
= m_pColumnNames
->end();
586 for(;aIter
!= aEnd
;++aIter
,++i
)
588 if ( m_pKeyColumnNames
->find(aIter
->first
) != m_pKeyColumnNames
->end() )
590 sKeyCondition
.append(::dbtools::quoteName( aQuote
,aIter
->second
.sRealName
));
591 if((_rOriginalRow
->get())[aIter
->second
.nPosition
].isNull())
592 sKeyCondition
.append(sIsNull
);
594 sKeyCondition
.append(sParam
);
595 sKeyCondition
.append(aAnd
);
599 ::std::vector
< Reference
<XNameAccess
> >::const_iterator aIndexEnd
= aAllIndexColumns
.end();
600 for( ::std::vector
< Reference
<XNameAccess
> >::const_iterator aIndexIter
= aAllIndexColumns
.begin();
601 aIndexIter
!= aIndexEnd
;++aIndexIter
)
603 if((*aIndexIter
)->hasByName(aIter
->first
))
605 sIndexCondition
.append(::dbtools::quoteName( aQuote
,aIter
->second
.sRealName
));
606 if((_rOriginalRow
->get())[aIter
->second
.nPosition
].isNull())
607 sIndexCondition
.append(sIsNull
);
610 sIndexCondition
.append(sParam
);
611 aIndexColumnPositions
.push_back(aIter
->second
.nPosition
);
613 sIndexCondition
.append(aAnd
);
618 if((_rInsertRow
->get())[aIter
->second
.nPosition
].isModified())
620 aSql
.append(::dbtools::quoteName( aQuote
,aIter
->second
.sRealName
) + aPara
);
624 if( aSql
.getLength() != nOldLength
)
626 aSql
.setLength(aSql
.getLength()-1);
629 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED
), SQL_GENERAL_ERROR
, m_xConnection
);
631 if(!sKeyCondition
.isEmpty() || !sIndexCondition
.isEmpty())
633 aSql
.append(" WHERE ");
634 if(!sKeyCondition
.isEmpty() && !sIndexCondition
.isEmpty())
636 aSql
.append(sKeyCondition
.makeStringAndClear() + sIndexCondition
.makeStringAndClear());
638 else if(!sKeyCondition
.isEmpty())
640 aSql
.append(sKeyCondition
.makeStringAndClear());
642 else if(!sIndexCondition
.isEmpty())
644 aSql
.append(sIndexCondition
.makeStringAndClear());
646 aSql
.setLength(aSql
.getLength()-5); // remove the last AND
649 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_CONDITION_FOR_PK
), SQL_GENERAL_ERROR
, m_xConnection
);
651 // now create end execute the prepared statement
653 executeUpdate(_rInsertRow
,_rOriginalRow
,aSql
.makeStringAndClear(),sEmpty
,aIndexColumnPositions
);
656 void OKeySet::executeUpdate(const ORowSetRow
& _rInsertRow
,const ORowSetRow
& _rOriginalRow
,const OUString
& i_sSQL
,const OUString
& i_sTableName
,const ::std::vector
<sal_Int32
>& _aIndexColumnPositions
)
658 // now create end execute the prepared statement
659 Reference
< XPreparedStatement
> xPrep(m_xConnection
->prepareStatement(i_sSQL
));
660 Reference
< XParameters
> xParameter(xPrep
,UNO_QUERY
);
662 bool bRefetch
= true;
663 Reference
<XRow
> xRow
;
665 // first the set values
666 SelectColumnsMetaData::const_iterator aIter
= m_pColumnNames
->begin();
667 SelectColumnsMetaData::const_iterator aEnd
= m_pColumnNames
->end();
669 for(;aIter
!= aEnd
;++aIter
,++j
)
671 if ( i_sTableName
.isEmpty() || aIter
->second
.sTableName
== i_sTableName
)
673 sal_Int32 nPos
= aIter
->second
.nPosition
;
674 if((_rInsertRow
->get())[nPos
].isModified())
678 bRefetch
= ::std::find(m_aFilterColumns
.begin(),m_aFilterColumns
.end(),aIter
->second
.sRealName
) == m_aFilterColumns
.end();
680 impl_convertValue_throw(_rInsertRow
,aIter
->second
);
681 (_rInsertRow
->get())[nPos
].setSigned((_rOriginalRow
->get())[nPos
].isSigned());
682 setParameter(i
++,xParameter
,(_rInsertRow
->get())[nPos
],aIter
->second
.nType
,aIter
->second
.nScale
);
686 // and then the values of the where condition
687 aIter
= m_pKeyColumnNames
->begin();
688 aEnd
= m_pKeyColumnNames
->end();
690 for(;aIter
!= aEnd
;++aIter
,++j
)
692 if ( i_sTableName
.isEmpty() || aIter
->second
.sTableName
== i_sTableName
)
694 setParameter(i
++,xParameter
,(_rOriginalRow
->get())[aIter
->second
.nPosition
],aIter
->second
.nType
,aIter
->second
.nScale
);
697 if ( !_aIndexColumnPositions
.empty() )
699 // now we have to set the index values
700 ::std::vector
<sal_Int32
>::const_iterator aIdxColIter
= _aIndexColumnPositions
.begin();
701 ::std::vector
<sal_Int32
>::const_iterator aIdxColEnd
= _aIndexColumnPositions
.end();
703 aIter
= m_pColumnNames
->begin();
704 for(;aIdxColIter
!= aIdxColEnd
;++aIdxColIter
,++i
,++j
,++aIter
)
706 setParameter(i
,xParameter
,(_rOriginalRow
->get())[*aIdxColIter
],(_rOriginalRow
->get())[*aIdxColIter
].getTypeKind(),aIter
->second
.nScale
);
709 const sal_Int32 nRowsUpdated
= xPrep
->executeUpdate();
710 m_bUpdated
= nRowsUpdated
> 0;
713 const sal_Int32 nBookmark
= ::comphelper::getINT32((_rInsertRow
->get())[0].getAny());
714 m_aKeyIter
= m_aKeyMap
.find(nBookmark
);
715 m_aKeyIter
->second
.second
.first
= 2;
716 m_aKeyIter
->second
.second
.second
= xRow
;
717 copyRowValue(_rInsertRow
,m_aKeyIter
->second
.first
,nBookmark
);
718 tryRefetch(_rInsertRow
,bRefetch
);
722 void SAL_CALL
OKeySet::insertRow( const ORowSetRow
& _rInsertRow
,const connectivity::OSQLTable
& _xTable
) throw(SQLException
, RuntimeException
)
724 Reference
<XPropertySet
> xSet(_xTable
,UNO_QUERY
);
727 OUStringBuffer
aSql( "INSERT INTO " + m_aComposedTableName
+ " ( ");
729 // set values and column names
730 OUStringBuffer
aValues(" VALUES ( ");
731 static const char aPara
[] = "?,";
732 OUString aQuote
= getIdentifierQuoteString();
733 static const char aComma
[] = ",";
735 SelectColumnsMetaData::const_iterator aIter
= m_pColumnNames
->begin();
736 SelectColumnsMetaData::const_iterator aEnd
= m_pColumnNames
->end();
738 bool bRefetch
= true;
739 bool bModified
= false;
740 for(;aIter
!= aEnd
;++aIter
,++j
)
742 if((_rInsertRow
->get())[aIter
->second
.nPosition
].isModified())
746 bRefetch
= ::std::find(m_aFilterColumns
.begin(),m_aFilterColumns
.end(),aIter
->second
.sRealName
) == m_aFilterColumns
.end();
748 aSql
.append(::dbtools::quoteName( aQuote
,aIter
->second
.sRealName
) + aComma
);
749 aValues
.append(aPara
);
754 ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED
), SQL_GENERAL_ERROR
, m_xConnection
);
756 aSql
[aSql
.getLength() - 1] = ')';
757 aValues
[aValues
.getLength() - 1] = ')';
758 aSql
.append(aValues
.makeStringAndClear());
759 // now create,fill and execute the prepared statement
761 executeInsert(_rInsertRow
,aSql
.makeStringAndClear(),sEmpty
,bRefetch
);
764 void OKeySet::executeInsert( const ORowSetRow
& _rInsertRow
,const OUString
& i_sSQL
,const OUString
& i_sTableName
,bool bRefetch
)
766 // now create,fill and execute the prepared statement
767 Reference
< XPreparedStatement
> xPrep(m_xConnection
->prepareStatement(i_sSQL
));
768 Reference
< XParameters
> xParameter(xPrep
,UNO_QUERY
);
770 SelectColumnsMetaData::const_iterator aIter
= m_pColumnNames
->begin();
771 SelectColumnsMetaData::const_iterator aEnd
= m_pColumnNames
->end();
772 for(sal_Int32 i
= 1;aIter
!= aEnd
;++aIter
)
774 if ( i_sTableName
.isEmpty() || aIter
->second
.sTableName
== i_sTableName
)
776 const sal_Int32 nPos
= aIter
->second
.nPosition
;
777 if((_rInsertRow
->get())[nPos
].isModified())
779 if((_rInsertRow
->get())[nPos
].isNull())
780 xParameter
->setNull(i
++,(_rInsertRow
->get())[nPos
].getTypeKind());
783 impl_convertValue_throw(_rInsertRow
,aIter
->second
);
784 (_rInsertRow
->get())[nPos
].setSigned(m_aSignedFlags
[nPos
-1]);
785 setParameter(i
++,xParameter
,(_rInsertRow
->get())[nPos
],aIter
->second
.nType
,aIter
->second
.nScale
);
791 m_bInserted
= xPrep
->executeUpdate() > 0;
792 bool bAutoValuesFetched
= false;
795 // first insert the default values into the insertrow
796 aIter
= m_pColumnNames
->begin();
797 for(;aIter
!= aEnd
;++aIter
)
799 if ( !(_rInsertRow
->get())[aIter
->second
.nPosition
].isModified() )
801 if(aIter
->second
.bNullable
&& aIter
->second
.sDefaultValue
.isEmpty())
803 (_rInsertRow
->get())[aIter
->second
.nPosition
].setTypeKind(aIter
->second
.nType
);
804 (_rInsertRow
->get())[aIter
->second
.nPosition
].setNull();
808 (_rInsertRow
->get())[aIter
->second
.nPosition
] = aIter
->second
.sDefaultValue
;
809 (_rInsertRow
->get())[aIter
->second
.nPosition
].setTypeKind(aIter
->second
.nType
);
815 Reference
< XGeneratedResultSet
> xGRes(xPrep
, UNO_QUERY
);
818 Reference
< XResultSet
> xRes
= xGRes
->getGeneratedValues();
819 Reference
< XRow
> xRow(xRes
,UNO_QUERY
);
820 if ( xRow
.is() && xRes
->next() )
822 Reference
< XResultSetMetaDataSupplier
> xMdSup(xRes
,UNO_QUERY
);
823 Reference
< XResultSetMetaData
> xMd
= xMdSup
->getMetaData();
824 sal_Int32 nColumnCount
= xMd
->getColumnCount();
825 ::std::vector
< OUString
>::iterator aAutoIter
= m_aAutoColumns
.begin();
826 ::std::vector
< OUString
>::iterator aAutoEnd
= m_aAutoColumns
.end();
827 for (sal_Int32 i
= 1;aAutoIter
!= aAutoEnd
&& i
<= nColumnCount
; ++aAutoIter
,++i
)
829 SelectColumnsMetaData::iterator aFind
= m_pKeyColumnNames
->find(*aAutoIter
);
830 if ( aFind
!= m_pKeyColumnNames
->end() )
831 (_rInsertRow
->get())[aFind
->second
.nPosition
].fill(i
, aFind
->second
.nType
, xRow
);
833 bAutoValuesFetched
= true;
837 catch(const Exception
&)
839 SAL_WARN("dbaccess", "Could not execute GeneratedKeys() stmt");
843 ::comphelper::disposeComponent(xPrep
);
845 if ( i_sTableName
.isEmpty() && !bAutoValuesFetched
&& m_bInserted
)
847 // first check if all key column values were set
848 const OUString
sMax(" MAX(");
849 const OUString
sMaxEnd("),");
850 const OUString sQuote
= getIdentifierQuoteString();
852 aEnd
= m_pKeyColumnNames
->end();
853 ::std::vector
< OUString
>::iterator aAutoIter
= m_aAutoColumns
.begin();
854 ::std::vector
< OUString
>::iterator aAutoEnd
= m_aAutoColumns
.end();
855 for (;aAutoIter
!= aAutoEnd
; ++aAutoIter
)
857 // we will only fetch values which are keycolumns
858 SelectColumnsMetaData::iterator aFind
= m_pKeyColumnNames
->find(*aAutoIter
);
862 sMaxStmt
+= ::dbtools::quoteName( sQuote
,aFind
->second
.sRealName
868 if(!sMaxStmt
.isEmpty())
870 sMaxStmt
= sMaxStmt
.replaceAt(sMaxStmt
.getLength()-1,1,OUString(" "));
871 OUString sStmt
= "SELECT " + sMaxStmt
+ "FROM ";
872 OUString sCatalog
,sSchema
,sTable
;
873 ::dbtools::qualifiedNameComponents(m_xConnection
->getMetaData(),m_sUpdateTableName
,sCatalog
,sSchema
,sTable
,::dbtools::eInDataManipulation
);
874 sStmt
+= ::dbtools::composeTableNameForSelect( m_xConnection
, sCatalog
, sSchema
, sTable
);
877 // now fetch the autoincrement values
878 Reference
<XStatement
> xStatement
= m_xConnection
->createStatement();
879 Reference
<XResultSet
> xRes
= xStatement
->executeQuery(sStmt
);
880 Reference
<XRow
> xRow(xRes
,UNO_QUERY
);
881 if(xRow
.is() && xRes
->next())
883 aAutoIter
= m_aAutoColumns
.begin();
884 for (sal_Int32 i
=1;aAutoIter
!= aAutoEnd
; ++aAutoIter
,++i
)
886 // we will only fetch values which are keycolumns
887 SelectColumnsMetaData::iterator aFind
= m_pKeyColumnNames
->find(*aAutoIter
);
889 (_rInsertRow
->get())[aFind
->second
.nPosition
].fill(i
, aFind
->second
.nType
, xRow
);
892 ::comphelper::disposeComponent(xStatement
);
896 SAL_WARN("dbaccess", "Could not fetch with MAX() ");
902 OKeySetMatrix::iterator aKeyIter
= m_aKeyMap
.end();
904 ORowSetRow aKeyRow
= new connectivity::ORowVector
< ORowSetValue
>(m_pKeyColumnNames
->size());
905 copyRowValue(_rInsertRow
,aKeyRow
,aKeyIter
->first
+ 1);
907 m_aKeyIter
= m_aKeyMap
.insert(OKeySetMatrix::value_type(aKeyIter
->first
+ 1,OKeySetValue(aKeyRow
,::std::pair
<sal_Int32
,Reference
<XRow
> >(1,Reference
<XRow
>())))).first
;
908 // now we set the bookmark for this row
909 (_rInsertRow
->get())[0] = makeAny((sal_Int32
)m_aKeyIter
->first
);
910 tryRefetch(_rInsertRow
,bRefetch
);
914 void OKeySet::tryRefetch(const ORowSetRow
& _rInsertRow
,bool bRefetch
)
920 bRefetch
= doTryRefetch_throw();
922 catch(const Exception
&)
929 m_aKeyIter
->second
.second
.second
= new OPrivateRow(_rInsertRow
->get());
933 void OKeySet::copyRowValue(const ORowSetRow
& _rInsertRow
,ORowSetRow
& _rKeyRow
,sal_Int32 i_nBookmark
)
935 connectivity::ORowVector
< ORowSetValue
>::Vector::iterator aIter
= _rKeyRow
->get().begin();
937 // check the if the parameter values have been changed
938 OSL_ENSURE((m_aParameterValueForCache
.get().size()-1) == m_pParameterNames
->size(),"OKeySet::copyRowValue: Parameter values and names differ!");
939 connectivity::ORowVector
< ORowSetValue
>::Vector::const_iterator aParaValuesIter
= m_aParameterValueForCache
.get().begin() +1;
941 bool bChanged
= false;
942 SelectColumnsMetaData::const_iterator aParaIter
= (*m_pParameterNames
).begin();
943 SelectColumnsMetaData::const_iterator aParaEnd
= (*m_pParameterNames
).end();
944 for(sal_Int32 i
= 1;aParaIter
!= aParaEnd
;++aParaIter
,++aParaValuesIter
,++i
)
946 ORowSetValue
aValue(*aParaValuesIter
);
947 aValue
.setSigned(m_aSignedFlags
[aParaIter
->second
.nPosition
]);
948 if ( (_rInsertRow
->get())[aParaIter
->second
.nPosition
] != aValue
)
950 ORowSetValueVector
aCopy(m_aParameterValueForCache
);
951 (aCopy
.get())[i
] = (_rInsertRow
->get())[aParaIter
->second
.nPosition
];
952 m_aUpdatedParameter
[i_nBookmark
] = aCopy
;
958 m_aUpdatedParameter
.erase(i_nBookmark
);
961 // update the key values
962 SelectColumnsMetaData::const_iterator aPosIter
= (*m_pKeyColumnNames
).begin();
963 const SelectColumnsMetaData::const_iterator aPosEnd
= (*m_pKeyColumnNames
).end();
964 for(;aPosIter
!= aPosEnd
;++aPosIter
,++aIter
)
966 impl_convertValue_throw(_rInsertRow
,aPosIter
->second
);
967 *aIter
= (_rInsertRow
->get())[aPosIter
->second
.nPosition
];
968 aIter
->setTypeKind(aPosIter
->second
.nType
);
972 void SAL_CALL
OKeySet::deleteRow(const ORowSetRow
& _rDeleteRow
,const connectivity::OSQLTable
& _xTable
) throw(SQLException
, RuntimeException
)
974 Reference
<XPropertySet
> xSet(_xTable
,UNO_QUERY
);
977 OUStringBuffer
aSql("DELETE FROM " + m_aComposedTableName
+ " WHERE ");
979 // list all columns that should be set
980 OUString aQuote
= getIdentifierQuoteString();
981 static const char aAnd
[] = " AND ";
983 // use keys and indexes for exact positioning
984 Reference
<XNameAccess
> xKeyColumns
= getKeyColumns();
985 // second the indexes
986 Reference
<XIndexesSupplier
> xIndexSup(_xTable
,UNO_QUERY
);
987 Reference
<XIndexAccess
> xIndexes
;
988 if ( xIndexSup
.is() )
989 xIndexes
.set(xIndexSup
->getIndexes(),UNO_QUERY
);
991 // Reference<XColumnsSupplier>
992 ::std::vector
< Reference
<XNameAccess
> > aAllIndexColumns
;
993 lcl_fillIndexColumns(xIndexes
,aAllIndexColumns
);
995 OUStringBuffer sIndexCondition
;
996 ::std::vector
<sal_Int32
> aIndexColumnPositions
;
997 SelectColumnsMetaData::const_iterator aIter
= m_pColumnNames
->begin();
998 SelectColumnsMetaData::const_iterator aEnd
= m_pColumnNames
->end();
1001 for(i
= 1;aIter
!= aEnd
;++aIter
,++i
)
1003 if ( m_pKeyColumnNames
->find(aIter
->first
) != m_pKeyColumnNames
->end() )
1005 aSql
.append(::dbtools::quoteName( aQuote
,aIter
->second
.sRealName
));
1006 if((_rDeleteRow
->get())[aIter
->second
.nPosition
].isNull())
1008 SAL_WARN("dbaccess", "can a primary key be null");
1009 aSql
.append(" IS NULL");
1012 aSql
.append(" = ?");
1017 ::std::vector
< Reference
<XNameAccess
> >::const_iterator aIndexEnd
= aAllIndexColumns
.end();
1018 for( ::std::vector
< Reference
<XNameAccess
> >::const_iterator aIndexIter
= aAllIndexColumns
.begin();
1019 aIndexIter
!= aIndexEnd
;++aIndexIter
)
1021 if((*aIndexIter
)->hasByName(aIter
->first
))
1023 sIndexCondition
.append(::dbtools::quoteName( aQuote
,aIter
->second
.sRealName
));
1024 if((_rDeleteRow
->get())[aIter
->second
.nPosition
].isNull())
1025 sIndexCondition
.append(" IS NULL");
1028 sIndexCondition
.append(" = ?");
1029 aIndexColumnPositions
.push_back(aIter
->second
.nPosition
);
1031 sIndexCondition
.append(aAnd
);
1038 aSql
.append(sIndexCondition
.makeStringAndClear());
1039 aSql
.setLength(aSql
.getLength()-5);
1041 // now create end execute the prepared statement
1042 Reference
< XPreparedStatement
> xPrep(m_xConnection
->prepareStatement(aSql
.makeStringAndClear()));
1043 Reference
< XParameters
> xParameter(xPrep
,UNO_QUERY
);
1045 aIter
= (*m_pKeyColumnNames
).begin();
1046 aEnd
= (*m_pKeyColumnNames
).end();
1048 for(;aIter
!= aEnd
;++aIter
,++i
)
1050 setParameter(i
,xParameter
,(_rDeleteRow
->get())[aIter
->second
.nPosition
],aIter
->second
.nType
,aIter
->second
.nScale
);
1053 // now we have to set the index values
1054 ::std::vector
<sal_Int32
>::iterator aIdxColIter
= aIndexColumnPositions
.begin();
1055 ::std::vector
<sal_Int32
>::iterator aIdxColEnd
= aIndexColumnPositions
.end();
1056 aIter
= m_pColumnNames
->begin();
1057 for(;aIdxColIter
!= aIdxColEnd
;++aIdxColIter
,++i
,++aIter
)
1059 setParameter(i
,xParameter
,(_rDeleteRow
->get())[*aIdxColIter
],(_rDeleteRow
->get())[*aIdxColIter
].getTypeKind(),aIter
->second
.nScale
);
1062 m_bDeleted
= xPrep
->executeUpdate() > 0;
1066 sal_Int32 nBookmark
= ::comphelper::getINT32((_rDeleteRow
->get())[0].getAny());
1067 if(m_aKeyIter
== m_aKeyMap
.find(nBookmark
) && m_aKeyIter
!= m_aKeyMap
.end())
1069 m_aKeyMap
.erase(nBookmark
);
1074 void SAL_CALL
OKeySet::cancelRowUpdates( ) throw(SQLException
, RuntimeException
)
1076 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
1079 void SAL_CALL
OKeySet::moveToInsertRow( ) throw(SQLException
, RuntimeException
)
1083 void SAL_CALL
OKeySet::moveToCurrentRow( ) throw(SQLException
, RuntimeException
)
1087 Reference
<XNameAccess
> OKeySet::getKeyColumns() const
1089 // use keys and indexes for exact positioning
1092 Reference
<XIndexAccess
> xKeys
= m_xTableKeys
;
1095 Reference
<XPropertySet
> xSet(m_xTable
,UNO_QUERY
);
1096 const Reference
<XNameAccess
> xPrimaryKeyColumns
= getPrimaryKeyColumns_throw(xSet
);
1097 return xPrimaryKeyColumns
;
1100 Reference
<XColumnsSupplier
> xKeyColsSup
;
1101 Reference
<XNameAccess
> xKeyColumns
;
1104 Reference
<XPropertySet
> xProp
;
1105 sal_Int32 nCount
= xKeys
->getCount();
1106 for(sal_Int32 i
= 0;i
< nCount
;++i
)
1108 xProp
.set(xKeys
->getByIndex(i
),UNO_QUERY
);
1111 sal_Int32 nKeyType
= 0;
1112 xProp
->getPropertyValue(PROPERTY_TYPE
) >>= nKeyType
;
1113 if(KeyType::PRIMARY
== nKeyType
)
1115 xKeyColsSup
.set(xProp
,UNO_QUERY
);
1116 OSL_ENSURE(xKeyColsSup
.is(),"Columnsupplier is null!");
1117 xKeyColumns
= xKeyColsSup
->getColumns();
1127 bool SAL_CALL
OKeySet::next( ) throw(SQLException
, RuntimeException
)
1129 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
1134 if(!m_bRowCountFinal
&& m_aKeyIter
== m_aKeyMap
.end())
1136 // not yet all records fetched, but we reached the end of those we fetched
1137 // try to fetch one more row
1140 OSL_ENSURE(!isAfterLast(), "fetchRow succeeded, but isAfterLast()");
1145 // nope, we arrived at end of data
1146 m_aKeyIter
= m_aKeyMap
.end();
1147 OSL_ENSURE(isAfterLast(), "fetchRow failed, but not end of data");
1152 return !isAfterLast();
1155 bool SAL_CALL
OKeySet::isBeforeFirst( ) throw(SQLException
, RuntimeException
)
1157 return m_aKeyIter
== m_aKeyMap
.begin();
1160 bool SAL_CALL
OKeySet::isAfterLast( ) throw(SQLException
, RuntimeException
)
1162 return m_bRowCountFinal
&& m_aKeyIter
== m_aKeyMap
.end();
1165 bool SAL_CALL
OKeySet::isFirst( ) throw(SQLException
, RuntimeException
)
1167 OKeySetMatrix::iterator aTemp
= m_aKeyMap
.begin();
1169 return m_aKeyIter
== aTemp
&& m_aKeyIter
!= m_aKeyMap
.end();
1172 bool SAL_CALL
OKeySet::isLast( ) throw(SQLException
, RuntimeException
)
1174 if(!m_bRowCountFinal
)
1177 OKeySetMatrix::iterator aTemp
= m_aKeyMap
.end();
1179 return m_aKeyIter
== aTemp
;
1182 void SAL_CALL
OKeySet::beforeFirst( ) throw(SQLException
, RuntimeException
)
1184 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
1185 m_aKeyIter
= m_aKeyMap
.begin();
1189 void SAL_CALL
OKeySet::afterLast( ) throw(SQLException
, RuntimeException
)
1191 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
1193 m_aKeyIter
= m_aKeyMap
.end();
1197 bool SAL_CALL
OKeySet::first( ) throw(SQLException
, RuntimeException
)
1199 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
1200 m_aKeyIter
= m_aKeyMap
.begin();
1202 if(m_aKeyIter
== m_aKeyMap
.end())
1206 m_aKeyIter
= m_aKeyMap
.end();
1212 return m_aKeyIter
!= m_aKeyMap
.end() && m_aKeyIter
!= m_aKeyMap
.begin();
1215 bool SAL_CALL
OKeySet::last( ) throw(SQLException
, RuntimeException
)
1217 return last_checked(true);
1220 bool OKeySet::last_checked( bool /* i_bFetchRow */ )
1222 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
1223 bool fetchedRow
= fillAllRows();
1225 m_aKeyIter
= m_aKeyMap
.end();
1231 return m_aKeyIter
!= m_aKeyMap
.end() && m_aKeyIter
!= m_aKeyMap
.begin();
1234 sal_Int32 SAL_CALL
OKeySet::getRow( ) throw(SQLException
, RuntimeException
)
1236 OSL_ENSURE(!isAfterLast(),"getRow is not allowed when afterlast record!");
1237 OSL_ENSURE(!isBeforeFirst(),"getRow is not allowed when beforefirst record!");
1239 return ::std::distance(m_aKeyMap
.begin(),m_aKeyIter
);
1242 bool SAL_CALL
OKeySet::absolute( sal_Int32 row
) throw(SQLException
, RuntimeException
)
1244 return absolute_checked(row
,true);
1247 bool OKeySet::absolute_checked( sal_Int32 row
, bool /* i_bFetchRow */ )
1249 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
1250 OSL_ENSURE(row
,"absolute(0) isn't allowed!");
1251 bool fetchedRow
= false;
1254 if(!m_bRowCountFinal
)
1255 fetchedRow
= fillAllRows();
1257 for(;row
< 0 && m_aKeyIter
!= m_aKeyMap
.begin();++row
)
1262 if(row
>= (sal_Int32
)m_aKeyMap
.size())
1264 // we don't have this row
1265 if(!m_bRowCountFinal
)
1267 // but there may still be rows to fetch.
1269 for(sal_Int32 i
=m_aKeyMap
.size()-1;i
< row
&& bNext
;++i
)
1271 // it is guaranteed that the above loop has executed at least once,
1272 // that is fetchRow called at least once.
1279 // reached end of data before desired row
1280 m_aKeyIter
= m_aKeyMap
.end();
1286 // no more rows to fetch -> fail
1287 m_aKeyIter
= m_aKeyMap
.end();
1293 m_aKeyIter
= m_aKeyMap
.begin();
1294 for(;row
> 0 && m_aKeyIter
!= m_aKeyMap
.end();--row
)
1303 return m_aKeyIter
!= m_aKeyMap
.end() && m_aKeyIter
!= m_aKeyMap
.begin();
1306 bool SAL_CALL
OKeySet::relative( sal_Int32 rows
) throw(SQLException
, RuntimeException
)
1313 return absolute(getRow()+rows
);
1316 bool OKeySet::previous_checked( bool /* i_bFetchRow */ )
1318 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
1319 if(m_aKeyIter
!= m_aKeyMap
.begin())
1324 return m_aKeyIter
!= m_aKeyMap
.begin();
1327 bool SAL_CALL
OKeySet::previous( ) throw(SQLException
, RuntimeException
)
1329 return previous_checked(true);
1332 bool OKeySet::doTryRefetch_throw() throw(SQLException
, RuntimeException
)
1335 // we just reassign the base members
1336 Reference
< XParameters
> xParameter(m_xStatement
,UNO_QUERY
);
1337 OSL_ENSURE(xParameter
.is(),"No Parameter interface!");
1338 xParameter
->clearParameters();
1341 connectivity::ORowVector
< ORowSetValue
>::Vector::const_iterator aParaIter
;
1342 connectivity::ORowVector
< ORowSetValue
>::Vector::const_iterator aParaEnd
;
1343 OUpdatedParameter::iterator aUpdateFind
= m_aUpdatedParameter
.find(m_aKeyIter
->first
);
1344 if ( aUpdateFind
== m_aUpdatedParameter
.end() )
1346 aParaIter
= m_aParameterValueForCache
.get().begin();
1347 aParaEnd
= m_aParameterValueForCache
.get().end();
1351 aParaIter
= aUpdateFind
->second
.get().begin();
1352 aParaEnd
= aUpdateFind
->second
.get().end();
1355 for(++aParaIter
;aParaIter
!= aParaEnd
;++aParaIter
,++nPos
)
1357 ::dbtools::setObjectWithInfo( xParameter
, nPos
, aParaIter
->makeAny(), aParaIter
->getTypeKind() );
1360 // now set the primary key column values
1361 connectivity::ORowVector
< ORowSetValue
>::Vector::const_iterator aIter
= m_aKeyIter
->second
.first
->get().begin();
1362 SelectColumnsMetaData::const_iterator aPosIter
= m_pKeyColumnNames
->begin();
1363 SelectColumnsMetaData::const_iterator aPosEnd
= m_pKeyColumnNames
->end();
1364 for(;aPosIter
!= aPosEnd
;++aPosIter
,++aIter
)
1365 setOneKeyColumnParameter(nPos
,xParameter
,*aIter
,aPosIter
->second
.nType
,aPosIter
->second
.nScale
);
1366 aPosIter
= m_pForeignColumnNames
->begin();
1367 aPosEnd
= m_pForeignColumnNames
->end();
1368 for(;aPosIter
!= aPosEnd
;++aPosIter
,++aIter
)
1369 setOneKeyColumnParameter(nPos
,xParameter
,*aIter
,aPosIter
->second
.nType
,aPosIter
->second
.nScale
);
1371 m_xSet
= m_xStatement
->executeQuery();
1372 OSL_ENSURE(m_xSet
.is(),"No resultset from statement!");
1373 return m_xSet
->next();
1376 void SAL_CALL
OKeySet::refreshRow() throw(SQLException
, RuntimeException
)
1380 if(isBeforeFirst() || isAfterLast())
1383 if ( m_aKeyIter
->second
.second
.second
.is() )
1385 m_xRow
= m_aKeyIter
->second
.second
.second
;
1389 bool bOK
= doTryRefetch_throw();
1392 // This row has disappeared; remove it.
1393 OKeySetMatrix::iterator aTemp
= m_aKeyIter
;
1396 m_aKeyMap
.erase(aTemp
);
1398 // adjust RowCount for the row we have removed
1399 if (m_rRowCount
> 0)
1402 SAL_WARN("dbaccess", "m_rRowCount got out of sync: non-empty m_aKeyMap, but m_rRowCount <= 0");
1404 if (m_aKeyIter
== m_aKeyMap
.end())
1406 ::comphelper::disposeComponent(m_xSet
);
1409 // it was the last fetched row,
1410 // but there may be another one to fetch
1413 // nope, that really was the last
1414 m_aKeyIter
= m_aKeyMap
.end();
1415 OSL_ENSURE(isAfterLast(), "fetchRow() failed but not isAfterLast()!");
1418 // Now, either fetchRow has set m_xRow or isAfterLast()
1427 m_xRow
.set(m_xSet
,UNO_QUERY
);
1428 OSL_ENSURE(m_xRow
.is(),"No row from statement!");
1432 bool OKeySet::fetchRow()
1434 // fetch the next row and append on the keyset
1436 if ( !m_bRowCountFinal
&& (!m_nMaxRows
|| sal_Int32(m_aKeyMap
.size()) < m_nMaxRows
) )
1437 bRet
= m_xDriverSet
->next();
1440 ORowSetRow aKeyRow
= new connectivity::ORowVector
< ORowSetValue
>((*m_pKeyColumnNames
).size() + m_pForeignColumnNames
->size());
1442 ::comphelper::disposeComponent(m_xSet
);
1443 m_xRow
.set(m_xDriverRow
, UNO_QUERY_THROW
);
1445 connectivity::ORowVector
< ORowSetValue
>::Vector::iterator aIter
= aKeyRow
->get().begin();
1447 SelectColumnsMetaData::const_iterator aPosIter
= (*m_pKeyColumnNames
).begin();
1448 SelectColumnsMetaData::const_iterator aPosEnd
= (*m_pKeyColumnNames
).end();
1449 for(;aPosIter
!= aPosEnd
;++aPosIter
,++aIter
)
1451 const SelectColumnDescription
& rColDesc
= aPosIter
->second
;
1452 aIter
->fill(rColDesc
.nPosition
, rColDesc
.nType
, m_xRow
);
1454 // copy missing columns from other tables
1455 aPosIter
= (*m_pForeignColumnNames
).begin();
1456 aPosEnd
= (*m_pForeignColumnNames
).end();
1457 for(;aPosIter
!= aPosEnd
;++aPosIter
,++aIter
)
1459 const SelectColumnDescription
& rColDesc
= aPosIter
->second
;
1460 aIter
->fill(rColDesc
.nPosition
, rColDesc
.nType
, m_xRow
);
1462 m_aKeyIter
= m_aKeyMap
.insert(OKeySetMatrix::value_type(m_aKeyMap
.rbegin()->first
+1,OKeySetValue(aKeyRow
,::std::pair
<sal_Int32
,Reference
<XRow
> >(0,Reference
<XRow
>())))).first
;
1465 m_bRowCountFinal
= true;
1469 bool OKeySet::fillAllRows()
1471 if(m_bRowCountFinal
)
1484 sal_Bool SAL_CALL
OKeySet::wasNull( ) throw(SQLException
, RuntimeException
, std::exception
)
1486 if ( ! m_xRow
.is() )
1487 throwGenericSQLException("Must call getFOO() for some FOO before wasNull()", *this);
1489 OSL_ENSURE(m_xRow
.is(),"m_xRow is null! I've thrown, but function execution continued?");
1490 return m_xRow
->wasNull();
1493 inline void OKeySet::ensureRowForData( ) throw(SQLException
, RuntimeException
)
1498 throwSQLException("Failed to refetch row", "02000", *this, -2);
1500 OSL_ENSURE(m_xRow
.is(),"m_xRow is null! I've called throwSQLException but execution continued?");
1503 OUString SAL_CALL
OKeySet::getString( sal_Int32 columnIndex
) throw(SQLException
, RuntimeException
, std::exception
)
1506 return m_xRow
->getString(columnIndex
);
1509 sal_Bool SAL_CALL
OKeySet::getBoolean( sal_Int32 columnIndex
) throw(SQLException
, RuntimeException
, std::exception
)
1512 return m_xRow
->getBoolean(columnIndex
);
1515 sal_Int8 SAL_CALL
OKeySet::getByte( sal_Int32 columnIndex
) throw(SQLException
, RuntimeException
, std::exception
)
1518 return m_xRow
->getByte(columnIndex
);
1521 sal_Int16 SAL_CALL
OKeySet::getShort( sal_Int32 columnIndex
) throw(SQLException
, RuntimeException
, std::exception
)
1524 return m_xRow
->getShort(columnIndex
);
1527 sal_Int32 SAL_CALL
OKeySet::getInt( sal_Int32 columnIndex
) throw(SQLException
, RuntimeException
, std::exception
)
1530 return m_xRow
->getInt(columnIndex
);
1533 sal_Int64 SAL_CALL
OKeySet::getLong( sal_Int32 columnIndex
) throw(SQLException
, RuntimeException
, std::exception
)
1536 return m_xRow
->getLong(columnIndex
);
1539 float SAL_CALL
OKeySet::getFloat( sal_Int32 columnIndex
) throw(SQLException
, RuntimeException
, std::exception
)
1542 return m_xRow
->getFloat(columnIndex
);
1545 double SAL_CALL
OKeySet::getDouble( sal_Int32 columnIndex
) throw(SQLException
, RuntimeException
, std::exception
)
1548 return m_xRow
->getDouble(columnIndex
);
1551 Sequence
< sal_Int8
> SAL_CALL
OKeySet::getBytes( sal_Int32 columnIndex
) throw(SQLException
, RuntimeException
, std::exception
)
1554 return m_xRow
->getBytes(columnIndex
);
1557 ::com::sun::star::util::Date SAL_CALL
OKeySet::getDate( sal_Int32 columnIndex
) throw(SQLException
, RuntimeException
, std::exception
)
1560 return m_xRow
->getDate(columnIndex
);
1563 ::com::sun::star::util::Time SAL_CALL
OKeySet::getTime( sal_Int32 columnIndex
) throw(SQLException
, RuntimeException
, std::exception
)
1566 return m_xRow
->getTime(columnIndex
);
1569 ::com::sun::star::util::DateTime SAL_CALL
OKeySet::getTimestamp( sal_Int32 columnIndex
) throw(SQLException
, RuntimeException
, std::exception
)
1572 return m_xRow
->getTimestamp(columnIndex
);
1575 Reference
< ::com::sun::star::io::XInputStream
> SAL_CALL
OKeySet::getBinaryStream( sal_Int32 columnIndex
) throw(SQLException
, RuntimeException
, std::exception
)
1578 return m_xRow
->getBinaryStream(columnIndex
);
1581 Reference
< ::com::sun::star::io::XInputStream
> SAL_CALL
OKeySet::getCharacterStream( sal_Int32 columnIndex
) throw(SQLException
, RuntimeException
, std::exception
)
1584 return m_xRow
->getCharacterStream(columnIndex
);
1587 Any SAL_CALL
OKeySet::getObject( sal_Int32 columnIndex
, const Reference
< ::com::sun::star::container::XNameAccess
>& typeMap
) throw(SQLException
, RuntimeException
, std::exception
)
1590 return m_xRow
->getObject(columnIndex
,typeMap
);
1593 Reference
< XRef
> SAL_CALL
OKeySet::getRef( sal_Int32 columnIndex
) throw(SQLException
, RuntimeException
, std::exception
)
1596 return m_xRow
->getRef(columnIndex
);
1599 Reference
< XBlob
> SAL_CALL
OKeySet::getBlob( sal_Int32 columnIndex
) throw(SQLException
, RuntimeException
, std::exception
)
1602 return m_xRow
->getBlob(columnIndex
);
1605 Reference
< XClob
> SAL_CALL
OKeySet::getClob( sal_Int32 columnIndex
) throw(SQLException
, RuntimeException
, std::exception
)
1608 return m_xRow
->getClob(columnIndex
);
1611 Reference
< XArray
> SAL_CALL
OKeySet::getArray( sal_Int32 columnIndex
) throw(SQLException
, RuntimeException
, std::exception
)
1614 return m_xRow
->getArray(columnIndex
);
1617 bool SAL_CALL
OKeySet::rowUpdated( ) throw(SQLException
, RuntimeException
)
1619 return m_aKeyIter
!= m_aKeyMap
.begin() && m_aKeyIter
!= m_aKeyMap
.end() && m_aKeyIter
->second
.second
.first
== 2;
1622 bool SAL_CALL
OKeySet::rowInserted( ) throw(SQLException
, RuntimeException
)
1624 return m_aKeyIter
!= m_aKeyMap
.begin() && m_aKeyIter
!= m_aKeyMap
.end() && m_aKeyIter
->second
.second
.first
== 1;
1627 bool SAL_CALL
OKeySet::rowDeleted( ) throw(SQLException
, RuntimeException
)
1629 bool bDeleted
= m_bDeleted
;
1637 void getColumnPositions(const Reference
<XNameAccess
>& _rxQueryColumns
,
1638 const ::com::sun::star::uno::Sequence
< OUString
>& _aColumnNames
,
1639 const OUString
& _rsUpdateTableName
,
1640 SelectColumnsMetaData
& o_rColumnNames
,
1641 bool i_bAppendTableName
)
1643 // get the real name of the columns
1644 Sequence
< OUString
> aSelNames(_rxQueryColumns
->getElementNames());
1645 const OUString
* pSelIter
= aSelNames
.getConstArray();
1646 const OUString
* pSelEnd
= pSelIter
+ aSelNames
.getLength();
1648 const OUString
* pTblColumnIter
= _aColumnNames
.getConstArray();
1649 const OUString
* pTblColumnEnd
= pTblColumnIter
+ _aColumnNames
.getLength();
1651 ::comphelper::UStringMixEqual
bCase(o_rColumnNames
.key_comp().isCaseSensitive());
1653 for(sal_Int32 nPos
= 1;pSelIter
!= pSelEnd
;++pSelIter
,++nPos
)
1655 Reference
<XPropertySet
> xQueryColumnProp(_rxQueryColumns
->getByName(*pSelIter
),UNO_QUERY_THROW
);
1656 OUString sRealName
,sTableName
;
1657 OSL_ENSURE(xQueryColumnProp
->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME
),"Property REALNAME not available!");
1658 OSL_ENSURE(xQueryColumnProp
->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME
),"Property TABLENAME not available!");
1659 xQueryColumnProp
->getPropertyValue(PROPERTY_REALNAME
) >>= sRealName
;
1660 xQueryColumnProp
->getPropertyValue(PROPERTY_TABLENAME
) >>= sTableName
;
1662 for(;pTblColumnIter
!= pTblColumnEnd
;++pTblColumnIter
)
1664 if(bCase(sRealName
,*pTblColumnIter
) && bCase(_rsUpdateTableName
,sTableName
) && o_rColumnNames
.find(*pTblColumnIter
) == o_rColumnNames
.end())
1666 sal_Int32 nType
= 0;
1667 xQueryColumnProp
->getPropertyValue(PROPERTY_TYPE
) >>= nType
;
1668 sal_Int32 nScale
= 0;
1669 xQueryColumnProp
->getPropertyValue(PROPERTY_SCALE
) >>= nScale
;
1670 OUString sColumnDefault
;
1671 if ( xQueryColumnProp
->getPropertySetInfo()->hasPropertyByName(PROPERTY_DEFAULTVALUE
) )
1672 xQueryColumnProp
->getPropertyValue(PROPERTY_DEFAULTVALUE
) >>= sColumnDefault
;
1674 sal_Int32 nNullable
= ColumnValue::NULLABLE_UNKNOWN
;
1675 OSL_VERIFY( xQueryColumnProp
->getPropertyValue( PROPERTY_ISNULLABLE
) >>= nNullable
);
1677 SelectColumnDescription
aColDesc( nPos
, nType
, nScale
, nNullable
!= sdbc::ColumnValue::NO_NULLS
, sColumnDefault
);
1679 if ( i_bAppendTableName
)
1681 sName
= sTableName
+ "." + sRealName
;
1682 aColDesc
.sRealName
= sRealName
;
1683 aColDesc
.sTableName
= sTableName
;
1689 o_rColumnNames
[sName
] = aColDesc
;
1694 pTblColumnIter
= _aColumnNames
.getConstArray();
1699 void OKeySet::impl_convertValue_throw(const ORowSetRow
& _rInsertRow
,const SelectColumnDescription
& i_aMetaData
)
1701 ORowSetValue
& aValue((_rInsertRow
->get())[i_aMetaData
.nPosition
]);
1702 switch(i_aMetaData
.nType
)
1704 case DataType::DECIMAL
:
1705 case DataType::NUMERIC
:
1707 OUString sValue
= aValue
.getString();
1708 sal_Int32 nIndex
= sValue
.indexOf('.');
1711 aValue
= sValue
.copy(0,::std::min(sValue
.getLength(),nIndex
+ (i_aMetaData
.nScale
> 0 ? i_aMetaData
.nScale
+ 1 : 0)));
1720 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */