LibreOffice Module dbaccess (master) 1
RowSetCache.cxx
Go to the documentation of this file.
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 <memory>
21#include "BookmarkSet.hxx"
22#include "KeySet.hxx"
23#include "OptimisticSet.hxx"
24#include "RowSetBase.hxx"
25#include "RowSetCache.hxx"
26#include "StaticSet.hxx"
27#include "WrappedResultSet.hxx"
28#include <core_resource.hxx>
29#include <strings.hrc>
30#include <strings.hxx>
31
32#include <com/sun/star/sdbc/ColumnValue.hpp>
33#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
34#include <com/sun/star/sdbc/ResultSetType.hpp>
35#include <com/sun/star/sdbcx/CompareBookmark.hpp>
36#include <com/sun/star/sdbcx/Privilege.hpp>
37#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
38#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
39
41#include <comphelper/types.hxx>
47#include <sqlbison.hxx>
49#include <o3tl/safeint.hxx>
50#include <osl/diagnose.h>
51
52#include <algorithm>
53
54using namespace dbaccess;
55using namespace dbtools;
56using namespace connectivity;
57using namespace ::com::sun::star::uno;
58using namespace ::com::sun::star::beans;
59using namespace ::com::sun::star::sdbc;
60using namespace ::com::sun::star::sdb;
61using namespace ::com::sun::star::sdbcx;
62using namespace ::com::sun::star::container;
63using namespace ::com::sun::star::lang;
64using namespace ::cppu;
65using namespace ::osl;
66
67// This class calls m_pCacheSet->FOO_checked(..., sal_False)
68// (where FOO is absolute, last, previous)
69// when it does not immediately care about the values in the row's columns.
70// As a corollary, m_pCacheSet may be left in an inconsistent state,
71// and all ->fillFOO calls (and ->getFOO) may fail or give wrong results,
72// until m_pCacheSet is moved (or refreshed) again.
73// So always make sure m_pCacheSet is moved or refreshed before accessing column values.
74
75
76ORowSetCache::ORowSetCache(const Reference< XResultSet >& _xRs,
77 const Reference< XSingleSelectQueryAnalyzer >& _xAnalyzer,
78 const Reference<XComponentContext>& _rContext,
79 const OUString& _rUpdateTableName,
80 bool& _bModified,
81 bool& _bNew,
82 const ORowSetValueVector& _aParameterValueForCache,
83 const OUString& i_sRowSetFilter,
84 sal_Int32 i_nMaxRows)
85 :m_xSet(_xRs)
86 ,m_xMetaData(Reference< XResultSetMetaDataSupplier >(_xRs,UNO_QUERY_THROW)->getMetaData())
87 ,m_aContext( _rContext )
88 ,m_nFetchSize(0)
89 ,m_nRowCount(0)
90 ,m_nPrivileges( Privilege::SELECT )
91 ,m_nPosition(0)
92 ,m_nStartPos(0)
93 ,m_nEndPos(0)
94 ,m_bRowCountFinal(false)
95 ,m_bBeforeFirst(true)
96 ,m_bAfterLast( false )
97 ,m_bModified(_bModified)
98 ,m_bNew(_bNew)
99{
100
101 // first try if the result can be used to do inserts and updates
102 Reference< XPropertySet> xProp(_xRs,UNO_QUERY);
103 Reference< XPropertySetInfo > xPropInfo = xProp->getPropertySetInfo();
104 bool bBookmarkable = false;
105 try
106 {
107 Reference< XResultSetUpdate> xUp(_xRs,UNO_QUERY_THROW);
108 bBookmarkable = xPropInfo->hasPropertyByName(PROPERTY_ISBOOKMARKABLE) &&
109 any2bool(xProp->getPropertyValue(PROPERTY_ISBOOKMARKABLE)) && Reference< XRowLocate >(_xRs, UNO_QUERY).is();
110 if ( bBookmarkable )
111 {
112 xUp->moveToInsertRow();
113 xUp->cancelRowUpdates();
114 _xRs->beforeFirst();
115 m_nPrivileges = Privilege::SELECT|Privilege::DELETE|Privilege::INSERT|Privilege::UPDATE;
116 m_xCacheSet = new WrappedResultSet(i_nMaxRows);
117 m_xCacheSet->construct(_xRs,i_sRowSetFilter);
118 return;
119 }
120 }
121 catch(const Exception&)
122 {
123 DBG_UNHANDLED_EXCEPTION("dbaccess.core");
124 }
125 try
126 {
127 if ( xPropInfo->hasPropertyByName(PROPERTY_RESULTSETTYPE) &&
128 ::comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETTYPE)) != ResultSetType::FORWARD_ONLY)
129 _xRs->beforeFirst();
130 }
131 catch(const SQLException&)
132 {
133 TOOLS_WARN_EXCEPTION("dbaccess.core", "ORowSetCache");
134 }
135
136 // check if all keys of the updateable table are fetched
137 bool bAllKeysFound = false;
138 sal_Int32 nTablesCount = 0;
139
140 bool bNeedKeySet = !bBookmarkable || (xPropInfo->hasPropertyByName(PROPERTY_RESULTSETCONCURRENCY) &&
141 ::comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY)) == ResultSetConcurrency::READ_ONLY);
142
143 OUString aUpdateTableName = _rUpdateTableName;
144 Reference< XConnection> xConnection;
145 // first we need a connection
146 Reference< XStatement> xStmt(_xRs->getStatement(),UNO_QUERY);
147 if(xStmt.is())
148 xConnection = xStmt->getConnection();
149 else
150 {
151 Reference< XPreparedStatement> xPrepStmt(_xRs->getStatement(),UNO_QUERY);
152 xConnection = xPrepStmt->getConnection();
153 }
154 OSL_ENSURE(xConnection.is(),"No connection!");
155 if(_xAnalyzer.is())
156 {
157 try
158 {
159 Reference<XTablesSupplier> xTabSup(_xAnalyzer,UNO_QUERY);
160 OSL_ENSURE(xTabSup.is(),"ORowSet::execute composer isn't a tablesupplier!");
161 Reference<XNameAccess> xTables = xTabSup->getTables();
162 Sequence< OUString> aTableNames = xTables->getElementNames();
163 if ( aTableNames.getLength() > 1 && _rUpdateTableName.isEmpty() && bNeedKeySet )
164 {// here we have a join or union and nobody told us which table to update, so we update them all
165 m_nPrivileges = Privilege::SELECT|Privilege::DELETE|Privilege::INSERT|Privilege::UPDATE;
166 rtl::Reference<OptimisticSet> pCursor = new OptimisticSet(m_aContext,xConnection,_xAnalyzer,_aParameterValueForCache,i_nMaxRows,m_nRowCount);
167 m_xCacheSet = pCursor;
168 try
169 {
170 m_xCacheSet->construct(_xRs,i_sRowSetFilter);
171 if ( pCursor->isReadOnly() )
172 m_nPrivileges = Privilege::SELECT;
173 m_aKeyColumns = pCursor->getJoinedKeyColumns();
174 return;
175 }
176 catch (const Exception&)
177 {
178 TOOLS_WARN_EXCEPTION("dbaccess.core", "ORowSetCache");
179 }
180 m_xCacheSet.clear();
181 }
182 else
183 {
184 if(!_rUpdateTableName.isEmpty() && xTables->hasByName(_rUpdateTableName))
185 xTables->getByName(_rUpdateTableName) >>= m_aUpdateTable;
186 else if(xTables->getElementNames().hasElements())
187 {
188 aUpdateTableName = xTables->getElementNames()[0];
189 xTables->getByName(aUpdateTableName) >>= m_aUpdateTable;
190 }
191 Reference<XIndexAccess> xIndexAccess(xTables,UNO_QUERY);
192 if(xIndexAccess.is())
193 nTablesCount = xIndexAccess->getCount();
194 else
195 nTablesCount = xTables->getElementNames().getLength();
196
197 if(m_aUpdateTable.is() && nTablesCount < 3) // for we can't handle more than 2 tables in our keyset
198 {
199 Reference<XPropertySet> xSet(m_aUpdateTable,UNO_QUERY);
200 const Reference<XNameAccess> xPrimaryKeyColumns = dbtools::getPrimaryKeyColumns_throw(xSet);
201 if ( xPrimaryKeyColumns.is() )
202 {
203 Reference<XColumnsSupplier> xColSup(_xAnalyzer,UNO_QUERY);
204 if ( xColSup.is() )
205 {
206 Reference<XNameAccess> xSelColumns = xColSup->getColumns();
207 Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
208 SelectColumnsMetaData aColumnNames(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers());
209 ::dbaccess::getColumnPositions(xSelColumns,xPrimaryKeyColumns->getElementNames(),aUpdateTableName,aColumnNames);
210 bAllKeysFound = !aColumnNames.empty() && aColumnNames.size() == o3tl::make_unsigned(xPrimaryKeyColumns->getElementNames().getLength());
211 }
212 }
213 }
214 }
215 }
216 catch (Exception const&)
217 {
218 TOOLS_WARN_EXCEPTION("dbaccess.core", "ORowSetCache");
219 }
220 }
221
222 // first check if resultset is bookmarkable
223 if(!bNeedKeySet)
224 {
225 try
226 {
227 m_xCacheSet = new OBookmarkSet(i_nMaxRows);
228 m_xCacheSet->construct(_xRs,i_sRowSetFilter);
229
230 // check privileges
231 m_nPrivileges = Privilege::SELECT;
232 if(Reference<XResultSetUpdate>(_xRs,UNO_QUERY).is()) // this interface is optional so we have to check it
233 {
234 Reference<XPropertySet> xTable(m_aUpdateTable,UNO_QUERY);
235 if(xTable.is() && xTable->getPropertySetInfo()->hasPropertyByName(PROPERTY_PRIVILEGES))
236 {
237 m_nPrivileges = 0;
238 xTable->getPropertyValue(PROPERTY_PRIVILEGES) >>= m_nPrivileges;
239 if(!m_nPrivileges)
240 m_nPrivileges = Privilege::SELECT;
241 }
242 }
243 }
244 catch (const SQLException&)
245 {
246 TOOLS_WARN_EXCEPTION("dbaccess.core", "ORowSetCache");
247 bNeedKeySet = true;
248 }
249
250 }
251 if(bNeedKeySet)
252 {
253 // need to check if we could handle this select clause
254 bAllKeysFound = bAllKeysFound && (nTablesCount == 1 || checkJoin(xConnection,_xAnalyzer,aUpdateTableName));
255
256 if(!bAllKeysFound )
257 {
258 if ( bBookmarkable )
259 {
260 // here I know that we have a read only bookmarkable cursor
261 _xRs->beforeFirst();
262 m_nPrivileges = Privilege::SELECT;
263 m_xCacheSet = new WrappedResultSet(i_nMaxRows);
264 m_xCacheSet->construct(_xRs,i_sRowSetFilter);
265 return;
266 }
267 m_xCacheSet = new OStaticSet(i_nMaxRows);
268 m_xCacheSet->construct(_xRs,i_sRowSetFilter);
269 m_nPrivileges = Privilege::SELECT;
270 }
271 else
272 {
273 Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
274 SelectColumnsMetaData aColumnNames(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers());
275 Reference<XColumnsSupplier> xColSup(_xAnalyzer,UNO_QUERY);
276 Reference<XNameAccess> xSelColumns = xColSup->getColumns();
277 Reference<XNameAccess> xColumns = m_aUpdateTable->getColumns();
278 ::dbaccess::getColumnPositions(xSelColumns,xColumns->getElementNames(),aUpdateTableName,aColumnNames);
279
280 // check privileges
281 m_nPrivileges = Privilege::SELECT;
282 bool bNoInsert = false;
283
284 Sequence< OUString> aNames(xColumns->getElementNames());
285 const OUString* pIter = aNames.getConstArray();
286 const OUString* pEnd = pIter + aNames.getLength();
287 for(;pIter != pEnd;++pIter)
288 {
289 Reference<XPropertySet> xColumn(xColumns->getByName(*pIter),UNO_QUERY);
290 OSL_ENSURE(xColumn.is(),"Column in table is null!");
291 if(xColumn.is())
292 {
293 sal_Int32 nNullable = 0;
294 xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable;
295 if(nNullable == ColumnValue::NO_NULLS && aColumnNames.find(*pIter) == aColumnNames.end())
296 { // we found a column where null is not allowed so we can't insert new values
297 bNoInsert = true;
298 break; // one column is enough
299 }
300 }
301 }
302
303 rtl::Reference<OKeySet> pKeySet = new OKeySet(m_aUpdateTable, aUpdateTableName ,_xAnalyzer,_aParameterValueForCache,i_nMaxRows,m_nRowCount);
304 try
305 {
306 m_xCacheSet = pKeySet;
307 pKeySet->construct(_xRs,i_sRowSetFilter);
308
309 if(Reference<XResultSetUpdate>(_xRs,UNO_QUERY).is()) // this interface is optional so we have to check it
310 {
311 Reference<XPropertySet> xTable(m_aUpdateTable,UNO_QUERY);
312 if(xTable.is() && xTable->getPropertySetInfo()->hasPropertyByName(PROPERTY_PRIVILEGES))
313 {
314 m_nPrivileges = 0;
315 xTable->getPropertyValue(PROPERTY_PRIVILEGES) >>= m_nPrivileges;
316 if(!m_nPrivileges)
317 m_nPrivileges = Privilege::SELECT;
318 }
319 }
320 if(bNoInsert)
321 m_nPrivileges |= ~Privilege::INSERT; // remove the insert privilege
322 }
323 catch (const SQLException&)
324 {
325 TOOLS_WARN_EXCEPTION("dbaccess.core", "ORowSetCache");
326 // we couldn't create a keyset here so we have to create a static cache
327 m_xCacheSet = new OStaticSet(i_nMaxRows);
328 m_xCacheSet->construct(_xRs,i_sRowSetFilter);
329 m_nPrivileges = Privilege::SELECT;
330 }
331 }
332
333 }
334 // last check
335 if(!bAllKeysFound && xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_RESULTSETCONCURRENCY) &&
336 ::comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY)) == ResultSetConcurrency::READ_ONLY)
337 m_nPrivileges = Privilege::SELECT;
338}
339
341{
342 m_xCacheSet.clear();
343 if(m_pMatrix)
344 {
345 m_pMatrix->clear();
346 m_pMatrix.reset();
347 }
348
350 {
351 m_pInsertMatrix->clear();
352 m_pInsertMatrix.reset();
353 }
354 m_xSet = WeakReference< XResultSet>();
355 m_xMetaData = nullptr;
356 m_aUpdateTable = nullptr;
357}
358
359void ORowSetCache::setFetchSize(sal_Int32 _nSize)
360{
361 if(_nSize == m_nFetchSize)
362 return;
363
364 m_nFetchSize = _nSize;
365 if(!m_pMatrix)
366 {
367 m_pMatrix.reset( new ORowSetMatrix(_nSize) );
368 m_aMatrixIter = m_pMatrix->end();
369 m_aMatrixEnd = m_pMatrix->end();
370
371 m_pInsertMatrix.reset( new ORowSetMatrix(1) ); // a little bit overkill but ??? :-)
373 }
374 else
375 {
376 // now correct the iterator in our iterator vector
377 std::vector<sal_Int32> aPositions;
378 std::map<sal_Int32,bool> aCacheIterToChange;
379 // first get the positions where they stand now
380 for(const auto& [rIndex, rHelper] : m_aCacheIterators)
381 {
382 aCacheIterToChange[rIndex] = false;
383 if ( !rHelper.pRowSet->isInsertRow()
384 /*&& rHelper.aIterator != m_pMatrix->end()*/ && !m_bModified )
385 {
386 ptrdiff_t nDist = rHelper.aIterator - m_pMatrix->begin();
387 aPositions.push_back(nDist);
388 aCacheIterToChange[rIndex] = true;
389 }
390 }
391 sal_Int32 nKeyPos = m_aMatrixIter - m_pMatrix->begin();
392 m_pMatrix->resize(_nSize);
393
394 if ( nKeyPos < _nSize )
395 m_aMatrixIter = m_pMatrix->begin() + nKeyPos;
396 else
397 m_aMatrixIter = m_pMatrix->end();
398 m_aMatrixEnd = m_pMatrix->end();
399
400 // now adjust their positions because a resize invalidates all iterators
401 std::vector<sal_Int32>::const_iterator aIter = aPositions.begin();
402 ORowSetCacheMap::iterator aCacheIter = m_aCacheIterators.begin();
403 for(const auto& rPosChange : aCacheIterToChange)
404 {
405 if ( rPosChange.second )
406 {
407 OSL_ENSURE((*aIter >= static_cast<ORowSetMatrix::difference_type>(0)) && (*aIter < static_cast<sal_Int32>(m_pMatrix->size())),"Position is invalid!");
408 if ( *aIter < _nSize )
409 aCacheIter->second.aIterator = m_pMatrix->begin() + *aIter++;
410 else
411 aCacheIter->second.aIterator = m_pMatrix->end();
412 }
413 ++aCacheIter;
414 }
415 }
416 if(!m_nPosition)
417 {
418 sal_Int32 nNewSt = 0;
419 fillMatrix(nNewSt,_nSize);
420 OSL_ENSURE(nNewSt == 0, "fillMatrix set new start to unexpected value");
421 m_nStartPos = 0;
422 m_nEndPos = _nSize;
423 }
425 {
426 sal_Int32 nNewSt = -1;
427 _nSize += m_nStartPos;
428 fillMatrix(nNewSt, _nSize);
429 if (nNewSt >= 0)
430 {
431 m_nStartPos = nNewSt;
432 m_nEndPos = _nSize;
434 }
435 else
436 {
438 }
439 }
440 else
441 {
442 OSL_FAIL("m_nPosition not between m_nStartPos and m_nEndpos");
443 // try to repair
444 moveWindow();
446 }
447}
448
449// XResultSetMetaDataSupplier
450
451static Any lcl_getBookmark(ORowSetValue& i_aValue,OCacheSet* i_pCacheSet)
452{
453 switch ( i_aValue.getTypeKind() )
454 {
455 case DataType::TINYINT:
456 case DataType::SMALLINT:
457 case DataType::INTEGER:
458 return Any(i_aValue.getInt32());
459 default:
460 if ( i_pCacheSet && i_aValue.isNull())
461 i_aValue = i_pCacheSet->getBookmark();
462 return i_aValue.getAny();
463 }
464}
465
466// css::sdbcx::XRowLocate
468{
469 if(m_bAfterLast)
471
472 if ( m_aMatrixIter >= m_pMatrix->end() || m_aMatrixIter < m_pMatrix->begin() || !(*m_aMatrixIter).is())
473 {
474 return Any(); // this is allowed here because the rowset knows what it is doing
475 }
476
477 return lcl_getBookmark((**m_aMatrixIter)[0],m_xCacheSet.get());
478}
479
480bool ORowSetCache::moveToBookmark( const Any& bookmark )
481{
482 if ( m_xCacheSet->moveToBookmark(bookmark) )
483 {
484 m_bBeforeFirst = false;
485 m_nPosition = m_xCacheSet->getRow();
486
488
489 if(!m_bAfterLast)
490 {
491 moveWindow();
493 if ( !m_bAfterLast )
494 {
496 OSL_ENSURE(m_aMatrixIter->is(),"Iterator after moveToBookmark not valid");
497 }
498 else
499 m_aMatrixIter = m_pMatrix->end();
500 }
501 else
502 m_aMatrixIter = m_pMatrix->end();
503 }
504 else
505 return false;
506
507 return m_aMatrixIter != m_pMatrix->end() && (*m_aMatrixIter).is();
508}
509
510bool ORowSetCache::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows )
511{
512 bool bRet( moveToBookmark( bookmark ) );
513 if ( bRet )
514 {
515 m_nPosition = m_xCacheSet->getRow() + rows;
517
518 bRet = m_aMatrixIter != m_pMatrix->end() && (*m_aMatrixIter).is();
519 }
520
521 return bRet;
522}
523
524sal_Int32 ORowSetCache::compareBookmarks( const Any& _first, const Any& _second )
525{
526 return (!_first.hasValue() || !_second.hasValue()) ? CompareBookmark::NOT_COMPARABLE : m_xCacheSet->compareBookmarks(_first,_second);
527}
528
530{
531 return m_xCacheSet->hasOrderedBookmarks();
532}
533
534sal_Int32 ORowSetCache::hashBookmark( const Any& bookmark )
535{
536 return m_xCacheSet->hashBookmark(bookmark);
537}
538
539// XRowUpdate
540void ORowSetCache::updateNull(sal_Int32 columnIndex,ORowSetValueVector::Vector& io_aRow
541 ,std::vector<sal_Int32>& o_ChangedColumns
542 )
543{
544 checkUpdateConditions(columnIndex);
545
547 if ( !rInsert[columnIndex].isNull() )
548 {
549 rInsert[columnIndex].setBound(true);
550 rInsert[columnIndex].setNull();
551 rInsert[columnIndex].setModified(true);
552 io_aRow[columnIndex].setNull();
553
554 m_xCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
555 impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
556 }
557}
558
559void ORowSetCache::updateValue(sal_Int32 columnIndex,const ORowSetValue& x
561 ,std::vector<sal_Int32>& o_ChangedColumns
562 )
563{
564 checkUpdateConditions(columnIndex);
565
567 if ( rInsert[columnIndex] != x )
568 {
569 rInsert[columnIndex].setBound(true);
570 rInsert[columnIndex] = x;
571 rInsert[columnIndex].setModified(true);
572 io_aRow[columnIndex] = rInsert[columnIndex];
573
574 m_xCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
575 impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
576 }
577}
578
579void ORowSetCache::updateCharacterStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x
580 , sal_Int32 length,ORowSetValueVector::Vector& io_aRow
581 ,std::vector<sal_Int32>& o_ChangedColumns
582 )
583{
584 checkUpdateConditions(columnIndex);
585
586 Sequence<sal_Int8> aSeq;
587 if(x.is())
588 x->readBytes(aSeq,length);
589
591 rInsert[columnIndex].setBound(true);
592 rInsert[columnIndex] = aSeq;
593 rInsert[columnIndex].setModified(true);
594 io_aRow[columnIndex] = Any(x);
595
596 m_xCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
597 impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
598}
599
600void ORowSetCache::updateObject( sal_Int32 columnIndex, const Any& x
602 ,std::vector<sal_Int32>& o_ChangedColumns
603 )
604{
605 checkUpdateConditions(columnIndex);
606
608 ORowSetValue aTemp;
609 aTemp.fill(x);
610 if ( rInsert[columnIndex] != aTemp )
611 {
612 rInsert[columnIndex].setBound(true);
613 rInsert[columnIndex] = aTemp;
614 rInsert[columnIndex].setModified(true);
615 io_aRow[columnIndex] = rInsert[columnIndex];
616
617 m_xCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
618 impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
619 }
620}
621
622void ORowSetCache::updateNumericObject( sal_Int32 columnIndex, const Any& x
624 ,std::vector<sal_Int32>& o_ChangedColumns
625 )
626{
627 checkUpdateConditions(columnIndex);
628
630 ORowSetValue aTemp;
631 aTemp.fill(x);
632 if ( rInsert[columnIndex] != aTemp )
633 {
634 rInsert[columnIndex].setBound(true);
635 rInsert[columnIndex] = aTemp;
636 rInsert[columnIndex].setModified(true);
637 io_aRow[columnIndex] = rInsert[columnIndex];
638
639 m_xCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
640 impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
641 }
642}
643
644// XResultSet
646{
647 if(!isAfterLast())
648 {
649 m_bBeforeFirst = false;
650 ++m_nPosition;
651
652 // after we increment the position we have to check if we are already after the last row
654 if(!m_bAfterLast)
655 {
656 moveWindow();
657
658 OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < static_cast<sal_Int32>(m_pMatrix->size()),"Position is behind end()!");
661 }
662 }
663
664 return !m_bAfterLast;
665}
666
667
669{
670 return m_nPosition == 1; // ask resultset for
671}
672
674{
675 return m_nPosition == m_nRowCount;
676}
677
679{
680 if(!m_bBeforeFirst)
681 {
682 m_bAfterLast = false;
683 m_nPosition = 0;
684 m_bBeforeFirst = true;
685 m_xCacheSet->beforeFirst();
686 moveWindow();
687 m_aMatrixIter = m_pMatrix->end();
688 }
689}
690
692{
693 if(m_bAfterLast)
694 return;
695
696 m_bBeforeFirst = false;
697 m_bAfterLast = true;
698
700 {
701 m_xCacheSet->last();
702 m_bRowCountFinal = true;
703 m_nRowCount = m_xCacheSet->getRow();// + 1 removed
704 }
705 m_xCacheSet->afterLast();
706
707 m_nPosition = 0;
708 m_aMatrixIter = m_pMatrix->end();
709}
710
711bool ORowSetCache::fillMatrix(sal_Int32& _nNewStartPos, sal_Int32 &_nNewEndPos)
712{
713 OSL_ENSURE((_nNewStartPos != _nNewEndPos) || (_nNewStartPos == 0 && _nNewEndPos == 0 && m_nRowCount == 0),
714 "ORowSetCache::fillMatrix: StartPos and EndPos can not be equal (unless the recordset is empty)!");
715 // If _nNewStartPos >= 0, then fill the whole window with new data
716 // Else if _nNewStartPos == -1, then fill only segment [m_nEndPos, _nNewEndPos)
717 // Else, undefined (invalid argument)
718 OSL_ENSURE( _nNewStartPos >= -1, "ORowSetCache::fillMatrix: invalid _nNewStartPos" );
719
720 ORowSetMatrix::iterator aIter;
721 sal_Int32 i;
722 bool bCheck;
723 sal_Int32 requestedStartPos;
724 if ( _nNewStartPos == -1 )
725 {
726 aIter = m_pMatrix->begin() + (m_nEndPos - m_nStartPos);
727 i = m_nEndPos + 1;
728 requestedStartPos = m_nStartPos;
729 }
730 else
731 {
732 aIter = m_pMatrix->begin();
733 i = _nNewStartPos + 1;
734 requestedStartPos = _nNewStartPos;
735 }
736 bCheck = m_xCacheSet->absolute(i);
737
738
739 for(; i <= _nNewEndPos; ++i,++aIter)
740 {
741 if(bCheck)
742 {
743 if(!aIter->is())
744 *aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
745 m_xCacheSet->fillValueRow(*aIter,i);
746 }
747 else
748 { // there are no more rows found so we can fetch some before start
749
751 {
752 if(m_xCacheSet->previous()) // because we stand after the last row
753 m_nRowCount = m_xCacheSet->getRow(); // here we have the row count
754 if(!m_nRowCount)
755 m_nRowCount = i-1; // it can be that getRow return zero
756 m_bRowCountFinal = true;
757 }
758 const ORowSetMatrix::iterator aEnd = aIter;
759 ORowSetMatrix::const_iterator aRealEnd = m_pMatrix->end();
760 sal_Int32 nPos;
762 {
764 }
765 else
766 {
767 nPos = 0;
768 }
769 _nNewStartPos = nPos;
770 _nNewEndPos = m_nRowCount;
771 ++nPos;
772 bCheck = m_xCacheSet->absolute(nPos);
773
774 for(;bCheck && nPos <= requestedStartPos && aIter != aRealEnd; ++aIter, ++nPos)
775 {
776 if(!aIter->is())
777 *aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
778 m_xCacheSet->fillValueRow(*aIter, nPos);
779 bCheck = m_xCacheSet->next();
780 }
781 if(aIter != aEnd)
782 std::rotate(m_pMatrix->begin(),aEnd,aIter);
783 break;
784 }
785 bCheck = m_xCacheSet->next();
786 }
787 // we have to read one row forward to ensure that we know when we are on last row
788 // but only when we don't know it already
790 {
791 if(!m_xCacheSet->next())
792 {
793 if(m_xCacheSet->previous()) // because we stand after the last row
794 m_nRowCount = m_xCacheSet->getRow(); // here we have the row count
795 m_bRowCountFinal = true;
796 }
797 else
798 m_nRowCount = std::max(i,m_nRowCount);
799
800 }
801 return bCheck;
802}
803
804// If m_nPosition is out of the current window,
805// move it and update m_nStartPos and m_nEndPos
806// Caller is responsible for updating m_aMatrixIter
808{
809 OSL_ENSURE(m_nStartPos >= 0,"ORowSetCache::moveWindow: m_nStartPos is less than 0!");
810 OSL_ENSURE(m_nEndPos >= m_nStartPos,"ORowSetCache::moveWindow: m_nStartPos not smaller than m_nEndPos");
811 OSL_ENSURE(m_nEndPos-m_nStartPos <= m_nFetchSize,"ORowSetCache::moveWindow: m_nStartPos and m_nEndPos too far apart");
812
814 {
815 // just move inside the window
816 OSL_ENSURE((m_nPosition - m_nStartPos) <= static_cast<sal_Int32>(m_pMatrix->size()),"Position is behind end()!");
817 // make double plus sure that we have fetched that row
819 OSL_ENSURE(m_aMatrixIter != m_pMatrix->end(), "New m_aMatrixIter is at end(), but should not.");
820 if(!m_aMatrixIter->is())
821 {
822 bool bOk( m_xCacheSet->absolute( m_nPosition ) );
823 if ( bOk )
824 {
825 *m_aMatrixIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
826 m_xCacheSet->fillValueRow(*m_aMatrixIter,m_nPosition);
827 // we have to read one row forward to ensure that we know when we are on last row
828 // but only when we don't know it already
829 if ( !m_bRowCountFinal )
830 {
831 bOk = m_xCacheSet->absolute( m_nPosition + 1 );
832 if ( bOk )
833 m_nRowCount = std::max(sal_Int32(m_nPosition+1),m_nRowCount);
834 }
835 }
836 if(!bOk && !m_bRowCountFinal)
837 {
838 // because we stand after the last row
839 m_nRowCount = m_xCacheSet->previous() ? m_xCacheSet->getRow() : 0;
840 m_bRowCountFinal = true;
841 }
842 }
843 return;
844 }
845
846 sal_Int32 nDiff = (m_nFetchSize - 1) / 2;
847 sal_Int32 nNewStartPos = (m_nPosition - nDiff) - 1; //m_nPosition is 1-based, but m_nStartPos is 0-based
848 sal_Int32 nNewEndPos = nNewStartPos + m_nFetchSize;
849
850 if ( nNewStartPos < 0 )
851 {
852 // The computed new window crashes through the floor (begins before first row);
853 // nNew*Pos has to be shifted by -nNewStartPos
854 nNewEndPos -= nNewStartPos;
855 nNewStartPos = 0;
856 }
857
858 if ( nNewStartPos < m_nStartPos )
859 { // need to fill data *before* m_nStartPos
860 if ( nNewEndPos > m_nStartPos )
861 { // The two regions are overlapping.
862 // We'll first rotate the contents of m_pMatrix so that the overlap area
863 // is positioned right; in the old window it is at the beginning,
864 // it has to go to the end.
865 // then we fill in the rows between new and old start pos.
866
867 bool bCheck;
868 bCheck = m_xCacheSet->absolute(nNewStartPos + 1);
869
870 // m_nEndPos < nNewEndPos when window not filled (e.g. there are fewer rows in total than window size)
871 m_nEndPos = std::min(nNewEndPos, m_nEndPos);
872 const sal_Int32 nOverlapSize = m_nEndPos - m_nStartPos;
873 const sal_Int32 nStartPosOffset = m_nStartPos - nNewStartPos; // by how much m_nStartPos moves
874 m_nStartPos = nNewStartPos;
875 OSL_ENSURE( o3tl::make_unsigned(nOverlapSize) <= m_pMatrix->size(), "new window end is after end of cache matrix!" );
876 // the first position in m_pMatrix whose data we don't keep;
877 // content will be moved to m_pMatrix.begin()
878 ORowSetMatrix::iterator aEnd (m_pMatrix->begin() + nOverlapSize);
879 // the first unused position after we are done; it == m_pMatrix.end() if and only if the window is full
880 ORowSetMatrix::iterator aNewEnd (aEnd + nStartPosOffset);
881 // *m_pMatrix now looks like:
882 // [0; nOverlapSize) i.e. [begin(); aEnd): data kept
883 // [nOverlapSize; nOverlapSize + nStartPosOffset) i.e. [aEnd, aNewEnd): new data of positions < old m_nStartPos
884 // [nOverlapSize + nStartPosOffset; size()) i.e. [aNewEnd, end()): unused
885 // Note that nOverlapSize + nStartPosOffset == m_nEndPos - m_nStartPos (new values)
886 // When we are finished:
887 // [0; nStartPosOffset) i.e. [begin(); aEnd): new data of positions < old m_nStartPos
888 // [nStartPosOffset; nOverlapSize + nStartPosOffset) i.e. [aEnd, aNewEnd): kept
889 // [nOverlapSize + nStartPosOffset; size()) i.e. [aNewEnd, end()): unused
890
891 if ( bCheck )
892 {
893 {
894 ORowSetMatrix::iterator aIter(aEnd);
895 sal_Int32 nPos = m_nStartPos + 1;
896 fill(aIter, aNewEnd, nPos, bCheck);
897 }
898
899 std::rotate(m_pMatrix->begin(), aEnd, aNewEnd);
900 if (!m_bModified)
901 {
902 // now correct the iterator in our iterator vector
903 // rotateCacheIterator(aEnd-m_pMatrix->begin()); //can't be used because they decrement and here we need to increment
904 for(auto& rCacheIter : m_aCacheIterators)
905 {
906 if ( !rCacheIter.second.pRowSet->isInsertRow()
907 && rCacheIter.second.aIterator != m_pMatrix->end() )
908 {
909 const ptrdiff_t nDist = rCacheIter.second.aIterator - m_pMatrix->begin();
910 if ( nDist >= nOverlapSize )
911 {
912 // That's from outside the overlap area; invalidate iterator.
913 rCacheIter.second.aIterator = m_pMatrix->end();
914 }
915 else
916 {
917 // Inside overlap area: move to correct position
918 OSL_ENSURE(((nDist + nStartPosOffset) >= static_cast<ORowSetMatrix::difference_type>(0)) &&
919 ((nDist + nStartPosOffset) < static_cast<sal_Int32>(m_pMatrix->size())),"Position is invalid!");
920 rCacheIter.second.aIterator += nStartPosOffset;
921 OSL_ENSURE(rCacheIter.second.aIterator >= m_pMatrix->begin()
922 && rCacheIter.second.aIterator < m_pMatrix->end(),"Iterator out of area!");
923 }
924 }
925 }
926 }
927 }
928 else
929 { // normally this should never happen
930 OSL_FAIL("What the hell is happen here!");
931 return;
932 }
933 }
934 else
935 {// no rows can be reused so fill again
936 reFillMatrix(nNewStartPos,nNewEndPos);
937 }
938 }
939
940 OSL_ENSURE(nNewStartPos >= m_nStartPos, "ORowSetCache::moveWindow internal error: new start pos before current start pos");
941 if ( m_nEndPos < nNewEndPos )
942 { // need to fill data *after* m_nEndPos
943 if( nNewStartPos < m_nEndPos )
944 { // The two regions are overlapping.
945 const sal_Int32 nRowsInCache = m_nEndPos - m_nStartPos;
946 if ( nRowsInCache < m_nFetchSize )
947 {
948 // There is some unused space in *m_pMatrix; fill it
949 OSL_ENSURE((nRowsInCache >= static_cast<ORowSetMatrix::difference_type>(0)) && (o3tl::make_unsigned(nRowsInCache) < m_pMatrix->size()),"Position is invalid!");
950 sal_Int32 nPos = m_nEndPos + 1;
951 bool bCheck = m_xCacheSet->absolute(nPos);
952 ORowSetMatrix::iterator aIter = m_pMatrix->begin() + nRowsInCache;
953 const sal_Int32 nRowsToFetch = std::min(nNewEndPos-m_nEndPos, m_nFetchSize-nRowsInCache);
954 const ORowSetMatrix::const_iterator aEnd = aIter + nRowsToFetch;
955 bCheck = fill(aIter, aEnd, nPos, bCheck);
956 m_nEndPos = nPos - 1;
957 OSL_ENSURE( (!bCheck && m_nEndPos <= nNewEndPos ) ||
958 ( bCheck && m_nEndPos == nNewEndPos ),
959 "ORowSetCache::moveWindow opportunistic fetch-after-current-end went badly");
960 }
961
962 // A priori, the rows from begin() [inclusive] to (begin() + nNewStartPos - m_nStartPos) [exclusive]
963 // have to be refilled with new to-be-fetched rows.
964 // The rows behind this can be reused
965 ORowSetMatrix::iterator aIter = m_pMatrix->begin();
966 const sal_Int32 nNewStartPosInMatrix = nNewStartPos - m_nStartPos;
967 OSL_ENSURE((nNewStartPosInMatrix >= static_cast<ORowSetMatrix::difference_type>(0)) && (o3tl::make_unsigned(nNewStartPosInMatrix) < m_pMatrix->size()),"Position is invalid!");
968 // first position we reuse
969 const ORowSetMatrix::const_iterator aEnd = m_pMatrix->begin() + nNewStartPosInMatrix;
970 // End of used portion of the matrix. Is < m_pMatrix->end() if less data than window size
971 ORowSetMatrix::iterator aDataEnd = m_pMatrix->begin() + (m_nEndPos - m_nStartPos);
972
973 sal_Int32 nPos = m_nEndPos + 1;
974 bool bCheck = m_xCacheSet->absolute(nPos);
975 bCheck = fill(aIter, aEnd, nPos, bCheck); // refill the region we don't need anymore
976 //aIter and nPos are now the position *after* last filled in one!
977
978 // bind end to front
979 if(bCheck)
980 {
981 OSL_ENSURE(aIter == aEnd, "fill() said went till end, but did not.");
982 // rotate the end to the front
983 std::rotate(m_pMatrix->begin(), aIter, aDataEnd);
984 // now correct the iterator in our iterator vector
985 rotateCacheIterator( nNewStartPosInMatrix );
986 m_nStartPos = nNewStartPos;
987 m_nEndPos = nNewEndPos;
988 // now I can say how many rows we have
989 // we have to read one row forward to ensure that we know when we are on last row
990 // but only when we don't know it already
991 bool bOk = true;
993 bOk = m_xCacheSet->next();
994 if(!bOk)
995 {
996 m_xCacheSet->previous(); // because we stand after the last row
997 m_nRowCount = nPos; // here we have the row count
998 OSL_ENSURE(nPos == m_xCacheSet->getRow(),"nPos is not valid!");
999 m_bRowCountFinal = true;
1000 }
1001 else if(!m_bRowCountFinal)
1002 m_nRowCount = std::max(nPos+1, m_nRowCount); //+1 because we successfully moved to row after nPos
1003 else
1004 OSL_ENSURE(m_nRowCount >= nPos, "Final m_nRowCount is smaller than row I moved to!");
1005 }
1006 else
1007 { // the end was reached before or at end() so we can set the start before or at nNewStartPos
1008 // and possibly keep more of m_pMatrix than planned.
1009 const ORowSetMatrix::const_iterator::difference_type nFetchedRows = aIter - m_pMatrix->begin();
1010 // *m_pMatrix now looks like:
1011 // [0; nFetchedRows) i.e. [begin(); aIter): newly fetched data for positions m_nEndPos to m_nEndPos+nFetchedRows
1012 // [nFetchedRows; ???) i.e. [aIter; aDataEnd]: data to be kept for positions m_nStartPos+nFetchedRows to ???
1013
1014 nPos -= 1;
1015 m_nStartPos += nFetchedRows;
1016 m_nEndPos = nPos;
1017 std::rotate(m_pMatrix->begin(), aIter, aDataEnd);
1018 // now correct the iterator in our iterator vector
1019 rotateCacheIterator( nFetchedRows );
1020
1021 if ( !m_bRowCountFinal )
1022 {
1023 m_xCacheSet->previous(); // because we stand after the last row
1024 m_nRowCount = std::max(m_nRowCount, nPos); // here we have the row count
1025 OSL_ENSURE(nPos == m_xCacheSet->getRow(),"nPos isn't valid!");
1026 m_bRowCountFinal = true;
1027 }
1028
1029 }
1030 // here we need only to check if the beginning row is valid. If not we have to fetch it.
1031 if(!m_pMatrix->begin()->is())
1032 {
1033 aIter = m_pMatrix->begin();
1034
1035 nPos = m_nStartPos + 1;
1036 bCheck = m_xCacheSet->absolute(nPos);
1037 for(; !aIter->is() && bCheck;++aIter, ++nPos)
1038 {
1039 OSL_ENSURE(aIter != m_pMatrix->end(),"Invalid iterator");
1040
1041 *aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
1042 m_xCacheSet->fillValueRow(*aIter, nPos);
1043
1044 bCheck = m_xCacheSet->next();
1045 }
1046 }
1047 }
1048 else // no rows can be reused so fill again
1049 reFillMatrix(nNewStartPos,nNewEndPos);
1050 }
1051
1052 if(!m_bRowCountFinal)
1054 OSL_ENSURE(m_nStartPos >= 0,"ORowSetCache::moveWindow: m_nStartPos is less than 0!");
1055 OSL_ENSURE(m_nEndPos > m_nStartPos,"ORowSetCache::moveWindow: m_nStartPos not smaller than m_nEndPos");
1056 OSL_ENSURE(m_nEndPos-m_nStartPos <= m_nFetchSize,"ORowSetCache::moveWindow: m_nStartPos and m_nEndPos too far apart");
1057}
1058
1060{
1061 // First move to the first row.
1062 // Then check if the cache window is at the beginning.
1063 // If not, then position the window and fill it with data.
1064 // We move the window smartly, i.e. we clear only the rows that are out of range
1065 bool bRet = m_xCacheSet->first();
1066 if(bRet)
1067 {
1068 m_bBeforeFirst = m_bAfterLast = false;
1069 m_nPosition = 1;
1070 moveWindow();
1071 m_aMatrixIter = m_pMatrix->begin();
1072 }
1073 else
1074 {
1077
1078 OSL_ENSURE(m_bBeforeFirst || m_bNew,"ORowSetCache::first return false and BeforeFirst isn't true");
1079 m_aMatrixIter = m_pMatrix->end();
1080 }
1081 return bRet;
1082}
1083
1085{
1086 bool bRet = m_xCacheSet->last();
1087 if(bRet)
1088 {
1089 m_bBeforeFirst = m_bAfterLast = false;
1090 if(!m_bRowCountFinal)
1091 {
1092 m_bRowCountFinal = true;
1093 m_nRowCount = m_xCacheSet->getRow(); // not + 1
1094 }
1095 m_nPosition = m_xCacheSet->getRow();
1096 moveWindow();
1097 // we have to repositioning because moveWindow can modify the cache
1098 m_xCacheSet->last();
1099 OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < static_cast<sal_Int32>(m_pMatrix->size()),"Position is behind end()!");
1101 }
1102 else
1103 {
1106 OSL_ENSURE(m_bBeforeFirst,"ORowSetCache::last return false and BeforeFirst isn't true");
1107 m_aMatrixIter = m_pMatrix->end();
1108 }
1109#if OSL_DEBUG_LEVEL > 0
1110 if(bRet)
1111 {
1112 assert((*m_aMatrixIter).is() && "ORowSetCache::last: Row not valid!");
1113 }
1114#endif
1115
1116 return bRet;
1117}
1118
1119sal_Int32 ORowSetCache::getRow( ) const
1120{
1121 return (isBeforeFirst() || isAfterLast()) ? 0 : m_nPosition;
1122}
1123
1124bool ORowSetCache::absolute( sal_Int32 row )
1125{
1126 if(!row )
1127 throw SQLException(DBA_RES(RID_STR_NO_ABS_ZERO),nullptr,SQLSTATE_GENERAL,1000,Any() );
1128
1129 if(row < 0)
1130 {
1131 // here we have to scroll from the last row to backward so we have to go to last row and
1132 // and to the previous
1133 if(m_bRowCountFinal || last())
1134 {
1135 m_nPosition = m_nRowCount + row + 1; // + row because row is negative and +1 because row==-1 means last row
1136 if(m_nPosition < 1)
1137 {
1138 m_bBeforeFirst = true;
1139 m_bAfterLast = false;
1140 m_aMatrixIter = m_pMatrix->end();
1141 }
1142 else
1143 {
1144 m_bBeforeFirst = false;
1146 moveWindow();
1147 OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < static_cast<sal_Int32>(m_pMatrix->size()),"Position is behind end()!");
1149 }
1150 }
1151 else
1152 m_aMatrixIter = m_pMatrix->end();
1153 }
1154 else
1155 {
1156 m_nPosition = row;
1157 // the position flags
1158 m_bBeforeFirst = false;
1160
1161 if(!m_bAfterLast)
1162 {
1163 moveWindow();
1165 if(!m_bAfterLast)
1167 else
1168 m_aMatrixIter = m_pMatrix->end();
1169 }
1170 else
1171 m_aMatrixIter = m_pMatrix->end();
1172 }
1173
1174 return !(m_bAfterLast || m_bBeforeFirst);
1175}
1176
1177bool ORowSetCache::relative( sal_Int32 rows )
1178{
1179 bool bErg = true;
1180 if(rows)
1181 {
1182 sal_Int32 nNewPosition = m_nPosition + rows;
1183
1184 if ( m_bBeforeFirst && rows > 0 )
1185 nNewPosition = rows;
1186 else if ( m_bRowCountFinal && m_bAfterLast && rows < 0 )
1187 nNewPosition = m_nRowCount + 1 + rows;
1188 else
1190 throw SQLException( DBA_RES( RID_STR_NO_RELATIVE ), nullptr, SQLSTATE_GENERAL, 1000, Any() );
1191 if ( nNewPosition )
1192 {
1193 bErg = absolute( nNewPosition );
1194 bErg = bErg && !isAfterLast() && !isBeforeFirst();
1195 }
1196 else
1197 {
1198 m_bBeforeFirst = true;
1199 bErg = false;
1200 }
1201 }
1202 return bErg;
1203}
1204
1206{
1207 bool bRet = false;
1208 if(!isBeforeFirst())
1209 {
1210 if(m_bAfterLast) // we stand after the last row so one before is the last row
1211 bRet = last();
1212 else
1213 {
1214 m_bAfterLast = false;
1215 --m_nPosition;
1216 moveWindow();
1217 OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < static_cast<sal_Int32>(m_pMatrix->size()),"Position is behind end()!");
1218
1220
1221 if(!m_nPosition)
1222 {
1223 m_bBeforeFirst = true;
1224 m_aMatrixIter = m_pMatrix->end();
1225 }
1226 else
1227 {
1229 bRet = (*m_aMatrixIter).is();
1230 }
1231 }
1232 }
1233 return bRet;
1234}
1235
1237{
1238 if(isAfterLast())
1239 throw SQLException(DBA_RES(RID_STR_NO_REFRESH_AFTERLAST),nullptr,SQLSTATE_GENERAL,1000,Any() );
1240 OSL_ENSURE(m_aMatrixIter != m_pMatrix->end(),"refreshRow() called for invalid row!");
1241 m_xCacheSet->refreshRow();
1242 m_xCacheSet->fillValueRow(*m_aMatrixIter,m_nPosition);
1243 if ( m_bNew )
1244 {
1246 }
1247}
1248
1250{
1251 return m_xCacheSet->rowUpdated();
1252}
1253
1255{
1256 return m_xCacheSet->rowInserted();
1257}
1258
1259// XResultSetUpdate
1260bool ORowSetCache::insertRow(std::vector< Any >& o_aBookmarks)
1261{
1262 if ( !m_bNew || !m_aInsertRow->is() )
1263 throw SQLException(DBA_RES(RID_STR_NO_MOVETOINSERTROW_CALLED),nullptr,SQLSTATE_GENERAL,1000,Any() );
1264
1266
1267 bool bRet( rowInserted() );
1268 if ( bRet )
1269 {
1270 ++m_nRowCount;
1271 Any aBookmark = (**m_aInsertRow)[0].makeAny();
1272 m_bAfterLast = m_bBeforeFirst = false;
1273 if(aBookmark.hasValue())
1274 {
1275 moveToBookmark(aBookmark);
1276 // update the cached values
1278 ORowSetMatrix::const_iterator aIter = m_pMatrix->begin();
1279 for(;aIter != m_pMatrix->end();++aIter)
1280 {
1281 if ( m_aMatrixIter != aIter && aIter->is() && m_xCacheSet->columnValuesUpdated(**aIter,rCurrentRow) )
1282 {
1283 o_aBookmarks.push_back(lcl_getBookmark((**aIter)[0], m_xCacheSet.get()));
1284 }
1285 }
1286 }
1287 else
1288 {
1289 OSL_FAIL("There must be a bookmark after the row was inserted!");
1290 }
1291 }
1292 return bRet;
1293}
1294
1295void ORowSetCache::resetInsertRow(bool _bClearInsertRow)
1296{
1297 if ( _bClearInsertRow )
1299 m_bNew = false;
1300 m_bModified = false;
1301}
1302
1304{
1305 // clear the insertrow references -> implies that the current row of the rowset changes as well
1306 for(auto& rCacheIter : m_aCacheIterators)
1307 {
1308 if ( rCacheIter.second.pRowSet->isInsertRow() && rCacheIter.second.aIterator == m_aInsertRow )
1309 rCacheIter.second.aIterator = m_pMatrix->end();
1310 }
1311 resetInsertRow(false);
1312}
1313
1314void ORowSetCache::updateRow( ORowSetMatrix::iterator const & _rUpdateRow, std::vector< Any >& o_aBookmarks )
1315{
1316 if(isAfterLast() || isBeforeFirst())
1317 throw SQLException(DBA_RES(RID_STR_NO_UPDATEROW),nullptr,SQLSTATE_GENERAL,1000,Any() );
1318
1319 Any aBookmark = (**_rUpdateRow)[0].makeAny();
1320 OSL_ENSURE(aBookmark.hasValue(),"Bookmark must have a value!");
1321 // here we don't have to reposition our CacheSet, when we try to update a row,
1322 // the row was already fetched
1323 moveToBookmark(aBookmark);
1324 m_xCacheSet->updateRow(*_rUpdateRow,*m_aMatrixIter,m_aUpdateTable);
1325 // refetch the whole row
1326 (*m_aMatrixIter) = nullptr;
1327
1328 if ( moveToBookmark(aBookmark) )
1329 {
1330 // update the cached values
1332 ORowSetMatrix::const_iterator aIter = m_pMatrix->begin();
1333 for(;aIter != m_pMatrix->end();++aIter)
1334 {
1335 if ( m_aMatrixIter != aIter && aIter->is() && m_xCacheSet->columnValuesUpdated(**aIter,rCurrentRow) )
1336 {
1337 o_aBookmarks.push_back(lcl_getBookmark((**aIter)[0], m_xCacheSet.get()));
1338 }
1339 }
1340 }
1341
1342 m_bModified = false;
1343}
1344
1346{
1347 if(isAfterLast() || isBeforeFirst())
1348 throw SQLException(DBA_RES(RID_STR_NO_DELETEROW),nullptr,SQLSTATE_GENERAL,1000,Any() );
1349
1351 if ( !m_xCacheSet->rowDeleted() )
1352 return false;
1353
1354 --m_nRowCount;
1355 OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < static_cast<sal_Int32>(m_pMatrix->size()),"Position is behind end()!");
1356 ORowSetMatrix::iterator aPos = calcPosition();
1357 (*aPos) = nullptr;
1358
1359 ORowSetMatrix::const_iterator aEnd = m_pMatrix->end();
1360 for(++aPos;aPos != aEnd && aPos->is();++aPos)
1361 {
1362 *(aPos-1) = *aPos;
1363 (*aPos) = nullptr;
1364 }
1365 m_aMatrixIter = m_pMatrix->end();
1366
1367 --m_nPosition;
1368 return true;
1369}
1370
1372{
1373 m_bNew = m_bModified = false;
1374 if(!m_nPosition)
1375 {
1376 OSL_FAIL("cancelRowUpdates:Invalid positions pos == 0");
1377 ::dbtools::throwFunctionSequenceException(nullptr);
1378 }
1379
1380 if(m_xCacheSet->absolute(m_nPosition))
1381 m_xCacheSet->fillValueRow(*m_aMatrixIter,m_nPosition);
1382 else
1383 {
1384 OSL_FAIL("cancelRowUpdates couldn't position right with absolute");
1385 ::dbtools::throwFunctionSequenceException(nullptr);
1386 }
1387}
1388
1390{
1391 m_bNew = true;
1392 m_bAfterLast = false;
1393
1394 m_aInsertRow = m_pInsertMatrix->begin();
1395 if(!m_aInsertRow->is())
1396 *m_aInsertRow = new ORowSetValueVector(m_xMetaData->getColumnCount());
1397
1398 // we don't unbound the bookmark column
1399 ORowSetValueVector::Vector::iterator aIter = (*m_aInsertRow)->begin()+1;
1400 ORowSetValueVector::Vector::const_iterator aEnd = (*m_aInsertRow)->end();
1401 for(sal_Int32 i = 1;aIter != aEnd;++aIter,++i)
1402 {
1403 aIter->setBound(false);
1404 aIter->setModified(false);
1405 aIter->setNull();
1406 aIter->setTypeKind(m_xMetaData->getColumnType(i));
1407 }
1408}
1409
1411{
1413 aHelper.aIterator = m_pMatrix->end();
1414 aHelper.pRowSet = _pRowSet;
1415 return ORowSetCacheIterator(m_aCacheIterators.insert(m_aCacheIterators.begin(),ORowSetCacheMap::value_type(m_aCacheIterators.size()+1,aHelper)),this,_pRowSet);
1416}
1417
1419{
1420 ORowSetCacheMap::const_iterator aCacheIter = m_aCacheIterators.begin();
1421 for(;aCacheIter != m_aCacheIterators.end();)
1422 {
1423 if ( aCacheIter->second.pRowSet == _pRowSet )
1424 {
1425 aCacheIter = m_aCacheIterators.erase(aCacheIter);
1426 }
1427 else
1428 ++aCacheIter;
1429 }
1430}
1431
1432void ORowSetCache::rotateCacheIterator(ORowSetMatrix::difference_type _nDist)
1433{
1434 if (m_bModified)
1435 return;
1436
1437 if(!_nDist)
1438 return;
1439
1440 // now correct the iterator in our iterator vector
1441 for(auto& rCacheIter : m_aCacheIterators)
1442 {
1443 if ( !rCacheIter.second.pRowSet->isInsertRow()
1444 && rCacheIter.second.aIterator != m_pMatrix->end())
1445 {
1446 ptrdiff_t nDist = rCacheIter.second.aIterator - m_pMatrix->begin();
1447 if(nDist < _nDist)
1448 {
1449 rCacheIter.second.aIterator = m_pMatrix->end();
1450 }
1451 else
1452 {
1453 OSL_ENSURE((rCacheIter.second.aIterator - m_pMatrix->begin()) >= _nDist,"Invalid Dist value!");
1454 rCacheIter.second.aIterator -= _nDist;
1455 OSL_ENSURE(rCacheIter.second.aIterator >= m_pMatrix->begin()
1456 && rCacheIter.second.aIterator < m_pMatrix->end(),"Iterator out of area!");
1457 }
1458 }
1459 }
1460}
1461
1463{
1464 if (m_bModified)
1465 return;
1466
1467 // now correct the iterator in our iterator vector
1468 for (auto& rCacheIter : m_aCacheIterators)
1469 {
1470 if (!rCacheIter.second.pRowSet->isInsertRow())
1471 {
1472 rCacheIter.second.aIterator = m_pMatrix->end();
1473 }
1474 }
1475}
1476
1477void ORowSetCache::setUpdateIterator(const ORowSetMatrix::iterator& _rOriginalRow)
1478{
1479 m_aInsertRow = m_pInsertMatrix->begin();
1480 if(!m_aInsertRow->is())
1481 *m_aInsertRow = new ORowSetValueVector(m_xMetaData->getColumnCount());
1482
1483 (*(*m_aInsertRow)) = *(*_rOriginalRow);
1484 // we don't unbound the bookmark column
1485 for(auto& rItem : **m_aInsertRow)
1486 rItem.setModified(false);
1487}
1488
1490{
1492 {
1494 if(m_bAfterLast)
1495 m_nPosition = 0;//m_nRowCount;
1496 }
1497}
1498
1499void ORowSetCache::checkUpdateConditions(sal_Int32 columnIndex)
1500{
1501 if(m_bAfterLast || columnIndex >= static_cast<sal_Int32>((*m_aInsertRow)->size()))
1503}
1504
1505bool ORowSetCache::checkInnerJoin(const ::connectivity::OSQLParseNode *pNode,const Reference< XConnection>& _xConnection,const OUString& _sUpdateTableName)
1506{
1507 bool bOk = false;
1508 if (pNode->count() == 3 && // expression in parentheses
1509 SQL_ISPUNCTUATION(pNode->getChild(0),"(") &&
1510 SQL_ISPUNCTUATION(pNode->getChild(2),")"))
1511 {
1512 bOk = checkInnerJoin(pNode->getChild(1),_xConnection,_sUpdateTableName);
1513 }
1514 else if ((SQL_ISRULE(pNode,search_condition) || SQL_ISRULE(pNode,boolean_term)) && // AND/OR link
1515 pNode->count() == 3)
1516 {
1517 // only allow an AND link
1518 if ( SQL_ISTOKEN(pNode->getChild(1),AND) )
1519 bOk = checkInnerJoin(pNode->getChild(0),_xConnection,_sUpdateTableName)
1520 && checkInnerJoin(pNode->getChild(2),_xConnection,_sUpdateTableName);
1521 }
1522 else if (SQL_ISRULE(pNode,comparison_predicate))
1523 {
1524 // only the comparison of columns is allowed
1525 OSL_ENSURE(pNode->count() == 3,"checkInnerJoin: Error in Parse Tree");
1526 if (!(SQL_ISRULE(pNode->getChild(0),column_ref) &&
1527 SQL_ISRULE(pNode->getChild(2),column_ref) &&
1528 pNode->getChild(1)->getNodeType() == SQLNodeType::Equal))
1529 {
1530 bOk = false;
1531 }
1532 else
1533 {
1534 OUString sColumnName,sTableRange;
1535 OSQLParseTreeIterator::getColumnRange( pNode->getChild(0), _xConnection, sColumnName, sTableRange );
1536 bOk = sTableRange == _sUpdateTableName;
1537 if ( !bOk )
1538 {
1539 OSQLParseTreeIterator::getColumnRange( pNode->getChild(2), _xConnection, sColumnName, sTableRange );
1540 bOk = sTableRange == _sUpdateTableName;
1541 }
1542 }
1543 }
1544 return bOk;
1545}
1546
1547bool ORowSetCache::checkJoin(const Reference< XConnection>& _xConnection,
1548 const Reference< XSingleSelectQueryAnalyzer >& _xAnalyzer,
1549 const OUString& _sUpdateTableName )
1550{
1551 bool bOk = false;
1552 OUString sSql = _xAnalyzer->getQuery();
1553 OUString sErrorMsg;
1555 std::unique_ptr< ::connectivity::OSQLParseNode> pSqlParseNode( aSqlParser.parseTree(sErrorMsg,sSql));
1556 if ( pSqlParseNode && SQL_ISRULE(pSqlParseNode, select_statement) )
1557 {
1559 OSL_ENSURE(pTableRefCommalist,"NO tables why!?");
1560 if(pTableRefCommalist && pTableRefCommalist->count() == 1)
1561 {
1562 // we found only one element so it must some kind of join here
1564 if(pJoin)
1565 { // we are only interested in qualified joins like RIGHT or LEFT
1566 OSQLParseNode* pJoinType = pJoin->getChild(1);
1567 OSQLParseNode* pOuterType = nullptr;
1568 if(SQL_ISRULE(pJoinType,join_type) && pJoinType->count() == 2)
1569 pOuterType = pJoinType->getChild(0);
1570 else if(SQL_ISRULE(pJoinType,outer_join_type))
1571 pOuterType = pJoinType;
1572
1573 bool bCheck = false;
1574 bool bLeftSide = false;
1575 if(pOuterType)
1576 { // found outer join
1577 bLeftSide = SQL_ISTOKEN(pOuterType->getChild(0),LEFT);
1578 bCheck = bLeftSide || SQL_ISTOKEN(pOuterType->getChild(0),RIGHT);
1579 }
1580
1581 if(bCheck)
1582 { // here we know that we have to check on which side our table resides
1583 const OSQLParseNode* pTableRef;
1584 if(bLeftSide)
1585 pTableRef = pJoin->getChild(0);
1586 else
1587 pTableRef = pJoin->getChild(3);
1588 OSL_ENSURE(SQL_ISRULE(pTableRef,table_ref),"Must be a tableref here!");
1589
1590 OUString sTableRange = OSQLParseNode::getTableRange(pTableRef);
1591 if(sTableRange.isEmpty())
1592 pTableRef->getChild(0)->parseNodeToStr( sTableRange, _xConnection, nullptr, false, false );
1593 bOk = sTableRange == _sUpdateTableName;
1594 }
1595 }
1596 }
1597 else
1598 {
1599 OSQLParseNode* pWhereOpt = pSqlParseNode->getChild(3)->getChild(1);
1600 if ( pWhereOpt && !pWhereOpt->isLeaf() )
1601 bOk = checkInnerJoin(pWhereOpt->getChild(1),_xConnection,_sUpdateTableName);
1602 }
1603 }
1604 return bOk;
1605}
1606
1608{
1609 // we don't unbound the bookmark column
1610 if ( m_aInsertRow != m_pInsertMatrix->end() && m_aInsertRow->is() )
1611 {
1612 ORowSetValueVector::Vector::iterator aIter = (*m_aInsertRow)->begin()+1;
1613 ORowSetValueVector::Vector::const_iterator aEnd = (*m_aInsertRow)->end();
1614 for(;aIter != aEnd;++aIter)
1615 {
1616 aIter->setBound(false);
1617 aIter->setModified(false);
1618 aIter->setNull();
1619 }
1620 }
1621}
1622
1623ORowSetMatrix::iterator ORowSetCache::calcPosition() const
1624{
1625 sal_Int32 nValue = (m_nPosition - m_nStartPos) - 1;
1626 OSL_ENSURE((nValue >= static_cast<ORowSetMatrix::difference_type>(0)) && (o3tl::make_unsigned(nValue) < m_pMatrix->size()),"Position is invalid!");
1627 return ( nValue < 0 || o3tl::make_unsigned(nValue) >= m_pMatrix->size() ) ? m_pMatrix->end() : (m_pMatrix->begin() + nValue);
1628}
1629
1631{
1633 m_aOldRows.push_back(pRef);
1634 return pRef;
1635}
1636
1638{
1639 TOldRowSetRows::iterator aOldRowIter = std::find_if(m_aOldRows.begin(), m_aOldRows.end(),
1640 [&_rRow](const TORowSetOldRowHelperRef& rxOldRow) { return rxOldRow.get() == _rRow.get(); });
1641 if (aOldRowIter != m_aOldRows.end())
1642 m_aOldRows.erase(aOldRowIter);
1643}
1644
1645bool ORowSetCache::reFillMatrix(sal_Int32 _nNewStartPos, sal_Int32 _nNewEndPos)
1646{
1647 for (const auto& rxOldRow : m_aOldRows)
1648 {
1649 if ( rxOldRow.is() && rxOldRow->getRow().is() )
1650 rxOldRow->setRow(new ORowSetValueVector( *(rxOldRow->getRow()) ) );
1651 }
1652 sal_Int32 nNewSt = _nNewStartPos;
1653 bool bRet = fillMatrix(nNewSt,_nNewEndPos);
1654 m_nStartPos = nNewSt;
1655 m_nEndPos = _nNewEndPos;
1656 rotateAllCacheIterators(); // invalidate every iterator
1657 return bRet;
1658}
1659
1660bool ORowSetCache::fill(ORowSetMatrix::iterator& _aIter, const ORowSetMatrix::const_iterator& _aEnd, sal_Int32& _nPos, bool _bCheck)
1661{
1662 const sal_Int32 nColumnCount = m_xMetaData->getColumnCount();
1663 for (; _bCheck && _aIter != _aEnd; ++_aIter, ++_nPos)
1664 {
1665 if ( !_aIter->is() )
1666 *_aIter = new ORowSetValueVector(nColumnCount);
1667 else
1668 {
1669 for (const auto& rxOldRow : m_aOldRows)
1670 {
1671 if ( rxOldRow->getRow() == *_aIter )
1672 *_aIter = new ORowSetValueVector(nColumnCount);
1673 }
1674 }
1675 m_xCacheSet->fillValueRow(*_aIter, _nPos);
1676 _bCheck = m_xCacheSet->next();
1677 }
1678 return _bCheck;
1679}
1680
1682{
1683 return m_xCacheSet->isResultSetChanged();
1684}
1685
1686void ORowSetCache::reset(const Reference< XResultSet>& _xDriverSet)
1687{
1688 m_xSet = _xDriverSet;
1689 m_xMetaData.set(Reference< XResultSetMetaDataSupplier >(_xDriverSet,UNO_QUERY_THROW)->getMetaData());
1690 m_xCacheSet->reset(_xDriverSet);
1691
1692 m_bRowCountFinal = false;
1693 m_nRowCount = 0;
1695}
1696
1698 ,std::vector<sal_Int32> const & o_ChangedColumns)
1699{
1700 if ( o_ChangedColumns.size() > 1 )
1701 {
1702 for (auto const& elem : *m_pMatrix)
1703 {
1704 if ( elem.is() && m_xCacheSet->updateColumnValues(*elem,io_aRow,o_ChangedColumns))
1705 {
1706 return;
1707 }
1708 }
1709 m_xCacheSet->fillMissingValues(io_aRow);
1710 }
1711}
1712
1713/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 m_nPosition
static Any lcl_getBookmark(ORowSetValue &i_aValue, OCacheSet *i_pCacheSet)
std::vector< VectorVal > Vector
sal_Int32 getInt32() const
sal_Int32 getTypeKind() const
void setModified(bool _bMod)
void fill(sal_Int32 _nPos, sal_Int32 _nType, const css::uno::Reference< css::sdbc::XRow > &_xRow)
const css::uno::Any & getAny() const
void parseNodeToStr(OUString &rString, const css::uno::Reference< css::sdbc::XConnection > &_rxConnection, const IParseContext *pContext=nullptr, bool _bIntl=false, bool _bQuote=true) const
static OUString getTableRange(const OSQLParseNode *_pTableRef)
OSQLParseNode * getChild(sal_uInt32 nPos) const
OSQLParseNode * getByRule(OSQLParseNode::Rule eRule) const
void getColumnRange(const OSQLParseNode *_pColumnRef, OUString &_rColumnName, OUString &_rTableRange) const
std::unique_ptr< OSQLParseNode > parseTree(OUString &rErrorMessage, const OUString &rStatement, bool bInternational=false)
virtual css::uno::Any getBookmark()=0
std::unique_ptr< ORowSetMatrix > m_pMatrix
Definition: RowSetCache.hxx:54
const css::uno::Reference< css::sdbc::XResultSetMetaData > & getMetaData() const
bool relative(sal_Int32 rows)
connectivity::OSQLTable m_aUpdateTable
Definition: RowSetCache.hxx:63
css::uno::Any getBookmark()
sal_Int32 compareBookmarks(const css::uno::Any &first, const css::uno::Any &second)
void reset(const css::uno::Reference< css::sdbc::XResultSet > &_xDriverSet)
void resetInsertRow(bool _bClearInsertRow)
bool absolute(sal_Int32 row)
std::map< sal_Int32, sal_Int32 > m_aKeyColumns
Definition: RowSetCache.hxx:46
void updateValue(sal_Int32 columnIndex, const connectivity::ORowSetValue &x, ORowSetValueVector::Vector &io_aRow, std::vector< sal_Int32 > &o_ChangedColumns)
css::uno::WeakReference< css::sdbc::XResultSet > m_xSet
Definition: RowSetCache.hxx:48
ORowSetCacheMap m_aCacheIterators
Definition: RowSetCache.hxx:57
void setUpdateIterator(const ORowSetMatrix::iterator &_rOriginalRow)
bool moveRelativeToBookmark(const css::uno::Any &bookmark, sal_Int32 rows)
void rotateCacheIterator(ORowSetMatrix::difference_type _nDist)
void updateRow(ORowSetMatrix::iterator const &_rUpdateRow, std::vector< css::uno::Any > &o_aBookmarks)
void updateObject(sal_Int32 columnIndex, const css::uno::Any &x, ORowSetValueVector::Vector &io_aRow, std::vector< sal_Int32 > &o_ChangedColumns)
sal_Int32 getRow() const
rtl::Reference< OCacheSet > m_xCacheSet
Definition: RowSetCache.hxx:52
bool moveToBookmark(const css::uno::Any &bookmark)
ORowSetMatrix::iterator m_aMatrixIter
Definition: RowSetCache.hxx:55
bool isResultSetChanged() const
bool checkJoin(const css::uno::Reference< css::sdbc::XConnection > &_xConnection, const css::uno::Reference< css::sdb::XSingleSelectQueryAnalyzer > &_xComposer, const OUString &_sUpdateTableName)
ORowSetCacheIterator createIterator(ORowSetBase *_pRowSet)
sal_Int32 hashBookmark(const css::uno::Any &bookmark)
bool fill(ORowSetMatrix::iterator &_aIter, const ORowSetMatrix::const_iterator &_aEnd, sal_Int32 &_nPos, bool _bCheck)
ORowSetMatrix::iterator m_aInsertRow
Definition: RowSetCache.hxx:61
bool insertRow(std::vector< css::uno::Any > &o_aBookmarks)
ORowSetMatrix::iterator calcPosition() const
bool checkInnerJoin(const ::connectivity::OSQLParseNode *pNode, const css::uno::Reference< css::sdbc::XConnection > &_xConnection, const OUString &_sUpdateTableName)
TOldRowSetRows m_aOldRows
Definition: RowSetCache.hxx:58
void impl_updateRowFromCache_throw(ORowSetValueVector::Vector &io_aRow, std::vector< sal_Int32 > const &o_ChangedColumns)
TORowSetOldRowHelperRef registerOldRow()
bool fillMatrix(sal_Int32 &_nNewStartPos, sal_Int32 &_nNewEndPos)
void deregisterOldRow(const TORowSetOldRowHelperRef &_rRow)
bool isBeforeFirst() const
void updateNumericObject(sal_Int32 columnIndex, const css::uno::Any &x, ORowSetValueVector::Vector &io_aRow, std::vector< sal_Int32 > &o_ChangedColumns)
friend class ORowSetCacheIterator
Definition: RowSetCache.hxx:42
void updateCharacterStream(sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream > &x, sal_Int32 length, ORowSetValueVector::Vector &io_aRow, std::vector< sal_Int32 > &o_ChangedColumns)
void setFetchSize(sal_Int32 _nSize)
void checkUpdateConditions(sal_Int32 columnIndex)
css::uno::Reference< css::uno::XComponentContext > m_aContext
Definition: RowSetCache.hxx:50
ORowSetMatrix::iterator m_aMatrixEnd
Definition: RowSetCache.hxx:56
void updateNull(sal_Int32 columnIndex, ORowSetValueVector::Vector &io_aRow, std::vector< sal_Int32 > &o_ChangedColumns)
css::uno::Reference< css::sdbc::XResultSetMetaData > m_xMetaData
Definition: RowSetCache.hxx:49
void deleteIterator(const ORowSetBase *_pRowSet)
bool isAfterLast() const
bool reFillMatrix(sal_Int32 _nNewStartPos, sal_Int32 nNewEndPos)
std::unique_ptr< ORowSetMatrix > m_pInsertMatrix
Definition: RowSetCache.hxx:60
#define DBA_RES(id)
Reference< XComponentContext > m_aContext
#define TOOLS_WARN_EXCEPTION(area, stream)
#define DBG_UNHANDLED_EXCEPTION(...)
float x
Any aHelper
sal_Int16 nValue
Reference< XColumn > xColumn
sal_Int32 nNullable
sal_uInt16 nPos
Sequence< sal_Int8 > aSeq
const sal_uInt32 LEFT
const sal_uInt32 RIGHT
@ Exception
bool any2bool(const css::uno::Any &rAny)
std::map< OUString, SelectColumnDescription, ::comphelper::UStringMixLess > SelectColumnsMetaData
Definition: KeySet.hxx:62
::rtl::Reference< ORowSetValueVector > ORowSetRow
Definition: RowSetRow.hxx:30
connectivity::ORowVector< connectivity::ORowSetValue > ORowSetValueVector
Definition: RowSetRow.hxx:29
void getColumnPositions(const Reference< XNameAccess > &_rxQueryColumns, const css::uno::Sequence< OUString > &_aColumnNames, std::u16string_view _rsUpdateTableName, SelectColumnsMetaData &o_rColumnNames, bool i_bAppendTableName)
Definition: KeySet.cxx:1381
std::vector< ORowSetRow > ORowSetMatrix
Definition: RowSetRow.hxx:31
void throwFunctionSequenceException(const Reference< XInterface > &Context, const Any &Next)
Reference< XNameAccess > getPrimaryKeyColumns_throw(const Any &i_aTable)
Reference
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
enumrange< T >::Iterator begin(enumrange< T >)
#define SQL_ISRULE(pParseNode, eRule)
#define SQL_ISPUNCTUATION(pParseNode, aString)
#define SQL_ISTOKEN(pParseNode, token)
constexpr OUStringLiteral PROPERTY_RESULTSETCONCURRENCY(u"ResultSetConcurrency")
constexpr OUStringLiteral PROPERTY_RESULTSETTYPE(u"ResultSetType")
constexpr OUStringLiteral PROPERTY_ISNULLABLE(u"IsNullable")
constexpr OUStringLiteral PROPERTY_ISBOOKMARKABLE(u"IsBookmarkable")
constexpr OUStringLiteral SQLSTATE_GENERAL
Definition: strings.hxx:267
constexpr OUStringLiteral PROPERTY_PRIVILEGES(u"Privileges")
SELECT
AND
sal_Int32 _nPos