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 <string_view>
24 #include <sal/log.hxx>
25 #include <core_resource.hxx>
26 #include <strings.hrc>
27 #include <strings.hxx>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
30 #include <com/sun/star/sdb/XParametersSupplier.hpp>
31 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
32 #include <com/sun/star/sdbc/ColumnValue.hpp>
33 #include <com/sun/star/sdbc/SQLException.hpp>
34 #include <com/sun/star/sdbc/XPreparedStatement.hpp>
35 #include <com/sun/star/sdbc/XParameters.hpp>
36 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
37 #include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
38 #include <com/sun/star/container/XIndexAccess.hpp>
39 #include <com/sun/star/sdbcx/CompareBookmark.hpp>
40 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
41 #include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
42 #include <comphelper/types.hxx>
43 #include <connectivity/dbtools.hxx>
44 #include <connectivity/dbexception.hxx>
46 #include <com/sun/star/io/XInputStream.hpp>
47 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
48 #include <composertools.hxx>
50 #include "PrivateRow.hxx"
52 using namespace dbaccess
;
53 using namespace ::connectivity
;
54 using namespace ::dbtools
;
55 using namespace ::com::sun::star::uno
;
56 using namespace ::com::sun::star::beans
;
57 using namespace ::com::sun::star::sdbc
;
58 using namespace ::com::sun::star::sdb
;
59 using namespace ::com::sun::star::sdbcx
;
60 using namespace ::com::sun::star::container
;
61 using namespace ::com::sun::star::lang
;
62 using namespace ::com::sun::star::util
;
63 using namespace ::com::sun::star::io
;
64 using namespace ::com::sun::star
;
65 using namespace ::cppu
;
70 void lcl_fillIndexColumns(const Reference
<XIndexAccess
>& _xIndexes
, std::vector
< Reference
<XNameAccess
> >& _rAllIndexColumns
)
72 if ( !_xIndexes
.is() )
75 Reference
<XPropertySet
> xIndexColsSup
;
76 sal_Int32 nCount
= _xIndexes
->getCount();
77 for(sal_Int32 j
= 0 ; j
< nCount
; ++j
)
79 xIndexColsSup
.set(_xIndexes
->getByIndex(j
),UNO_QUERY
);
80 if( xIndexColsSup
.is()
81 && comphelper::getBOOL(xIndexColsSup
->getPropertyValue(PROPERTY_ISUNIQUE
))
82 && !comphelper::getBOOL(xIndexColsSup
->getPropertyValue(PROPERTY_ISPRIMARYKEYINDEX
))
84 _rAllIndexColumns
.push_back(Reference
<XColumnsSupplier
>(xIndexColsSup
,UNO_QUERY_THROW
)->getColumns());
88 template < typename T
> void tryDispose( Reference
<T
> &r
)
92 ::comphelper::disposeComponent(r
);
94 catch(const Exception
&)
100 SAL_WARN("dbaccess", "Unknown Exception occurred");
106 OKeySet::OKeySet(connectivity::OSQLTable _xTable
,
107 OUString _sUpdateTableName
, // this can be the alias or the full qualified name
108 const Reference
< XSingleSelectQueryAnalyzer
>& _xComposer
,
109 const ORowSetValueVector
& _aParameterValueForCache
,
110 sal_Int32 i_nMaxRows
,
111 sal_Int32
& o_nRowCount
)
112 :OCacheSet(i_nMaxRows
)
113 ,m_aParameterValueForCache(new ORowSetValueVector(_aParameterValueForCache
))
114 ,m_xTable(std::move(_xTable
))
115 ,m_xComposer(_xComposer
)
116 ,m_sUpdateTableName(std::move(_sUpdateTableName
))
117 ,m_rRowCount(o_nRowCount
)
118 ,m_bRowCountFinal(false)
125 // m_xStatement is necessarily one of those
126 for (auto & statement
: m_vStatements
)
128 tryDispose(statement
.second
);
131 m_xComposer
= nullptr;
135 void OKeySet::initColumns()
137 Reference
<XDatabaseMetaData
> xMeta
= m_xConnection
->getMetaData();
138 bool bCase
= xMeta
.is() && xMeta
->supportsMixedCaseQuotedIdentifiers();
139 m_pKeyColumnNames
.reset( new SelectColumnsMetaData(comphelper::UStringMixLess(bCase
)) );
140 m_pColumnNames
.reset( new SelectColumnsMetaData(comphelper::UStringMixLess(bCase
)) );
141 m_pParameterNames
.reset( new SelectColumnsMetaData(comphelper::UStringMixLess(bCase
)) );
142 m_pForeignColumnNames
.reset( new SelectColumnsMetaData(comphelper::UStringMixLess(bCase
)) );
145 void OKeySet::findTableColumnsMatching_throw( const Any
& i_aTable
,
146 const OUString
& i_rUpdateTableName
,
147 const Reference
<XDatabaseMetaData
>& i_xMeta
,
148 const Reference
<XNameAccess
>& i_xQueryColumns
,
149 std::unique_ptr
<SelectColumnsMetaData
> const & o_pKeyColumnNames
)
151 // first ask the database itself for the best columns which can be used
152 Sequence
< OUString
> aBestColumnNames
;
153 Reference
<XNameAccess
> xKeyColumns
= getPrimaryKeyColumns_throw(i_aTable
);
154 if ( xKeyColumns
.is() )
155 aBestColumnNames
= xKeyColumns
->getElementNames();
157 const Reference
<XColumnsSupplier
> xTblColSup(i_aTable
,UNO_QUERY_THROW
);
158 const Reference
<XNameAccess
> xTblColumns
= xTblColSup
->getColumns();
159 // locate parameter in select columns
160 Reference
<XParametersSupplier
> xParaSup(m_xComposer
,UNO_QUERY
);
161 Reference
<XIndexAccess
> xQueryParameters
= xParaSup
->getParameters();
162 const sal_Int32 nParaCount
= xQueryParameters
->getCount();
163 Sequence
< OUString
> aParameterColumns(nParaCount
);
164 auto aParameterColumnsRange
= asNonConstRange(aParameterColumns
);
165 for(sal_Int32 i
= 0; i
< nParaCount
;++i
)
167 Reference
<XPropertySet
> xPara(xQueryParameters
->getByIndex(i
),UNO_QUERY_THROW
);
168 xPara
->getPropertyValue(PROPERTY_REALNAME
) >>= aParameterColumnsRange
[i
];
171 OUString
sUpdateTableName( i_rUpdateTableName
);
172 if ( sUpdateTableName
.isEmpty() )
174 SAL_WARN("dbaccess", "OKeySet::findTableColumnsMatching_throw: This is a fallback only - it won't work when the table has an alias name." );
175 // If i_aTable originates from a query composer, and is a table which appears with an alias in the SELECT statement,
176 // then the below code will not produce correct results.
177 // For instance, imagine a "SELECT alias.col FROM table AS alias". Now i_aTable would be the table named
178 // "table", so our sUpdateTableName would be "table" as well - not the information about the "alias" is
179 // already lost here.
180 // now getColumnPositions would traverse the columns, and check which of them belong to the table denoted
181 // by sUpdateTableName. Since the latter is "table", but the columns only know that they belong to a table
182 // named "alias", there will be no matching - so getColumnPositions wouldn't find anything.
184 OUString sCatalog
, sSchema
, sTable
;
185 Reference
<XPropertySet
> xTableProp( i_aTable
, UNO_QUERY_THROW
);
186 xTableProp
->getPropertyValue( PROPERTY_CATALOGNAME
)>>= sCatalog
;
187 xTableProp
->getPropertyValue( PROPERTY_SCHEMANAME
) >>= sSchema
;
188 xTableProp
->getPropertyValue( PROPERTY_NAME
) >>= sTable
;
189 sUpdateTableName
= dbtools::composeTableName( i_xMeta
, sCatalog
, sSchema
, sTable
, false, ::dbtools::EComposeRule::InDataManipulation
);
192 ::dbaccess::getColumnPositions(i_xQueryColumns
,aBestColumnNames
,sUpdateTableName
,(*o_pKeyColumnNames
),true);
193 ::dbaccess::getColumnPositions(i_xQueryColumns
,xTblColumns
->getElementNames(),sUpdateTableName
,(*m_pColumnNames
),true);
194 ::dbaccess::getColumnPositions(i_xQueryColumns
,aParameterColumns
,sUpdateTableName
,(*m_pParameterNames
),true);
196 if ( o_pKeyColumnNames
->empty() )
198 ::dbtools::throwGenericSQLException(u
"Could not find any key column."_ustr
, *this );
201 for (auto const& keyColumn
: *o_pKeyColumnNames
)
203 if ( !xTblColumns
->hasByName( keyColumn
.second
.sRealName
) )
206 Reference
<XPropertySet
> xProp( xTblColumns
->getByName( keyColumn
.second
.sRealName
), UNO_QUERY
);
208 if ( ( xProp
->getPropertyValue( PROPERTY_ISAUTOINCREMENT
) >>= bAuto
) && bAuto
)
209 m_aAutoColumns
.push_back( keyColumn
.first
);
215 void appendOneKeyColumnClause( std::u16string_view tblName
, const OUString
&colName
, const connectivity::ORowSetValue
&_rValue
, OUStringBuffer
&o_buf
)
221 fullName
= OUString::Concat(tblName
) + "." + colName
;
222 if ( _rValue
.isNull() )
224 o_buf
.append(fullName
+ " IS NULL ");
228 o_buf
.append(fullName
+ " = ? ");
233 void OKeySet::setOneKeyColumnParameter( sal_Int32
&nPos
, const Reference
< XParameters
> &_xParameter
, const connectivity::ORowSetValue
&_rValue
, sal_Int32 _nType
, sal_Int32 _nScale
)
235 if ( _rValue
.isNull() )
237 // Nothing to do, appendOneKeyColumnClause took care of it,
238 // the "IS NULL" is hardcoded in the query
242 setParameter( nPos
++, _xParameter
, _rValue
, _nType
, _nScale
);
246 OUStringBuffer
OKeySet::createKeyFilter()
248 connectivity::ORowVector
< ORowSetValue
>::Vector::const_iterator aIter
= m_aKeyIter
->second
.m_aRowSetRow
->begin();
250 static const char aAnd
[] = " AND ";
251 const OUString aQuote
= getIdentifierQuoteString();
252 OUStringBuffer aFilter
;
253 // create the where clause
254 Reference
<XDatabaseMetaData
> xMeta
= m_xConnection
->getMetaData();
255 for (auto const& keyColumnName
: *m_pKeyColumnNames
)
257 if ( ! aFilter
.isEmpty() )
258 aFilter
.append(aAnd
);
259 appendOneKeyColumnClause(::dbtools::quoteTableName(xMeta
, keyColumnName
.second
.sTableName
, ::dbtools::EComposeRule::InDataManipulation
),
260 ::dbtools::quoteName(aQuote
, keyColumnName
.second
.sRealName
),
264 for (auto const& foreignColumnName
: * m_pForeignColumnNames
)
266 if ( ! aFilter
.isEmpty() )
267 aFilter
.append(aAnd
);
268 appendOneKeyColumnClause(::dbtools::quoteTableName(xMeta
, foreignColumnName
.second
.sTableName
, ::dbtools::EComposeRule::InDataManipulation
),
269 ::dbtools::quoteName(aQuote
, foreignColumnName
.second
.sRealName
),
276 void OKeySet::construct(const Reference
< XResultSet
>& _xDriverSet
, const OUString
& i_sRowSetFilter
)
278 OCacheSet::construct(_xDriverSet
,i_sRowSetFilter
);
282 Reference
<XDatabaseMetaData
> xMeta
= m_xConnection
->getMetaData();
283 Reference
<XColumnsSupplier
> xQueryColSup(m_xComposer
, UNO_QUERY
);
284 const Reference
<XNameAccess
> xQueryColumns
= xQueryColSup
->getColumns();
285 findTableColumnsMatching_throw( Any(m_xTable
), m_sUpdateTableName
, xMeta
, xQueryColumns
, m_pKeyColumnNames
);
287 Reference
< XSingleSelectQueryComposer
> xSourceComposer(m_xComposer
,UNO_QUERY
);
288 Reference
< XMultiServiceFactory
> xFactory(m_xConnection
, UNO_QUERY_THROW
);
289 Reference
<XSingleSelectQueryComposer
> xAnalyzer(xFactory
->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
),UNO_QUERY
);
290 xAnalyzer
->setElementaryQuery(xSourceComposer
->getElementaryQuery());
291 Reference
<XTablesSupplier
> xTabSup(xAnalyzer
,uno::UNO_QUERY
);
292 Reference
<XNameAccess
> xSelectTables
= xTabSup
->getTables();
293 const Sequence
< OUString
> aSeq
= xSelectTables
->getElementNames();
294 if ( aSeq
.getLength() > 1 ) // special handling for join
296 for (auto& name
: aSeq
)
298 if (name
!= m_sUpdateTableName
)
300 connectivity::OSQLTable
xSelColSup(xSelectTables
->getByName(name
), uno::UNO_QUERY
);
301 Reference
<XPropertySet
> xProp(xSelColSup
,uno::UNO_QUERY
);
302 OUString sSelectTableName
= ::dbtools::composeTableName( xMeta
, xProp
, ::dbtools::EComposeRule::InDataManipulation
, false );
304 ::dbaccess::getColumnPositions(xQueryColumns
, xSelColSup
->getColumns()->getElementNames(), sSelectTableName
, (*m_pForeignColumnNames
), true);
306 // LEM: there used to be a break here; however, I see no reason to stop
307 // at first non-updateTable, so I removed it. (think of multiple joins...)
312 // the first row is empty because it's now easier for us to distinguish when we are beforefirst or first
313 // without extra variable to be set
314 OKeySetValue keySetValue
{nullptr,0,nullptr};
315 m_aKeyMap
.emplace(0, keySetValue
);
316 m_aKeyIter
= m_aKeyMap
.begin();
319 void OKeySet::reset(const Reference
< XResultSet
>& _xDriverSet
)
321 OCacheSet::construct(_xDriverSet
, m_sRowSetFilter
);
322 m_bRowCountFinal
= false;
324 OKeySetValue keySetValue
{nullptr,0,nullptr};
325 m_aKeyMap
.emplace(0,keySetValue
);
326 m_aKeyIter
= m_aKeyMap
.begin();
329 void OKeySet::ensureStatement( )
331 // do we already have a statement for the current combination of NULLness
332 // of key & foreign columns?
333 std::vector
<bool> FilterColumnsNULL
;
334 FilterColumnsNULL
.reserve(m_aKeyIter
->second
.m_aRowSetRow
->size());
335 for (auto const& elem
: *m_aKeyIter
->second
.m_aRowSetRow
)
336 FilterColumnsNULL
.push_back(elem
.isNull());
337 vStatements_t::const_iterator
pNewStatement(m_vStatements
.find(FilterColumnsNULL
));
338 if(pNewStatement
== m_vStatements
.end())
340 // no: make a new one
342 std::pair
< vStatements_t::const_iterator
, bool > insert_result
343 (m_vStatements
.emplace( FilterColumnsNULL
, m_xStatement
));
344 (void) insert_result
; // WaE: unused variable
345 assert(insert_result
.second
);
349 m_xStatement
= pNewStatement
->second
;
352 void OKeySet::makeNewStatement()
354 Reference
< XSingleSelectQueryComposer
> xSourceComposer(m_xComposer
,UNO_QUERY
);
355 Reference
< XMultiServiceFactory
> xFactory(m_xConnection
, UNO_QUERY_THROW
);
356 Reference
<XSingleSelectQueryComposer
> xAnalyzer(xFactory
->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
),UNO_QUERY
);
357 xAnalyzer
->setElementaryQuery(xSourceComposer
->getElementaryQuery());
359 OUStringBuffer
aFilter(createKeyFilter());
360 executeStatement(aFilter
, xAnalyzer
);
363 void OKeySet::executeStatement(OUStringBuffer
& io_aFilter
, Reference
<XSingleSelectQueryComposer
>& io_xAnalyzer
)
365 bool bFilterSet
= !m_sRowSetFilter
.isEmpty();
368 FilterCreator aFilterCreator
;
369 aFilterCreator
.append( m_sRowSetFilter
);
370 aFilterCreator
.append( io_aFilter
.makeStringAndClear() );
371 io_aFilter
= aFilterCreator
.getComposedAndClear();
373 io_xAnalyzer
->setFilter(io_aFilter
.makeStringAndClear());
376 for (auto& rOr
: io_xAnalyzer
->getStructuredFilter())
378 for (auto& rAnd
: rOr
)
381 if (!(rAnd
.Value
>>= sValue
) || !(sValue
== "?" || sValue
.startsWith(":")))
382 { // we have a criteria which has to be taken into account for updates
383 m_aFilterColumns
.push_back(rAnd
.Name
);
388 m_xStatement
= m_xConnection
->prepareStatement(io_xAnalyzer
->getQueryWithSubstitution());
389 ::comphelper::disposeComponent(io_xAnalyzer
);
392 void OKeySet::invalidateRow()
395 ::comphelper::disposeComponent(m_xSet
);
398 Any
OKeySet::getBookmark()
400 OSL_ENSURE(m_aKeyIter
!= m_aKeyMap
.end() && m_aKeyIter
!= m_aKeyMap
.begin(),
401 "getBookmark is only possible when we stand on a valid row!");
402 return Any(m_aKeyIter
->first
);
405 bool OKeySet::moveToBookmark( const Any
& bookmark
)
407 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
408 m_aKeyIter
= m_aKeyMap
.find(::comphelper::getINT32(bookmark
));
410 return m_aKeyIter
!= m_aKeyMap
.end();
413 sal_Int32
OKeySet::compareBookmarks( const Any
& _first
, const Any
& _second
)
415 sal_Int32 nFirst
= 0, nSecond
= 0;
419 return (nFirst
!= nSecond
) ? CompareBookmark::NOT_EQUAL
: CompareBookmark::EQUAL
;
422 bool OKeySet::hasOrderedBookmarks( )
427 sal_Int32
OKeySet::hashBookmark( const Any
& bookmark
)
429 return ::comphelper::getINT32(bookmark
);
433 void OKeySet::updateRow(const ORowSetRow
& _rInsertRow
,const ORowSetRow
& _rOriginalRow
,const connectivity::OSQLTable
& _xTable
)
435 Reference
<XPropertySet
> xSet(_xTable
,UNO_QUERY
);
438 OUStringBuffer aSql
= "UPDATE " + m_aComposedTableName
+ " SET ";
439 // list all columns that should be set
440 static constexpr OUStringLiteral
aPara(u
" = ?,");
441 OUString aQuote
= getIdentifierQuoteString();
442 static constexpr OUString
aAnd(u
" AND "_ustr
);
443 OUString
sIsNull(u
" IS NULL"_ustr
);
444 OUString
sParam(u
" = ?"_ustr
);
446 // use keys and indexes for exact positioning
447 Reference
<XIndexesSupplier
> xIndexSup(_xTable
,UNO_QUERY
);
448 Reference
<XIndexAccess
> xIndexes
;
449 if ( xIndexSup
.is() )
450 xIndexes
.set(xIndexSup
->getIndexes(),UNO_QUERY
);
452 std::vector
< Reference
<XNameAccess
> > aAllIndexColumns
;
453 lcl_fillIndexColumns(xIndexes
,aAllIndexColumns
);
455 OUStringBuffer sKeyCondition
,sIndexCondition
;
456 std::vector
<sal_Int32
> aIndexColumnPositions
;
458 const sal_Int32 nOldLength
= aSql
.getLength();
459 // here we build the condition part for the update statement
460 for (auto const& columnName
: *m_pColumnNames
)
462 if ( m_pKeyColumnNames
->find(columnName
.first
) != m_pKeyColumnNames
->end() )
464 sKeyCondition
.append(::dbtools::quoteName( aQuote
,columnName
.second
.sRealName
));
465 if((*_rOriginalRow
)[columnName
.second
.nPosition
].isNull())
466 sKeyCondition
.append(sIsNull
);
468 sKeyCondition
.append(sParam
);
469 sKeyCondition
.append(aAnd
);
473 for (auto const& indexColumn
: aAllIndexColumns
)
475 if(indexColumn
->hasByName(columnName
.first
))
477 sIndexCondition
.append(::dbtools::quoteName( aQuote
,columnName
.second
.sRealName
));
478 if((*_rOriginalRow
)[columnName
.second
.nPosition
].isNull())
479 sIndexCondition
.append(sIsNull
);
482 sIndexCondition
.append(sParam
);
483 aIndexColumnPositions
.push_back(columnName
.second
.nPosition
);
485 sIndexCondition
.append(aAnd
);
490 if((*_rInsertRow
)[columnName
.second
.nPosition
].isModified())
492 aSql
.append(::dbtools::quoteName( aQuote
,columnName
.second
.sRealName
) + aPara
);
496 if( aSql
.getLength() != nOldLength
)
498 aSql
.setLength(aSql
.getLength()-1);
501 ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_VALUE_CHANGED
), StandardSQLState::GENERAL_ERROR
, m_xConnection
);
503 if(!sKeyCondition
.isEmpty() || !sIndexCondition
.isEmpty())
505 aSql
.append(" WHERE ");
506 if(!sKeyCondition
.isEmpty() && !sIndexCondition
.isEmpty())
508 aSql
.append(sKeyCondition
+ sIndexCondition
);
510 else if(!sKeyCondition
.isEmpty())
512 aSql
.append(sKeyCondition
);
514 else if(!sIndexCondition
.isEmpty())
516 aSql
.append(sIndexCondition
);
518 aSql
.setLength(aSql
.getLength()-5); // remove the last AND
521 ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_CONDITION_FOR_PK
), StandardSQLState::GENERAL_ERROR
, m_xConnection
);
523 // now create end execute the prepared statement
524 executeUpdate(_rInsertRow
,_rOriginalRow
,aSql
.makeStringAndClear(),u
"",aIndexColumnPositions
);
527 void OKeySet::executeUpdate(const ORowSetRow
& _rInsertRow
,const ORowSetRow
& _rOriginalRow
,const OUString
& i_sSQL
,std::u16string_view i_sTableName
,const std::vector
<sal_Int32
>& _aIndexColumnPositions
)
529 // now create end execute the prepared statement
530 Reference
< XPreparedStatement
> xPrep(m_xConnection
->prepareStatement(i_sSQL
));
531 Reference
< XParameters
> xParameter(xPrep
,UNO_QUERY
);
533 bool bRefetch
= true;
535 // first the set values
536 for (auto const& columnName
: *m_pColumnNames
)
538 if ( i_sTableName
.empty() || columnName
.second
.sTableName
== i_sTableName
)
540 sal_Int32 nPos
= columnName
.second
.nPosition
;
541 if((*_rInsertRow
)[nPos
].isModified())
545 bRefetch
= std::find(m_aFilterColumns
.begin(),m_aFilterColumns
.end(),columnName
.second
.sRealName
) == m_aFilterColumns
.end();
547 impl_convertValue_throw(_rInsertRow
,columnName
.second
);
548 (*_rInsertRow
)[nPos
].setSigned((*_rOriginalRow
)[nPos
].isSigned());
549 setParameter(i
++,xParameter
,(*_rInsertRow
)[nPos
],columnName
.second
.nType
,columnName
.second
.nScale
);
553 // and then the values of the where condition
554 for (auto const& keyColumnName
: *m_pKeyColumnNames
)
556 if ( i_sTableName
.empty() || keyColumnName
.second
.sTableName
== i_sTableName
)
558 setParameter(i
++,xParameter
,(*_rOriginalRow
)[keyColumnName
.second
.nPosition
],keyColumnName
.second
.nType
,keyColumnName
.second
.nScale
);
561 if ( !_aIndexColumnPositions
.empty() )
563 // now we have to set the index values
564 auto aIter
= m_pColumnNames
->begin();
565 for (auto const& indexColumnPosition
: _aIndexColumnPositions
)
567 setParameter(i
++,xParameter
,(*_rOriginalRow
)[indexColumnPosition
],(*_rOriginalRow
)[indexColumnPosition
].getTypeKind(),aIter
->second
.nScale
);
571 const sal_Int32 nRowsUpdated
= xPrep
->executeUpdate();
572 m_bUpdated
= nRowsUpdated
> 0;
575 const sal_Int32 nBookmark
= ::comphelper::getINT32((*_rInsertRow
)[0].getAny());
576 m_aKeyIter
= m_aKeyMap
.find(nBookmark
);
577 assert(m_aKeyIter
!= m_aKeyMap
.end());
578 m_aKeyIter
->second
.m_nUpdateInsert
= 2;
579 m_aKeyIter
->second
.m_xRow
.clear();
580 copyRowValue(_rInsertRow
, m_aKeyIter
->second
.m_aRowSetRow
, nBookmark
);
581 tryRefetch(_rInsertRow
,bRefetch
);
585 void OKeySet::insertRow( const ORowSetRow
& _rInsertRow
,const connectivity::OSQLTable
& _xTable
)
587 Reference
<XPropertySet
> xSet(_xTable
,UNO_QUERY
);
590 OUStringBuffer
aSql( "INSERT INTO " + m_aComposedTableName
+ " ( ");
592 // set values and column names
593 OUStringBuffer
aValues(" VALUES ( ");
594 OUString aQuote
= getIdentifierQuoteString();
596 bool bRefetch
= true;
597 bool bModified
= false;
598 for (auto const& columnName
: *m_pColumnNames
)
600 if((*_rInsertRow
)[columnName
.second
.nPosition
].isModified())
604 bRefetch
= std::find(m_aFilterColumns
.begin(),m_aFilterColumns
.end(),columnName
.second
.sRealName
) == m_aFilterColumns
.end();
606 aSql
.append(::dbtools::quoteName( aQuote
,columnName
.second
.sRealName
) + ",");
607 aValues
.append("?,");
612 ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_VALUE_CHANGED
), StandardSQLState::GENERAL_ERROR
, m_xConnection
);
614 aSql
[aSql
.getLength() - 1] = ')';
615 aValues
[aValues
.getLength() - 1] = ')';
616 aSql
.append(aValues
);
617 // now create,fill and execute the prepared statement
618 executeInsert(_rInsertRow
,aSql
.makeStringAndClear(),u
"",bRefetch
);
621 void OKeySet::executeInsert( const ORowSetRow
& _rInsertRow
,const OUString
& i_sSQL
,std::u16string_view i_sTableName
,bool bRefetch
)
623 // now create,fill and execute the prepared statement
624 Reference
< XPreparedStatement
> xPrep(m_xConnection
->prepareStatement(i_sSQL
));
625 Reference
< XParameters
> xParameter(xPrep
,UNO_QUERY
);
628 for (auto const& columnName
: *m_pColumnNames
)
630 if ( i_sTableName
.empty() || columnName
.second
.sTableName
== i_sTableName
)
632 const sal_Int32 nPos
= columnName
.second
.nPosition
;
633 if((*_rInsertRow
)[nPos
].isModified())
635 if((*_rInsertRow
)[nPos
].isNull())
636 xParameter
->setNull(i
++,(*_rInsertRow
)[nPos
].getTypeKind());
639 impl_convertValue_throw(_rInsertRow
,columnName
.second
);
640 (*_rInsertRow
)[nPos
].setSigned(m_aSignedFlags
[nPos
-1]);
641 setParameter(i
++,xParameter
,(*_rInsertRow
)[nPos
],columnName
.second
.nType
,columnName
.second
.nScale
);
647 m_bInserted
= xPrep
->executeUpdate() > 0;
648 bool bAutoValuesFetched
= false;
651 // first insert the default values into the insertrow
652 for (auto const& columnName
: *m_pColumnNames
)
654 if ( !(*_rInsertRow
)[columnName
.second
.nPosition
].isModified() )
656 if(columnName
.second
.bNullable
&& columnName
.second
.sDefaultValue
.isEmpty())
658 (*_rInsertRow
)[columnName
.second
.nPosition
].setTypeKind(columnName
.second
.nType
);
659 (*_rInsertRow
)[columnName
.second
.nPosition
].setNull();
663 (*_rInsertRow
)[columnName
.second
.nPosition
] = columnName
.second
.sDefaultValue
;
664 (*_rInsertRow
)[columnName
.second
.nPosition
].setTypeKind(columnName
.second
.nType
);
670 Reference
< XGeneratedResultSet
> xGRes(xPrep
, UNO_QUERY
);
673 Reference
< XResultSet
> xRes
= xGRes
->getGeneratedValues();
674 Reference
< XRow
> xRow(xRes
,UNO_QUERY
);
675 if ( xRow
.is() && xRes
->next() )
677 Reference
< XResultSetMetaDataSupplier
> xMdSup(xRes
,UNO_QUERY
);
678 Reference
< XResultSetMetaData
> xMd
= xMdSup
->getMetaData();
679 sal_Int32 nColumnCount
= xMd
->getColumnCount();
680 std::vector
< OUString
>::const_iterator aAutoIter
= m_aAutoColumns
.begin();
681 std::vector
< OUString
>::const_iterator aAutoEnd
= m_aAutoColumns
.end();
682 for (sal_Int32 j
= 1;aAutoIter
!= aAutoEnd
&& j
<= nColumnCount
; ++aAutoIter
,++j
)
684 SelectColumnsMetaData::const_iterator aFind
= m_pKeyColumnNames
->find(*aAutoIter
);
685 if ( aFind
!= m_pKeyColumnNames
->end() )
686 (*_rInsertRow
)[aFind
->second
.nPosition
].fill(j
, aFind
->second
.nType
, xRow
);
688 bAutoValuesFetched
= true;
692 catch(const Exception
&)
694 SAL_WARN("dbaccess", "Could not execute GeneratedKeys() stmt");
698 ::comphelper::disposeComponent(xPrep
);
700 if ( i_sTableName
.empty() && !bAutoValuesFetched
&& m_bInserted
)
702 // first check if all key column values were set
703 const OUString sQuote
= getIdentifierQuoteString();
704 OUStringBuffer sMaxStmt
;
705 auto aEnd
= m_pKeyColumnNames
->end();
706 for (auto const& autoColumn
: m_aAutoColumns
)
708 // we will only fetch values which are keycolumns
709 SelectColumnsMetaData::const_iterator aFind
= m_pKeyColumnNames
->find(autoColumn
);
712 sMaxStmt
.append(" MAX(" + ::dbtools::quoteName( sQuote
,aFind
->second
.sRealName
) + "),");
716 if(!sMaxStmt
.isEmpty())
718 sMaxStmt
[sMaxStmt
.getLength()-1] = ' ';
719 OUString sStmt
= "SELECT " + sMaxStmt
+ "FROM ";
720 OUString sCatalog
,sSchema
,sTable
;
721 ::dbtools::qualifiedNameComponents(m_xConnection
->getMetaData(),m_sUpdateTableName
,sCatalog
,sSchema
,sTable
,::dbtools::EComposeRule::InDataManipulation
);
722 sStmt
+= ::dbtools::composeTableNameForSelect( m_xConnection
, sCatalog
, sSchema
, sTable
);
725 // now fetch the autoincrement values
726 Reference
<XStatement
> xStatement
= m_xConnection
->createStatement();
727 Reference
<XResultSet
> xRes
= xStatement
->executeQuery(sStmt
);
728 Reference
<XRow
> xRow(xRes
,UNO_QUERY
);
729 if(xRow
.is() && xRes
->next())
732 for (auto const& autoColumn
: m_aAutoColumns
)
734 // we will only fetch values which are keycolumns
735 SelectColumnsMetaData::const_iterator aFind
= m_pKeyColumnNames
->find(autoColumn
);
737 (*_rInsertRow
)[aFind
->second
.nPosition
].fill(j
++, aFind
->second
.nType
, xRow
);
740 ::comphelper::disposeComponent(xStatement
);
744 SAL_WARN("dbaccess", "Could not fetch with MAX() ");
750 OKeySetMatrix::const_iterator aKeyIter
= m_aKeyMap
.end();
752 ORowSetRow aKeyRow
= new connectivity::ORowVector
< ORowSetValue
>(m_pKeyColumnNames
->size());
753 copyRowValue(_rInsertRow
,aKeyRow
,aKeyIter
->first
+ 1);
755 m_aKeyIter
= m_aKeyMap
.emplace( aKeyIter
->first
+ 1, OKeySetValue
{aKeyRow
,1,nullptr} ).first
;
756 // now we set the bookmark for this row
757 (*_rInsertRow
)[0] = Any(static_cast<sal_Int32
>(m_aKeyIter
->first
));
758 tryRefetch(_rInsertRow
,bRefetch
);
762 void OKeySet::tryRefetch(const ORowSetRow
& _rInsertRow
,bool bRefetch
)
768 bRefetch
= doTryRefetch_throw();
770 catch(const Exception
&)
777 m_aKeyIter
->second
.m_xRow
= new OPrivateRow(std::vector(*_rInsertRow
));
781 void OKeySet::copyRowValue(const ORowSetRow
& _rInsertRow
, ORowSetRow
const & _rKeyRow
, sal_Int32 i_nBookmark
)
783 connectivity::ORowVector
< ORowSetValue
>::Vector::iterator aIter
= _rKeyRow
->begin();
785 // check the if the parameter values have been changed
786 OSL_ENSURE((m_aParameterValueForCache
->size()-1) == m_pParameterNames
->size(),"OKeySet::copyRowValue: Parameter values and names differ!");
787 connectivity::ORowVector
< ORowSetValue
>::Vector::const_iterator aParaValuesIter
= m_aParameterValueForCache
->begin() +1;
789 bool bChanged
= false;
791 for (auto const& parameterName
: *m_pParameterNames
)
793 ORowSetValue
aValue(*aParaValuesIter
);
794 aValue
.setSigned(m_aSignedFlags
[parameterName
.second
.nPosition
-1]);
795 if ( (*_rInsertRow
)[parameterName
.second
.nPosition
] != aValue
)
797 rtl::Reference
aCopy(
798 new ORowSetValueVector(*m_aParameterValueForCache
));
799 (*aCopy
)[i
] = (*_rInsertRow
)[parameterName
.second
.nPosition
];
800 m_aUpdatedParameter
[i_nBookmark
] = std::move(aCopy
);
808 m_aUpdatedParameter
.erase(i_nBookmark
);
811 // update the key values
812 for (auto const& keyColumnName
: *m_pKeyColumnNames
)
814 impl_convertValue_throw(_rInsertRow
,keyColumnName
.second
);
815 *aIter
= (*_rInsertRow
)[keyColumnName
.second
.nPosition
];
816 aIter
->setTypeKind(keyColumnName
.second
.nType
);
821 void OKeySet::deleteRow(const ORowSetRow
& _rDeleteRow
,const connectivity::OSQLTable
& _xTable
)
823 Reference
<XPropertySet
> xSet(_xTable
,UNO_QUERY
);
826 OUStringBuffer
aSql("DELETE FROM " + m_aComposedTableName
+ " WHERE ");
828 // list all columns that should be set
829 OUString aQuote
= getIdentifierQuoteString();
830 static const char aAnd
[] = " AND ";
832 // use keys and indexes for exact positioning
833 Reference
<XIndexesSupplier
> xIndexSup(_xTable
,UNO_QUERY
);
834 Reference
<XIndexAccess
> xIndexes
;
835 if ( xIndexSup
.is() )
836 xIndexes
.set(xIndexSup
->getIndexes(),UNO_QUERY
);
838 // Reference<XColumnsSupplier>
839 std::vector
< Reference
<XNameAccess
> > aAllIndexColumns
;
840 lcl_fillIndexColumns(xIndexes
,aAllIndexColumns
);
842 OUStringBuffer sIndexCondition
;
843 std::vector
<sal_Int32
> aIndexColumnPositions
;
845 for (auto const& columnName
: *m_pColumnNames
)
847 if ( m_pKeyColumnNames
->find(columnName
.first
) != m_pKeyColumnNames
->end() )
849 aSql
.append(::dbtools::quoteName( aQuote
,columnName
.second
.sRealName
));
850 if((*_rDeleteRow
)[columnName
.second
.nPosition
].isNull())
852 SAL_WARN("dbaccess", "can a primary key be null");
853 aSql
.append(" IS NULL");
861 for (auto const& indexColumn
: aAllIndexColumns
)
863 if(indexColumn
->hasByName(columnName
.first
))
865 sIndexCondition
.append(::dbtools::quoteName( aQuote
,columnName
.second
.sRealName
));
866 if((*_rDeleteRow
)[columnName
.second
.nPosition
].isNull())
867 sIndexCondition
.append(" IS NULL");
870 sIndexCondition
.append(" = ?");
871 aIndexColumnPositions
.push_back(columnName
.second
.nPosition
);
873 sIndexCondition
.append(aAnd
);
880 aSql
.append(sIndexCondition
);
881 aSql
.setLength(aSql
.getLength()-5);
883 // now create end execute the prepared statement
884 Reference
< XPreparedStatement
> xPrep(m_xConnection
->prepareStatement(aSql
.makeStringAndClear()));
885 Reference
< XParameters
> xParameter(xPrep
,UNO_QUERY
);
888 for (auto const& keyColumnName
: *m_pKeyColumnNames
)
890 setParameter(i
++,xParameter
,(*_rDeleteRow
)[keyColumnName
.second
.nPosition
],keyColumnName
.second
.nType
,keyColumnName
.second
.nScale
);
893 // now we have to set the index values
894 auto aIter
= m_pColumnNames
->begin();
895 for (auto const& indexColumnPosition
: aIndexColumnPositions
)
897 setParameter(i
++,xParameter
,(*_rDeleteRow
)[indexColumnPosition
],(*_rDeleteRow
)[indexColumnPosition
].getTypeKind(),aIter
->second
.nScale
);
901 m_bDeleted
= xPrep
->executeUpdate() > 0;
905 sal_Int32 nBookmark
= ::comphelper::getINT32((*_rDeleteRow
)[0].getAny());
906 const auto iter
= m_aKeyMap
.find(nBookmark
);
907 assert(iter
!= m_aKeyMap
.end());
908 if(m_aKeyIter
== iter
&& m_aKeyIter
!= m_aKeyMap
.end())
910 m_aKeyMap
.erase(nBookmark
);
917 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
922 if(!m_bRowCountFinal
&& m_aKeyIter
== m_aKeyMap
.end())
924 // not yet all records fetched, but we reached the end of those we fetched
925 // try to fetch one more row
928 OSL_ENSURE(!isAfterLast(), "fetchRow succeeded, but isAfterLast()");
933 // nope, we arrived at end of data
934 m_aKeyIter
= m_aKeyMap
.end();
935 OSL_ENSURE(isAfterLast(), "fetchRow failed, but not end of data");
940 return !isAfterLast();
943 bool OKeySet::isBeforeFirst( )
945 return m_aKeyIter
== m_aKeyMap
.begin();
948 bool OKeySet::isAfterLast( )
950 return m_bRowCountFinal
&& m_aKeyIter
== m_aKeyMap
.end();
953 void OKeySet::beforeFirst( )
955 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
956 m_aKeyIter
= m_aKeyMap
.begin();
960 void OKeySet::afterLast( )
962 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
964 m_aKeyIter
= m_aKeyMap
.end();
968 bool OKeySet::first()
970 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
971 m_aKeyIter
= m_aKeyMap
.begin();
973 if(m_aKeyIter
== m_aKeyMap
.end())
977 m_aKeyIter
= m_aKeyMap
.end();
983 return m_aKeyIter
!= m_aKeyMap
.end() && m_aKeyIter
!= m_aKeyMap
.begin();
986 bool OKeySet::last( )
988 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
989 bool bFetchedRow
= fillAllRows();
991 m_aKeyIter
= m_aKeyMap
.end();
997 return m_aKeyIter
!= m_aKeyMap
.end() && m_aKeyIter
!= m_aKeyMap
.begin();
1000 sal_Int32
OKeySet::getRow( )
1002 OSL_ENSURE(!isAfterLast(),"getRow is not allowed when afterlast record!");
1003 OSL_ENSURE(!isBeforeFirst(),"getRow is not allowed when beforefirst record!");
1005 return std::distance(m_aKeyMap
.begin(),m_aKeyIter
);
1008 bool OKeySet::absolute( sal_Int32 row
)
1010 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
1011 OSL_ENSURE(row
,"absolute(0) isn't allowed!");
1012 bool bFetchedRow
= false;
1015 if(!m_bRowCountFinal
)
1016 bFetchedRow
= fillAllRows();
1018 row
= std::min(std::abs(row
), static_cast<sal_Int32
>(std::distance(m_aKeyMap
.begin(), m_aKeyIter
)));
1019 m_aKeyIter
= std::prev(m_aKeyIter
, row
);
1023 if(row
>= static_cast<sal_Int32
>(m_aKeyMap
.size()))
1025 // we don't have this row
1026 if(!m_bRowCountFinal
)
1028 // but there may still be rows to fetch.
1030 for(sal_Int32 i
=m_aKeyMap
.size()-1;i
< row
&& bNext
;++i
)
1032 // it is guaranteed that the above loop has executed at least once,
1033 // that is fetchRow called at least once.
1040 // reached end of data before desired row
1041 m_aKeyIter
= m_aKeyMap
.end();
1047 // no more rows to fetch -> fail
1048 m_aKeyIter
= m_aKeyMap
.end();
1054 m_aKeyIter
= std::next(m_aKeyMap
.begin(), row
);
1062 return m_aKeyIter
!= m_aKeyMap
.end() && m_aKeyIter
!= m_aKeyMap
.begin();
1065 bool OKeySet::previous()
1067 m_bInserted
= m_bUpdated
= m_bDeleted
= false;
1068 if(m_aKeyIter
!= m_aKeyMap
.begin())
1073 return m_aKeyIter
!= m_aKeyMap
.begin();
1076 bool OKeySet::doTryRefetch_throw()
1079 // we just reassign the base members
1080 Reference
< XParameters
> xParameter(m_xStatement
,UNO_QUERY
);
1081 OSL_ENSURE(xParameter
.is(),"No Parameter interface!");
1082 xParameter
->clearParameters();
1085 connectivity::ORowVector
< ORowSetValue
>::Vector::const_iterator aParaIter
;
1086 connectivity::ORowVector
< ORowSetValue
>::Vector::const_iterator aParaEnd
;
1087 OUpdatedParameter::const_iterator aUpdateFind
= m_aUpdatedParameter
.find(m_aKeyIter
->first
);
1088 if ( aUpdateFind
== m_aUpdatedParameter
.end() )
1090 aParaIter
= m_aParameterValueForCache
->begin();
1091 aParaEnd
= m_aParameterValueForCache
->end();
1095 aParaIter
= aUpdateFind
->second
->begin();
1096 aParaEnd
= aUpdateFind
->second
->end();
1099 for(++aParaIter
;aParaIter
!= aParaEnd
;++aParaIter
,++nPos
)
1101 ::dbtools::setObjectWithInfo( xParameter
, nPos
, aParaIter
->makeAny(), aParaIter
->getTypeKind() );
1104 // now set the primary key column values
1105 connectivity::ORowVector
< ORowSetValue
>::Vector::const_iterator aIter
= m_aKeyIter
->second
.m_aRowSetRow
->begin();
1106 for (auto const& keyColumnName
: *m_pKeyColumnNames
)
1107 setOneKeyColumnParameter(nPos
,xParameter
,*aIter
++,keyColumnName
.second
.nType
,keyColumnName
.second
.nScale
);
1108 for (auto const& foreignColumnName
: *m_pForeignColumnNames
)
1109 setOneKeyColumnParameter(nPos
,xParameter
,*aIter
++,foreignColumnName
.second
.nType
,foreignColumnName
.second
.nScale
);
1111 m_xSet
= m_xStatement
->executeQuery();
1112 OSL_ENSURE(m_xSet
.is(),"No resultset from statement!");
1113 return m_xSet
->next();
1116 void OKeySet::refreshRow()
1120 if(isBeforeFirst() || isAfterLast())
1123 if ( m_aKeyIter
->second
.m_xRow
.is() )
1125 m_xRow
= m_aKeyIter
->second
.m_xRow
;
1129 bool bOK
= doTryRefetch_throw();
1132 // This row has disappeared; remove it.
1133 OKeySetMatrix::const_iterator aTemp
= m_aKeyIter
;
1136 m_aKeyMap
.erase(aTemp
);
1138 // adjust RowCount for the row we have removed
1139 if (m_rRowCount
> 0)
1142 SAL_WARN("dbaccess", "m_rRowCount got out of sync: non-empty m_aKeyMap, but m_rRowCount <= 0");
1144 if (m_aKeyIter
== m_aKeyMap
.end())
1146 ::comphelper::disposeComponent(m_xSet
);
1149 // it was the last fetched row,
1150 // but there may be another one to fetch
1153 // nope, that really was the last
1154 m_aKeyIter
= m_aKeyMap
.end();
1155 OSL_ENSURE(isAfterLast(), "fetchRow() failed but not isAfterLast()!");
1158 // Now, either fetchRow has set m_xRow or isAfterLast()
1167 m_xRow
.set(m_xSet
,UNO_QUERY
);
1168 OSL_ENSURE(m_xRow
.is(),"No row from statement!");
1172 bool OKeySet::fetchRow()
1174 // fetch the next row and append on the keyset
1176 if ( !m_bRowCountFinal
&& (!m_nMaxRows
|| sal_Int32(m_aKeyMap
.size()) < m_nMaxRows
) )
1177 bRet
= m_xDriverSet
->next();
1180 ORowSetRow aKeyRow
= new connectivity::ORowVector
< ORowSetValue
>((*m_pKeyColumnNames
).size() + m_pForeignColumnNames
->size());
1182 ::comphelper::disposeComponent(m_xSet
);
1183 m_xRow
.set(m_xDriverRow
, UNO_SET_THROW
);
1185 connectivity::ORowVector
< ORowSetValue
>::Vector::iterator aIter
= aKeyRow
->begin();
1187 for (auto const& keyColumnName
: *m_pKeyColumnNames
)
1189 const SelectColumnDescription
& rColDesc
= keyColumnName
.second
;
1190 aIter
->fill(rColDesc
.nPosition
, rColDesc
.nType
, m_xRow
);
1193 // copy missing columns from other tables
1194 for (auto const& foreignColumnName
: *m_pForeignColumnNames
)
1196 const SelectColumnDescription
& rColDesc
= foreignColumnName
.second
;
1197 aIter
->fill(rColDesc
.nPosition
, rColDesc
.nType
, m_xRow
);
1200 m_aKeyIter
= m_aKeyMap
.emplace( m_aKeyMap
.rbegin()->first
+1,OKeySetValue
{aKeyRow
,0,nullptr} ).first
;
1203 m_bRowCountFinal
= true;
1207 bool OKeySet::fillAllRows()
1209 if(m_bRowCountFinal
)
1222 sal_Bool SAL_CALL
OKeySet::wasNull( )
1224 if ( ! m_xRow
.is() )
1225 throwGenericSQLException(u
"Must call getFOO() for some FOO before wasNull()"_ustr
, *this);
1227 OSL_ENSURE(m_xRow
.is(),"m_xRow is null! I've thrown, but function execution continued?");
1228 return m_xRow
->wasNull();
1231 inline void OKeySet::ensureRowForData( )
1236 throwSQLException(u
"Failed to refetch row"_ustr
, u
"02000"_ustr
, *this, -2);
1238 OSL_ENSURE(m_xRow
.is(),"m_xRow is null! I've called throwSQLException but execution continued?");
1241 OUString SAL_CALL
OKeySet::getString( sal_Int32 columnIndex
)
1244 return m_xRow
->getString(columnIndex
);
1247 sal_Bool SAL_CALL
OKeySet::getBoolean( sal_Int32 columnIndex
)
1250 return m_xRow
->getBoolean(columnIndex
);
1253 sal_Int8 SAL_CALL
OKeySet::getByte( sal_Int32 columnIndex
)
1256 return m_xRow
->getByte(columnIndex
);
1259 sal_Int16 SAL_CALL
OKeySet::getShort( sal_Int32 columnIndex
)
1262 return m_xRow
->getShort(columnIndex
);
1265 sal_Int32 SAL_CALL
OKeySet::getInt( sal_Int32 columnIndex
)
1268 return m_xRow
->getInt(columnIndex
);
1271 sal_Int64 SAL_CALL
OKeySet::getLong( sal_Int32 columnIndex
)
1274 return m_xRow
->getLong(columnIndex
);
1277 float SAL_CALL
OKeySet::getFloat( sal_Int32 columnIndex
)
1280 return m_xRow
->getFloat(columnIndex
);
1283 double SAL_CALL
OKeySet::getDouble( sal_Int32 columnIndex
)
1286 return m_xRow
->getDouble(columnIndex
);
1289 Sequence
< sal_Int8
> SAL_CALL
OKeySet::getBytes( sal_Int32 columnIndex
)
1292 return m_xRow
->getBytes(columnIndex
);
1295 css::util::Date SAL_CALL
OKeySet::getDate( sal_Int32 columnIndex
)
1298 return m_xRow
->getDate(columnIndex
);
1301 css::util::Time SAL_CALL
OKeySet::getTime( sal_Int32 columnIndex
)
1304 return m_xRow
->getTime(columnIndex
);
1307 css::util::DateTime SAL_CALL
OKeySet::getTimestamp( sal_Int32 columnIndex
)
1310 return m_xRow
->getTimestamp(columnIndex
);
1313 Reference
< css::io::XInputStream
> SAL_CALL
OKeySet::getBinaryStream( sal_Int32 columnIndex
)
1316 return m_xRow
->getBinaryStream(columnIndex
);
1319 Reference
< css::io::XInputStream
> SAL_CALL
OKeySet::getCharacterStream( sal_Int32 columnIndex
)
1322 return m_xRow
->getCharacterStream(columnIndex
);
1325 Any SAL_CALL
OKeySet::getObject( sal_Int32 columnIndex
, const Reference
< css::container::XNameAccess
>& typeMap
)
1328 return m_xRow
->getObject(columnIndex
,typeMap
);
1331 Reference
< XRef
> SAL_CALL
OKeySet::getRef( sal_Int32 columnIndex
)
1334 return m_xRow
->getRef(columnIndex
);
1337 Reference
< XBlob
> SAL_CALL
OKeySet::getBlob( sal_Int32 columnIndex
)
1340 return m_xRow
->getBlob(columnIndex
);
1343 Reference
< XClob
> SAL_CALL
OKeySet::getClob( sal_Int32 columnIndex
)
1346 return m_xRow
->getClob(columnIndex
);
1349 Reference
< XArray
> SAL_CALL
OKeySet::getArray( sal_Int32 columnIndex
)
1352 return m_xRow
->getArray(columnIndex
);
1355 bool OKeySet::rowUpdated( )
1357 return m_aKeyIter
!= m_aKeyMap
.begin() && m_aKeyIter
!= m_aKeyMap
.end() && m_aKeyIter
->second
.m_nUpdateInsert
== 2;
1360 bool OKeySet::rowInserted( )
1362 return m_aKeyIter
!= m_aKeyMap
.begin() && m_aKeyIter
!= m_aKeyMap
.end() && m_aKeyIter
->second
.m_nUpdateInsert
== 1;
1365 bool OKeySet::rowDeleted( )
1367 bool bDeleted
= m_bDeleted
;
1375 void getColumnPositions(const Reference
<XNameAccess
>& _rxQueryColumns
,
1376 const css::uno::Sequence
< OUString
>& _aColumnNames
,
1377 std::u16string_view _rsUpdateTableName
,
1378 SelectColumnsMetaData
& o_rColumnNames
,
1379 bool i_bAppendTableName
)
1381 // get the real name of the columns
1382 ::comphelper::UStringMixEqual
bCase(o_rColumnNames
.key_comp().isCaseSensitive());
1385 for (auto& queryColumnName
: _rxQueryColumns
->getElementNames())
1388 Reference
<XPropertySet
> xQueryColumnProp(_rxQueryColumns
->getByName(queryColumnName
),UNO_QUERY_THROW
);
1389 OUString sRealName
,sTableName
;
1390 OSL_ENSURE(xQueryColumnProp
->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME
),"Property REALNAME not available!");
1391 OSL_ENSURE(xQueryColumnProp
->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME
),"Property TABLENAME not available!");
1392 xQueryColumnProp
->getPropertyValue(PROPERTY_REALNAME
) >>= sRealName
;
1393 xQueryColumnProp
->getPropertyValue(PROPERTY_TABLENAME
) >>= sTableName
;
1395 for (auto& tableColumnName
: _aColumnNames
)
1397 if(bCase(sRealName
,tableColumnName
) && bCase(_rsUpdateTableName
,sTableName
) && o_rColumnNames
.find(tableColumnName
) == o_rColumnNames
.end())
1399 sal_Int32 nType
= 0;
1400 xQueryColumnProp
->getPropertyValue(PROPERTY_TYPE
) >>= nType
;
1401 sal_Int32 nScale
= 0;
1402 xQueryColumnProp
->getPropertyValue(PROPERTY_SCALE
) >>= nScale
;
1403 OUString sColumnDefault
;
1404 if ( xQueryColumnProp
->getPropertySetInfo()->hasPropertyByName(PROPERTY_DEFAULTVALUE
) )
1405 xQueryColumnProp
->getPropertyValue(PROPERTY_DEFAULTVALUE
) >>= sColumnDefault
;
1407 sal_Int32 nNullable
= ColumnValue::NULLABLE_UNKNOWN
;
1408 OSL_VERIFY( xQueryColumnProp
->getPropertyValue( PROPERTY_ISNULLABLE
) >>= nNullable
);
1410 SelectColumnDescription
aColDesc( nPos
, nType
, nScale
, nNullable
!= sdbc::ColumnValue::NO_NULLS
, sColumnDefault
);
1412 if ( i_bAppendTableName
)
1414 sName
= sTableName
+ "." + sRealName
;
1415 aColDesc
.sRealName
= sRealName
;
1416 aColDesc
.sTableName
= sTableName
;
1422 o_rColumnNames
[sName
] = std::move(aColDesc
);
1431 void OKeySet::impl_convertValue_throw(const ORowSetRow
& _rInsertRow
,const SelectColumnDescription
& i_aMetaData
)
1433 ORowSetValue
& aValue((*_rInsertRow
)[i_aMetaData
.nPosition
]);
1434 switch(i_aMetaData
.nType
)
1436 case DataType::DECIMAL
:
1437 case DataType::NUMERIC
:
1439 OUString sValue
= aValue
.getString();
1440 sal_Int32 nIndex
= sValue
.indexOf('.');
1443 aValue
= sValue
.copy(0,std::min(sValue
.getLength(),nIndex
+ (i_aMetaData
.nScale
> 0 ? i_aMetaData
.nScale
+ 1 : 0)));
1452 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */