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 .
22 #include <sal/log.hxx>
23 #include <core_resource.hxx>
24 #include <strings.hrc>
25 #include <strings.hxx>
26 #include <com/sun/star/beans/XPropertySet.hpp>
27 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
28 #include <com/sun/star/sdb/XParametersSupplier.hpp>
29 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
30 #include <com/sun/star/sdbc/ColumnValue.hpp>
31 #include <com/sun/star/sdbc/SQLException.hpp>
32 #include <com/sun/star/sdbc/XPreparedStatement.hpp>
33 #include <com/sun/star/sdbc/XParameters.hpp>
34 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
35 #include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
36 #include <com/sun/star/container/XIndexAccess.hpp>
37 #include <com/sun/star/sdbcx/CompareBookmark.hpp>
38 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
39 #include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
40 #include <comphelper/types.hxx>
41 #include <connectivity/dbtools.hxx>
42 #include <connectivity/dbexception.hxx>
44 #include <com/sun/star/io/XInputStream.hpp>
45 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
46 #include <composertools.hxx>
47 #include "PrivateRow.hxx"
49 using namespace dbaccess
;
50 using namespace ::connectivity
;
51 using namespace ::dbtools
;
52 using namespace ::com::sun::star::uno
;
53 using namespace ::com::sun::star::beans
;
54 using namespace ::com::sun::star::sdbc
;
55 using namespace ::com::sun::star::sdb
;
56 using namespace ::com::sun::star::sdbcx
;
57 using namespace ::com::sun::star::container
;
58 using namespace ::com::sun::star::lang
;
59 using namespace ::com::sun::star::util
;
60 using namespace ::com::sun::star::io
;
61 using namespace ::com::sun::star
;
62 using namespace ::cppu
;
63 using namespace ::osl
;
68 void lcl_fillIndexColumns(const Reference
<XIndexAccess
>& _xIndexes
, std::vector
< Reference
<XNameAccess
> >& _rAllIndexColumns
)
70 if ( !_xIndexes
.is() )
73 Reference
<XPropertySet
> xIndexColsSup
;
74 sal_Int32 nCount
= _xIndexes
->getCount();
75 for(sal_Int32 j
= 0 ; j
< nCount
; ++j
)
77 xIndexColsSup
.set(_xIndexes
->getByIndex(j
),UNO_QUERY
);
78 if( xIndexColsSup
.is()
79 && comphelper::getBOOL(xIndexColsSup
->getPropertyValue(PROPERTY_ISUNIQUE
))
80 && !comphelper::getBOOL(xIndexColsSup
->getPropertyValue(PROPERTY_ISPRIMARYKEYINDEX
))
82 _rAllIndexColumns
.push_back(Reference
<XColumnsSupplier
>(xIndexColsSup
,UNO_QUERY_THROW
)->getColumns());
86 template < typename T
> void tryDispose( Reference
<T
> &r
)
90 ::comphelper::disposeComponent(r
);
92 catch(const Exception
&)
98 SAL_WARN("dbaccess", "Unknown Exception occurred");
104 OKeySet::OKeySet(const connectivity::OSQLTable
& _xTable
,
105 const OUString
& _rUpdateTableName
, // this can be the alias or the full qualified name
106 const Reference
< XSingleSelectQueryAnalyzer
>& _xComposer
,
107 const ORowSetValueVector
& _aParameterValueForCache
,
108 sal_Int32 i_nMaxRows
,
109 sal_Int32
& o_nRowCount
)
110 :OCacheSet(i_nMaxRows
)
111 ,m_aParameterValueForCache(new ORowSetValueVector(_aParameterValueForCache
))
113 ,m_xComposer(_xComposer
)
114 ,m_sUpdateTableName(_rUpdateTableName
)
115 ,m_rRowCount(o_nRowCount
)
116 ,m_bRowCountFinal(false)
123 // m_xStatement is necessarily one of those
124 for (auto & statement
: m_vStatements
)
126 tryDispose(statement
.second
);
129 m_xComposer
= nullptr;
133 void OKeySet::initColumns()
135 Reference
<XDatabaseMetaData
> xMeta
= m_xConnection
->getMetaData();
136 bool bCase
= xMeta
.is() && xMeta
->supportsMixedCaseQuotedIdentifiers();
137 m_pKeyColumnNames
.reset( new SelectColumnsMetaData(bCase
) );
138 m_pColumnNames
.reset( new SelectColumnsMetaData(bCase
) );
139 m_pParameterNames
.reset( new SelectColumnsMetaData(bCase
) );
140 m_pForeignColumnNames
.reset( new SelectColumnsMetaData(bCase
) );
143 void OKeySet::findTableColumnsMatching_throw( const Any
& i_aTable
,
144 const OUString
& i_rUpdateTableName
,
145 const Reference
<XDatabaseMetaData
>& i_xMeta
,
146 const Reference
<XNameAccess
>& i_xQueryColumns
,
147 std::unique_ptr
<SelectColumnsMetaData
> const & o_pKeyColumnNames
)
149 // first ask the database itself for the best columns which can be used
150 Sequence
< OUString
> aBestColumnNames
;
151 Reference
<XNameAccess
> xKeyColumns
= getPrimaryKeyColumns_throw(i_aTable
);
152 if ( xKeyColumns
.is() )
153 aBestColumnNames
= xKeyColumns
->getElementNames();
155 const Reference
<XColumnsSupplier
> xTblColSup(i_aTable
,UNO_QUERY_THROW
);
156 const Reference
<XNameAccess
> xTblColumns
= xTblColSup
->getColumns();
157 // locate parameter in select columns
158 Reference
<XParametersSupplier
> xParaSup(m_xComposer
,UNO_QUERY
);
159 Reference
<XIndexAccess
> xQueryParameters
= xParaSup
->getParameters();
160 const sal_Int32 nParaCount
= xQueryParameters
->getCount();
161 Sequence
< OUString
> aParameterColumns(nParaCount
);
162 for(sal_Int32 i
= 0; i
< nParaCount
;++i
)
164 Reference
<XPropertySet
> xPara(xQueryParameters
->getByIndex(i
),UNO_QUERY_THROW
);
165 xPara
->getPropertyValue(PROPERTY_REALNAME
) >>= aParameterColumns
[i
];
168 OUString
sUpdateTableName( i_rUpdateTableName
);
169 if ( sUpdateTableName
.isEmpty() )
171 SAL_WARN("dbaccess", "OKeySet::findTableColumnsMatching_throw: This is a fallback only - it won't work when the table has an alias name." );
172 // If i_aTable originates from a query composer, and is a table which appears with an alias in the SELECT statement,
173 // then the below code will not produce correct results.
174 // For instance, imagine a "SELECT alias.col FROM table AS alias". Now i_aTable would be the table named
175 // "table", so our sUpdateTableName would be "table" as well - not the information about the "alias" is
176 // already lost here.
177 // now getColumnPositions would traverse the columns, and check which of them belong to the table denoted
178 // by sUpdateTableName. Since the latter is "table", but the columns only know that they belong to a table
179 // named "alias", there will be no matching - so getColumnPositions wouldn't find anything.
181 OUString sCatalog
, sSchema
, sTable
;
182 Reference
<XPropertySet
> xTableProp( i_aTable
, UNO_QUERY_THROW
);
183 xTableProp
->getPropertyValue( PROPERTY_CATALOGNAME
)>>= sCatalog
;
184 xTableProp
->getPropertyValue( PROPERTY_SCHEMANAME
) >>= sSchema
;
185 xTableProp
->getPropertyValue( PROPERTY_NAME
) >>= sTable
;
186 sUpdateTableName
= dbtools::composeTableName( i_xMeta
, sCatalog
, sSchema
, sTable
, false, ::dbtools::EComposeRule::InDataManipulation
);
189 ::dbaccess::getColumnPositions(i_xQueryColumns
,aBestColumnNames
,sUpdateTableName
,(*o_pKeyColumnNames
),true);
190 ::dbaccess::getColumnPositions(i_xQueryColumns
,xTblColumns
->getElementNames(),sUpdateTableName
,(*m_pColumnNames
),true);
191 ::dbaccess::getColumnPositions(i_xQueryColumns
,aParameterColumns
,sUpdateTableName
,(*m_pParameterNames
),true);
193 if ( o_pKeyColumnNames
->empty() )
195 ::dbtools::throwGenericSQLException("Could not find any key column.", *this );
198 for (auto const& keyColumn
: *o_pKeyColumnNames
)
200 if ( !xTblColumns
->hasByName( keyColumn
.second
.sRealName
) )
203 Reference
<XPropertySet
> xProp( xTblColumns
->getByName( keyColumn
.second
.sRealName
), UNO_QUERY
);
205 if ( ( xProp
->getPropertyValue( PROPERTY_ISAUTOINCREMENT
) >>= bAuto
) && bAuto
)
206 m_aAutoColumns
.push_back( keyColumn
.first
);
212 void appendOneKeyColumnClause( const OUString
&tblName
, const OUString
&colName
, const connectivity::ORowSetValue
&_rValue
, OUStringBuffer
&o_buf
)
215 if (tblName
.isEmpty())
218 fullName
= tblName
+ "." + colName
;
219 if ( _rValue
.isNull() )
221 o_buf
.append(fullName
).append(" IS NULL ");
225 o_buf
.append(fullName
).append(" = ? ");
230 void OKeySet::setOneKeyColumnParameter( sal_Int32
&nPos
, const Reference
< XParameters
> &_xParameter
, const connectivity::ORowSetValue
&_rValue
, sal_Int32 _nType
, sal_Int32 _nScale
)
232 if ( _rValue
.isNull() )
234 // Nothing to do, appendOneKeyColumnClause took care of it,
235 // the "IS NULL" is hardcoded in the query
239 setParameter( nPos
++, _xParameter
, _rValue
, _nType
, _nScale
);
243 OUStringBuffer
OKeySet::createKeyFilter()
245 connectivity::ORowVector
< ORowSetValue
>::Vector::const_iterator aIter
= m_aKeyIter
->second
.first
->begin();
247 static const char aAnd
[] = " AND ";
248 const OUString aQuote
= getIdentifierQuoteString();
249 OUStringBuffer aFilter
;
250 // create the where clause
251 Reference
<XDatabaseMetaData
> xMeta
= m_xConnection
->getMetaData();
252 for (auto const& keyColumnName
: *m_pKeyColumnNames
)
254 if ( ! aFilter
.isEmpty() )
255 aFilter
.append(aAnd
);
256 appendOneKeyColumnClause(::dbtools::quoteTableName(xMeta
, keyColumnName
.second
.sTableName
, ::dbtools::EComposeRule::InDataManipulation
),
257 ::dbtools::quoteName(aQuote
, keyColumnName
.second
.sRealName
),
261 for (auto const& foreignColumnName
: * m_pForeignColumnNames
)
263 if ( ! aFilter
.isEmpty() )
264 aFilter
.append(aAnd
);
265 appendOneKeyColumnClause(::dbtools::quoteTableName(xMeta
, foreignColumnName
.second
.sTableName
, ::dbtools::EComposeRule::InDataManipulation
),
266 ::dbtools::quoteName(aQuote
, foreignColumnName
.second
.sRealName
),
273 void OKeySet::construct(const Reference
< XResultSet
>& _xDriverSet
, const OUString
& i_sRowSetFilter
)
275 OCacheSet::construct(_xDriverSet
,i_sRowSetFilter
);
279 Reference
<XDatabaseMetaData
> xMeta
= m_xConnection
->getMetaData();
280 Reference
<XColumnsSupplier
> xQueryColSup(m_xComposer
, UNO_QUERY
);
281 const Reference
<XNameAccess
> xQueryColumns
= xQueryColSup
->getColumns();
282 findTableColumnsMatching_throw( makeAny(m_xTable
), m_sUpdateTableName
, xMeta
, xQueryColumns
, m_pKeyColumnNames
);
284 Reference
< XSingleSelectQueryComposer
> xSourceComposer(m_xComposer
,UNO_QUERY
);
285 Reference
< XMultiServiceFactory
> xFactory(m_xConnection
, UNO_QUERY_THROW
);
286 Reference
<XSingleSelectQueryComposer
> xAnalyzer(xFactory
->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
),UNO_QUERY
);
287 xAnalyzer
->setElementaryQuery(xSourceComposer
->getElementaryQuery());
288 Reference
<XTablesSupplier
> xTabSup(xAnalyzer
,uno::UNO_QUERY
);
289 Reference
<XNameAccess
> xSelectTables
= xTabSup
->getTables();
290 const Sequence
< OUString
> aSeq
= xSelectTables
->getElementNames();
291 if ( aSeq
.getLength() > 1 ) // special handling for join
293 const OUString
* pIter
= aSeq
.getConstArray();
294 const OUString
* const pEnd
= pIter
+ aSeq
.getLength();
295 for(;pIter
!= pEnd
;++pIter
)
297 if ( *pIter
!= m_sUpdateTableName
)
299 connectivity::OSQLTable
xSelColSup(xSelectTables
->getByName(*pIter
),uno::UNO_QUERY
);
300 Reference
<XPropertySet
> xProp(xSelColSup
,uno::UNO_QUERY
);
301 OUString sSelectTableName
= ::dbtools::composeTableName( xMeta
, xProp
, ::dbtools::EComposeRule::InDataManipulation
, false );
303 ::dbaccess::getColumnPositions(xQueryColumns
, xSelColSup
->getColumns()->getElementNames(), sSelectTableName
, (*m_pForeignColumnNames
), true);
305 // LEM: there used to be a break here; however, I see no reason to stop
306 // at first non-updateTable, so I removed it. (think of multiple joins...)
311 // the first row is empty because it's now easier for us to distinguish when we are beforefirst or first
312 // without extra variable to be set
313 OKeySetValue
keySetValue(nullptr,std::pair
<sal_Int32
,Reference
<XRow
> >(0,Reference
<XRow
>()));
314 m_aKeyMap
.emplace(0, keySetValue
);
315 m_aKeyIter
= m_aKeyMap
.begin();
318 void OKeySet::reset(const Reference
< XResultSet
>& _xDriverSet
)
320 OCacheSet::construct(_xDriverSet
, m_sRowSetFilter
);
321 m_bRowCountFinal
= false;
323 OKeySetValue
keySetValue(nullptr,std::pair
<sal_Int32
,Reference
<XRow
> >(0,Reference
<XRow
>()));
324 m_aKeyMap
.emplace(0,keySetValue
);
325 m_aKeyIter
= m_aKeyMap
.begin();
328 void OKeySet::ensureStatement( )
330 // do we already have a statement for the current combination of NULLness
331 // of key & foreign columns?
332 std::vector
<bool> FilterColumnsNULL
;
333 FilterColumnsNULL
.reserve(m_aKeyIter
->second
.first
->size());
334 for (auto const& elem
: *m_aKeyIter
->second
.first
)
335 FilterColumnsNULL
.push_back(elem
.isNull());
336 vStatements_t::const_iterator
pNewStatement(m_vStatements
.find(FilterColumnsNULL
));
337 if(pNewStatement
== m_vStatements
.end())
339 // no: make a new one
341 std::pair
< vStatements_t::const_iterator
, bool > insert_result
342 (m_vStatements
.emplace( FilterColumnsNULL
, m_xStatement
));
343 (void) insert_result
; // WaE: unused variable
344 assert(insert_result
.second
);
348 m_xStatement
= pNewStatement
->second
;
351 void OKeySet::makeNewStatement()
353 Reference
< XSingleSelectQueryComposer
> xSourceComposer(m_xComposer
,UNO_QUERY
);
354 Reference
< XMultiServiceFactory
> xFactory(m_xConnection
, UNO_QUERY_THROW
);
355 Reference
<XSingleSelectQueryComposer
> xAnalyzer(xFactory
->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
),UNO_QUERY
);
356 xAnalyzer
->setElementaryQuery(xSourceComposer
->getElementaryQuery());
358 OUStringBuffer
aFilter(createKeyFilter());
359 executeStatement(aFilter
, xAnalyzer
);
362 void OKeySet::executeStatement(OUStringBuffer
& io_aFilter
, Reference
<XSingleSelectQueryComposer
>& io_xAnalyzer
)
364 bool bFilterSet
= !m_sRowSetFilter
.isEmpty();
367 FilterCreator aFilterCreator
;
368 aFilterCreator
.append( m_sRowSetFilter
);
369 aFilterCreator
.append( io_aFilter
.makeStringAndClear() );
370 io_aFilter
= aFilterCreator
.getComposedAndClear();
372 io_xAnalyzer
->setFilter(io_aFilter
.makeStringAndClear());
375 Sequence
< Sequence
< PropertyValue
> > aFilter2
= io_xAnalyzer
->getStructuredFilter();
376 const Sequence
< PropertyValue
>* pOr
= aFilter2
.getConstArray();
377 const Sequence
< PropertyValue
>* pOrEnd
= pOr
+ aFilter2
.getLength();
378 for(;pOr
!= pOrEnd
;++pOr
)
380 const PropertyValue
* pAnd
= pOr
->getConstArray();
381 const PropertyValue
* pAndEnd
= pAnd
+ pOr
->getLength();
382 for(;pAnd
!= pAndEnd
;++pAnd
)
385 if ( !(pAnd
->Value
>>= sValue
) || !( sValue
== "?" || sValue
.startsWith( ":" ) ) )
386 { // we have a criteria which has to be taken into account for updates
387 m_aFilterColumns
.push_back(pAnd
->Name
);
392 m_xStatement
= m_xConnection
->prepareStatement(io_xAnalyzer
->getQueryWithSubstitution());
393 ::comphelper::disposeComponent(io_xAnalyzer
);
396 void OKeySet::invalidateRow()
399 ::comphelper::disposeComponent(m_xSet
);
402 Any
OKeySet::getBookmark()
404 OSL_ENSURE(m_aKeyIter
!= m_aKeyMap
.end() && m_aKeyIter
!= m_aKeyMap
.begin(),
405 "getBookmark is only possible when we stand on a valid row!");
406 return makeAny(m_aKeyIter
->first
);
409 bool OKeySet::moveToBookmark( const Any
& bookmark
)
411 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
412 m_aKeyIter
= m_aKeyMap
.find(::comphelper::getINT32(bookmark
));
414 return m_aKeyIter
!= m_aKeyMap
.end();
417 sal_Int32
OKeySet::compareBookmarks( const Any
& _first
, const Any
& _second
)
419 sal_Int32 nFirst
= 0, nSecond
= 0;
423 return (nFirst
!= nSecond
) ? CompareBookmark::NOT_EQUAL
: CompareBookmark::EQUAL
;
426 bool OKeySet::hasOrderedBookmarks( )
431 sal_Int32
OKeySet::hashBookmark( const Any
& bookmark
)
433 return ::comphelper::getINT32(bookmark
);
437 void OKeySet::updateRow(const ORowSetRow
& _rInsertRow
,const ORowSetRow
& _rOriginalRow
,const connectivity::OSQLTable
& _xTable
)
439 Reference
<XPropertySet
> xSet(_xTable
,UNO_QUERY
);
442 OUStringBuffer aSql
= "UPDATE " + m_aComposedTableName
+ " SET ";
443 // list all columns that should be set
444 static OUString
aPara(" = ?,");
445 OUString aQuote
= getIdentifierQuoteString();
446 static OUString
aAnd(" AND ");
447 OUString
sIsNull(" IS NULL");
448 OUString
sParam(" = ?");
450 // use keys and indexes for exact positioning
451 Reference
<XIndexesSupplier
> xIndexSup(_xTable
,UNO_QUERY
);
452 Reference
<XIndexAccess
> xIndexes
;
453 if ( xIndexSup
.is() )
454 xIndexes
.set(xIndexSup
->getIndexes(),UNO_QUERY
);
456 std::vector
< Reference
<XNameAccess
> > aAllIndexColumns
;
457 lcl_fillIndexColumns(xIndexes
,aAllIndexColumns
);
459 OUStringBuffer sKeyCondition
,sIndexCondition
;
460 std::vector
<sal_Int32
> aIndexColumnPositions
;
462 const sal_Int32 nOldLength
= aSql
.getLength();
464 // here we build the condition part for the update statement
465 for (auto const& columnName
: *m_pColumnNames
)
467 if ( m_pKeyColumnNames
->find(columnName
.first
) != m_pKeyColumnNames
->end() )
469 sKeyCondition
.append(::dbtools::quoteName( aQuote
,columnName
.second
.sRealName
));
470 if((*_rOriginalRow
)[columnName
.second
.nPosition
].isNull())
471 sKeyCondition
.append(sIsNull
);
473 sKeyCondition
.append(sParam
);
474 sKeyCondition
.append(aAnd
);
478 for (auto const& indexColumn
: aAllIndexColumns
)
480 if(indexColumn
->hasByName(columnName
.first
))
482 sIndexCondition
.append(::dbtools::quoteName( aQuote
,columnName
.second
.sRealName
));
483 if((*_rOriginalRow
)[columnName
.second
.nPosition
].isNull())
484 sIndexCondition
.append(sIsNull
);
487 sIndexCondition
.append(sParam
);
488 aIndexColumnPositions
.push_back(columnName
.second
.nPosition
);
490 sIndexCondition
.append(aAnd
);
495 if((*_rInsertRow
)[columnName
.second
.nPosition
].isModified())
497 aSql
.append(::dbtools::quoteName( aQuote
,columnName
.second
.sRealName
)).append(aPara
);
502 if( aSql
.getLength() != nOldLength
)
504 aSql
.setLength(aSql
.getLength()-1);
507 ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_VALUE_CHANGED
), StandardSQLState::GENERAL_ERROR
, m_xConnection
);
509 if(!sKeyCondition
.isEmpty() || !sIndexCondition
.isEmpty())
511 aSql
.append(" WHERE ");
512 if(!sKeyCondition
.isEmpty() && !sIndexCondition
.isEmpty())
514 aSql
.append(sKeyCondition
.makeStringAndClear()).append(sIndexCondition
.makeStringAndClear());
516 else if(!sKeyCondition
.isEmpty())
518 aSql
.append(sKeyCondition
.makeStringAndClear());
520 else if(!sIndexCondition
.isEmpty())
522 aSql
.append(sIndexCondition
.makeStringAndClear());
524 aSql
.setLength(aSql
.getLength()-5); // remove the last AND
527 ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_CONDITION_FOR_PK
), StandardSQLState::GENERAL_ERROR
, m_xConnection
);
529 // now create end execute the prepared statement
530 executeUpdate(_rInsertRow
,_rOriginalRow
,aSql
.makeStringAndClear(),"",aIndexColumnPositions
);
533 void OKeySet::executeUpdate(const ORowSetRow
& _rInsertRow
,const ORowSetRow
& _rOriginalRow
,const OUString
& i_sSQL
,const OUString
& i_sTableName
,const std::vector
<sal_Int32
>& _aIndexColumnPositions
)
535 // now create end execute the prepared statement
536 Reference
< XPreparedStatement
> xPrep(m_xConnection
->prepareStatement(i_sSQL
));
537 Reference
< XParameters
> xParameter(xPrep
,UNO_QUERY
);
539 bool bRefetch
= true;
540 Reference
<XRow
> xRow
;
542 // first the set values
543 for (auto const& columnName
: *m_pColumnNames
)
545 if ( i_sTableName
.isEmpty() || columnName
.second
.sTableName
== i_sTableName
)
547 sal_Int32 nPos
= columnName
.second
.nPosition
;
548 if((*_rInsertRow
)[nPos
].isModified())
552 bRefetch
= std::find(m_aFilterColumns
.begin(),m_aFilterColumns
.end(),columnName
.second
.sRealName
) == m_aFilterColumns
.end();
554 impl_convertValue_throw(_rInsertRow
,columnName
.second
);
555 (*_rInsertRow
)[nPos
].setSigned((*_rOriginalRow
)[nPos
].isSigned());
556 setParameter(i
++,xParameter
,(*_rInsertRow
)[nPos
],columnName
.second
.nType
,columnName
.second
.nScale
);
560 // and then the values of the where condition
561 for (auto const& keyColumnName
: *m_pKeyColumnNames
)
563 if ( i_sTableName
.isEmpty() || keyColumnName
.second
.sTableName
== i_sTableName
)
565 setParameter(i
++,xParameter
,(*_rOriginalRow
)[keyColumnName
.second
.nPosition
],keyColumnName
.second
.nType
,keyColumnName
.second
.nScale
);
568 if ( !_aIndexColumnPositions
.empty() )
570 // now we have to set the index values
571 auto aIter
= m_pColumnNames
->begin();
572 for (auto const& indexColumnPosition
: _aIndexColumnPositions
)
574 setParameter(i
++,xParameter
,(*_rOriginalRow
)[indexColumnPosition
],(*_rOriginalRow
)[indexColumnPosition
].getTypeKind(),aIter
->second
.nScale
);
578 const sal_Int32 nRowsUpdated
= xPrep
->executeUpdate();
579 m_bUpdated
= nRowsUpdated
> 0;
582 const sal_Int32 nBookmark
= ::comphelper::getINT32((*_rInsertRow
)[0].getAny());
583 m_aKeyIter
= m_aKeyMap
.find(nBookmark
);
584 m_aKeyIter
->second
.second
.first
= 2;
585 m_aKeyIter
->second
.second
.second
= xRow
;
586 copyRowValue(_rInsertRow
,m_aKeyIter
->second
.first
,nBookmark
);
587 tryRefetch(_rInsertRow
,bRefetch
);
591 void OKeySet::insertRow( const ORowSetRow
& _rInsertRow
,const connectivity::OSQLTable
& _xTable
)
593 Reference
<XPropertySet
> xSet(_xTable
,UNO_QUERY
);
596 OUStringBuffer
aSql( "INSERT INTO " + m_aComposedTableName
+ " ( ");
598 // set values and column names
599 OUStringBuffer
aValues(" VALUES ( ");
600 OUString aQuote
= getIdentifierQuoteString();
602 bool bRefetch
= true;
603 bool bModified
= false;
604 for (auto const& columnName
: *m_pColumnNames
)
606 if((*_rInsertRow
)[columnName
.second
.nPosition
].isModified())
610 bRefetch
= std::find(m_aFilterColumns
.begin(),m_aFilterColumns
.end(),columnName
.second
.sRealName
) == m_aFilterColumns
.end();
612 aSql
.append(::dbtools::quoteName( aQuote
,columnName
.second
.sRealName
)).append(",");
613 aValues
.append("?,");
618 ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_VALUE_CHANGED
), StandardSQLState::GENERAL_ERROR
, m_xConnection
);
620 aSql
[aSql
.getLength() - 1] = ')';
621 aValues
[aValues
.getLength() - 1] = ')';
622 aSql
.append(aValues
.makeStringAndClear());
623 // now create,fill and execute the prepared statement
624 executeInsert(_rInsertRow
,aSql
.makeStringAndClear(),"",bRefetch
);
627 void OKeySet::executeInsert( const ORowSetRow
& _rInsertRow
,const OUString
& i_sSQL
,const OUString
& i_sTableName
,bool bRefetch
)
629 // now create,fill and execute the prepared statement
630 Reference
< XPreparedStatement
> xPrep(m_xConnection
->prepareStatement(i_sSQL
));
631 Reference
< XParameters
> xParameter(xPrep
,UNO_QUERY
);
634 for (auto const& columnName
: *m_pColumnNames
)
636 if ( i_sTableName
.isEmpty() || columnName
.second
.sTableName
== i_sTableName
)
638 const sal_Int32 nPos
= columnName
.second
.nPosition
;
639 if((*_rInsertRow
)[nPos
].isModified())
641 if((*_rInsertRow
)[nPos
].isNull())
642 xParameter
->setNull(i
++,(*_rInsertRow
)[nPos
].getTypeKind());
645 impl_convertValue_throw(_rInsertRow
,columnName
.second
);
646 (*_rInsertRow
)[nPos
].setSigned(m_aSignedFlags
[nPos
-1]);
647 setParameter(i
++,xParameter
,(*_rInsertRow
)[nPos
],columnName
.second
.nType
,columnName
.second
.nScale
);
653 m_bInserted
= xPrep
->executeUpdate() > 0;
654 bool bAutoValuesFetched
= false;
657 // first insert the default values into the insertrow
658 for (auto const& columnName
: *m_pColumnNames
)
660 if ( !(*_rInsertRow
)[columnName
.second
.nPosition
].isModified() )
662 if(columnName
.second
.bNullable
&& columnName
.second
.sDefaultValue
.isEmpty())
664 (*_rInsertRow
)[columnName
.second
.nPosition
].setTypeKind(columnName
.second
.nType
);
665 (*_rInsertRow
)[columnName
.second
.nPosition
].setNull();
669 (*_rInsertRow
)[columnName
.second
.nPosition
] = columnName
.second
.sDefaultValue
;
670 (*_rInsertRow
)[columnName
.second
.nPosition
].setTypeKind(columnName
.second
.nType
);
676 Reference
< XGeneratedResultSet
> xGRes(xPrep
, UNO_QUERY
);
679 Reference
< XResultSet
> xRes
= xGRes
->getGeneratedValues();
680 Reference
< XRow
> xRow(xRes
,UNO_QUERY
);
681 if ( xRow
.is() && xRes
->next() )
683 Reference
< XResultSetMetaDataSupplier
> xMdSup(xRes
,UNO_QUERY
);
684 Reference
< XResultSetMetaData
> xMd
= xMdSup
->getMetaData();
685 sal_Int32 nColumnCount
= xMd
->getColumnCount();
686 std::vector
< OUString
>::const_iterator aAutoIter
= m_aAutoColumns
.begin();
687 std::vector
< OUString
>::const_iterator aAutoEnd
= m_aAutoColumns
.end();
688 for (sal_Int32 j
= 1;aAutoIter
!= aAutoEnd
&& j
<= nColumnCount
; ++aAutoIter
,++j
)
690 SelectColumnsMetaData::const_iterator aFind
= m_pKeyColumnNames
->find(*aAutoIter
);
691 if ( aFind
!= m_pKeyColumnNames
->end() )
692 (*_rInsertRow
)[aFind
->second
.nPosition
].fill(j
, aFind
->second
.nType
, xRow
);
694 bAutoValuesFetched
= true;
698 catch(const Exception
&)
700 SAL_WARN("dbaccess", "Could not execute GeneratedKeys() stmt");
704 ::comphelper::disposeComponent(xPrep
);
706 if ( i_sTableName
.isEmpty() && !bAutoValuesFetched
&& m_bInserted
)
708 // first check if all key column values were set
709 const OUString sQuote
= getIdentifierQuoteString();
710 OUStringBuffer sMaxStmt
;
711 auto aEnd
= m_pKeyColumnNames
->end();
712 for (auto const& autoColumn
: m_aAutoColumns
)
714 // we will only fetch values which are keycolumns
715 SelectColumnsMetaData::const_iterator aFind
= m_pKeyColumnNames
->find(autoColumn
);
718 sMaxStmt
.append(" MAX(").append(::dbtools::quoteName( sQuote
,aFind
->second
.sRealName
)).append("),");
722 if(!sMaxStmt
.isEmpty())
724 sMaxStmt
[sMaxStmt
.getLength()-1] = ' ';
725 OUString sStmt
= "SELECT " + sMaxStmt
.makeStringAndClear() + "FROM ";
726 OUString sCatalog
,sSchema
,sTable
;
727 ::dbtools::qualifiedNameComponents(m_xConnection
->getMetaData(),m_sUpdateTableName
,sCatalog
,sSchema
,sTable
,::dbtools::EComposeRule::InDataManipulation
);
728 sStmt
+= ::dbtools::composeTableNameForSelect( m_xConnection
, sCatalog
, sSchema
, sTable
);
731 // now fetch the autoincrement values
732 Reference
<XStatement
> xStatement
= m_xConnection
->createStatement();
733 Reference
<XResultSet
> xRes
= xStatement
->executeQuery(sStmt
);
734 Reference
<XRow
> xRow(xRes
,UNO_QUERY
);
735 if(xRow
.is() && xRes
->next())
738 for (auto const& autoColumn
: m_aAutoColumns
)
740 // we will only fetch values which are keycolumns
741 SelectColumnsMetaData::const_iterator aFind
= m_pKeyColumnNames
->find(autoColumn
);
743 (*_rInsertRow
)[aFind
->second
.nPosition
].fill(j
++, aFind
->second
.nType
, xRow
);
746 ::comphelper::disposeComponent(xStatement
);
750 SAL_WARN("dbaccess", "Could not fetch with MAX() ");
756 OKeySetMatrix::const_iterator aKeyIter
= m_aKeyMap
.end();
758 ORowSetRow aKeyRow
= new connectivity::ORowVector
< ORowSetValue
>(m_pKeyColumnNames
->size());
759 copyRowValue(_rInsertRow
,aKeyRow
,aKeyIter
->first
+ 1);
761 m_aKeyIter
= m_aKeyMap
.emplace( aKeyIter
->first
+ 1, OKeySetValue(aKeyRow
,std::pair
<sal_Int32
,Reference
<XRow
> >(1,Reference
<XRow
>())) ).first
;
762 // now we set the bookmark for this row
763 (*_rInsertRow
)[0] = makeAny(static_cast<sal_Int32
>(m_aKeyIter
->first
));
764 tryRefetch(_rInsertRow
,bRefetch
);
768 void OKeySet::tryRefetch(const ORowSetRow
& _rInsertRow
,bool bRefetch
)
774 bRefetch
= doTryRefetch_throw();
776 catch(const Exception
&)
783 m_aKeyIter
->second
.second
.second
= new OPrivateRow(*_rInsertRow
);
787 void OKeySet::copyRowValue(const ORowSetRow
& _rInsertRow
, ORowSetRow
const & _rKeyRow
, sal_Int32 i_nBookmark
)
789 connectivity::ORowVector
< ORowSetValue
>::Vector::iterator aIter
= _rKeyRow
->begin();
791 // check the if the parameter values have been changed
792 OSL_ENSURE((m_aParameterValueForCache
->size()-1) == m_pParameterNames
->size(),"OKeySet::copyRowValue: Parameter values and names differ!");
793 connectivity::ORowVector
< ORowSetValue
>::Vector::const_iterator aParaValuesIter
= m_aParameterValueForCache
->begin() +1;
795 bool bChanged
= false;
797 for (auto const& parameterName
: *m_pParameterNames
)
799 ORowSetValue
aValue(*aParaValuesIter
);
800 aValue
.setSigned(m_aSignedFlags
[parameterName
.second
.nPosition
-1]);
801 if ( (*_rInsertRow
)[parameterName
.second
.nPosition
] != aValue
)
803 rtl::Reference
aCopy(
804 new ORowSetValueVector(*m_aParameterValueForCache
));
805 (*aCopy
)[i
] = (*_rInsertRow
)[parameterName
.second
.nPosition
];
806 m_aUpdatedParameter
[i_nBookmark
] = aCopy
;
814 m_aUpdatedParameter
.erase(i_nBookmark
);
817 // update the key values
818 for (auto const& keyColumnName
: *m_pKeyColumnNames
)
820 impl_convertValue_throw(_rInsertRow
,keyColumnName
.second
);
821 *aIter
= (*_rInsertRow
)[keyColumnName
.second
.nPosition
];
822 aIter
->setTypeKind(keyColumnName
.second
.nType
);
827 void OKeySet::deleteRow(const ORowSetRow
& _rDeleteRow
,const connectivity::OSQLTable
& _xTable
)
829 Reference
<XPropertySet
> xSet(_xTable
,UNO_QUERY
);
832 OUStringBuffer
aSql("DELETE FROM " + m_aComposedTableName
+ " WHERE ");
834 // list all columns that should be set
835 OUString aQuote
= getIdentifierQuoteString();
836 static const char aAnd
[] = " AND ";
838 // use keys and indexes for exact positioning
839 Reference
<XIndexesSupplier
> xIndexSup(_xTable
,UNO_QUERY
);
840 Reference
<XIndexAccess
> xIndexes
;
841 if ( xIndexSup
.is() )
842 xIndexes
.set(xIndexSup
->getIndexes(),UNO_QUERY
);
844 // Reference<XColumnsSupplier>
845 std::vector
< Reference
<XNameAccess
> > aAllIndexColumns
;
846 lcl_fillIndexColumns(xIndexes
,aAllIndexColumns
);
848 OUStringBuffer sIndexCondition
;
849 std::vector
<sal_Int32
> aIndexColumnPositions
;
851 for (auto const& columnName
: *m_pColumnNames
)
853 if ( m_pKeyColumnNames
->find(columnName
.first
) != m_pKeyColumnNames
->end() )
855 aSql
.append(::dbtools::quoteName( aQuote
,columnName
.second
.sRealName
));
856 if((*_rDeleteRow
)[columnName
.second
.nPosition
].isNull())
858 SAL_WARN("dbaccess", "can a primary key be null");
859 aSql
.append(" IS NULL");
867 for (auto const& indexColumn
: aAllIndexColumns
)
869 if(indexColumn
->hasByName(columnName
.first
))
871 sIndexCondition
.append(::dbtools::quoteName( aQuote
,columnName
.second
.sRealName
));
872 if((*_rDeleteRow
)[columnName
.second
.nPosition
].isNull())
873 sIndexCondition
.append(" IS NULL");
876 sIndexCondition
.append(" = ?");
877 aIndexColumnPositions
.push_back(columnName
.second
.nPosition
);
879 sIndexCondition
.append(aAnd
);
886 aSql
.append(sIndexCondition
.makeStringAndClear());
887 aSql
.setLength(aSql
.getLength()-5);
889 // now create end execute the prepared statement
890 Reference
< XPreparedStatement
> xPrep(m_xConnection
->prepareStatement(aSql
.makeStringAndClear()));
891 Reference
< XParameters
> xParameter(xPrep
,UNO_QUERY
);
894 for (auto const& keyColumnName
: *m_pKeyColumnNames
)
896 setParameter(i
++,xParameter
,(*_rDeleteRow
)[keyColumnName
.second
.nPosition
],keyColumnName
.second
.nType
,keyColumnName
.second
.nScale
);
899 // now we have to set the index values
900 auto aIter
= m_pColumnNames
->begin();
901 for (auto const& indexColumnPosition
: aIndexColumnPositions
)
903 setParameter(i
++,xParameter
,(*_rDeleteRow
)[indexColumnPosition
],(*_rDeleteRow
)[indexColumnPosition
].getTypeKind(),aIter
->second
.nScale
);
907 m_bDeleted
= xPrep
->executeUpdate() > 0;
911 sal_Int32 nBookmark
= ::comphelper::getINT32((*_rDeleteRow
)[0].getAny());
912 if(m_aKeyIter
== m_aKeyMap
.find(nBookmark
) && m_aKeyIter
!= m_aKeyMap
.end())
914 m_aKeyMap
.erase(nBookmark
);
921 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
926 if(!m_bRowCountFinal
&& m_aKeyIter
== m_aKeyMap
.end())
928 // not yet all records fetched, but we reached the end of those we fetched
929 // try to fetch one more row
932 OSL_ENSURE(!isAfterLast(), "fetchRow succeeded, but isAfterLast()");
937 // nope, we arrived at end of data
938 m_aKeyIter
= m_aKeyMap
.end();
939 OSL_ENSURE(isAfterLast(), "fetchRow failed, but not end of data");
944 return !isAfterLast();
947 bool OKeySet::isBeforeFirst( )
949 return m_aKeyIter
== m_aKeyMap
.begin();
952 bool OKeySet::isAfterLast( )
954 return m_bRowCountFinal
&& m_aKeyIter
== m_aKeyMap
.end();
957 void OKeySet::beforeFirst( )
959 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
960 m_aKeyIter
= m_aKeyMap
.begin();
964 void OKeySet::afterLast( )
966 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
968 m_aKeyIter
= m_aKeyMap
.end();
972 bool OKeySet::first()
974 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
975 m_aKeyIter
= m_aKeyMap
.begin();
977 if(m_aKeyIter
== m_aKeyMap
.end())
981 m_aKeyIter
= m_aKeyMap
.end();
987 return m_aKeyIter
!= m_aKeyMap
.end() && m_aKeyIter
!= m_aKeyMap
.begin();
990 bool OKeySet::last( )
992 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
993 bool bFetchedRow
= fillAllRows();
995 m_aKeyIter
= m_aKeyMap
.end();
1001 return m_aKeyIter
!= m_aKeyMap
.end() && m_aKeyIter
!= m_aKeyMap
.begin();
1004 sal_Int32
OKeySet::getRow( )
1006 OSL_ENSURE(!isAfterLast(),"getRow is not allowed when afterlast record!");
1007 OSL_ENSURE(!isBeforeFirst(),"getRow is not allowed when beforefirst record!");
1009 return std::distance(m_aKeyMap
.begin(),m_aKeyIter
);
1012 bool OKeySet::absolute( sal_Int32 row
)
1014 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
1015 OSL_ENSURE(row
,"absolute(0) isn't allowed!");
1016 bool bFetchedRow
= false;
1019 if(!m_bRowCountFinal
)
1020 bFetchedRow
= fillAllRows();
1022 row
= std::min(std::abs(row
), static_cast<sal_Int32
>(std::distance(m_aKeyMap
.begin(), m_aKeyIter
)));
1023 m_aKeyIter
= std::prev(m_aKeyIter
, row
);
1027 if(row
>= static_cast<sal_Int32
>(m_aKeyMap
.size()))
1029 // we don't have this row
1030 if(!m_bRowCountFinal
)
1032 // but there may still be rows to fetch.
1034 for(sal_Int32 i
=m_aKeyMap
.size()-1;i
< row
&& bNext
;++i
)
1036 // it is guaranteed that the above loop has executed at least once,
1037 // that is fetchRow called at least once.
1044 // reached end of data before desired row
1045 m_aKeyIter
= m_aKeyMap
.end();
1051 // no more rows to fetch -> fail
1052 m_aKeyIter
= m_aKeyMap
.end();
1058 m_aKeyIter
= std::next(m_aKeyMap
.begin(), row
);
1066 return m_aKeyIter
!= m_aKeyMap
.end() && m_aKeyIter
!= m_aKeyMap
.begin();
1069 bool OKeySet::previous()
1071 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
1072 if(m_aKeyIter
!= m_aKeyMap
.begin())
1077 return m_aKeyIter
!= m_aKeyMap
.begin();
1080 bool OKeySet::doTryRefetch_throw()
1083 // we just reassign the base members
1084 Reference
< XParameters
> xParameter(m_xStatement
,UNO_QUERY
);
1085 OSL_ENSURE(xParameter
.is(),"No Parameter interface!");
1086 xParameter
->clearParameters();
1089 connectivity::ORowVector
< ORowSetValue
>::Vector::const_iterator aParaIter
;
1090 connectivity::ORowVector
< ORowSetValue
>::Vector::const_iterator aParaEnd
;
1091 OUpdatedParameter::const_iterator aUpdateFind
= m_aUpdatedParameter
.find(m_aKeyIter
->first
);
1092 if ( aUpdateFind
== m_aUpdatedParameter
.end() )
1094 aParaIter
= m_aParameterValueForCache
->begin();
1095 aParaEnd
= m_aParameterValueForCache
->end();
1099 aParaIter
= aUpdateFind
->second
->begin();
1100 aParaEnd
= aUpdateFind
->second
->end();
1103 for(++aParaIter
;aParaIter
!= aParaEnd
;++aParaIter
,++nPos
)
1105 ::dbtools::setObjectWithInfo( xParameter
, nPos
, aParaIter
->makeAny(), aParaIter
->getTypeKind() );
1108 // now set the primary key column values
1109 connectivity::ORowVector
< ORowSetValue
>::Vector::const_iterator aIter
= m_aKeyIter
->second
.first
->begin();
1110 for (auto const& keyColumnName
: *m_pKeyColumnNames
)
1111 setOneKeyColumnParameter(nPos
,xParameter
,*aIter
++,keyColumnName
.second
.nType
,keyColumnName
.second
.nScale
);
1112 for (auto const& foreignColumnName
: *m_pForeignColumnNames
)
1113 setOneKeyColumnParameter(nPos
,xParameter
,*aIter
++,foreignColumnName
.second
.nType
,foreignColumnName
.second
.nScale
);
1115 m_xSet
= m_xStatement
->executeQuery();
1116 OSL_ENSURE(m_xSet
.is(),"No resultset from statement!");
1117 return m_xSet
->next();
1120 void OKeySet::refreshRow()
1124 if(isBeforeFirst() || isAfterLast())
1127 if ( m_aKeyIter
->second
.second
.second
.is() )
1129 m_xRow
= m_aKeyIter
->second
.second
.second
;
1133 bool bOK
= doTryRefetch_throw();
1136 // This row has disappeared; remove it.
1137 OKeySetMatrix::const_iterator aTemp
= m_aKeyIter
;
1140 m_aKeyMap
.erase(aTemp
);
1142 // adjust RowCount for the row we have removed
1143 if (m_rRowCount
> 0)
1146 SAL_WARN("dbaccess", "m_rRowCount got out of sync: non-empty m_aKeyMap, but m_rRowCount <= 0");
1148 if (m_aKeyIter
== m_aKeyMap
.end())
1150 ::comphelper::disposeComponent(m_xSet
);
1153 // it was the last fetched row,
1154 // but there may be another one to fetch
1157 // nope, that really was the last
1158 m_aKeyIter
= m_aKeyMap
.end();
1159 OSL_ENSURE(isAfterLast(), "fetchRow() failed but not isAfterLast()!");
1162 // Now, either fetchRow has set m_xRow or isAfterLast()
1171 m_xRow
.set(m_xSet
,UNO_QUERY
);
1172 OSL_ENSURE(m_xRow
.is(),"No row from statement!");
1176 bool OKeySet::fetchRow()
1178 // fetch the next row and append on the keyset
1180 if ( !m_bRowCountFinal
&& (!m_nMaxRows
|| sal_Int32(m_aKeyMap
.size()) < m_nMaxRows
) )
1181 bRet
= m_xDriverSet
->next();
1184 ORowSetRow aKeyRow
= new connectivity::ORowVector
< ORowSetValue
>((*m_pKeyColumnNames
).size() + m_pForeignColumnNames
->size());
1186 ::comphelper::disposeComponent(m_xSet
);
1187 m_xRow
.set(m_xDriverRow
, UNO_SET_THROW
);
1189 connectivity::ORowVector
< ORowSetValue
>::Vector::iterator aIter
= aKeyRow
->begin();
1191 for (auto const& keyColumnName
: *m_pKeyColumnNames
)
1193 const SelectColumnDescription
& rColDesc
= keyColumnName
.second
;
1194 aIter
->fill(rColDesc
.nPosition
, rColDesc
.nType
, m_xRow
);
1197 // copy missing columns from other tables
1198 for (auto const& foreignColumnName
: *m_pForeignColumnNames
)
1200 const SelectColumnDescription
& rColDesc
= foreignColumnName
.second
;
1201 aIter
->fill(rColDesc
.nPosition
, rColDesc
.nType
, m_xRow
);
1204 m_aKeyIter
= m_aKeyMap
.emplace( m_aKeyMap
.rbegin()->first
+1,OKeySetValue(aKeyRow
,std::pair
<sal_Int32
,Reference
<XRow
> >(0,Reference
<XRow
>())) ).first
;
1207 m_bRowCountFinal
= true;
1211 bool OKeySet::fillAllRows()
1213 if(m_bRowCountFinal
)
1226 sal_Bool SAL_CALL
OKeySet::wasNull( )
1228 if ( ! m_xRow
.is() )
1229 throwGenericSQLException("Must call getFOO() for some FOO before wasNull()", *this);
1231 OSL_ENSURE(m_xRow
.is(),"m_xRow is null! I've thrown, but function execution continued?");
1232 return m_xRow
->wasNull();
1235 inline void OKeySet::ensureRowForData( )
1240 throwSQLException("Failed to refetch row", "02000", *this, -2);
1242 OSL_ENSURE(m_xRow
.is(),"m_xRow is null! I've called throwSQLException but execution continued?");
1245 OUString SAL_CALL
OKeySet::getString( sal_Int32 columnIndex
)
1248 return m_xRow
->getString(columnIndex
);
1251 sal_Bool SAL_CALL
OKeySet::getBoolean( sal_Int32 columnIndex
)
1254 return m_xRow
->getBoolean(columnIndex
);
1257 sal_Int8 SAL_CALL
OKeySet::getByte( sal_Int32 columnIndex
)
1260 return m_xRow
->getByte(columnIndex
);
1263 sal_Int16 SAL_CALL
OKeySet::getShort( sal_Int32 columnIndex
)
1266 return m_xRow
->getShort(columnIndex
);
1269 sal_Int32 SAL_CALL
OKeySet::getInt( sal_Int32 columnIndex
)
1272 return m_xRow
->getInt(columnIndex
);
1275 sal_Int64 SAL_CALL
OKeySet::getLong( sal_Int32 columnIndex
)
1278 return m_xRow
->getLong(columnIndex
);
1281 float SAL_CALL
OKeySet::getFloat( sal_Int32 columnIndex
)
1284 return m_xRow
->getFloat(columnIndex
);
1287 double SAL_CALL
OKeySet::getDouble( sal_Int32 columnIndex
)
1290 return m_xRow
->getDouble(columnIndex
);
1293 Sequence
< sal_Int8
> SAL_CALL
OKeySet::getBytes( sal_Int32 columnIndex
)
1296 return m_xRow
->getBytes(columnIndex
);
1299 css::util::Date SAL_CALL
OKeySet::getDate( sal_Int32 columnIndex
)
1302 return m_xRow
->getDate(columnIndex
);
1305 css::util::Time SAL_CALL
OKeySet::getTime( sal_Int32 columnIndex
)
1308 return m_xRow
->getTime(columnIndex
);
1311 css::util::DateTime SAL_CALL
OKeySet::getTimestamp( sal_Int32 columnIndex
)
1314 return m_xRow
->getTimestamp(columnIndex
);
1317 Reference
< css::io::XInputStream
> SAL_CALL
OKeySet::getBinaryStream( sal_Int32 columnIndex
)
1320 return m_xRow
->getBinaryStream(columnIndex
);
1323 Reference
< css::io::XInputStream
> SAL_CALL
OKeySet::getCharacterStream( sal_Int32 columnIndex
)
1326 return m_xRow
->getCharacterStream(columnIndex
);
1329 Any SAL_CALL
OKeySet::getObject( sal_Int32 columnIndex
, const Reference
< css::container::XNameAccess
>& typeMap
)
1332 return m_xRow
->getObject(columnIndex
,typeMap
);
1335 Reference
< XRef
> SAL_CALL
OKeySet::getRef( sal_Int32 columnIndex
)
1338 return m_xRow
->getRef(columnIndex
);
1341 Reference
< XBlob
> SAL_CALL
OKeySet::getBlob( sal_Int32 columnIndex
)
1344 return m_xRow
->getBlob(columnIndex
);
1347 Reference
< XClob
> SAL_CALL
OKeySet::getClob( sal_Int32 columnIndex
)
1350 return m_xRow
->getClob(columnIndex
);
1353 Reference
< XArray
> SAL_CALL
OKeySet::getArray( sal_Int32 columnIndex
)
1356 return m_xRow
->getArray(columnIndex
);
1359 bool OKeySet::rowUpdated( )
1361 return m_aKeyIter
!= m_aKeyMap
.begin() && m_aKeyIter
!= m_aKeyMap
.end() && m_aKeyIter
->second
.second
.first
== 2;
1364 bool OKeySet::rowInserted( )
1366 return m_aKeyIter
!= m_aKeyMap
.begin() && m_aKeyIter
!= m_aKeyMap
.end() && m_aKeyIter
->second
.second
.first
== 1;
1369 bool OKeySet::rowDeleted( )
1371 bool bDeleted
= m_bDeleted
;
1379 void getColumnPositions(const Reference
<XNameAccess
>& _rxQueryColumns
,
1380 const css::uno::Sequence
< OUString
>& _aColumnNames
,
1381 const OUString
& _rsUpdateTableName
,
1382 SelectColumnsMetaData
& o_rColumnNames
,
1383 bool i_bAppendTableName
)
1385 // get the real name of the columns
1386 Sequence
< OUString
> aSelNames(_rxQueryColumns
->getElementNames());
1387 const OUString
* pSelIter
= aSelNames
.getConstArray();
1388 const OUString
* pSelEnd
= pSelIter
+ aSelNames
.getLength();
1390 const OUString
* pTblColumnIter
= _aColumnNames
.getConstArray();
1391 const OUString
* pTblColumnEnd
= pTblColumnIter
+ _aColumnNames
.getLength();
1393 ::comphelper::UStringMixEqual
bCase(o_rColumnNames
.key_comp().isCaseSensitive());
1395 for(sal_Int32 nPos
= 1;pSelIter
!= pSelEnd
;++pSelIter
,++nPos
)
1397 Reference
<XPropertySet
> xQueryColumnProp(_rxQueryColumns
->getByName(*pSelIter
),UNO_QUERY_THROW
);
1398 OUString sRealName
,sTableName
;
1399 OSL_ENSURE(xQueryColumnProp
->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME
),"Property REALNAME not available!");
1400 OSL_ENSURE(xQueryColumnProp
->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME
),"Property TABLENAME not available!");
1401 xQueryColumnProp
->getPropertyValue(PROPERTY_REALNAME
) >>= sRealName
;
1402 xQueryColumnProp
->getPropertyValue(PROPERTY_TABLENAME
) >>= sTableName
;
1404 for(;pTblColumnIter
!= pTblColumnEnd
;++pTblColumnIter
)
1406 if(bCase(sRealName
,*pTblColumnIter
) && bCase(_rsUpdateTableName
,sTableName
) && o_rColumnNames
.find(*pTblColumnIter
) == o_rColumnNames
.end())
1408 sal_Int32 nType
= 0;
1409 xQueryColumnProp
->getPropertyValue(PROPERTY_TYPE
) >>= nType
;
1410 sal_Int32 nScale
= 0;
1411 xQueryColumnProp
->getPropertyValue(PROPERTY_SCALE
) >>= nScale
;
1412 OUString sColumnDefault
;
1413 if ( xQueryColumnProp
->getPropertySetInfo()->hasPropertyByName(PROPERTY_DEFAULTVALUE
) )
1414 xQueryColumnProp
->getPropertyValue(PROPERTY_DEFAULTVALUE
) >>= sColumnDefault
;
1416 sal_Int32 nNullable
= ColumnValue::NULLABLE_UNKNOWN
;
1417 OSL_VERIFY( xQueryColumnProp
->getPropertyValue( PROPERTY_ISNULLABLE
) >>= nNullable
);
1419 SelectColumnDescription
aColDesc( nPos
, nType
, nScale
, nNullable
!= sdbc::ColumnValue::NO_NULLS
, sColumnDefault
);
1421 if ( i_bAppendTableName
)
1423 sName
= sTableName
+ "." + sRealName
;
1424 aColDesc
.sRealName
= sRealName
;
1425 aColDesc
.sTableName
= sTableName
;
1431 o_rColumnNames
[sName
] = aColDesc
;
1436 pTblColumnIter
= _aColumnNames
.getConstArray();
1441 void OKeySet::impl_convertValue_throw(const ORowSetRow
& _rInsertRow
,const SelectColumnDescription
& i_aMetaData
)
1443 ORowSetValue
& aValue((*_rInsertRow
)[i_aMetaData
.nPosition
]);
1444 switch(i_aMetaData
.nType
)
1446 case DataType::DECIMAL
:
1447 case DataType::NUMERIC
:
1449 OUString sValue
= aValue
.getString();
1450 sal_Int32 nIndex
= sValue
.indexOf('.');
1453 aValue
= sValue
.copy(0,std::min(sValue
.getLength(),nIndex
+ (i_aMetaData
.nScale
> 0 ? i_aMetaData
.nScale
+ 1 : 0)));
1462 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */