Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "KeySet.hxx"
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>
41 : #include <list>
42 : #include <algorithm>
43 : #include <string.h>
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"
50 :
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;
66 : using std::vector;
67 :
68 : namespace
69 : {
70 21 : void lcl_fillIndexColumns(const Reference<XIndexAccess>& _xIndexes, ::std::vector< Reference<XNameAccess> >& _rAllIndexColumns)
71 : {
72 21 : if ( _xIndexes.is() )
73 : {
74 21 : Reference<XPropertySet> xIndexColsSup;
75 21 : sal_Int32 nCount = _xIndexes->getCount();
76 42 : for(sal_Int32 j = 0 ; j < nCount ; ++j)
77 : {
78 21 : xIndexColsSup.set(_xIndexes->getByIndex(j),UNO_QUERY);
79 63 : if( xIndexColsSup.is()
80 63 : && comphelper::getBOOL(xIndexColsSup->getPropertyValue(PROPERTY_ISUNIQUE))
81 84 : && !comphelper::getBOOL(xIndexColsSup->getPropertyValue(PROPERTY_ISPRIMARYKEYINDEX))
82 : )
83 21 : _rAllIndexColumns.push_back(Reference<XColumnsSupplier>(xIndexColsSup,UNO_QUERY)->getColumns());
84 21 : }
85 : }
86 21 : }
87 :
88 14 : template < typename T > inline void tryDispose( Reference<T> &r )
89 : {
90 : try
91 : {
92 14 : ::comphelper::disposeComponent(r);
93 : }
94 0 : catch(const Exception&)
95 : {
96 0 : r = NULL;
97 : }
98 0 : catch(...)
99 : {
100 : SAL_WARN("dbaccess", "Unknown Exception occurred");
101 : }
102 14 : }
103 : }
104 :
105 :
106 9 : 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)
115 : ,m_xTable(_xTable)
116 : ,m_xTableKeys(_xTableKeys)
117 : ,m_xComposer(_xComposer)
118 : ,m_sUpdateTableName(_rUpdateTableName)
119 : ,m_rRowCount(o_nRowCount)
120 9 : ,m_bRowCountFinal(false)
121 : {
122 9 : }
123 :
124 27 : OKeySet::~OKeySet()
125 : {
126 9 : tryDispose(m_xSet);
127 : // m_xStatement is necessarily one of those
128 9 : const vStatements_t::const_iterator end(m_vStatements.end());
129 14 : for(vStatements_t::iterator i(m_vStatements.begin());
130 : i != end;
131 : ++i)
132 : {
133 5 : tryDispose(i->second);
134 : }
135 :
136 9 : m_xComposer = NULL;
137 :
138 18 : }
139 :
140 9 : void OKeySet::initColumns()
141 : {
142 9 : Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
143 9 : bool bCase = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers();
144 9 : m_pKeyColumnNames.reset( new SelectColumnsMetaData(bCase) );
145 9 : m_pColumnNames.reset( new SelectColumnsMetaData(bCase) );
146 9 : m_pParameterNames.reset( new SelectColumnsMetaData(bCase) );
147 9 : m_pForeignColumnNames.reset( new SelectColumnsMetaData(bCase) );
148 9 : }
149 :
150 9 : 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)
155 : {
156 : // first ask the database itself for the best columns which can be used
157 9 : Sequence< OUString> aBestColumnNames;
158 18 : Reference<XNameAccess> xKeyColumns = getPrimaryKeyColumns_throw(i_aTable);
159 9 : if ( xKeyColumns.is() )
160 9 : aBestColumnNames = xKeyColumns->getElementNames();
161 :
162 18 : const Reference<XColumnsSupplier> xTblColSup(i_aTable,UNO_QUERY_THROW);
163 18 : const Reference<XNameAccess> xTblColumns = xTblColSup->getColumns();
164 : // locate parameter in select columns
165 18 : Reference<XParametersSupplier> xParaSup(m_xComposer,UNO_QUERY);
166 18 : Reference<XIndexAccess> xQueryParameters = xParaSup->getParameters();
167 9 : const sal_Int32 nParaCount = xQueryParameters->getCount();
168 18 : Sequence< OUString> aParameterColumns(nParaCount);
169 11 : for(sal_Int32 i = 0; i< nParaCount;++i)
170 : {
171 2 : Reference<XPropertySet> xPara(xQueryParameters->getByIndex(i),UNO_QUERY_THROW);
172 2 : xPara->getPropertyValue(PROPERTY_REALNAME) >>= aParameterColumns[i];
173 2 : }
174 :
175 18 : OUString sUpdateTableName( i_rUpdateTableName );
176 9 : if ( sUpdateTableName.isEmpty() )
177 : {
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.
187 :
188 0 : OUString sCatalog, sSchema, sTable;
189 0 : Reference<XPropertySet> xTableProp( i_aTable, UNO_QUERY_THROW );
190 0 : xTableProp->getPropertyValue( PROPERTY_CATALOGNAME )>>= sCatalog;
191 0 : xTableProp->getPropertyValue( PROPERTY_SCHEMANAME ) >>= sSchema;
192 0 : xTableProp->getPropertyValue( PROPERTY_NAME ) >>= sTable;
193 0 : sUpdateTableName = dbtools::composeTableName( i_xMeta, sCatalog, sSchema, sTable, false, ::dbtools::eInDataManipulation );
194 : }
195 :
196 9 : ::dbaccess::getColumnPositions(i_xQueryColumns,aBestColumnNames,sUpdateTableName,(*o_pKeyColumnNames),true);
197 9 : ::dbaccess::getColumnPositions(i_xQueryColumns,xTblColumns->getElementNames(),sUpdateTableName,(*m_pColumnNames),true);
198 9 : ::dbaccess::getColumnPositions(i_xQueryColumns,aParameterColumns,sUpdateTableName,(*m_pParameterNames),true);
199 :
200 9 : if ( o_pKeyColumnNames->empty() )
201 : {
202 0 : ::dbtools::throwGenericSQLException("Could not find any key column.", *this );
203 : }
204 :
205 54 : for ( SelectColumnsMetaData::const_iterator keyColumn = o_pKeyColumnNames->begin();
206 36 : keyColumn != o_pKeyColumnNames->end();
207 : ++keyColumn
208 : )
209 : {
210 9 : if ( !xTblColumns->hasByName( keyColumn->second.sRealName ) )
211 0 : continue;
212 :
213 9 : Reference<XPropertySet> xProp( xTblColumns->getByName( keyColumn->second.sRealName ), UNO_QUERY );
214 9 : bool bAuto = false;
215 9 : if ( ( xProp->getPropertyValue( PROPERTY_ISAUTOINCREMENT ) >>= bAuto ) && bAuto )
216 1 : m_aAutoColumns.push_back( keyColumn->first );
217 18 : }
218 9 : }
219 :
220 : namespace
221 : {
222 5 : void appendOneKeyColumnClause( const OUString &tblName, const OUString &colName, const connectivity::ORowSetValue &_rValue, OUStringBuffer &o_buf )
223 : {
224 : static const char s_sDot[] = ".";
225 5 : OUString fullName;
226 5 : if (tblName.isEmpty())
227 0 : fullName = colName;
228 : else
229 5 : fullName = tblName + s_sDot + colName;
230 5 : if ( _rValue.isNull() )
231 : {
232 0 : o_buf.append(fullName + " IS NULL ");
233 : }
234 : else
235 : {
236 5 : o_buf.append(fullName + " = ? ");
237 5 : }
238 5 : }
239 : }
240 :
241 13478 : void OKeySet::setOneKeyColumnParameter( sal_Int32 &nPos, const Reference< XParameters > &_xParameter, const connectivity::ORowSetValue &_rValue, sal_Int32 _nType, sal_Int32 _nScale )
242 : {
243 13478 : if ( _rValue.isNull() )
244 : {
245 : // Nothing to do, appendOneKeyColumnClause took care of it,
246 : // the "IS NULL" is hardcoded in the query
247 : }
248 : else
249 : {
250 13478 : setParameter( nPos++, _xParameter, _rValue, _nType, _nScale );
251 : }
252 13478 : }
253 :
254 5 : OUStringBuffer OKeySet::createKeyFilter()
255 : {
256 5 : connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aIter = m_aKeyIter->second.first->get().begin();
257 :
258 : static const char aAnd[] = " AND ";
259 5 : const OUString aQuote = getIdentifierQuoteString();
260 5 : OUStringBuffer aFilter;
261 : // create the where clause
262 10 : Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
263 5 : SelectColumnsMetaData::const_iterator aPosEnd = m_pKeyColumnNames->end();
264 10 : for(SelectColumnsMetaData::const_iterator aPosIter = m_pKeyColumnNames->begin();aPosIter != aPosEnd; ++aPosIter)
265 : {
266 5 : if ( ! aFilter.isEmpty() )
267 0 : aFilter.append(aAnd);
268 5 : appendOneKeyColumnClause(::dbtools::quoteTableName(xMeta, aPosIter->second.sTableName, ::dbtools::eInDataManipulation),
269 5 : ::dbtools::quoteName(aQuote, aPosIter->second.sRealName),
270 10 : *aIter++,
271 10 : aFilter);
272 : }
273 5 : aPosEnd = m_pForeignColumnNames->end();
274 5 : for(SelectColumnsMetaData::const_iterator aPosIter = m_pForeignColumnNames->begin(); aPosIter != aPosEnd; ++aPosIter)
275 : {
276 0 : if ( ! aFilter.isEmpty() )
277 0 : aFilter.append(aAnd);
278 0 : appendOneKeyColumnClause(::dbtools::quoteTableName(xMeta, aPosIter->second.sTableName, ::dbtools::eInDataManipulation),
279 0 : ::dbtools::quoteName(aQuote, aPosIter->second.sRealName),
280 0 : *aIter++,
281 0 : aFilter);
282 : }
283 10 : return aFilter;
284 : }
285 :
286 9 : void OKeySet::construct(const Reference< XResultSet>& _xDriverSet, const OUString& i_sRowSetFilter)
287 : {
288 9 : OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
289 :
290 9 : initColumns();
291 :
292 9 : Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
293 18 : Reference<XColumnsSupplier> xQueryColSup(m_xComposer, UNO_QUERY);
294 18 : const Reference<XNameAccess> xQueryColumns = xQueryColSup->getColumns();
295 9 : findTableColumnsMatching_throw( makeAny(m_xTable), m_sUpdateTableName, xMeta, xQueryColumns, m_pKeyColumnNames );
296 :
297 18 : Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
298 18 : Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
299 18 : Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
300 9 : xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
301 18 : Reference<XTablesSupplier> xTabSup(xAnalyzer,uno::UNO_QUERY);
302 18 : Reference<XNameAccess> xSelectTables(xTabSup->getTables(),uno::UNO_QUERY);
303 18 : const Sequence< OUString> aSeq = xSelectTables->getElementNames();
304 9 : if ( aSeq.getLength() > 1 ) // special handling for join
305 : {
306 0 : const OUString* pIter = aSeq.getConstArray();
307 0 : const OUString* const pEnd = pIter + aSeq.getLength();
308 0 : for(;pIter != pEnd;++pIter)
309 : {
310 0 : if ( *pIter != m_sUpdateTableName )
311 : {
312 0 : connectivity::OSQLTable xSelColSup(xSelectTables->getByName(*pIter),uno::UNO_QUERY);
313 0 : Reference<XPropertySet> xProp(xSelColSup,uno::UNO_QUERY);
314 0 : OUString sSelectTableName = ::dbtools::composeTableName( xMeta, xProp, ::dbtools::eInDataManipulation, false, false, false );
315 :
316 0 : ::dbaccess::getColumnPositions(xQueryColumns, xSelColSup->getColumns()->getElementNames(), sSelectTableName, (*m_pForeignColumnNames), true);
317 :
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...)
320 : }
321 : }
322 : }
323 :
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 18 : OKeySetValue keySetValue(nullptr,::std::pair<sal_Int32,Reference<XRow> >(0,Reference<XRow>()));
327 9 : m_aKeyMap.insert(OKeySetMatrix::value_type(0, keySetValue));
328 18 : m_aKeyIter = m_aKeyMap.begin();
329 9 : }
330 :
331 0 : void OKeySet::reset(const Reference< XResultSet>& _xDriverSet)
332 : {
333 0 : OCacheSet::construct(_xDriverSet, m_sRowSetFilter);
334 0 : m_bRowCountFinal = false;
335 0 : m_aKeyMap.clear();
336 0 : OKeySetValue keySetValue(nullptr,::std::pair<sal_Int32,Reference<XRow> >(0,Reference<XRow>()));
337 0 : m_aKeyMap.insert(OKeySetMatrix::value_type(0,keySetValue));
338 0 : m_aKeyIter = m_aKeyMap.begin();
339 0 : }
340 :
341 13478 : void OKeySet::ensureStatement( )
342 : {
343 : // do we already have a statement for the current combination of NULLness
344 : // of key & foreign columns?
345 13478 : FilterColumnsNULL_t FilterColumnsNULL;
346 13478 : FilterColumnsNULL.reserve(m_aKeyIter->second.first->get().size());
347 13478 : connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aIter = m_aKeyIter->second.first->get().begin();
348 13478 : const connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aEnd = m_aKeyIter->second.first->get().end();
349 40434 : for( ; aIter != aEnd; ++aIter )
350 26956 : FilterColumnsNULL.push_back(aIter->isNull());
351 13478 : vStatements_t::iterator pNewStatement(m_vStatements.find(FilterColumnsNULL));
352 13478 : if(pNewStatement == m_vStatements.end())
353 : {
354 : // no: make a new one
355 5 : makeNewStatement();
356 : std::pair< vStatements_t::iterator, bool > insert_result
357 5 : (m_vStatements.insert(vStatements_t::value_type(FilterColumnsNULL, m_xStatement)));
358 : (void) insert_result; // WaE: unused variable
359 : assert(insert_result.second);
360 : }
361 : else
362 : // yes: use it
363 13473 : m_xStatement = pNewStatement->second;
364 13478 : }
365 :
366 5 : void OKeySet::makeNewStatement()
367 : {
368 5 : Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
369 10 : Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
370 10 : Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
371 5 : xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
372 :
373 10 : OUStringBuffer aFilter(createKeyFilter());
374 10 : executeStatement(aFilter, xAnalyzer);
375 5 : }
376 :
377 5 : void OKeySet::executeStatement(OUStringBuffer& io_aFilter, Reference<XSingleSelectQueryComposer>& io_xAnalyzer)
378 : {
379 5 : bool bFilterSet = !m_sRowSetFilter.isEmpty();
380 5 : if ( bFilterSet )
381 : {
382 0 : FilterCreator aFilterCreator;
383 0 : aFilterCreator.append( m_sRowSetFilter );
384 0 : aFilterCreator.append( io_aFilter.makeStringAndClear() );
385 0 : io_aFilter = aFilterCreator.getComposedAndClear();
386 : }
387 5 : io_xAnalyzer->setFilter(io_aFilter.makeStringAndClear());
388 5 : if ( bFilterSet )
389 : {
390 0 : Sequence< Sequence< PropertyValue > > aFilter2 = io_xAnalyzer->getStructuredFilter();
391 0 : const Sequence< PropertyValue >* pOr = aFilter2.getConstArray();
392 0 : const Sequence< PropertyValue >* pOrEnd = pOr + aFilter2.getLength();
393 0 : for(;pOr != pOrEnd;++pOr)
394 : {
395 0 : const PropertyValue* pAnd = pOr->getConstArray();
396 0 : const PropertyValue* pAndEnd = pAnd + pOr->getLength();
397 0 : for(;pAnd != pAndEnd;++pAnd)
398 : {
399 0 : OUString sValue;
400 0 : if ( !(pAnd->Value >>= sValue) || !( sValue == "?" || sValue.startsWith( ":" ) ) )
401 : { // we have a criteria which has to be taken into account for updates
402 0 : m_aFilterColumns.push_back(pAnd->Name);
403 : }
404 0 : }
405 0 : }
406 : }
407 5 : m_xStatement = m_xConnection->prepareStatement(io_xAnalyzer->getQueryWithSubstitution());
408 5 : ::comphelper::disposeComponent(io_xAnalyzer);
409 5 : }
410 :
411 33337 : void OKeySet::invalidateRow()
412 : {
413 33337 : m_xRow = NULL;
414 33337 : ::comphelper::disposeComponent(m_xSet);
415 33337 : }
416 :
417 13603 : Any SAL_CALL OKeySet::getBookmark() throw(SQLException, RuntimeException)
418 : {
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 13603 : return makeAny(m_aKeyIter->first);
422 : }
423 :
424 4516 : bool SAL_CALL OKeySet::moveToBookmark( const Any& bookmark ) throw(SQLException, RuntimeException)
425 : {
426 4516 : m_bInserted = m_bUpdated = m_bDeleted = false;
427 4516 : m_aKeyIter = m_aKeyMap.find(::comphelper::getINT32(bookmark));
428 4516 : invalidateRow();
429 4516 : return m_aKeyIter != m_aKeyMap.end();
430 : }
431 :
432 0 : bool SAL_CALL OKeySet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows ) throw(SQLException, RuntimeException)
433 : {
434 0 : m_bInserted = m_bUpdated = m_bDeleted = false;
435 0 : m_aKeyIter = m_aKeyMap.find(::comphelper::getINT32(bookmark));
436 0 : if(m_aKeyIter != m_aKeyMap.end())
437 : {
438 0 : return relative(rows);
439 : }
440 :
441 0 : invalidateRow();
442 0 : return false;
443 : }
444 :
445 5904 : sal_Int32 SAL_CALL OKeySet::compareBookmarks( const Any& _first, const Any& _second ) throw(SQLException, RuntimeException)
446 : {
447 5904 : sal_Int32 nFirst = 0, nSecond = 0;
448 5904 : _first >>= nFirst;
449 5904 : _second >>= nSecond;
450 :
451 5904 : return (nFirst != nSecond) ? CompareBookmark::NOT_EQUAL : CompareBookmark::EQUAL;
452 : }
453 :
454 0 : bool SAL_CALL OKeySet::hasOrderedBookmarks( ) throw(SQLException, RuntimeException)
455 : {
456 0 : return true;
457 : }
458 :
459 0 : sal_Int32 SAL_CALL OKeySet::hashBookmark( const Any& bookmark ) throw(SQLException, RuntimeException)
460 : {
461 0 : return ::comphelper::getINT32(bookmark);
462 : }
463 :
464 : // ::com::sun::star::sdbcx::XDeleteRows
465 0 : Sequence< sal_Int32 > SAL_CALL OKeySet::deleteRows( const Sequence< Any >& rows ,const connectivity::OSQLTable& _xTable) throw(SQLException, RuntimeException)
466 : {
467 0 : Reference<XPropertySet> xSet(_xTable,UNO_QUERY);
468 0 : fillTableName(xSet);
469 :
470 0 : OUStringBuffer aSql("DELETE FROM " + m_aComposedTableName + " WHERE ");
471 :
472 : // list all columns that should be set
473 0 : const OUString aQuote = getIdentifierQuoteString();
474 : static const char aAnd[] = " AND ";
475 : static const char aOr[] = " OR ";
476 : static const char aEqual[] = " = ?";
477 :
478 : // use keys for exact positioning
479 0 : Reference<XNameAccess> xKeyColumns = getKeyColumns();
480 :
481 0 : OUStringBuffer aCondition("( ");
482 :
483 0 : SelectColumnsMetaData::const_iterator aIter = (*m_pKeyColumnNames).begin();
484 0 : const SelectColumnsMetaData::const_iterator aPosEnd = (*m_pKeyColumnNames).end();
485 0 : for(;aIter != aPosEnd;++aIter)
486 : {
487 0 : aCondition.append(::dbtools::quoteName( aQuote,aIter->second.sRealName) + aEqual + aAnd);
488 : }
489 0 : 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 0 : const OUString sCon( aCondition.makeStringAndClear() );
493 :
494 : // since we need to delete all rows in "rows",
495 : // we need to OR as many row locators.
496 0 : const Any* pBegin = rows.getConstArray();
497 0 : const Any* const pEnd = pBegin + rows.getLength();
498 0 : for(;pBegin != pEnd;++pBegin)
499 : {
500 0 : aSql.append(sCon + aOr);
501 : }
502 0 : aSql.setLength(aSql.getLength()-3);
503 :
504 : // now create end execute the prepared statement
505 :
506 0 : Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(aSql.makeStringAndClear()));
507 0 : Reference< XParameters > xParameter(xPrep,UNO_QUERY);
508 :
509 : // now, fill in the parameters in the row locators
510 0 : pBegin = rows.getConstArray();
511 0 : sal_Int32 i=1;
512 0 : for(;pBegin != pEnd;++pBegin)
513 : {
514 0 : 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 0 : if(m_aKeyIter != m_aKeyMap.end())
521 : {
522 0 : connectivity::ORowVector< ORowSetValue >::Vector::iterator aKeyIter = m_aKeyIter->second.first->get().begin();
523 0 : connectivity::ORowVector< ORowSetValue >::Vector::iterator aKeyEnd = m_aKeyIter->second.first->get().end();
524 0 : SelectColumnsMetaData::const_iterator aPosIter = (*m_pKeyColumnNames).begin();
525 0 : for(sal_uInt16 j = 0;aKeyIter != aKeyEnd;++aKeyIter,++j,++aPosIter)
526 : {
527 0 : setParameter(i++,xParameter,*aKeyIter,aPosIter->second.nType,aPosIter->second.nScale);
528 : }
529 : }
530 : }
531 :
532 0 : bool bOk = xPrep->executeUpdate() > 0;
533 0 : Sequence< sal_Int32 > aRet(rows.getLength());
534 0 : memset(aRet.getArray(),bOk,sizeof(sal_Int32)*aRet.getLength());
535 0 : if(bOk)
536 : {
537 0 : pBegin = rows.getConstArray();
538 :
539 0 : for(;pBegin != pEnd;++pBegin)
540 : {
541 0 : sal_Int32 nPos = 0;
542 0 : *pBegin >>= nPos;
543 0 : if(m_aKeyIter == m_aKeyMap.find(nPos) && m_aKeyIter != m_aKeyMap.end())
544 0 : ++m_aKeyIter;
545 0 : m_aKeyMap.erase(nPos);
546 0 : m_bDeleted = true;
547 : }
548 : }
549 0 : return aRet;
550 : }
551 :
552 1 : void SAL_CALL OKeySet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& _xTable ) throw(SQLException, RuntimeException)
553 : {
554 1 : Reference<XPropertySet> xSet(_xTable,UNO_QUERY);
555 1 : fillTableName(xSet);
556 :
557 2 : OUStringBuffer aSql = "UPDATE " + m_aComposedTableName + " SET ";
558 : // list all columns that should be set
559 1 : static OUString aPara(" = ?,");
560 2 : OUString aQuote = getIdentifierQuoteString();
561 1 : static OUString aAnd(" AND ");
562 2 : OUString sIsNull(" IS NULL");
563 2 : OUString sParam(" = ?");
564 :
565 : // use keys and indexes for exact positioning
566 : // first the keys
567 2 : Reference<XNameAccess> xKeyColumns = getKeyColumns();
568 :
569 : // second the indexes
570 2 : Reference<XIndexesSupplier> xIndexSup(_xTable,UNO_QUERY);
571 2 : Reference<XIndexAccess> xIndexes;
572 1 : if ( xIndexSup.is() )
573 1 : xIndexes.set(xIndexSup->getIndexes(),UNO_QUERY);
574 :
575 2 : ::std::vector< Reference<XNameAccess> > aAllIndexColumns;
576 1 : lcl_fillIndexColumns(xIndexes,aAllIndexColumns);
577 :
578 2 : OUStringBuffer sKeyCondition,sIndexCondition;
579 2 : ::std::vector<sal_Int32> aIndexColumnPositions;
580 :
581 1 : const sal_Int32 nOldLength = aSql.getLength();
582 1 : sal_Int32 i = 1;
583 : // here we build the condition part for the update statement
584 1 : SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
585 1 : SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
586 3 : for(;aIter != aEnd;++aIter,++i)
587 : {
588 2 : if ( m_pKeyColumnNames->find(aIter->first) != m_pKeyColumnNames->end() )
589 : {
590 1 : sKeyCondition.append(::dbtools::quoteName( aQuote,aIter->second.sRealName));
591 1 : if((_rOriginalRow->get())[aIter->second.nPosition].isNull())
592 0 : sKeyCondition.append(sIsNull);
593 : else
594 1 : sKeyCondition.append(sParam);
595 1 : sKeyCondition.append(aAnd);
596 : }
597 : else
598 : {
599 1 : ::std::vector< Reference<XNameAccess> >::const_iterator aIndexEnd = aAllIndexColumns.end();
600 2 : for( ::std::vector< Reference<XNameAccess> >::const_iterator aIndexIter = aAllIndexColumns.begin();
601 : aIndexIter != aIndexEnd;++aIndexIter)
602 : {
603 1 : if((*aIndexIter)->hasByName(aIter->first))
604 : {
605 0 : sIndexCondition.append(::dbtools::quoteName( aQuote,aIter->second.sRealName));
606 0 : if((_rOriginalRow->get())[aIter->second.nPosition].isNull())
607 0 : sIndexCondition.append(sIsNull);
608 : else
609 : {
610 0 : sIndexCondition.append(sParam);
611 0 : aIndexColumnPositions.push_back(aIter->second.nPosition);
612 : }
613 0 : sIndexCondition.append(aAnd);
614 0 : break;
615 : }
616 : }
617 : }
618 2 : if((_rInsertRow->get())[aIter->second.nPosition].isModified())
619 : {
620 2 : aSql.append(::dbtools::quoteName( aQuote,aIter->second.sRealName) + aPara);
621 : }
622 : }
623 :
624 1 : if( aSql.getLength() != nOldLength )
625 : {
626 1 : aSql.setLength(aSql.getLength()-1);
627 : }
628 : else
629 0 : ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED ), SQL_GENERAL_ERROR, m_xConnection );
630 :
631 1 : if(!sKeyCondition.isEmpty() || !sIndexCondition.isEmpty())
632 : {
633 1 : aSql.append(" WHERE ");
634 1 : if(!sKeyCondition.isEmpty() && !sIndexCondition.isEmpty())
635 : {
636 0 : aSql.append(sKeyCondition.makeStringAndClear() + sIndexCondition.makeStringAndClear());
637 : }
638 1 : else if(!sKeyCondition.isEmpty())
639 : {
640 1 : aSql.append(sKeyCondition.makeStringAndClear());
641 : }
642 0 : else if(!sIndexCondition.isEmpty())
643 : {
644 0 : aSql.append(sIndexCondition.makeStringAndClear());
645 : }
646 1 : aSql.setLength(aSql.getLength()-5); // remove the last AND
647 : }
648 : else
649 0 : ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_CONDITION_FOR_PK ), SQL_GENERAL_ERROR, m_xConnection );
650 :
651 : // now create end execute the prepared statement
652 2 : OUString sEmpty;
653 2 : executeUpdate(_rInsertRow ,_rOriginalRow,aSql.makeStringAndClear(),sEmpty,aIndexColumnPositions);
654 1 : }
655 :
656 1 : void OKeySet::executeUpdate(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const OUString& i_sSQL,const OUString& i_sTableName,const ::std::vector<sal_Int32>& _aIndexColumnPositions)
657 : {
658 : // now create end execute the prepared statement
659 1 : Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL));
660 2 : Reference< XParameters > xParameter(xPrep,UNO_QUERY);
661 :
662 1 : bool bRefetch = true;
663 2 : Reference<XRow> xRow;
664 1 : sal_Int32 i = 1;
665 : // first the set values
666 1 : SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
667 1 : SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
668 1 : sal_uInt16 j = 0;
669 3 : for(;aIter != aEnd;++aIter,++j)
670 : {
671 2 : if ( i_sTableName.isEmpty() || aIter->second.sTableName == i_sTableName )
672 : {
673 2 : sal_Int32 nPos = aIter->second.nPosition;
674 2 : if((_rInsertRow->get())[nPos].isModified())
675 : {
676 2 : if ( bRefetch )
677 : {
678 2 : bRefetch = ::std::find(m_aFilterColumns.begin(),m_aFilterColumns.end(),aIter->second.sRealName) == m_aFilterColumns.end();
679 : }
680 2 : impl_convertValue_throw(_rInsertRow,aIter->second);
681 2 : (_rInsertRow->get())[nPos].setSigned((_rOriginalRow->get())[nPos].isSigned());
682 2 : setParameter(i++,xParameter,(_rInsertRow->get())[nPos],aIter->second.nType,aIter->second.nScale);
683 : }
684 : }
685 : }
686 : // and then the values of the where condition
687 1 : aIter = m_pKeyColumnNames->begin();
688 1 : aEnd = m_pKeyColumnNames->end();
689 1 : j = 0;
690 2 : for(;aIter != aEnd;++aIter,++j)
691 : {
692 1 : if ( i_sTableName.isEmpty() || aIter->second.sTableName == i_sTableName )
693 : {
694 1 : setParameter(i++,xParameter,(_rOriginalRow->get())[aIter->second.nPosition],aIter->second.nType,aIter->second.nScale);
695 : }
696 : }
697 1 : if ( !_aIndexColumnPositions.empty() )
698 : {
699 : // now we have to set the index values
700 0 : ::std::vector<sal_Int32>::const_iterator aIdxColIter = _aIndexColumnPositions.begin();
701 0 : ::std::vector<sal_Int32>::const_iterator aIdxColEnd = _aIndexColumnPositions.end();
702 0 : j = 0;
703 0 : aIter = m_pColumnNames->begin();
704 0 : for(;aIdxColIter != aIdxColEnd;++aIdxColIter,++i,++j,++aIter)
705 : {
706 0 : setParameter(i,xParameter,(_rOriginalRow->get())[*aIdxColIter],(_rOriginalRow->get())[*aIdxColIter].getTypeKind(),aIter->second.nScale);
707 : }
708 : }
709 1 : const sal_Int32 nRowsUpdated = xPrep->executeUpdate();
710 1 : m_bUpdated = nRowsUpdated > 0;
711 1 : if(m_bUpdated)
712 : {
713 1 : const sal_Int32 nBookmark = ::comphelper::getINT32((_rInsertRow->get())[0].getAny());
714 1 : m_aKeyIter = m_aKeyMap.find(nBookmark);
715 1 : m_aKeyIter->second.second.first = 2;
716 1 : m_aKeyIter->second.second.second = xRow;
717 1 : copyRowValue(_rInsertRow,m_aKeyIter->second.first,nBookmark);
718 1 : tryRefetch(_rInsertRow,bRefetch);
719 1 : }
720 1 : }
721 :
722 1 : void SAL_CALL OKeySet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) throw(SQLException, RuntimeException)
723 : {
724 1 : Reference<XPropertySet> xSet(_xTable,UNO_QUERY);
725 1 : fillTableName(xSet);
726 :
727 2 : OUStringBuffer aSql( "INSERT INTO " + m_aComposedTableName + " ( ");
728 :
729 : // set values and column names
730 2 : OUStringBuffer aValues(" VALUES ( ");
731 : static const char aPara[] = "?,";
732 2 : OUString aQuote = getIdentifierQuoteString();
733 : static const char aComma[] = ",";
734 :
735 1 : SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
736 1 : SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
737 1 : sal_Int32 j = 1;
738 1 : bool bRefetch = true;
739 1 : bool bModified = false;
740 3 : for(;aIter != aEnd;++aIter,++j)
741 : {
742 2 : if((_rInsertRow->get())[aIter->second.nPosition].isModified())
743 : {
744 2 : if ( bRefetch )
745 : {
746 2 : bRefetch = ::std::find(m_aFilterColumns.begin(),m_aFilterColumns.end(),aIter->second.sRealName) == m_aFilterColumns.end();
747 : }
748 2 : aSql.append(::dbtools::quoteName( aQuote,aIter->second.sRealName) + aComma);
749 2 : aValues.append(aPara);
750 2 : bModified = true;
751 : }
752 : }
753 1 : if ( !bModified )
754 0 : ::dbtools::throwSQLException( DBACORE_RESSTRING( RID_STR_NO_VALUE_CHANGED ), SQL_GENERAL_ERROR, m_xConnection );
755 :
756 1 : aSql[aSql.getLength() - 1] = ')';
757 1 : aValues[aValues.getLength() - 1] = ')';
758 1 : aSql.append(aValues.makeStringAndClear());
759 : // now create,fill and execute the prepared statement
760 2 : OUString sEmpty;
761 2 : executeInsert(_rInsertRow,aSql.makeStringAndClear(),sEmpty,bRefetch);
762 1 : }
763 :
764 1 : void OKeySet::executeInsert( const ORowSetRow& _rInsertRow,const OUString& i_sSQL,const OUString& i_sTableName,bool bRefetch )
765 : {
766 : // now create,fill and execute the prepared statement
767 1 : Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL));
768 2 : Reference< XParameters > xParameter(xPrep,UNO_QUERY);
769 :
770 1 : SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
771 1 : SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
772 3 : for(sal_Int32 i = 1;aIter != aEnd;++aIter)
773 : {
774 2 : if ( i_sTableName.isEmpty() || aIter->second.sTableName == i_sTableName )
775 : {
776 2 : const sal_Int32 nPos = aIter->second.nPosition;
777 2 : if((_rInsertRow->get())[nPos].isModified())
778 : {
779 2 : if((_rInsertRow->get())[nPos].isNull())
780 0 : xParameter->setNull(i++,(_rInsertRow->get())[nPos].getTypeKind());
781 : else
782 : {
783 2 : impl_convertValue_throw(_rInsertRow,aIter->second);
784 2 : (_rInsertRow->get())[nPos].setSigned(m_aSignedFlags[nPos-1]);
785 2 : setParameter(i++,xParameter,(_rInsertRow->get())[nPos],aIter->second.nType,aIter->second.nScale);
786 : }
787 : }
788 : }
789 : }
790 :
791 1 : m_bInserted = xPrep->executeUpdate() > 0;
792 1 : bool bAutoValuesFetched = false;
793 1 : if ( m_bInserted )
794 : {
795 : // first insert the default values into the insertrow
796 1 : aIter = m_pColumnNames->begin();
797 3 : for(;aIter != aEnd;++aIter)
798 : {
799 2 : if ( !(_rInsertRow->get())[aIter->second.nPosition].isModified() )
800 0 : (_rInsertRow->get())[aIter->second.nPosition] = aIter->second.sDefaultValue;
801 : }
802 : try
803 : {
804 1 : Reference< XGeneratedResultSet > xGRes(xPrep, UNO_QUERY);
805 1 : if ( xGRes.is() )
806 : {
807 1 : Reference< XResultSet > xRes = xGRes->getGeneratedValues();
808 2 : Reference< XRow > xRow(xRes,UNO_QUERY);
809 1 : if ( xRow.is() && xRes->next() )
810 : {
811 1 : Reference< XResultSetMetaDataSupplier > xMdSup(xRes,UNO_QUERY);
812 2 : Reference< XResultSetMetaData > xMd = xMdSup->getMetaData();
813 1 : sal_Int32 nColumnCount = xMd->getColumnCount();
814 1 : ::std::vector< OUString >::iterator aAutoIter = m_aAutoColumns.begin();
815 1 : ::std::vector< OUString >::iterator aAutoEnd = m_aAutoColumns.end();
816 1 : for (sal_Int32 i = 1;aAutoIter != aAutoEnd && i <= nColumnCount; ++aAutoIter,++i)
817 : {
818 0 : SelectColumnsMetaData::iterator aFind = m_pKeyColumnNames->find(*aAutoIter);
819 0 : if ( aFind != m_pKeyColumnNames->end() )
820 0 : (_rInsertRow->get())[aFind->second.nPosition].fill(i, aFind->second.nType, xRow);
821 : }
822 2 : bAutoValuesFetched = true;
823 1 : }
824 1 : }
825 : }
826 0 : catch(const Exception&)
827 : {
828 : SAL_WARN("dbaccess", "Could not execute GeneratedKeys() stmt");
829 : }
830 : }
831 :
832 1 : ::comphelper::disposeComponent(xPrep);
833 :
834 1 : if ( i_sTableName.isEmpty() && !bAutoValuesFetched && m_bInserted )
835 : {
836 : // first check if all key column values were set
837 0 : const OUString sMax(" MAX(");
838 0 : const OUString sMaxEnd("),");
839 0 : const OUString sQuote = getIdentifierQuoteString();
840 0 : OUString sMaxStmt;
841 0 : aEnd = m_pKeyColumnNames->end();
842 0 : ::std::vector< OUString >::iterator aAutoIter = m_aAutoColumns.begin();
843 0 : ::std::vector< OUString >::iterator aAutoEnd = m_aAutoColumns.end();
844 0 : for (;aAutoIter != aAutoEnd; ++aAutoIter)
845 : {
846 : // we will only fetch values which are keycolumns
847 0 : SelectColumnsMetaData::iterator aFind = m_pKeyColumnNames->find(*aAutoIter);
848 0 : if ( aFind != aEnd )
849 : {
850 0 : sMaxStmt += sMax;
851 0 : sMaxStmt += ::dbtools::quoteName( sQuote,aFind->second.sRealName
852 0 : );
853 0 : sMaxStmt += sMaxEnd;
854 : }
855 : }
856 :
857 0 : if(!sMaxStmt.isEmpty())
858 : {
859 0 : sMaxStmt = sMaxStmt.replaceAt(sMaxStmt.getLength()-1,1,OUString(" "));
860 0 : OUString sStmt = "SELECT " + sMaxStmt + "FROM ";
861 0 : OUString sCatalog,sSchema,sTable;
862 0 : ::dbtools::qualifiedNameComponents(m_xConnection->getMetaData(),m_sUpdateTableName,sCatalog,sSchema,sTable,::dbtools::eInDataManipulation);
863 0 : sStmt += ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
864 : try
865 : {
866 : // now fetch the autoincrement values
867 0 : Reference<XStatement> xStatement = m_xConnection->createStatement();
868 0 : Reference<XResultSet> xRes = xStatement->executeQuery(sStmt);
869 0 : Reference<XRow> xRow(xRes,UNO_QUERY);
870 0 : if(xRow.is() && xRes->next())
871 : {
872 0 : aAutoIter = m_aAutoColumns.begin();
873 0 : for (sal_Int32 i=1;aAutoIter != aAutoEnd; ++aAutoIter,++i)
874 : {
875 : // we will only fetch values which are keycolumns
876 0 : SelectColumnsMetaData::iterator aFind = m_pKeyColumnNames->find(*aAutoIter);
877 0 : if ( aFind != aEnd )
878 0 : (_rInsertRow->get())[aFind->second.nPosition].fill(i, aFind->second.nType, xRow);
879 : }
880 : }
881 0 : ::comphelper::disposeComponent(xStatement);
882 : }
883 0 : catch(SQLException&)
884 : {
885 : SAL_WARN("dbaccess", "Could not fetch with MAX() ");
886 0 : }
887 0 : }
888 : }
889 1 : if ( m_bInserted )
890 : {
891 1 : OKeySetMatrix::iterator aKeyIter = m_aKeyMap.end();
892 1 : --aKeyIter;
893 1 : ORowSetRow aKeyRow = new connectivity::ORowVector< ORowSetValue >(m_pKeyColumnNames->size());
894 1 : copyRowValue(_rInsertRow,aKeyRow,aKeyIter->first + 1);
895 :
896 1 : m_aKeyIter = m_aKeyMap.insert(OKeySetMatrix::value_type(aKeyIter->first + 1,OKeySetValue(aKeyRow,::std::pair<sal_Int32,Reference<XRow> >(1,Reference<XRow>())))).first;
897 : // now we set the bookmark for this row
898 1 : (_rInsertRow->get())[0] = makeAny((sal_Int32)m_aKeyIter->first);
899 1 : tryRefetch(_rInsertRow,bRefetch);
900 1 : }
901 1 : }
902 :
903 2 : void OKeySet::tryRefetch(const ORowSetRow& _rInsertRow,bool bRefetch)
904 : {
905 2 : if ( bRefetch )
906 : {
907 : try
908 : {
909 2 : bRefetch = doTryRefetch_throw();
910 : }
911 0 : catch(const Exception&)
912 : {
913 0 : bRefetch = false;
914 : }
915 : }
916 2 : if ( !bRefetch )
917 : {
918 0 : m_aKeyIter->second.second.second = new OPrivateRow(_rInsertRow->get());
919 : }
920 2 : }
921 :
922 2 : void OKeySet::copyRowValue(const ORowSetRow& _rInsertRow,ORowSetRow& _rKeyRow,sal_Int32 i_nBookmark)
923 : {
924 2 : connectivity::ORowVector< ORowSetValue >::Vector::iterator aIter = _rKeyRow->get().begin();
925 :
926 : // check the if the parameter values have been changed
927 : OSL_ENSURE((m_aParameterValueForCache.get().size()-1) == m_pParameterNames->size(),"OKeySet::copyRowValue: Parameter values and names differ!");
928 2 : connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aParaValuesIter = m_aParameterValueForCache.get().begin() +1;
929 :
930 2 : bool bChanged = false;
931 2 : SelectColumnsMetaData::const_iterator aParaIter = (*m_pParameterNames).begin();
932 2 : SelectColumnsMetaData::const_iterator aParaEnd = (*m_pParameterNames).end();
933 2 : for(sal_Int32 i = 1;aParaIter != aParaEnd;++aParaIter,++aParaValuesIter,++i)
934 : {
935 0 : ORowSetValue aValue(*aParaValuesIter);
936 0 : aValue.setSigned(m_aSignedFlags[aParaIter->second.nPosition]);
937 0 : if ( (_rInsertRow->get())[aParaIter->second.nPosition] != aValue )
938 : {
939 0 : ORowSetValueVector aCopy(m_aParameterValueForCache);
940 0 : (aCopy.get())[i] = (_rInsertRow->get())[aParaIter->second.nPosition];
941 0 : m_aUpdatedParameter[i_nBookmark] = aCopy;
942 0 : bChanged = true;
943 : }
944 0 : }
945 2 : if ( !bChanged )
946 : {
947 2 : m_aUpdatedParameter.erase(i_nBookmark);
948 : }
949 :
950 : // update the key values
951 2 : SelectColumnsMetaData::const_iterator aPosIter = (*m_pKeyColumnNames).begin();
952 2 : const SelectColumnsMetaData::const_iterator aPosEnd = (*m_pKeyColumnNames).end();
953 4 : for(;aPosIter != aPosEnd;++aPosIter,++aIter)
954 : {
955 2 : impl_convertValue_throw(_rInsertRow,aPosIter->second);
956 2 : *aIter = (_rInsertRow->get())[aPosIter->second.nPosition];
957 2 : aIter->setTypeKind(aPosIter->second.nType);
958 : }
959 2 : }
960 :
961 20 : void SAL_CALL OKeySet::deleteRow(const ORowSetRow& _rDeleteRow,const connectivity::OSQLTable& _xTable ) throw(SQLException, RuntimeException)
962 : {
963 20 : Reference<XPropertySet> xSet(_xTable,UNO_QUERY);
964 20 : fillTableName(xSet);
965 :
966 40 : OUStringBuffer aSql("DELETE FROM " + m_aComposedTableName + " WHERE ");
967 :
968 : // list all columns that should be set
969 40 : OUString aQuote = getIdentifierQuoteString();
970 : static const char aAnd[] = " AND ";
971 :
972 : // use keys and indexes for exact positioning
973 40 : Reference<XNameAccess> xKeyColumns = getKeyColumns();
974 : // second the indexes
975 40 : Reference<XIndexesSupplier> xIndexSup(_xTable,UNO_QUERY);
976 40 : Reference<XIndexAccess> xIndexes;
977 20 : if ( xIndexSup.is() )
978 20 : xIndexes.set(xIndexSup->getIndexes(),UNO_QUERY);
979 :
980 : // Reference<XColumnsSupplier>
981 40 : ::std::vector< Reference<XNameAccess> > aAllIndexColumns;
982 20 : lcl_fillIndexColumns(xIndexes,aAllIndexColumns);
983 :
984 40 : OUStringBuffer sIndexCondition;
985 40 : ::std::vector<sal_Int32> aIndexColumnPositions;
986 20 : SelectColumnsMetaData::const_iterator aIter = m_pColumnNames->begin();
987 20 : SelectColumnsMetaData::const_iterator aEnd = m_pColumnNames->end();
988 :
989 20 : sal_Int32 i = 1;
990 60 : for(i = 1;aIter != aEnd;++aIter,++i)
991 : {
992 40 : if ( m_pKeyColumnNames->find(aIter->first) != m_pKeyColumnNames->end() )
993 : {
994 20 : aSql.append(::dbtools::quoteName( aQuote,aIter->second.sRealName));
995 20 : if((_rDeleteRow->get())[aIter->second.nPosition].isNull())
996 : {
997 : SAL_WARN("dbaccess", "can a primary key be null");
998 0 : aSql.append(" IS NULL");
999 : }
1000 : else
1001 20 : aSql.append(" = ?");
1002 20 : aSql.append(aAnd);
1003 : }
1004 : else
1005 : {
1006 20 : ::std::vector< Reference<XNameAccess> >::const_iterator aIndexEnd = aAllIndexColumns.end();
1007 40 : for( ::std::vector< Reference<XNameAccess> >::const_iterator aIndexIter = aAllIndexColumns.begin();
1008 : aIndexIter != aIndexEnd;++aIndexIter)
1009 : {
1010 20 : if((*aIndexIter)->hasByName(aIter->first))
1011 : {
1012 0 : sIndexCondition.append(::dbtools::quoteName( aQuote,aIter->second.sRealName));
1013 0 : if((_rDeleteRow->get())[aIter->second.nPosition].isNull())
1014 0 : sIndexCondition.append(" IS NULL");
1015 : else
1016 : {
1017 0 : sIndexCondition.append(" = ?");
1018 0 : aIndexColumnPositions.push_back(aIter->second.nPosition);
1019 : }
1020 0 : sIndexCondition.append(aAnd);
1021 :
1022 0 : break;
1023 : }
1024 : }
1025 : }
1026 : }
1027 20 : aSql.append(sIndexCondition.makeStringAndClear());
1028 20 : aSql.setLength(aSql.getLength()-5);
1029 :
1030 : // now create end execute the prepared statement
1031 40 : Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(aSql.makeStringAndClear()));
1032 40 : Reference< XParameters > xParameter(xPrep,UNO_QUERY);
1033 :
1034 20 : aIter = (*m_pKeyColumnNames).begin();
1035 20 : aEnd = (*m_pKeyColumnNames).end();
1036 20 : i = 1;
1037 40 : for(;aIter != aEnd;++aIter,++i)
1038 : {
1039 20 : setParameter(i,xParameter,(_rDeleteRow->get())[aIter->second.nPosition],aIter->second.nType,aIter->second.nScale);
1040 : }
1041 :
1042 : // now we have to set the index values
1043 20 : ::std::vector<sal_Int32>::iterator aIdxColIter = aIndexColumnPositions.begin();
1044 20 : ::std::vector<sal_Int32>::iterator aIdxColEnd = aIndexColumnPositions.end();
1045 20 : aIter = m_pColumnNames->begin();
1046 20 : for(;aIdxColIter != aIdxColEnd;++aIdxColIter,++i,++aIter)
1047 : {
1048 0 : setParameter(i,xParameter,(_rDeleteRow->get())[*aIdxColIter],(_rDeleteRow->get())[*aIdxColIter].getTypeKind(),aIter->second.nScale);
1049 : }
1050 :
1051 20 : m_bDeleted = xPrep->executeUpdate() > 0;
1052 :
1053 20 : if(m_bDeleted)
1054 : {
1055 20 : sal_Int32 nBookmark = ::comphelper::getINT32((_rDeleteRow->get())[0].getAny());
1056 20 : if(m_aKeyIter == m_aKeyMap.find(nBookmark) && m_aKeyIter != m_aKeyMap.end())
1057 10 : ++m_aKeyIter;
1058 20 : m_aKeyMap.erase(nBookmark);
1059 20 : m_bDeleted = true;
1060 20 : }
1061 20 : }
1062 :
1063 0 : void SAL_CALL OKeySet::cancelRowUpdates( ) throw(SQLException, RuntimeException)
1064 : {
1065 0 : m_bInserted = m_bUpdated = m_bDeleted = false;
1066 0 : }
1067 :
1068 0 : void SAL_CALL OKeySet::moveToInsertRow( ) throw(SQLException, RuntimeException)
1069 : {
1070 0 : }
1071 :
1072 0 : void SAL_CALL OKeySet::moveToCurrentRow( ) throw(SQLException, RuntimeException)
1073 : {
1074 0 : }
1075 :
1076 21 : Reference<XNameAccess> OKeySet::getKeyColumns() const
1077 : {
1078 : // use keys and indexes for exact positioning
1079 : // first the keys
1080 :
1081 21 : Reference<XIndexAccess> xKeys = m_xTableKeys;
1082 21 : if ( !xKeys.is() )
1083 : {
1084 21 : Reference<XPropertySet> xSet(m_xTable,UNO_QUERY);
1085 42 : const Reference<XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(xSet);
1086 42 : return xPrimaryKeyColumns;
1087 : }
1088 :
1089 0 : Reference<XColumnsSupplier> xKeyColsSup;
1090 0 : Reference<XNameAccess> xKeyColumns;
1091 0 : if(xKeys.is())
1092 : {
1093 0 : Reference<XPropertySet> xProp;
1094 0 : sal_Int32 nCount = xKeys->getCount();
1095 0 : for(sal_Int32 i = 0;i< nCount;++i)
1096 : {
1097 0 : xProp.set(xKeys->getByIndex(i),UNO_QUERY);
1098 0 : if ( xProp.is() )
1099 : {
1100 0 : sal_Int32 nKeyType = 0;
1101 0 : xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType;
1102 0 : if(KeyType::PRIMARY == nKeyType)
1103 : {
1104 0 : xKeyColsSup.set(xProp,UNO_QUERY);
1105 : OSL_ENSURE(xKeyColsSup.is(),"Columnsupplier is null!");
1106 0 : xKeyColumns = xKeyColsSup->getColumns();
1107 0 : break;
1108 : }
1109 : }
1110 0 : }
1111 : }
1112 :
1113 21 : return xKeyColumns;
1114 : }
1115 :
1116 13617 : bool SAL_CALL OKeySet::next( ) throw(SQLException, RuntimeException)
1117 : {
1118 13617 : m_bInserted = m_bUpdated = m_bDeleted = false;
1119 :
1120 13617 : if(isAfterLast())
1121 0 : return false;
1122 13617 : ++m_aKeyIter;
1123 13617 : if(!m_bRowCountFinal && m_aKeyIter == m_aKeyMap.end())
1124 : {
1125 : // not yet all records fetched, but we reached the end of those we fetched
1126 : // try to fetch one more row
1127 161 : if (fetchRow())
1128 : {
1129 : OSL_ENSURE(!isAfterLast(), "fetchRow succeeded, but isAfterLast()");
1130 157 : return true;
1131 : }
1132 : else
1133 : {
1134 : // nope, we arrived at end of data
1135 4 : m_aKeyIter = m_aKeyMap.end();
1136 : OSL_ENSURE(isAfterLast(), "fetchRow failed, but not end of data");
1137 : }
1138 : }
1139 :
1140 13460 : invalidateRow();
1141 13460 : return !isAfterLast();
1142 : }
1143 :
1144 13476 : bool SAL_CALL OKeySet::isBeforeFirst( ) throw(SQLException, RuntimeException)
1145 : {
1146 13476 : return m_aKeyIter == m_aKeyMap.begin();
1147 : }
1148 :
1149 40553 : bool SAL_CALL OKeySet::isAfterLast( ) throw(SQLException, RuntimeException)
1150 : {
1151 40553 : return m_bRowCountFinal && m_aKeyIter == m_aKeyMap.end();
1152 : }
1153 :
1154 0 : bool SAL_CALL OKeySet::isFirst( ) throw(SQLException, RuntimeException)
1155 : {
1156 0 : OKeySetMatrix::iterator aTemp = m_aKeyMap.begin();
1157 0 : ++aTemp;
1158 0 : return m_aKeyIter == aTemp && m_aKeyIter != m_aKeyMap.end();
1159 : }
1160 :
1161 0 : bool SAL_CALL OKeySet::isLast( ) throw(SQLException, RuntimeException)
1162 : {
1163 0 : if(!m_bRowCountFinal)
1164 0 : return false;
1165 :
1166 0 : OKeySetMatrix::iterator aTemp = m_aKeyMap.end();
1167 0 : --aTemp;
1168 0 : return m_aKeyIter == aTemp;
1169 : }
1170 :
1171 12 : void SAL_CALL OKeySet::beforeFirst( ) throw(SQLException, RuntimeException)
1172 : {
1173 12 : m_bInserted = m_bUpdated = m_bDeleted = false;
1174 12 : m_aKeyIter = m_aKeyMap.begin();
1175 12 : invalidateRow();
1176 12 : }
1177 :
1178 2 : void SAL_CALL OKeySet::afterLast( ) throw(SQLException, RuntimeException)
1179 : {
1180 2 : m_bInserted = m_bUpdated = m_bDeleted = false;
1181 2 : fillAllRows();
1182 2 : m_aKeyIter = m_aKeyMap.end();
1183 2 : invalidateRow();
1184 2 : }
1185 :
1186 14 : bool SAL_CALL OKeySet::first( ) throw(SQLException, RuntimeException)
1187 : {
1188 14 : m_bInserted = m_bUpdated = m_bDeleted = false;
1189 14 : m_aKeyIter = m_aKeyMap.begin();
1190 14 : ++m_aKeyIter;
1191 14 : if(m_aKeyIter == m_aKeyMap.end())
1192 : {
1193 0 : if (!fetchRow())
1194 : {
1195 0 : m_aKeyIter = m_aKeyMap.end();
1196 0 : return false;
1197 : }
1198 : }
1199 : else
1200 14 : invalidateRow();
1201 14 : return m_aKeyIter != m_aKeyMap.end() && m_aKeyIter != m_aKeyMap.begin();
1202 : }
1203 :
1204 20 : bool SAL_CALL OKeySet::last( ) throw(SQLException, RuntimeException)
1205 : {
1206 20 : return last_checked(true);
1207 : }
1208 :
1209 21 : bool OKeySet::last_checked( bool /* i_bFetchRow */ )
1210 : {
1211 21 : m_bInserted = m_bUpdated = m_bDeleted = false;
1212 21 : bool fetchedRow = fillAllRows();
1213 :
1214 21 : m_aKeyIter = m_aKeyMap.end();
1215 21 : --m_aKeyIter;
1216 21 : if ( !fetchedRow )
1217 : {
1218 17 : invalidateRow();
1219 : }
1220 21 : return m_aKeyIter != m_aKeyMap.end() && m_aKeyIter != m_aKeyMap.begin();
1221 : }
1222 :
1223 4533 : sal_Int32 SAL_CALL OKeySet::getRow( ) throw(SQLException, RuntimeException)
1224 : {
1225 : OSL_ENSURE(!isAfterLast(),"getRow is not allowed when afterlast record!");
1226 : OSL_ENSURE(!isBeforeFirst(),"getRow is not allowed when beforefirst record!");
1227 :
1228 4533 : return ::std::distance(m_aKeyMap.begin(),m_aKeyIter);
1229 : }
1230 :
1231 1845 : bool SAL_CALL OKeySet::absolute( sal_Int32 row ) throw(SQLException, RuntimeException)
1232 : {
1233 1845 : return absolute_checked(row,true);
1234 : }
1235 :
1236 1845 : bool OKeySet::absolute_checked( sal_Int32 row, bool /* i_bFetchRow */ )
1237 : {
1238 1845 : m_bInserted = m_bUpdated = m_bDeleted = false;
1239 : OSL_ENSURE(row,"absolute(0) isn't allowed!");
1240 1845 : bool fetchedRow = false;
1241 1845 : if(row < 0)
1242 : {
1243 0 : if(!m_bRowCountFinal)
1244 0 : fetchedRow = fillAllRows();
1245 :
1246 0 : for(;row < 0 && m_aKeyIter != m_aKeyMap.begin();++row)
1247 0 : --m_aKeyIter;
1248 : }
1249 : else
1250 : {
1251 1845 : if(row >= (sal_Int32)m_aKeyMap.size())
1252 : {
1253 : // we don't have this row
1254 10 : if(!m_bRowCountFinal)
1255 : {
1256 : // but there may still be rows to fetch.
1257 9 : bool bNext = true;
1258 18 : for(sal_Int32 i=m_aKeyMap.size()-1;i < row && bNext;++i)
1259 9 : bNext = fetchRow();
1260 : // it is guaranteed that the above loop has executed at least once,
1261 : // that is fetchRow called at least once.
1262 9 : if ( bNext )
1263 : {
1264 8 : fetchedRow = true;
1265 : }
1266 : else
1267 : {
1268 : // reached end of data before desired row
1269 1 : m_aKeyIter = m_aKeyMap.end();
1270 1 : return false;
1271 : }
1272 : }
1273 : else
1274 : {
1275 : // no more rows to fetch -> fail
1276 1 : m_aKeyIter = m_aKeyMap.end();
1277 1 : return false;
1278 : }
1279 : }
1280 : else
1281 : {
1282 1835 : m_aKeyIter = m_aKeyMap.begin();
1283 105030 : for(;row > 0 && m_aKeyIter != m_aKeyMap.end();--row)
1284 103195 : ++m_aKeyIter;
1285 : }
1286 : }
1287 1843 : if ( !fetchedRow )
1288 : {
1289 1835 : invalidateRow();
1290 : }
1291 :
1292 1843 : return m_aKeyIter != m_aKeyMap.end() && m_aKeyIter != m_aKeyMap.begin();
1293 : }
1294 :
1295 0 : bool SAL_CALL OKeySet::relative( sal_Int32 rows ) throw(SQLException, RuntimeException)
1296 : {
1297 0 : if(!rows)
1298 : {
1299 0 : invalidateRow();
1300 0 : return true;
1301 : }
1302 0 : return absolute(getRow()+rows);
1303 : }
1304 :
1305 5 : bool OKeySet::previous_checked( bool /* i_bFetchRow */ )
1306 : {
1307 5 : m_bInserted = m_bUpdated = m_bDeleted = false;
1308 5 : if(m_aKeyIter != m_aKeyMap.begin())
1309 : {
1310 5 : --m_aKeyIter;
1311 5 : invalidateRow();
1312 : }
1313 5 : return m_aKeyIter != m_aKeyMap.begin();
1314 : }
1315 :
1316 0 : bool SAL_CALL OKeySet::previous( ) throw(SQLException, RuntimeException)
1317 : {
1318 0 : return previous_checked(true);
1319 : }
1320 :
1321 13478 : bool OKeySet::doTryRefetch_throw() throw(SQLException, RuntimeException)
1322 : {
1323 13478 : ensureStatement( );
1324 : // we just reassign the base members
1325 13478 : Reference< XParameters > xParameter(m_xStatement,UNO_QUERY);
1326 : OSL_ENSURE(xParameter.is(),"No Parameter interface!");
1327 13478 : xParameter->clearParameters();
1328 :
1329 13478 : sal_Int32 nPos=1;
1330 13478 : connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aParaIter;
1331 13478 : connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aParaEnd;
1332 13478 : OUpdatedParameter::iterator aUpdateFind = m_aUpdatedParameter.find(m_aKeyIter->first);
1333 13478 : if ( aUpdateFind == m_aUpdatedParameter.end() )
1334 : {
1335 13478 : aParaIter = m_aParameterValueForCache.get().begin();
1336 13478 : aParaEnd = m_aParameterValueForCache.get().end();
1337 : }
1338 : else
1339 : {
1340 0 : aParaIter = aUpdateFind->second.get().begin();
1341 0 : aParaEnd = aUpdateFind->second.get().end();
1342 : }
1343 :
1344 13478 : for(++aParaIter;aParaIter != aParaEnd;++aParaIter,++nPos)
1345 : {
1346 0 : ::dbtools::setObjectWithInfo( xParameter, nPos, aParaIter->makeAny(), aParaIter->getTypeKind() );
1347 : }
1348 :
1349 : // now set the primary key column values
1350 13478 : connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aIter = m_aKeyIter->second.first->get().begin();
1351 13478 : SelectColumnsMetaData::const_iterator aPosIter = m_pKeyColumnNames->begin();
1352 13478 : SelectColumnsMetaData::const_iterator aPosEnd = m_pKeyColumnNames->end();
1353 26956 : for(;aPosIter != aPosEnd;++aPosIter,++aIter)
1354 13478 : setOneKeyColumnParameter(nPos,xParameter,*aIter,aPosIter->second.nType,aPosIter->second.nScale);
1355 13478 : aPosIter = m_pForeignColumnNames->begin();
1356 13478 : aPosEnd = m_pForeignColumnNames->end();
1357 13478 : for(;aPosIter != aPosEnd;++aPosIter,++aIter)
1358 0 : setOneKeyColumnParameter(nPos,xParameter,*aIter,aPosIter->second.nType,aPosIter->second.nScale);
1359 :
1360 13478 : m_xSet = m_xStatement->executeQuery();
1361 : OSL_ENSURE(m_xSet.is(),"No resultset from statement!");
1362 13478 : return m_xSet->next();
1363 : }
1364 :
1365 13476 : void SAL_CALL OKeySet::refreshRow() throw(SQLException, RuntimeException)
1366 : {
1367 13476 : invalidateRow();
1368 :
1369 13476 : if(isBeforeFirst() || isAfterLast())
1370 0 : return;
1371 :
1372 13476 : if ( m_aKeyIter->second.second.second.is() )
1373 : {
1374 0 : m_xRow = m_aKeyIter->second.second.second;
1375 0 : return;
1376 : }
1377 :
1378 13476 : bool bOK = doTryRefetch_throw();
1379 13476 : if ( !bOK )
1380 : {
1381 : // This row has disappeared; remove it.
1382 0 : OKeySetMatrix::iterator aTemp = m_aKeyIter;
1383 : // use *next* row
1384 0 : ++m_aKeyIter;
1385 0 : m_aKeyMap.erase(aTemp);
1386 :
1387 : // adjust RowCount for the row we have removed
1388 0 : if (m_rRowCount > 0)
1389 0 : --m_rRowCount;
1390 : else
1391 : SAL_WARN("dbaccess", "m_rRowCount got out of sync: non-empty m_aKeyMap, but m_rRowCount <= 0");
1392 :
1393 0 : if (m_aKeyIter == m_aKeyMap.end())
1394 : {
1395 0 : ::comphelper::disposeComponent(m_xSet);
1396 0 : if (!isAfterLast())
1397 : {
1398 : // it was the last fetched row,
1399 : // but there may be another one to fetch
1400 0 : if (!fetchRow())
1401 : {
1402 : // nope, that really was the last
1403 0 : m_aKeyIter = m_aKeyMap.end();
1404 : OSL_ENSURE(isAfterLast(), "fetchRow() failed but not isAfterLast()!");
1405 : }
1406 : }
1407 : // Now, either fetchRow has set m_xRow or isAfterLast()
1408 : }
1409 : else
1410 : {
1411 0 : refreshRow();
1412 : }
1413 : }
1414 : else
1415 : {
1416 13476 : m_xRow.set(m_xSet,UNO_QUERY);
1417 : OSL_ENSURE(m_xRow.is(),"No row from statement!");
1418 : }
1419 : }
1420 :
1421 526 : bool OKeySet::fetchRow()
1422 : {
1423 : // fetch the next row and append on the keyset
1424 526 : bool bRet = false;
1425 526 : if ( !m_bRowCountFinal && (!m_nMaxRows || sal_Int32(m_aKeyMap.size()) < m_nMaxRows) )
1426 526 : bRet = m_xDriverSet->next();
1427 526 : if ( bRet )
1428 : {
1429 517 : ORowSetRow aKeyRow = new connectivity::ORowVector< ORowSetValue >((*m_pKeyColumnNames).size() + m_pForeignColumnNames->size());
1430 :
1431 517 : ::comphelper::disposeComponent(m_xSet);
1432 517 : m_xRow.set(m_xDriverRow, UNO_QUERY_THROW);
1433 :
1434 517 : connectivity::ORowVector< ORowSetValue >::Vector::iterator aIter = aKeyRow->get().begin();
1435 : // copy key columns
1436 517 : SelectColumnsMetaData::const_iterator aPosIter = (*m_pKeyColumnNames).begin();
1437 517 : SelectColumnsMetaData::const_iterator aPosEnd = (*m_pKeyColumnNames).end();
1438 1034 : for(;aPosIter != aPosEnd;++aPosIter,++aIter)
1439 : {
1440 517 : const SelectColumnDescription& rColDesc = aPosIter->second;
1441 517 : aIter->fill(rColDesc.nPosition, rColDesc.nType, m_xRow);
1442 : }
1443 : // copy missing columns from other tables
1444 517 : aPosIter = (*m_pForeignColumnNames).begin();
1445 517 : aPosEnd = (*m_pForeignColumnNames).end();
1446 517 : for(;aPosIter != aPosEnd;++aPosIter,++aIter)
1447 : {
1448 0 : const SelectColumnDescription& rColDesc = aPosIter->second;
1449 0 : aIter->fill(rColDesc.nPosition, rColDesc.nType, m_xRow);
1450 : }
1451 517 : 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;
1452 : }
1453 : else
1454 9 : m_bRowCountFinal = true;
1455 526 : return bRet;
1456 : }
1457 :
1458 23 : bool OKeySet::fillAllRows()
1459 : {
1460 23 : if(m_bRowCountFinal)
1461 : {
1462 19 : return false;
1463 : }
1464 : else
1465 : {
1466 4 : while(fetchRow())
1467 : ;
1468 4 : return true;
1469 : }
1470 : }
1471 :
1472 : // XRow
1473 27451 : sal_Bool SAL_CALL OKeySet::wasNull( ) throw(SQLException, RuntimeException, std::exception)
1474 : {
1475 27451 : if ( ! m_xRow.is() )
1476 0 : throwGenericSQLException("Must call getFOO() for some FOO before wasNull()", *this);
1477 :
1478 : OSL_ENSURE(m_xRow.is(),"m_xRow is null! I've thrown, but function execution continued?");
1479 27451 : return m_xRow->wasNull();
1480 : }
1481 :
1482 27451 : inline void OKeySet::ensureRowForData( ) throw(SQLException, RuntimeException)
1483 : {
1484 27451 : if (! m_xRow.is() )
1485 13475 : refreshRow();
1486 27451 : if (! m_xRow.is() )
1487 0 : throwSQLException("Failed to refetch row", "02000", *this, -2);
1488 :
1489 : OSL_ENSURE(m_xRow.is(),"m_xRow is null! I've called throwSQLException but execution continued?");
1490 27451 : }
1491 :
1492 13739 : OUString SAL_CALL OKeySet::getString( sal_Int32 columnIndex ) throw(SQLException, RuntimeException, std::exception)
1493 : {
1494 13739 : ensureRowForData();
1495 13739 : return m_xRow->getString(columnIndex);
1496 : }
1497 :
1498 0 : sal_Bool SAL_CALL OKeySet::getBoolean( sal_Int32 columnIndex ) throw(SQLException, RuntimeException, std::exception)
1499 : {
1500 0 : ensureRowForData();
1501 0 : return m_xRow->getBoolean(columnIndex);
1502 : }
1503 :
1504 0 : sal_Int8 SAL_CALL OKeySet::getByte( sal_Int32 columnIndex ) throw(SQLException, RuntimeException, std::exception)
1505 : {
1506 0 : ensureRowForData();
1507 0 : return m_xRow->getByte(columnIndex);
1508 : }
1509 :
1510 0 : sal_Int16 SAL_CALL OKeySet::getShort( sal_Int32 columnIndex ) throw(SQLException, RuntimeException, std::exception)
1511 : {
1512 0 : ensureRowForData();
1513 0 : return m_xRow->getShort(columnIndex);
1514 : }
1515 :
1516 13676 : sal_Int32 SAL_CALL OKeySet::getInt( sal_Int32 columnIndex ) throw(SQLException, RuntimeException, std::exception)
1517 : {
1518 13676 : ensureRowForData();
1519 13676 : return m_xRow->getInt(columnIndex);
1520 : }
1521 :
1522 0 : sal_Int64 SAL_CALL OKeySet::getLong( sal_Int32 columnIndex ) throw(SQLException, RuntimeException, std::exception)
1523 : {
1524 0 : ensureRowForData();
1525 0 : return m_xRow->getLong(columnIndex);
1526 : }
1527 :
1528 0 : float SAL_CALL OKeySet::getFloat( sal_Int32 columnIndex ) throw(SQLException, RuntimeException, std::exception)
1529 : {
1530 0 : ensureRowForData();
1531 0 : return m_xRow->getFloat(columnIndex);
1532 : }
1533 :
1534 0 : double SAL_CALL OKeySet::getDouble( sal_Int32 columnIndex ) throw(SQLException, RuntimeException, std::exception)
1535 : {
1536 0 : ensureRowForData();
1537 0 : return m_xRow->getDouble(columnIndex);
1538 : }
1539 :
1540 0 : Sequence< sal_Int8 > SAL_CALL OKeySet::getBytes( sal_Int32 columnIndex ) throw(SQLException, RuntimeException, std::exception)
1541 : {
1542 0 : ensureRowForData();
1543 0 : return m_xRow->getBytes(columnIndex);
1544 : }
1545 :
1546 36 : ::com::sun::star::util::Date SAL_CALL OKeySet::getDate( sal_Int32 columnIndex ) throw(SQLException, RuntimeException, std::exception)
1547 : {
1548 36 : ensureRowForData();
1549 36 : return m_xRow->getDate(columnIndex);
1550 : }
1551 :
1552 0 : ::com::sun::star::util::Time SAL_CALL OKeySet::getTime( sal_Int32 columnIndex ) throw(SQLException, RuntimeException, std::exception)
1553 : {
1554 0 : ensureRowForData();
1555 0 : return m_xRow->getTime(columnIndex);
1556 : }
1557 :
1558 0 : ::com::sun::star::util::DateTime SAL_CALL OKeySet::getTimestamp( sal_Int32 columnIndex ) throw(SQLException, RuntimeException, std::exception)
1559 : {
1560 0 : ensureRowForData();
1561 0 : return m_xRow->getTimestamp(columnIndex);
1562 : }
1563 :
1564 0 : Reference< ::com::sun::star::io::XInputStream > SAL_CALL OKeySet::getBinaryStream( sal_Int32 columnIndex ) throw(SQLException, RuntimeException, std::exception)
1565 : {
1566 0 : ensureRowForData();
1567 0 : return m_xRow->getBinaryStream(columnIndex);
1568 : }
1569 :
1570 0 : Reference< ::com::sun::star::io::XInputStream > SAL_CALL OKeySet::getCharacterStream( sal_Int32 columnIndex ) throw(SQLException, RuntimeException, std::exception)
1571 : {
1572 0 : ensureRowForData();
1573 0 : return m_xRow->getCharacterStream(columnIndex);
1574 : }
1575 :
1576 0 : Any SAL_CALL OKeySet::getObject( sal_Int32 columnIndex, const Reference< ::com::sun::star::container::XNameAccess >& typeMap ) throw(SQLException, RuntimeException, std::exception)
1577 : {
1578 0 : ensureRowForData();
1579 0 : return m_xRow->getObject(columnIndex,typeMap);
1580 : }
1581 :
1582 0 : Reference< XRef > SAL_CALL OKeySet::getRef( sal_Int32 columnIndex ) throw(SQLException, RuntimeException, std::exception)
1583 : {
1584 0 : ensureRowForData();
1585 0 : return m_xRow->getRef(columnIndex);
1586 : }
1587 :
1588 0 : Reference< XBlob > SAL_CALL OKeySet::getBlob( sal_Int32 columnIndex ) throw(SQLException, RuntimeException, std::exception)
1589 : {
1590 0 : ensureRowForData();
1591 0 : return m_xRow->getBlob(columnIndex);
1592 : }
1593 :
1594 0 : Reference< XClob > SAL_CALL OKeySet::getClob( sal_Int32 columnIndex ) throw(SQLException, RuntimeException, std::exception)
1595 : {
1596 0 : ensureRowForData();
1597 0 : return m_xRow->getClob(columnIndex);
1598 : }
1599 :
1600 0 : Reference< XArray > SAL_CALL OKeySet::getArray( sal_Int32 columnIndex ) throw(SQLException, RuntimeException, std::exception)
1601 : {
1602 0 : ensureRowForData();
1603 0 : return m_xRow->getArray(columnIndex);
1604 : }
1605 :
1606 0 : bool SAL_CALL OKeySet::rowUpdated( ) throw(SQLException, RuntimeException)
1607 : {
1608 0 : return m_aKeyIter != m_aKeyMap.begin() && m_aKeyIter != m_aKeyMap.end() && m_aKeyIter->second.second.first == 2;
1609 : }
1610 :
1611 1 : bool SAL_CALL OKeySet::rowInserted( ) throw(SQLException, RuntimeException)
1612 : {
1613 1 : return m_aKeyIter != m_aKeyMap.begin() && m_aKeyIter != m_aKeyMap.end() && m_aKeyIter->second.second.first == 1;
1614 : }
1615 :
1616 20 : bool SAL_CALL OKeySet::rowDeleted( ) throw(SQLException, RuntimeException)
1617 : {
1618 20 : bool bDeleted = m_bDeleted;
1619 20 : m_bDeleted = false;
1620 20 : return bDeleted;
1621 : }
1622 :
1623 : namespace dbaccess
1624 : {
1625 :
1626 45 : void getColumnPositions(const Reference<XNameAccess>& _rxQueryColumns,
1627 : const ::com::sun::star::uno::Sequence< OUString >& _aColumnNames,
1628 : const OUString& _rsUpdateTableName,
1629 : SelectColumnsMetaData& o_rColumnNames,
1630 : bool i_bAppendTableName)
1631 : {
1632 : // get the real name of the columns
1633 45 : Sequence< OUString> aSelNames(_rxQueryColumns->getElementNames());
1634 45 : const OUString* pSelIter = aSelNames.getConstArray();
1635 45 : const OUString* pSelEnd = pSelIter + aSelNames.getLength();
1636 :
1637 45 : const OUString* pTblColumnIter = _aColumnNames.getConstArray();
1638 45 : const OUString* pTblColumnEnd = pTblColumnIter + _aColumnNames.getLength();
1639 :
1640 45 : ::comphelper::UStringMixEqual bCase(o_rColumnNames.key_comp().isCaseSensitive());
1641 :
1642 275 : for(sal_Int32 nPos = 1;pSelIter != pSelEnd;++pSelIter,++nPos)
1643 : {
1644 230 : Reference<XPropertySet> xQueryColumnProp(_rxQueryColumns->getByName(*pSelIter),UNO_QUERY_THROW);
1645 460 : OUString sRealName,sTableName;
1646 : OSL_ENSURE(xQueryColumnProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME),"Property REALNAME not available!");
1647 : OSL_ENSURE(xQueryColumnProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME),"Property TABLENAME not available!");
1648 230 : xQueryColumnProp->getPropertyValue(PROPERTY_REALNAME) >>= sRealName;
1649 230 : xQueryColumnProp->getPropertyValue(PROPERTY_TABLENAME) >>= sTableName;
1650 :
1651 807 : for(;pTblColumnIter != pTblColumnEnd;++pTblColumnIter)
1652 : {
1653 689 : if(bCase(sRealName,*pTblColumnIter) && bCase(_rsUpdateTableName,sTableName) && o_rColumnNames.find(*pTblColumnIter) == o_rColumnNames.end())
1654 : {
1655 112 : sal_Int32 nType = 0;
1656 112 : xQueryColumnProp->getPropertyValue(PROPERTY_TYPE) >>= nType;
1657 112 : sal_Int32 nScale = 0;
1658 112 : xQueryColumnProp->getPropertyValue(PROPERTY_SCALE) >>= nScale;
1659 112 : OUString sColumnDefault;
1660 112 : if ( xQueryColumnProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_DEFAULTVALUE) )
1661 112 : xQueryColumnProp->getPropertyValue(PROPERTY_DEFAULTVALUE) >>= sColumnDefault;
1662 :
1663 112 : sal_Int32 nNullable = ColumnValue::NULLABLE_UNKNOWN;
1664 112 : OSL_VERIFY( xQueryColumnProp->getPropertyValue( PROPERTY_ISNULLABLE ) >>= nNullable );
1665 :
1666 224 : SelectColumnDescription aColDesc( nPos, nType, nScale, nNullable != sdbc::ColumnValue::NO_NULLS, sColumnDefault );
1667 224 : OUString sName;
1668 112 : if ( i_bAppendTableName )
1669 : {
1670 57 : sName = sTableName + "." + sRealName;
1671 57 : aColDesc.sRealName = sRealName;
1672 57 : aColDesc.sTableName = sTableName;
1673 : }
1674 : else
1675 : {
1676 55 : sName = sRealName;
1677 : }
1678 112 : o_rColumnNames[sName] = aColDesc;
1679 :
1680 224 : break;
1681 : }
1682 : }
1683 230 : pTblColumnIter = _aColumnNames.getConstArray();
1684 275 : }
1685 45 : }
1686 : }
1687 :
1688 6 : void OKeySet::impl_convertValue_throw(const ORowSetRow& _rInsertRow,const SelectColumnDescription& i_aMetaData)
1689 : {
1690 6 : ORowSetValue& aValue((_rInsertRow->get())[i_aMetaData.nPosition]);
1691 6 : switch(i_aMetaData.nType)
1692 : {
1693 : case DataType::DECIMAL:
1694 : case DataType::NUMERIC:
1695 : {
1696 0 : OUString sValue = aValue.getString();
1697 0 : sal_Int32 nIndex = sValue.indexOf('.');
1698 0 : if ( nIndex != -1 )
1699 : {
1700 0 : aValue = sValue.copy(0,::std::min(sValue.getLength(),nIndex + (i_aMetaData.nScale > 0 ? i_aMetaData.nScale + 1 : 0)));
1701 0 : }
1702 : }
1703 0 : break;
1704 : default:
1705 6 : break;
1706 : }
1707 6 : }
1708 :
1709 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|