1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "BookmarkSet.hxx"
22 #include "CRowSetColumn.hxx"
23 #include "CRowSetDataColumn.hxx"
25 #include "OptimisticSet.hxx"
26 #include "RowSetBase.hxx"
27 #include "RowSetCache.hxx"
28 #include "StaticSet.hxx"
29 #include "WrappedResultSet.hxx"
30 #include "core_resource.hrc"
31 #include "core_resource.hxx"
32 #include "dbastrings.hrc"
34 #include <com/sun/star/sdbc/ColumnValue.hpp>
35 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
36 #include <com/sun/star/sdbcx/CompareBookmark.hpp>
37 #include <com/sun/star/sdbcx/KeyType.hpp>
38 #include <com/sun/star/sdbcx/Privilege.hpp>
39 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
40 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
41 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
43 #include <comphelper/extract.hxx>
44 #include <comphelper/property.hxx>
45 #include <comphelper/seqstream.hxx>
46 #include <comphelper/uno3.hxx>
47 #include <connectivity/dbexception.hxx>
48 #include <connectivity/dbtools.hxx>
49 #include <connectivity/sqliterator.hxx>
50 #include <connectivity/sqlnode.hxx>
51 #include <connectivity/sqlparse.hxx>
52 #include <tools/debug.hxx>
53 #include <tools/diagnose_ex.h>
54 #include <osl/diagnose.h>
58 using namespace dbaccess
;
59 using namespace dbtools
;
60 using namespace connectivity
;
61 using namespace ::com::sun::star::uno
;
62 using namespace ::com::sun::star::beans
;
63 using namespace ::com::sun::star::sdbc
;
64 using namespace ::com::sun::star::sdb
;
65 using namespace ::com::sun::star::sdbcx
;
66 using namespace ::com::sun::star::container
;
67 using namespace ::com::sun::star::lang
;
68 using namespace ::cppu
;
69 using namespace ::osl
;
71 #define CHECK_MATRIX_POS(M) OSL_ENSURE(((M) >= static_cast<ORowSetMatrix::difference_type>(0)) && ((M) < static_cast<sal_Int32>(m_pMatrix->size())),"Position is invalid!")
73 // This class calls m_pCacheSet->FOO_checked(..., sal_False)
74 // (where FOO is absolute, last, previous)
75 // when it does not immediately care about the values in the row's columns.
76 // As a corollary, m_pCacheSet may be left in an inconsistent state,
77 // and all ->fillFOO calls (and ->getFOO) may fail or give wrong results,
78 // until m_pCacheSet is moved (or refreshed) again.
79 // So always make sure m_pCacheSet is moved or refreshed before accessing column values.
81 DBG_NAME(ORowSetCache
)
83 ORowSetCache::ORowSetCache(const Reference
< XResultSet
>& _xRs
,
84 const Reference
< XSingleSelectQueryAnalyzer
>& _xAnalyzer
,
85 const ::comphelper::ComponentContext
& _rContext
,
86 const ::rtl::OUString
& _rUpdateTableName
,
89 const ORowSetValueVector
& _aParameterValueForCache
,
90 const ::rtl::OUString
& i_sRowSetFilter
,
93 ,m_xMetaData(Reference
< XResultSetMetaDataSupplier
>(_xRs
,UNO_QUERY
)->getMetaData())
94 ,m_aContext( _rContext
)
97 ,m_pInsertMatrix(NULL
)
98 ,m_nLastColumnIndex(0)
101 ,m_nPrivileges( Privilege::SELECT
)
105 ,m_bRowCountFinal(sal_False
)
106 ,m_bBeforeFirst(sal_True
)
107 ,m_bAfterLast( sal_False
)
108 ,m_bUpdated(sal_False
)
109 ,m_bModified(_bModified
)
112 DBG_CTOR(ORowSetCache
,NULL
);
114 // first try if the result can be used to do inserts and updates
115 Reference
< XPropertySet
> xProp(_xRs
,UNO_QUERY
);
116 Reference
< XPropertySetInfo
> xPropInfo
= xProp
->getPropertySetInfo();
117 sal_Bool bBookmarkable
= sal_False
;
120 Reference
< XResultSetUpdate
> xUp(_xRs
,UNO_QUERY_THROW
);
121 bBookmarkable
= xPropInfo
->hasPropertyByName(PROPERTY_ISBOOKMARKABLE
) &&
122 any2bool(xProp
->getPropertyValue(PROPERTY_ISBOOKMARKABLE
)) && Reference
< XRowLocate
>(_xRs
, UNO_QUERY
).is();
125 xUp
->moveToInsertRow();
126 xUp
->cancelRowUpdates();
128 m_nPrivileges
= Privilege::SELECT
|Privilege::DELETE
|Privilege::INSERT
|Privilege::UPDATE
;
129 m_pCacheSet
= new WrappedResultSet(i_nMaxRows
);
130 m_xCacheSet
= m_pCacheSet
;
131 m_pCacheSet
->construct(_xRs
,i_sRowSetFilter
);
135 catch(const Exception
& ex
)
141 if ( xPropInfo
->hasPropertyByName(PROPERTY_RESULTSETTYPE
) &&
142 ::comphelper::getINT32(xProp
->getPropertyValue(PROPERTY_RESULTSETTYPE
)) != ResultSetType::FORWARD_ONLY
)
145 catch(const SQLException
& e
)
150 // check if all keys of the updateable table are fetched
151 sal_Bool bAllKeysFound
= sal_False
;
152 sal_Int32 nTablesCount
= 0;
154 sal_Bool bNeedKeySet
= !bBookmarkable
|| (xPropInfo
->hasPropertyByName(PROPERTY_RESULTSETCONCURRENCY
) &&
155 ::comphelper::getINT32(xProp
->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY
)) == ResultSetConcurrency::READ_ONLY
);
157 Reference
< XIndexAccess
> xUpdateTableKeys
;
158 ::rtl::OUString aUpdateTableName
= _rUpdateTableName
;
159 Reference
< XConnection
> xConnection
;
160 // first we need a connection
161 Reference
< XStatement
> xStmt(_xRs
->getStatement(),UNO_QUERY
);
163 xConnection
= xStmt
->getConnection();
166 Reference
< XPreparedStatement
> xPrepStmt(_xRs
->getStatement(),UNO_QUERY
);
167 xConnection
= xPrepStmt
->getConnection();
169 OSL_ENSURE(xConnection
.is(),"No connection!");
174 Reference
<XTablesSupplier
> xTabSup(_xAnalyzer
,UNO_QUERY
);
175 OSL_ENSURE(xTabSup
.is(),"ORowSet::execute composer isn't a tablesupplier!");
176 Reference
<XNameAccess
> xTables
= xTabSup
->getTables();
177 Sequence
< ::rtl::OUString
> aTableNames
= xTables
->getElementNames();
178 if ( aTableNames
.getLength() > 1 && _rUpdateTableName
.isEmpty() && bNeedKeySet
)
179 {// here we have a join or union and nobody told us which table to update, so we update them all
180 m_nPrivileges
= Privilege::SELECT
|Privilege::DELETE
|Privilege::INSERT
|Privilege::UPDATE
;
181 OptimisticSet
* pCursor
= new OptimisticSet(m_aContext
,xConnection
,_xAnalyzer
,_aParameterValueForCache
,i_nMaxRows
,m_nRowCount
);
182 m_pCacheSet
= pCursor
;
183 m_xCacheSet
= m_pCacheSet
;
186 m_pCacheSet
->construct(_xRs
,i_sRowSetFilter
);
187 if ( pCursor
->isReadOnly() )
188 m_nPrivileges
= Privilege::SELECT
;
189 m_aKeyColumns
= pCursor
->getJoinedKeyColumns();
192 catch(const Exception
&)
200 if(!_rUpdateTableName
.isEmpty() && xTables
->hasByName(_rUpdateTableName
))
201 xTables
->getByName(_rUpdateTableName
) >>= m_aUpdateTable
;
202 else if(xTables
->getElementNames().getLength())
204 aUpdateTableName
= xTables
->getElementNames()[0];
205 xTables
->getByName(aUpdateTableName
) >>= m_aUpdateTable
;
207 Reference
<XIndexAccess
> xIndexAccess(xTables
,UNO_QUERY
);
208 if(xIndexAccess
.is())
209 nTablesCount
= xIndexAccess
->getCount();
211 nTablesCount
= xTables
->getElementNames().getLength();
213 if(m_aUpdateTable
.is() && nTablesCount
< 3) // for we can't handle more than 2 tables in our keyset
215 Reference
<XPropertySet
> xSet(m_aUpdateTable
,UNO_QUERY
);
216 const Reference
<XNameAccess
> xPrimaryKeyColumns
= dbtools::getPrimaryKeyColumns_throw(xSet
);
217 if ( xPrimaryKeyColumns
.is() )
219 Reference
<XColumnsSupplier
> xColSup(_xAnalyzer
,UNO_QUERY
);
222 Reference
<XNameAccess
> xSelColumns
= xColSup
->getColumns();
223 Reference
<XDatabaseMetaData
> xMeta
= xConnection
->getMetaData();
224 SelectColumnsMetaData
aColumnNames(xMeta
.is() && xMeta
->supportsMixedCaseQuotedIdentifiers() ? true : false);
225 ::dbaccess::getColumnPositions(xSelColumns
,xPrimaryKeyColumns
->getElementNames(),aUpdateTableName
,aColumnNames
);
226 bAllKeysFound
= !aColumnNames
.empty() && sal_Int32(aColumnNames
.size()) == xPrimaryKeyColumns
->getElementNames().getLength();
237 // first check if resultset is bookmarkable
242 m_pCacheSet
= new OBookmarkSet(i_nMaxRows
);
243 m_xCacheSet
= m_pCacheSet
;
244 m_pCacheSet
->construct(_xRs
,i_sRowSetFilter
);
247 m_nPrivileges
= Privilege::SELECT
;
248 if(Reference
<XResultSetUpdate
>(_xRs
,UNO_QUERY
).is()) // this interface is optional so we have to check it
250 Reference
<XPropertySet
> xTable(m_aUpdateTable
,UNO_QUERY
);
251 if(xTable
.is() && xTable
->getPropertySetInfo()->hasPropertyByName(PROPERTY_PRIVILEGES
))
254 xTable
->getPropertyValue(PROPERTY_PRIVILEGES
) >>= m_nPrivileges
;
256 m_nPrivileges
= Privilege::SELECT
;
260 catch(const SQLException
&)
262 bNeedKeySet
= sal_True
;
268 // need to check if we could handle this select clause
269 bAllKeysFound
= bAllKeysFound
&& (nTablesCount
== 1 || checkJoin(xConnection
,_xAnalyzer
,aUpdateTableName
));
275 // here I know that we have a read only bookmarkable cursor
277 m_nPrivileges
= Privilege::SELECT
;
278 m_pCacheSet
= new WrappedResultSet(i_nMaxRows
);
279 m_xCacheSet
= m_pCacheSet
;
280 m_pCacheSet
->construct(_xRs
,i_sRowSetFilter
);
283 m_pCacheSet
= new OStaticSet(i_nMaxRows
);
284 m_xCacheSet
= m_pCacheSet
;
285 m_pCacheSet
->construct(_xRs
,i_sRowSetFilter
);
286 m_nPrivileges
= Privilege::SELECT
;
290 Reference
<XDatabaseMetaData
> xMeta
= xConnection
->getMetaData();
291 SelectColumnsMetaData
aColumnNames(xMeta
.is() && xMeta
->supportsMixedCaseQuotedIdentifiers() ? true : false);
292 Reference
<XColumnsSupplier
> xColSup(_xAnalyzer
,UNO_QUERY
);
293 Reference
<XNameAccess
> xSelColumns
= xColSup
->getColumns();
294 Reference
<XNameAccess
> xColumns
= m_aUpdateTable
->getColumns();
295 ::dbaccess::getColumnPositions(xSelColumns
,xColumns
->getElementNames(),aUpdateTableName
,aColumnNames
);
298 m_nPrivileges
= Privilege::SELECT
;
299 sal_Bool bNoInsert
= sal_False
;
301 Sequence
< ::rtl::OUString
> aNames(xColumns
->getElementNames());
302 const ::rtl::OUString
* pIter
= aNames
.getConstArray();
303 const ::rtl::OUString
* pEnd
= pIter
+ aNames
.getLength();
304 for(;pIter
!= pEnd
;++pIter
)
306 Reference
<XPropertySet
> xColumn(xColumns
->getByName(*pIter
),UNO_QUERY
);
307 OSL_ENSURE(xColumn
.is(),"Column in table is null!");
310 sal_Int32 nNullable
= 0;
311 xColumn
->getPropertyValue(PROPERTY_ISNULLABLE
) >>= nNullable
;
312 if(nNullable
== ColumnValue::NO_NULLS
&& aColumnNames
.find(*pIter
) == aColumnNames
.end())
313 { // we found a column where null is not allowed so we can't insert new values
314 bNoInsert
= sal_True
;
315 break; // one column is enough
320 OKeySet
* pKeySet
= new OKeySet(m_aUpdateTable
,xUpdateTableKeys
,aUpdateTableName
,_xAnalyzer
,_aParameterValueForCache
,i_nMaxRows
,m_nRowCount
);
323 m_pCacheSet
= pKeySet
;
324 m_xCacheSet
= m_pCacheSet
;
325 pKeySet
->construct(_xRs
,i_sRowSetFilter
);
327 if(Reference
<XResultSetUpdate
>(_xRs
,UNO_QUERY
).is()) // this interface is optional so we have to check it
329 Reference
<XPropertySet
> xTable(m_aUpdateTable
,UNO_QUERY
);
330 if(xTable
.is() && xTable
->getPropertySetInfo()->hasPropertyByName(PROPERTY_PRIVILEGES
))
333 xTable
->getPropertyValue(PROPERTY_PRIVILEGES
) >>= m_nPrivileges
;
335 m_nPrivileges
= Privilege::SELECT
;
339 m_nPrivileges
|= ~Privilege::INSERT
; // remove the insert privilege
341 catch(const SQLException
&)
343 // we couldn't create a keyset here so we have to create a static cache
347 m_pCacheSet
= new OStaticSet(i_nMaxRows
);
348 m_xCacheSet
= m_pCacheSet
;
349 m_pCacheSet
->construct(_xRs
,i_sRowSetFilter
);
350 m_nPrivileges
= Privilege::SELECT
;
356 if(!bAllKeysFound
&& xProp
->getPropertySetInfo()->hasPropertyByName(PROPERTY_RESULTSETCONCURRENCY
) &&
357 ::comphelper::getINT32(xProp
->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY
)) == ResultSetConcurrency::READ_ONLY
)
358 m_nPrivileges
= Privilege::SELECT
;
361 ORowSetCache::~ORowSetCache()
373 m_pInsertMatrix
->clear();
374 delete m_pInsertMatrix
;
376 m_xSet
= WeakReference
< XResultSet
>();
378 m_aUpdateTable
= NULL
;
380 DBG_DTOR(ORowSetCache
,NULL
);
383 void ORowSetCache::setFetchSize(sal_Int32 _nSize
)
385 if(_nSize
== m_nFetchSize
)
388 m_nFetchSize
= _nSize
;
391 m_pMatrix
= new ORowSetMatrix(_nSize
);
392 m_aMatrixIter
= m_pMatrix
->end();
393 m_aMatrixEnd
= m_pMatrix
->end();
395 m_pInsertMatrix
= new ORowSetMatrix(1); // a little bit overkill but ??? :-)
396 m_aInsertRow
= m_pInsertMatrix
->end();
400 // now correct the iterator in our iterator vector
401 ::std::vector
<sal_Int32
> aPositions
;
402 ::std::map
<sal_Int32
,sal_Bool
> aCacheIterToChange
;
403 // first get the positions where they stand now
404 ORowSetCacheMap::iterator aCacheIter
= m_aCacheIterators
.begin();
405 ORowSetCacheMap::iterator aCacheEnd
= m_aCacheIterators
.end();
406 for(;aCacheIter
!= aCacheEnd
;++aCacheIter
)
408 aCacheIterToChange
[aCacheIter
->first
] = sal_False
;
409 if ( !aCacheIter
->second
.pRowSet
->isInsertRow()
410 /*&& aCacheIter->second.aIterator != m_pMatrix->end()*/ && !m_bModified
)
412 ptrdiff_t nDist
= (aCacheIter
->second
.aIterator
- m_pMatrix
->begin());
413 aPositions
.push_back(nDist
);
414 aCacheIterToChange
[aCacheIter
->first
] = sal_True
;
417 sal_Int32 nKeyPos
= (m_aMatrixIter
- m_pMatrix
->begin());
418 m_pMatrix
->resize(_nSize
);
420 if ( nKeyPos
< _nSize
)
421 m_aMatrixIter
= m_pMatrix
->begin() + nKeyPos
;
423 m_aMatrixIter
= m_pMatrix
->end();
424 m_aMatrixEnd
= m_pMatrix
->end();
426 // now adjust their positions because a resize invalidates all iterators
427 ::std::vector
<sal_Int32
>::const_iterator aIter
= aPositions
.begin();
428 ::std::map
<sal_Int32
,sal_Bool
>::const_iterator aPosChangeIter
= aCacheIterToChange
.begin();
429 for( aCacheIter
= m_aCacheIterators
.begin();
430 aPosChangeIter
!= aCacheIterToChange
.end();
431 ++aPosChangeIter
,++aCacheIter
)
433 if ( aPosChangeIter
->second
)
435 CHECK_MATRIX_POS(*aIter
);
436 if ( *aIter
< _nSize
)
437 aCacheIter
->second
.aIterator
= m_pMatrix
->begin() + *aIter
++;
439 aCacheIter
->second
.aIterator
= m_pMatrix
->end();
445 sal_Int32 nNewSt
= 0;
446 fillMatrix(nNewSt
,_nSize
);
447 OSL_ENSURE(nNewSt
== 0, "fillMatrix set new start to unexpected value");
451 else if (m_nStartPos
< m_nPosition
&& m_nPosition
<= m_nEndPos
)
453 sal_Int32 nNewSt
= -1;
454 _nSize
+= m_nStartPos
;
455 fillMatrix(nNewSt
, _nSize
);
458 m_nStartPos
= nNewSt
;
460 m_aMatrixIter
= calcPosition();
464 m_nEndPos
= m_nStartPos
+ m_nFetchSize
;
469 OSL_FAIL("m_nPosition not between m_nStartPos and m_nEndpos");
472 m_aMatrixIter
= calcPosition();
476 // XResultSetMetaDataSupplier
477 Reference
< XResultSetMetaData
> ORowSetCache::getMetaData( )
482 static Any
lcl_getBookmark(ORowSetValue
& i_aValue
,OCacheSet
* i_pCacheSet
)
484 switch ( i_aValue
.getTypeKind() )
486 case DataType::TINYINT
:
487 case DataType::SMALLINT
:
488 case DataType::INTEGER
:
489 return makeAny((sal_Int32
)i_aValue
);
491 if ( i_pCacheSet
&& i_aValue
.isNull())
492 i_aValue
= i_pCacheSet
->getBookmark();
493 return i_aValue
.getAny();
497 // ::com::sun::star::sdbcx::XRowLocate
498 Any
ORowSetCache::getBookmark( )
501 throwFunctionSequenceException(m_xSet
.get());
503 if ( m_aMatrixIter
>= m_pMatrix
->end() || m_aMatrixIter
< m_pMatrix
->begin() || !(*m_aMatrixIter
).is())
505 return Any(); // this is allowed here because the rowset knowns what it is doing
508 return lcl_getBookmark(((*m_aMatrixIter
)->get())[0],m_pCacheSet
);
511 sal_Bool
ORowSetCache::moveToBookmark( const Any
& bookmark
)
513 if ( m_pCacheSet
->moveToBookmark(bookmark
) )
515 m_bBeforeFirst
= sal_False
;
516 m_nPosition
= m_pCacheSet
->getRow();
518 checkPositionFlags();
523 checkPositionFlags();
526 m_aMatrixIter
= calcPosition();
527 OSL_ENSURE(m_aMatrixIter
->is(),"Iterator after moveToBookmark not valid");
530 m_aMatrixIter
= m_pMatrix
->end();
533 m_aMatrixIter
= m_pMatrix
->end();
538 return m_aMatrixIter
!= m_pMatrix
->end() && (*m_aMatrixIter
).is();
541 sal_Bool
ORowSetCache::moveRelativeToBookmark( const Any
& bookmark
, sal_Int32 rows
)
543 sal_Bool
bRet( moveToBookmark( bookmark
) );
546 m_nPosition
= m_pCacheSet
->getRow() + rows
;
547 absolute(m_nPosition
);
549 bRet
= m_aMatrixIter
!= m_pMatrix
->end() && (*m_aMatrixIter
).is();
555 sal_Int32
ORowSetCache::compareBookmarks( const Any
& _first
, const Any
& _second
)
557 return (!_first
.hasValue() || !_second
.hasValue()) ? CompareBookmark::NOT_COMPARABLE
: m_pCacheSet
->compareBookmarks(_first
,_second
);
560 sal_Bool
ORowSetCache::hasOrderedBookmarks( )
562 return m_pCacheSet
->hasOrderedBookmarks();
565 sal_Int32
ORowSetCache::hashBookmark( const Any
& bookmark
)
567 return m_pCacheSet
->hashBookmark(bookmark
);
571 void ORowSetCache::updateNull(sal_Int32 columnIndex
,ORowSetValueVector::Vector
& io_aRow
572 ,::std::vector
<sal_Int32
>& o_ChangedColumns
575 checkUpdateConditions(columnIndex
);
577 ORowSetValueVector::Vector
& rInsert
= ((*m_aInsertRow
)->get());
578 if ( !rInsert
[columnIndex
].isNull() )
580 rInsert
[columnIndex
].setBound(sal_True
);
581 rInsert
[columnIndex
].setNull();
582 rInsert
[columnIndex
].setModified();
583 io_aRow
[columnIndex
].setNull();
585 m_pCacheSet
->mergeColumnValues(columnIndex
,rInsert
,io_aRow
,o_ChangedColumns
);
586 impl_updateRowFromCache_throw(io_aRow
,o_ChangedColumns
);
590 void ORowSetCache::updateValue(sal_Int32 columnIndex
,const ORowSetValue
& x
591 ,ORowSetValueVector::Vector
& io_aRow
592 ,::std::vector
<sal_Int32
>& o_ChangedColumns
595 checkUpdateConditions(columnIndex
);
597 ORowSetValueVector::Vector
& rInsert
= ((*m_aInsertRow
)->get());
598 if ( rInsert
[columnIndex
] != x
)
600 rInsert
[columnIndex
].setBound(sal_True
);
601 rInsert
[columnIndex
] = x
;
602 rInsert
[columnIndex
].setModified();
603 io_aRow
[columnIndex
] = rInsert
[columnIndex
];
605 m_pCacheSet
->mergeColumnValues(columnIndex
,rInsert
,io_aRow
,o_ChangedColumns
);
606 impl_updateRowFromCache_throw(io_aRow
,o_ChangedColumns
);
610 void ORowSetCache::updateCharacterStream( sal_Int32 columnIndex
, const Reference
< ::com::sun::star::io::XInputStream
>& x
611 , sal_Int32 length
,ORowSetValueVector::Vector
& io_aRow
612 ,::std::vector
<sal_Int32
>& o_ChangedColumns
615 checkUpdateConditions(columnIndex
);
617 Sequence
<sal_Int8
> aSeq
;
619 x
->readBytes(aSeq
,length
);
621 ORowSetValueVector::Vector
& rInsert
= ((*m_aInsertRow
)->get());
622 rInsert
[columnIndex
].setBound(sal_True
);
623 rInsert
[columnIndex
] = aSeq
;
624 rInsert
[columnIndex
].setModified();
625 io_aRow
[columnIndex
] = makeAny(x
);
627 m_pCacheSet
->mergeColumnValues(columnIndex
,rInsert
,io_aRow
,o_ChangedColumns
);
628 impl_updateRowFromCache_throw(io_aRow
,o_ChangedColumns
);
631 void ORowSetCache::updateObject( sal_Int32 columnIndex
, const Any
& x
632 ,ORowSetValueVector::Vector
& io_aRow
633 ,::std::vector
<sal_Int32
>& o_ChangedColumns
636 checkUpdateConditions(columnIndex
);
638 ORowSetValueVector::Vector
& rInsert
= ((*m_aInsertRow
)->get());
641 if ( rInsert
[columnIndex
] != aTemp
)
643 rInsert
[columnIndex
].setBound(sal_True
);
644 rInsert
[columnIndex
] = aTemp
;
645 rInsert
[columnIndex
].setModified();
646 io_aRow
[columnIndex
] = rInsert
[columnIndex
];
648 m_pCacheSet
->mergeColumnValues(columnIndex
,rInsert
,io_aRow
,o_ChangedColumns
);
649 impl_updateRowFromCache_throw(io_aRow
,o_ChangedColumns
);
653 void ORowSetCache::updateNumericObject( sal_Int32 columnIndex
, const Any
& x
, sal_Int32
/*scale*/
654 ,ORowSetValueVector::Vector
& io_aRow
655 ,::std::vector
<sal_Int32
>& o_ChangedColumns
658 checkUpdateConditions(columnIndex
);
660 ORowSetValueVector::Vector
& rInsert
= ((*m_aInsertRow
)->get());
663 if ( rInsert
[columnIndex
] != aTemp
)
665 rInsert
[columnIndex
].setBound(sal_True
);
666 rInsert
[columnIndex
] = aTemp
;
667 rInsert
[columnIndex
].setModified();
668 io_aRow
[columnIndex
] = rInsert
[columnIndex
];
670 m_pCacheSet
->mergeColumnValues(columnIndex
,rInsert
,io_aRow
,o_ChangedColumns
);
671 impl_updateRowFromCache_throw(io_aRow
,o_ChangedColumns
);
676 sal_Bool
ORowSetCache::next( )
680 m_bBeforeFirst
= sal_False
;
683 // after we increment the position we have to check if we are already after the last row
684 checkPositionFlags();
689 OSL_ENSURE(((m_nPosition
- m_nStartPos
) - 1) < (sal_Int32
)m_pMatrix
->size(),"Position is behind end()!");
690 m_aMatrixIter
= calcPosition();
691 checkPositionFlags();
695 return !m_bAfterLast
;
698 sal_Bool
ORowSetCache::isBeforeFirst( )
700 return m_bBeforeFirst
;
703 sal_Bool
ORowSetCache::isAfterLast( )
708 sal_Bool
ORowSetCache::isFirst( )
710 return m_nPosition
== 1; // ask resultset for
713 sal_Bool
ORowSetCache::isLast( )
715 return m_nPosition
== m_nRowCount
;
718 sal_Bool
ORowSetCache::beforeFirst( )
722 m_bAfterLast
= sal_False
;
724 m_bBeforeFirst
= sal_True
;
725 m_pCacheSet
->beforeFirst();
727 m_aMatrixIter
= m_pMatrix
->end();
732 sal_Bool
ORowSetCache::afterLast( )
736 m_bBeforeFirst
= sal_False
;
737 m_bAfterLast
= sal_True
;
739 if(!m_bRowCountFinal
)
741 m_pCacheSet
->last_checked(sal_False
);
742 m_bRowCountFinal
= sal_True
;
743 m_nRowCount
= m_pCacheSet
->getRow();// + 1 removed
745 m_pCacheSet
->afterLast();
748 m_aMatrixIter
= m_pMatrix
->end();
753 sal_Bool
ORowSetCache::fillMatrix(sal_Int32
& _nNewStartPos
, sal_Int32
&_nNewEndPos
)
755 OSL_ENSURE(_nNewStartPos
!= _nNewEndPos
,"ORowSetCache::fillMatrix: StartPos and EndPos can not be equal!");
756 // If _nNewStartPos >= 0, then fill the whole window with new data
757 // Else if _nNewStartPos == -1, then fill only segment [m_nEndPos, _nNewEndPos)
758 // Else, undefined (invalid argument)
759 OSL_ENSURE( _nNewStartPos
>= -1, "ORowSetCache::fillMatrix: invalid _nNewStartPos" );
761 ORowSetMatrix::iterator aIter
;
764 sal_Int32 requestedStartPos
;
765 if ( _nNewStartPos
== -1 )
767 aIter
= m_pMatrix
->begin() + (m_nEndPos
- m_nStartPos
);
769 requestedStartPos
= m_nStartPos
;
773 aIter
= m_pMatrix
->begin();
774 i
= _nNewStartPos
+ 1;
775 requestedStartPos
= _nNewStartPos
;
777 bCheck
= m_pCacheSet
->absolute(i
);
780 for(; i
<= _nNewEndPos
; ++i
,++aIter
)
785 *aIter
= new ORowSetValueVector(m_xMetaData
->getColumnCount());
786 m_pCacheSet
->fillValueRow(*aIter
,i
);
789 { // there are no more rows found so we can fetch some before start
791 if(!m_bRowCountFinal
)
793 if(m_pCacheSet
->previous_checked(sal_False
)) // because we stand after the last row
794 m_nRowCount
= m_pCacheSet
->getRow(); // here we have the row count
796 m_nRowCount
= i
-1; // it can be that getRow return zero
797 m_bRowCountFinal
= sal_True
;
799 const ORowSetMatrix::iterator aEnd
= aIter
;
800 ORowSetMatrix::iterator aRealEnd
= m_pMatrix
->end();
802 if (m_nRowCount
>= m_nFetchSize
)
804 nPos
= m_nRowCount
- m_nFetchSize
;
810 _nNewStartPos
= nPos
;
811 _nNewEndPos
= m_nRowCount
;
813 bCheck
= m_pCacheSet
->absolute(nPos
);
815 for(;bCheck
&& nPos
<= requestedStartPos
&& aIter
!= aRealEnd
; ++aIter
, ++nPos
)
818 *aIter
= new ORowSetValueVector(m_xMetaData
->getColumnCount());
819 m_pCacheSet
->fillValueRow(*aIter
, nPos
);
820 bCheck
= m_pCacheSet
->next();
823 ::std::rotate(m_pMatrix
->begin(),aEnd
,aIter
);
826 bCheck
= m_pCacheSet
->next();
828 // we have to read one row forward to ensure that we know when we are on last row
829 // but only when we don't know it already
830 if(!m_bRowCountFinal
)
832 if(!m_pCacheSet
->next())
834 if(m_pCacheSet
->previous_checked(sal_False
)) // because we stand after the last row
835 m_nRowCount
= m_pCacheSet
->getRow(); // here we have the row count
836 m_bRowCountFinal
= sal_True
;
839 m_nRowCount
= std::max(i
,m_nRowCount
);
845 // If m_nPosition is out of the current window,
846 // move it and update m_nStartPos and m_nEndPos
847 // Caller is responsible for updating m_aMatrixIter
848 sal_Bool
ORowSetCache::moveWindow()
850 OSL_ENSURE(m_nStartPos
>= 0,"ORowSetCache::moveWindow: m_nStartPos is less than 0!");
851 OSL_ENSURE(m_nEndPos
>= m_nStartPos
,"ORowSetCache::moveWindow: m_nStartPos not smaller than m_nEndPos");
852 OSL_ENSURE(m_nEndPos
-m_nStartPos
<= m_nFetchSize
,"ORowSetCache::moveWindow: m_nStartPos and m_nEndPos too far apart");
854 if ( m_nStartPos
< m_nPosition
&& m_nPosition
<= m_nEndPos
)
856 // just move inside the window
857 OSL_ENSURE((m_nPosition
- m_nStartPos
) <= (sal_Int32
)m_pMatrix
->size(),"Position is behind end()!");
858 // make double plus sure that we have fetched that row
859 m_aMatrixIter
= calcPosition();
860 OSL_ENSURE(m_aMatrixIter
!= m_pMatrix
->end(), "New m_aMatrixIter is at end(), but should not.");
861 if(!m_aMatrixIter
->is())
863 sal_Bool
bOk( m_pCacheSet
->absolute( m_nPosition
) );
866 *m_aMatrixIter
= new ORowSetValueVector(m_xMetaData
->getColumnCount());
867 m_pCacheSet
->fillValueRow(*m_aMatrixIter
,m_nPosition
);
868 // we have to read one row forward to ensure that we know when we are on last row
869 // but only when we don't know it already
870 if ( !m_bRowCountFinal
)
872 bOk
= m_pCacheSet
->absolute_checked( m_nPosition
+ 1,sal_False
);
874 m_nRowCount
= std::max(sal_Int32(m_nPosition
+1),m_nRowCount
);
877 if(!bOk
&& !m_bRowCountFinal
)
879 // because we stand after the last row
880 m_nRowCount
= m_pCacheSet
->previous_checked(sal_False
) ? m_pCacheSet
->getRow() : 0;
881 m_bRowCountFinal
= sal_True
;
887 sal_Bool bRet
= sal_True
;
889 sal_Int32 nDiff
= (m_nFetchSize
- 1) / 2;
890 sal_Int32 nNewStartPos
= (m_nPosition
- nDiff
) - 1; //m_nPosition is 1-based, but m_nStartPos is 0-based
891 sal_Int32 nNewEndPos
= nNewStartPos
+ m_nFetchSize
;
893 if ( nNewStartPos
< 0 )
895 // The computed new window crashes through the floor (begins before first row);
896 // nNew*Pos has to be shifted by -nNewStartPos
897 nNewEndPos
-= nNewStartPos
;
901 if ( nNewStartPos
< m_nStartPos
)
902 { // need to fill data *before* m_nStartPos
903 if ( nNewEndPos
> m_nStartPos
)
904 { // The two regions are overlapping.
905 // We'll first rotate the contents of m_pMatrix so that the overlap area
906 // is positioned right; in the old window it is at the beginning,
907 // it has to go to the end.
908 // then we fill in the rows between new and old start pos.
911 bCheck
= m_pCacheSet
->absolute(nNewStartPos
+ 1);
913 // m_nEndPos < nNewEndPos when window not filled (e.g. there are less rows in total than window size)
914 m_nEndPos
= std::min(nNewEndPos
, m_nEndPos
);
915 const sal_Int32 nOverlapSize
= m_nEndPos
- m_nStartPos
;
916 const sal_Int32 nStartPosOffset
= m_nStartPos
- nNewStartPos
; // by how much m_nStartPos moves
917 m_nStartPos
= nNewStartPos
;
918 OSL_ENSURE( static_cast<ORowSetMatrix::size_type
>(nOverlapSize
) <= m_pMatrix
->size(), "new window end is after end of cache matrix!" );
919 // the first position in m_pMatrix whose data we don't keep;
920 // content will be moved to m_pMatrix.begin()
921 ORowSetMatrix::iterator
aEnd (m_pMatrix
->begin() + nOverlapSize
);
922 // the first unused position after we are done; it == m_pMatrix.end() if and only if the window is full
923 ORowSetMatrix::iterator
aNewEnd (aEnd
+ nStartPosOffset
);
924 // *m_pMatrix now looks like:
925 // [0; nOverlapSize) i.e. [begin(); aEnd): data kept
926 // [nOverlapSize; nOverlapSize + nStartPosOffet) i.e. [aEnd, aNewEnd): new data of positions < old m_nStartPos
927 // [nOverlapSize + nStartPosOffet; size()) i.e. [aNewEnd, end()): unused
928 // Note that nOverlapSize + nStartPosOffet == m_nEndPos - m_nStartPos (new values)
929 // When we are finished:
930 // [0; nStartPosOffset) i.e. [begin(); aEnd): new data of positions < old m_nStartPos
931 // [nStartPosOffset; nOverlapSize + nStartPosOffet) i.e. [aEnd, aNewEnd): kept
932 // [nOverlapSize + nStartPosOffet; size()) i.e. [aNewEnd, end()): unused
937 ORowSetMatrix::iterator
aIter(aEnd
);
938 sal_Int32 nPos
= m_nStartPos
+ 1;
939 bCheck
= fill(aIter
, aNewEnd
, nPos
, bCheck
);
942 ::std::rotate(m_pMatrix
->begin(), aEnd
, aNewEnd
);
943 // now correct the iterator in our iterator vector
944 // rotateCacheIterator(aEnd-m_pMatrix->begin()); //can't be used because they decrement and here we need to increment
945 ORowSetCacheMap::iterator aCacheIter
= m_aCacheIterators
.begin();
946 const ORowSetCacheMap::const_iterator aCacheEnd
= m_aCacheIterators
.end();
947 for(;aCacheIter
!= aCacheEnd
;++aCacheIter
)
949 if ( !aCacheIter
->second
.pRowSet
->isInsertRow()
950 && aCacheIter
->second
.aIterator
!= m_pMatrix
->end() && !m_bModified
)
952 const ptrdiff_t nDist
= (aCacheIter
->second
.aIterator
- m_pMatrix
->begin());
953 if ( nDist
>= nOverlapSize
)
955 // That's from outside the overlap area; invalidate iterator.
956 aCacheIter
->second
.aIterator
= m_pMatrix
->end();
960 // Inside overlap area: move to correct position
961 CHECK_MATRIX_POS( (nDist
+ nStartPosOffset
) );
962 aCacheIter
->second
.aIterator
+= nStartPosOffset
;
963 OSL_ENSURE(aCacheIter
->second
.aIterator
>= m_pMatrix
->begin()
964 && aCacheIter
->second
.aIterator
< m_pMatrix
->end(),"Iterator out of area!");
970 { // normally this should never happen
971 OSL_FAIL("What the hell is happen here!");
976 {// no rows can be reused so fill again
977 bRet
= reFillMatrix(nNewStartPos
,nNewEndPos
);
981 OSL_ENSURE(nNewStartPos
>= m_nStartPos
, "ORowSetCache::moveWindow internal error: new start pos before current start pos");
982 if ( m_nEndPos
< nNewEndPos
)
983 { // need to fill data *after* m_nEndPos
984 if( nNewStartPos
< m_nEndPos
)
985 { // The two regions are overlapping.
986 const sal_Int32 nRowsInCache
= m_nEndPos
- m_nStartPos
;
987 if ( nRowsInCache
< m_nFetchSize
)
989 // There is some unused space in *m_pMatrix; fill it
990 CHECK_MATRIX_POS(nRowsInCache
);
991 sal_Int32 nPos
= m_nEndPos
+ 1;
992 sal_Bool bCheck
= m_pCacheSet
->absolute(nPos
);
993 ORowSetMatrix::iterator aIter
= m_pMatrix
->begin() + nRowsInCache
;
994 const sal_Int32 nRowsToFetch
= std::min(nNewEndPos
-m_nEndPos
, m_nFetchSize
-nRowsInCache
);
995 const ORowSetMatrix::const_iterator aEnd
= aIter
+ nRowsToFetch
;
996 bCheck
= fill(aIter
, aEnd
, nPos
, bCheck
);
997 m_nEndPos
= nPos
- 1;
998 OSL_ENSURE( (!bCheck
&& m_nEndPos
<= nNewEndPos
) ||
999 ( bCheck
&& m_nEndPos
== nNewEndPos
),
1000 "ORowSetCache::moveWindow opportunistic fetch-after-current-end went badly");
1003 // À priori, the rows from begin() [inclusive] to (begin() + nNewStartPos - m_nStartPos) [exclusive]
1004 // have to be refilled with new to-be-fetched rows.
1005 // The rows behind this can be reused
1006 ORowSetMatrix::iterator aIter
= m_pMatrix
->begin();
1007 const sal_Int32 nNewStartPosInMatrix
= nNewStartPos
- m_nStartPos
;
1008 CHECK_MATRIX_POS( nNewStartPosInMatrix
);
1009 // first position we reuse
1010 const ORowSetMatrix::const_iterator aEnd
= m_pMatrix
->begin() + nNewStartPosInMatrix
;
1011 // End of used portion of the matrix. Is < m_pMatrix->end() if less data than window size
1012 ORowSetMatrix::iterator aDataEnd
= m_pMatrix
->begin() + (m_nEndPos
- m_nStartPos
);
1014 sal_Int32 nPos
= m_nEndPos
+ 1;
1015 sal_Bool bCheck
= m_pCacheSet
->absolute(nPos
);
1016 bCheck
= fill(aIter
, aEnd
, nPos
, bCheck
); // refill the region we don't need anymore
1017 //aIter and nPos are now the position *after* last filled in one!
1019 // bind end to front
1022 OSL_ENSURE(aIter
== aEnd
, "fill() said went till end, but did not.");
1023 // rotate the end to the front
1024 ::std::rotate(m_pMatrix
->begin(), aIter
, aDataEnd
);
1025 // now correct the iterator in our iterator vector
1026 rotateCacheIterator( nNewStartPosInMatrix
);
1027 m_nStartPos
= nNewStartPos
;
1028 m_nEndPos
= nNewEndPos
;
1029 // now I can say how many rows we have
1030 // we have to read one row forward to ensure that we know when we are on last row
1031 // but only when we don't know it already
1032 sal_Bool bOk
= sal_True
;
1033 if(!m_bRowCountFinal
)
1034 bOk
= m_pCacheSet
->next();
1037 m_pCacheSet
->previous_checked(sal_False
); // because we stand after the last row
1038 m_nRowCount
= nPos
; // here we have the row count
1039 OSL_ENSURE(nPos
== m_pCacheSet
->getRow(),"nPos is not valid!");
1040 m_bRowCountFinal
= sal_True
;
1042 else if(!m_bRowCountFinal
)
1043 m_nRowCount
= std::max(nPos
+1, m_nRowCount
); //+1 because we successfully moved to row after nPos
1045 OSL_ENSURE(m_nRowCount
>= nPos
, "Final m_nRowCount is smaller than row I moved to!");
1048 { // the end was reached before or at end() so we can set the start before or at nNewStartPos
1049 // and possibly keep more of m_pMatrix than planned.
1050 const ORowSetMatrix::iterator::difference_type nFetchedRows
= aIter
- m_pMatrix
->begin();
1051 // *m_pMatrix now looks like:
1052 // [0; nFetchedRows) i.e. [begin(); aIter): newly fetched data for positions m_nEndPos to m_nEndPos+nFetchedRows
1053 // [nFetchedRows; ???) i.e. [aIter; aDataEnd]: data to be kept for positions m_nStartPos+nFetchedRows to ???
1056 m_nStartPos
+= nFetchedRows
;
1058 ::std::rotate(m_pMatrix
->begin(), aIter
, aDataEnd
);
1059 // now correct the iterator in our iterator vector
1060 rotateCacheIterator( nFetchedRows
);
1062 if ( !m_bRowCountFinal
)
1064 m_pCacheSet
->previous_checked(sal_False
); // because we stand after the last row
1065 m_nRowCount
= std::max(m_nRowCount
, nPos
); // here we have the row count
1066 OSL_ENSURE(nPos
== m_pCacheSet
->getRow(),"nPos isn't valid!");
1067 m_bRowCountFinal
= sal_True
;
1071 // here we need only to check if the beginning row is valid. If not we have to fetch it.
1072 if(!m_pMatrix
->begin()->is())
1074 aIter
= m_pMatrix
->begin();
1076 nPos
= m_nStartPos
+ 1;
1077 bCheck
= m_pCacheSet
->absolute_checked(nPos
, sal_True
);
1078 for(; !aIter
->is() && bCheck
;++aIter
, ++nPos
)
1080 OSL_ENSURE(aIter
!= m_pMatrix
->end(),"Invalid iterator");
1082 *aIter
= new ORowSetValueVector(m_xMetaData
->getColumnCount());
1083 m_pCacheSet
->fillValueRow(*aIter
, nPos
);
1085 bCheck
= m_pCacheSet
->next();
1089 else // no rows can be reused so fill again
1090 bRet
= reFillMatrix(nNewStartPos
,nNewEndPos
);
1093 if(!m_bRowCountFinal
)
1094 m_nRowCount
= std::max(m_nPosition
,m_nRowCount
);
1095 OSL_ENSURE(m_nStartPos
>= 0,"ORowSetCache::moveWindow: m_nStartPos is less than 0!");
1096 OSL_ENSURE(m_nEndPos
> m_nStartPos
,"ORowSetCache::moveWindow: m_nStartPos not smaller than m_nEndPos");
1097 OSL_ENSURE(m_nEndPos
-m_nStartPos
<= m_nFetchSize
,"ORowSetCache::moveWindow: m_nStartPos and m_nEndPos too far apart");
1102 sal_Bool
ORowSetCache::first( )
1104 // First move to the first row.
1105 // Then check if the cache window is at the beginning.
1106 // If not, then position the window and fill it with data.
1107 // We move the window smartly, i.e. we clear only the rows that are out of range
1108 sal_Bool bRet
= m_pCacheSet
->first();
1111 m_bBeforeFirst
= m_bAfterLast
= sal_False
;
1114 m_aMatrixIter
= m_pMatrix
->begin();
1118 m_bRowCountFinal
= m_bBeforeFirst
= m_bAfterLast
= sal_True
;
1119 m_nRowCount
= m_nPosition
= 0;
1121 OSL_ENSURE(m_bBeforeFirst
|| m_bNew
,"ORowSetCache::first return false and BeforeFirst isn't true");
1122 m_aMatrixIter
= m_pMatrix
->end();
1127 sal_Bool
ORowSetCache::last( )
1129 sal_Bool bRet
= m_pCacheSet
->last();
1132 m_bBeforeFirst
= m_bAfterLast
= sal_False
;
1133 if(!m_bRowCountFinal
)
1135 m_bRowCountFinal
= sal_True
;
1136 m_nRowCount
= m_pCacheSet
->getRow(); // not + 1
1138 m_nPosition
= m_pCacheSet
->getRow();
1140 // we have to repositioning because moveWindow can modify the cache
1141 m_pCacheSet
->last();
1142 OSL_ENSURE(((m_nPosition
- m_nStartPos
) - 1) < (sal_Int32
)m_pMatrix
->size(),"Position is behind end()!");
1143 m_aMatrixIter
= calcPosition();
1147 m_bRowCountFinal
= m_bBeforeFirst
= m_bAfterLast
= sal_True
;
1148 m_nRowCount
= m_nPosition
= 0;
1149 OSL_ENSURE(m_bBeforeFirst
,"ORowSetCache::last return false and BeforeFirst isn't true");
1150 m_aMatrixIter
= m_pMatrix
->end();
1152 #if OSL_DEBUG_LEVEL > 1
1155 OSL_ENSURE((*m_aMatrixIter
).is(),"ORowSetCache::last: Row not valid!");
1162 sal_Int32
ORowSetCache::getRow( )
1164 return (isBeforeFirst() || isAfterLast()) ? 0 : m_nPosition
;
1167 sal_Bool
ORowSetCache::absolute( sal_Int32 row
)
1170 throw SQLException(DBACORE_RESSTRING(RID_STR_NO_ABS_ZERO
),NULL
,SQLSTATE_GENERAL
,1000,Any() );
1174 // here we have to scroll from the last row to backward so we have to go to last row and
1175 // and two the previous
1176 if(m_bRowCountFinal
|| last())
1178 m_nPosition
= m_nRowCount
+ row
+ 1; // + row because row is negative and +1 because row==-1 means last row
1181 m_bBeforeFirst
= sal_True
;
1182 m_bAfterLast
= sal_False
;
1183 m_aMatrixIter
= m_pMatrix
->end();
1187 m_bBeforeFirst
= sal_False
;
1188 m_bAfterLast
= m_nPosition
> m_nRowCount
;
1190 OSL_ENSURE(((m_nPosition
- m_nStartPos
) - 1) < (sal_Int32
)m_pMatrix
->size(),"Position is behind end()!");
1191 m_aMatrixIter
= calcPosition();
1195 m_aMatrixIter
= m_pMatrix
->end();
1200 // the position flags
1201 m_bBeforeFirst
= sal_False
;
1202 checkPositionFlags();
1207 checkPositionFlags();
1209 m_aMatrixIter
= calcPosition();
1211 m_aMatrixIter
= m_pMatrix
->end();
1214 m_aMatrixIter
= m_pMatrix
->end();
1217 return !(m_bAfterLast
|| m_bBeforeFirst
);
1220 sal_Bool
ORowSetCache::relative( sal_Int32 rows
)
1222 sal_Bool bErg
= sal_True
;
1225 sal_Int32 nNewPosition
= m_nPosition
+ rows
;
1227 if ( m_bBeforeFirst
&& rows
> 0 )
1228 nNewPosition
= rows
;
1229 else if ( m_bRowCountFinal
&& m_bAfterLast
&& rows
< 0 )
1230 nNewPosition
= m_nRowCount
+ 1 + rows
;
1232 if ( m_bBeforeFirst
|| ( m_bRowCountFinal
&& m_bAfterLast
) )
1233 throw SQLException( DBACORE_RESSTRING( RID_STR_NO_RELATIVE
), NULL
, SQLSTATE_GENERAL
, 1000, Any() );
1236 bErg
= absolute( nNewPosition
);
1237 bErg
= bErg
&& !isAfterLast() && !isBeforeFirst();
1241 m_bBeforeFirst
= sal_True
;
1248 sal_Bool
ORowSetCache::previous( )
1250 sal_Bool bRet
= sal_False
;
1251 if(!isBeforeFirst())
1253 if(m_bAfterLast
) // we stand after the last row so one before is the last row
1257 m_bAfterLast
= sal_False
;
1260 OSL_ENSURE(((m_nPosition
- m_nStartPos
) - 1) < (sal_Int32
)m_pMatrix
->size(),"Position is behind end()!");
1262 checkPositionFlags();
1266 m_bBeforeFirst
= sal_True
;
1267 m_aMatrixIter
= m_pMatrix
->end();
1271 m_aMatrixIter
= calcPosition();
1272 bRet
= (*m_aMatrixIter
).is();
1279 void ORowSetCache::refreshRow( )
1282 throw SQLException(DBACORE_RESSTRING(RID_STR_NO_REFESH_AFTERLAST
),NULL
,SQLSTATE_GENERAL
,1000,Any() );
1283 OSL_ENSURE(m_aMatrixIter
!= m_pMatrix
->end(),"refreshRow() called for invalid row!");
1284 m_pCacheSet
->refreshRow();
1285 m_pCacheSet
->fillValueRow(*m_aMatrixIter
,m_nPosition
);
1288 cancelRowModification();
1292 sal_Bool
ORowSetCache::rowUpdated( )
1294 return m_pCacheSet
->rowUpdated();
1297 sal_Bool
ORowSetCache::rowInserted( )
1299 return m_pCacheSet
->rowInserted();
1303 sal_Bool
ORowSetCache::insertRow(::std::vector
< Any
>& o_aBookmarks
)
1305 if ( !m_bNew
|| !m_aInsertRow
->is() )
1306 throw SQLException(DBACORE_RESSTRING(RID_STR_NO_MOVETOINSERTROW_CALLED
),NULL
,SQLSTATE_GENERAL
,1000,Any() );
1308 m_pCacheSet
->insertRow(*m_aInsertRow
,m_aUpdateTable
);
1310 sal_Bool
bRet( rowInserted() );
1314 Any aBookmark
= ((*m_aInsertRow
)->get())[0].makeAny();
1315 m_bAfterLast
= m_bBeforeFirst
= sal_False
;
1316 if(aBookmark
.hasValue())
1318 moveToBookmark(aBookmark
);
1319 // update the cached values
1320 ORowSetValueVector::Vector
& rCurrentRow
= ((*m_aMatrixIter
))->get();
1321 ORowSetMatrix::iterator aIter
= m_pMatrix
->begin();
1322 for(;aIter
!= m_pMatrix
->end();++aIter
)
1324 if ( m_aMatrixIter
!= aIter
&& aIter
->is() && m_pCacheSet
->columnValuesUpdated((*aIter
)->get(),rCurrentRow
) )
1326 o_aBookmarks
.push_back(lcl_getBookmark((*aIter
)->get()[0],m_pCacheSet
));
1332 OSL_FAIL("There must be a bookmark after the row was inserted!");
1338 void ORowSetCache::resetInsertRow(sal_Bool _bClearInsertRow
)
1340 if ( _bClearInsertRow
)
1343 m_bModified
= sal_False
;
1346 void ORowSetCache::cancelRowModification()
1348 // clear the insertrow references -> implies that the current row of the rowset changes as well
1349 ORowSetCacheMap::iterator aCacheIter
= m_aCacheIterators
.begin();
1350 ORowSetCacheMap::iterator aCacheEnd
= m_aCacheIterators
.end();
1351 for(;aCacheIter
!= aCacheEnd
;++aCacheIter
)
1353 if ( aCacheIter
->second
.pRowSet
->isInsertRow() && aCacheIter
->second
.aIterator
== m_aInsertRow
)
1354 aCacheIter
->second
.aIterator
= m_pMatrix
->end();
1356 resetInsertRow(sal_False
);
1359 void ORowSetCache::updateRow( ORowSetMatrix::iterator
& _rUpdateRow
,::std::vector
< Any
>& o_aBookmarks
)
1361 if(isAfterLast() || isBeforeFirst())
1362 throw SQLException(DBACORE_RESSTRING(RID_STR_NO_UPDATEROW
),NULL
,SQLSTATE_GENERAL
,1000,Any() );
1364 Any aBookmark
= ((*_rUpdateRow
)->get())[0].makeAny();
1365 OSL_ENSURE(aBookmark
.hasValue(),"Bookmark must have a value!");
1366 // here we don't have to reposition our CacheSet, when we try to update a row,
1367 // the row was already fetched
1368 moveToBookmark(aBookmark
);
1369 m_pCacheSet
->updateRow(*_rUpdateRow
,*m_aMatrixIter
,m_aUpdateTable
);
1370 // refetch the whole row
1371 (*m_aMatrixIter
) = NULL
;
1373 if ( moveToBookmark(aBookmark
) )
1375 // update the cached values
1376 ORowSetValueVector::Vector
& rCurrentRow
= ((*m_aMatrixIter
))->get();
1377 ORowSetMatrix::iterator aIter
= m_pMatrix
->begin();
1378 for(;aIter
!= m_pMatrix
->end();++aIter
)
1380 if ( m_aMatrixIter
!= aIter
&& aIter
->is() && m_pCacheSet
->columnValuesUpdated((*aIter
)->get(),rCurrentRow
) )
1382 o_aBookmarks
.push_back(lcl_getBookmark((*aIter
)->get()[0],m_pCacheSet
));
1387 m_bModified
= sal_False
;
1390 bool ORowSetCache::deleteRow( )
1392 if(isAfterLast() || isBeforeFirst())
1393 throw SQLException(DBACORE_RESSTRING(RID_STR_NO_DELETEROW
),NULL
,SQLSTATE_GENERAL
,1000,Any() );
1395 m_pCacheSet
->deleteRow(*m_aMatrixIter
,m_aUpdateTable
);
1396 if ( !m_pCacheSet
->rowDeleted() )
1400 OSL_ENSURE(((m_nPosition
- m_nStartPos
) - 1) < (sal_Int32
)m_pMatrix
->size(),"Position is behind end()!");
1401 ORowSetMatrix::iterator aPos
= calcPosition();
1404 ORowSetMatrix::iterator aEnd
= m_pMatrix
->end();
1405 for(++aPos
;aPos
!= aEnd
&& aPos
->is();++aPos
)
1410 m_aMatrixIter
= m_pMatrix
->end();
1416 void ORowSetCache::cancelRowUpdates( )
1418 m_bNew
= m_bModified
= sal_False
;
1421 OSL_FAIL("cancelRowUpdates:Invalid positions pos == 0");
1422 ::dbtools::throwFunctionSequenceException(NULL
);
1425 if(m_pCacheSet
->absolute(m_nPosition
))
1426 m_pCacheSet
->fillValueRow(*m_aMatrixIter
,m_nPosition
);
1429 OSL_FAIL("cancelRowUpdates couldn't position right with absolute");
1430 ::dbtools::throwFunctionSequenceException(NULL
);
1434 void ORowSetCache::moveToInsertRow( )
1437 m_bUpdated
= m_bAfterLast
= sal_False
;
1439 m_aInsertRow
= m_pInsertMatrix
->begin();
1440 if(!m_aInsertRow
->is())
1441 *m_aInsertRow
= new ORowSetValueVector(m_xMetaData
->getColumnCount());
1443 // we don't unbound the bookmark column
1444 ORowSetValueVector::Vector::iterator aIter
= (*m_aInsertRow
)->get().begin()+1;
1445 ORowSetValueVector::Vector::iterator aEnd
= (*m_aInsertRow
)->get().end();
1446 for(sal_Int32 i
= 1;aIter
!= aEnd
;++aIter
,++i
)
1448 aIter
->setBound(sal_False
);
1449 aIter
->setModified(sal_False
);
1451 aIter
->setTypeKind(m_xMetaData
->getColumnType(i
));
1455 ORowSetCacheIterator
ORowSetCache::createIterator(ORowSetBase
* _pRowSet
)
1457 ORowSetCacheIterator_Helper aHelper
;
1458 aHelper
.aIterator
= m_pMatrix
->end();
1459 aHelper
.pRowSet
= _pRowSet
;
1460 return ORowSetCacheIterator(m_aCacheIterators
.insert(m_aCacheIterators
.begin(),ORowSetCacheMap::value_type(m_aCacheIterators
.size()+1,aHelper
)),this,_pRowSet
);
1463 void ORowSetCache::deleteIterator(const ORowSetBase
* _pRowSet
)
1465 ORowSetCacheMap::iterator aCacheIter
= m_aCacheIterators
.begin();
1466 for(;aCacheIter
!= m_aCacheIterators
.end();)
1468 if ( aCacheIter
->second
.pRowSet
== _pRowSet
)
1470 m_aCacheIterators
.erase(aCacheIter
);
1471 aCacheIter
= m_aCacheIterators
.begin();
1478 void ORowSetCache::rotateCacheIterator(ORowSetMatrix::difference_type _nDist
)
1482 // now correct the iterator in our iterator vector
1483 ORowSetCacheMap::iterator aCacheIter
= m_aCacheIterators
.begin();
1484 ORowSetCacheMap::iterator aCacheEnd
= m_aCacheIterators
.end();
1485 for(;aCacheIter
!= aCacheEnd
;++aCacheIter
)
1487 if ( !aCacheIter
->second
.pRowSet
->isInsertRow()
1488 && aCacheIter
->second
.aIterator
!= m_pMatrix
->end() && !m_bModified
)
1490 ptrdiff_t nDist
= (aCacheIter
->second
.aIterator
- m_pMatrix
->begin());
1493 aCacheIter
->second
.aIterator
= m_pMatrix
->end();
1497 OSL_ENSURE((aCacheIter
->second
.aIterator
- m_pMatrix
->begin()) >= _nDist
,"Invalid Dist value!");
1498 aCacheIter
->second
.aIterator
-= _nDist
;
1499 OSL_ENSURE(aCacheIter
->second
.aIterator
>= m_pMatrix
->begin()
1500 && aCacheIter
->second
.aIterator
< m_pMatrix
->end(),"Iterator out of area!");
1507 void ORowSetCache::setUpdateIterator(const ORowSetMatrix::iterator
& _rOriginalRow
)
1509 m_aInsertRow
= m_pInsertMatrix
->begin();
1510 if(!m_aInsertRow
->is())
1511 *m_aInsertRow
= new ORowSetValueVector(m_xMetaData
->getColumnCount());
1513 (*(*m_aInsertRow
)) = (*(*_rOriginalRow
));
1514 // we don't unbound the bookmark column
1515 ORowSetValueVector::Vector::iterator aIter
= (*m_aInsertRow
)->get().begin();
1516 ORowSetValueVector::Vector::iterator aEnd
= (*m_aInsertRow
)->get().end();
1517 for(;aIter
!= aEnd
;++aIter
)
1518 aIter
->setModified(sal_False
);
1521 void ORowSetCache::checkPositionFlags()
1523 if(m_bRowCountFinal
)
1525 m_bAfterLast
= m_nPosition
> m_nRowCount
;
1527 m_nPosition
= 0;//m_nRowCount;
1531 void ORowSetCache::checkUpdateConditions(sal_Int32 columnIndex
)
1533 if(m_bAfterLast
|| columnIndex
>= (sal_Int32
)(*m_aInsertRow
)->get().size())
1534 throwFunctionSequenceException(m_xSet
.get());
1537 sal_Bool
ORowSetCache::checkInnerJoin(const ::connectivity::OSQLParseNode
*pNode
,const Reference
< XConnection
>& _xConnection
,const ::rtl::OUString
& _sUpdateTableName
)
1539 sal_Bool bOk
= sal_False
;
1540 if (pNode
->count() == 3 && // Ausdruck is geklammert
1541 SQL_ISPUNCTUATION(pNode
->getChild(0),"(") &&
1542 SQL_ISPUNCTUATION(pNode
->getChild(2),")"))
1544 bOk
= checkInnerJoin(pNode
->getChild(1),_xConnection
,_sUpdateTableName
);
1546 else if ((SQL_ISRULE(pNode
,search_condition
) || SQL_ISRULE(pNode
,boolean_term
)) && // AND/OR link
1547 pNode
->count() == 3)
1549 // only allow an AND link
1550 if ( SQL_ISTOKEN(pNode
->getChild(1),AND
) )
1551 bOk
= checkInnerJoin(pNode
->getChild(0),_xConnection
,_sUpdateTableName
)
1552 && checkInnerJoin(pNode
->getChild(2),_xConnection
,_sUpdateTableName
);
1554 else if (SQL_ISRULE(pNode
,comparison_predicate
))
1556 // only the comparison of columns is allowed
1557 OSL_ENSURE(pNode
->count() == 3,"checkInnerJoin: Fehler im Parse Tree");
1558 if (!(SQL_ISRULE(pNode
->getChild(0),column_ref
) &&
1559 SQL_ISRULE(pNode
->getChild(2),column_ref
) &&
1560 pNode
->getChild(1)->getNodeType() == SQL_NODE_EQUAL
))
1564 ::rtl::OUString sColumnName
,sTableRange
;
1565 OSQLParseTreeIterator::getColumnRange( pNode
->getChild(0), _xConnection
, sColumnName
, sTableRange
);
1566 bOk
= sTableRange
== _sUpdateTableName
;
1569 OSQLParseTreeIterator::getColumnRange( pNode
->getChild(2), _xConnection
, sColumnName
, sTableRange
);
1570 bOk
= sTableRange
== _sUpdateTableName
;
1576 sal_Bool
ORowSetCache::checkJoin(const Reference
< XConnection
>& _xConnection
,
1577 const Reference
< XSingleSelectQueryAnalyzer
>& _xAnalyzer
,
1578 const ::rtl::OUString
& _sUpdateTableName
)
1580 sal_Bool bOk
= sal_False
;
1581 ::rtl::OUString sSql
= _xAnalyzer
->getQuery();
1582 ::rtl::OUString sErrorMsg
;
1583 ::connectivity::OSQLParser
aSqlParser( m_aContext
.getUNOContext() );
1584 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1585 ::std::auto_ptr
< ::connectivity::OSQLParseNode
> pSqlParseNode( aSqlParser
.parseTree(sErrorMsg
,sSql
));
1586 SAL_WNODEPRECATED_DECLARATIONS_POP
1587 if ( pSqlParseNode
.get() && SQL_ISRULE(pSqlParseNode
, select_statement
) )
1589 OSQLParseNode
* pTableRefCommalist
= pSqlParseNode
->getByRule(::connectivity::OSQLParseNode::table_ref_commalist
);
1590 OSL_ENSURE(pTableRefCommalist
,"NO tables why!?");
1591 if(pTableRefCommalist
&& pTableRefCommalist
->count() == 1)
1593 // we found only one element so it must some kind of join here
1594 OSQLParseNode
* pJoin
= pTableRefCommalist
->getByRule(::connectivity::OSQLParseNode::qualified_join
);
1596 { // we are only intereseted in qualified joins like RIGHT or LEFT
1597 OSQLParseNode
* pJoinType
= pJoin
->getChild(1);
1598 OSQLParseNode
* pOuterType
= NULL
;
1599 if(SQL_ISRULE(pJoinType
,join_type
) && pJoinType
->count() == 2)
1600 pOuterType
= pJoinType
->getChild(0);
1601 else if(SQL_ISRULE(pJoinType
,outer_join_type
))
1602 pOuterType
= pJoinType
;
1604 sal_Bool bCheck
= sal_False
;
1605 sal_Bool bLeftSide
= sal_False
;
1607 { // found outer join
1608 bLeftSide
= SQL_ISTOKEN(pOuterType
->getChild(0),LEFT
);
1609 bCheck
= bLeftSide
|| SQL_ISTOKEN(pOuterType
->getChild(0),RIGHT
);
1613 { // here we know that we have to check on which side our table resides
1614 const OSQLParseNode
* pTableRef
= pJoin
->getByRule(::connectivity::OSQLParseNode::qualified_join
);
1616 pTableRef
= pJoin
->getChild(0);
1618 pTableRef
= pJoin
->getChild(3);
1619 OSL_ENSURE(SQL_ISRULE(pTableRef
,table_ref
),"Must be a tableref here!");
1621 ::rtl::OUString sTableRange
= OSQLParseNode::getTableRange(pTableRef
);
1622 if(sTableRange
.isEmpty())
1623 pTableRef
->getChild(0)->parseNodeToStr( sTableRange
, _xConnection
, NULL
, sal_False
, sal_False
);
1624 bOk
= sTableRange
== _sUpdateTableName
;
1630 OSQLParseNode
* pWhereOpt
= pSqlParseNode
->getChild(3)->getChild(1);
1631 if ( pWhereOpt
&& !pWhereOpt
->isLeaf() )
1632 bOk
= checkInnerJoin(pWhereOpt
->getChild(1),_xConnection
,_sUpdateTableName
);
1638 void ORowSetCache::clearInsertRow()
1640 // we don't unbound the bookmark column
1641 if ( m_aInsertRow
!= m_pInsertMatrix
->end() && m_aInsertRow
->is() )
1643 ORowSetValueVector::Vector::iterator aIter
= (*m_aInsertRow
)->get().begin()+1;
1644 ORowSetValueVector::Vector::iterator aEnd
= (*m_aInsertRow
)->get().end();
1645 for(;aIter
!= aEnd
;++aIter
)
1647 aIter
->setBound(sal_False
);
1648 aIter
->setModified(sal_False
);
1654 ORowSetMatrix::iterator
ORowSetCache::calcPosition() const
1656 sal_Int32 nValue
= (m_nPosition
- m_nStartPos
) - 1;
1657 CHECK_MATRIX_POS(nValue
);
1658 return ( nValue
< 0 || nValue
>= static_cast<sal_Int32
>(m_pMatrix
->size()) ) ? m_pMatrix
->end() : (m_pMatrix
->begin() + nValue
);
1661 TORowSetOldRowHelperRef
ORowSetCache::registerOldRow()
1663 TORowSetOldRowHelperRef pRef
= new ORowSetOldRowHelper(ORowSetRow());
1664 m_aOldRows
.push_back(pRef
);
1668 void ORowSetCache::deregisterOldRow(const TORowSetOldRowHelperRef
& _rRow
)
1670 TOldRowSetRows::iterator aOldRowEnd
= m_aOldRows
.end();
1671 for (TOldRowSetRows::iterator aOldRowIter
= m_aOldRows
.begin(); aOldRowIter
!= aOldRowEnd
; ++aOldRowIter
)
1673 if ( aOldRowIter
->get() == _rRow
.get() )
1675 m_aOldRows
.erase(aOldRowIter
);
1682 sal_Bool
ORowSetCache::reFillMatrix(sal_Int32 _nNewStartPos
,sal_Int32 _nNewEndPos
)
1684 OSL_ENSURE( _nNewEndPos
- _nNewStartPos
== m_nFetchSize
, "reFillMatrix called with Start/EndPos not m_nFetchSize apart");
1685 const TOldRowSetRows::const_iterator aOldRowEnd
= m_aOldRows
.end();
1686 for (TOldRowSetRows::iterator aOldRowIter
= m_aOldRows
.begin(); aOldRowIter
!= aOldRowEnd
; ++aOldRowIter
)
1688 if ( aOldRowIter
->is() && (*aOldRowIter
)->getRow().is() )
1689 (*aOldRowIter
)->setRow(new ORowSetValueVector( *((*aOldRowIter
)->getRow()) ) );
1691 sal_Int32 nNewSt
= _nNewStartPos
;
1692 sal_Bool bRet
= fillMatrix(nNewSt
,_nNewEndPos
);
1693 m_nStartPos
= nNewSt
;
1694 m_nEndPos
= _nNewEndPos
;
1695 rotateCacheIterator(static_cast<ORowSetMatrix::difference_type
>(m_nFetchSize
+1)); // invalidate every iterator
1699 sal_Bool
ORowSetCache::fill(ORowSetMatrix::iterator
& _aIter
,const ORowSetMatrix::const_iterator
& _aEnd
,sal_Int32
& _nPos
,sal_Bool _bCheck
)
1701 const sal_Int32 nColumnCount
= m_xMetaData
->getColumnCount();
1702 for(; _bCheck
&& _aIter
!= _aEnd
; _aIter
++, _nPos
++)
1704 if ( !_aIter
->is() )
1705 *_aIter
= new ORowSetValueVector(nColumnCount
);
1708 const TOldRowSetRows::const_iterator aOldRowEnd
= m_aOldRows
.end();
1709 for (TOldRowSetRows::iterator aOldRowIter
= m_aOldRows
.begin(); aOldRowIter
!= aOldRowEnd
; ++aOldRowIter
)
1711 if ( (*aOldRowIter
)->getRow() == *_aIter
)
1712 *_aIter
= new ORowSetValueVector(nColumnCount
);
1715 m_pCacheSet
->fillValueRow(*_aIter
, _nPos
);
1716 _bCheck
= m_pCacheSet
->next();
1721 bool ORowSetCache::isResultSetChanged() const
1723 return m_pCacheSet
->isResultSetChanged();
1726 void ORowSetCache::reset(const Reference
< XResultSet
>& _xDriverSet
)
1728 m_xMetaData
.set(Reference
< XResultSetMetaDataSupplier
>(_xDriverSet
,UNO_QUERY
)->getMetaData());
1729 m_pCacheSet
->reset(_xDriverSet
);
1731 m_bRowCountFinal
= sal_False
;
1733 reFillMatrix(m_nStartPos
,m_nEndPos
);
1736 void ORowSetCache::impl_updateRowFromCache_throw(ORowSetValueVector::Vector
& io_aRow
1737 ,::std::vector
<sal_Int32
>& o_ChangedColumns
)
1739 if ( o_ChangedColumns
.size() > 1 )
1741 ORowSetMatrix::iterator aIter
= m_pMatrix
->begin();
1742 for(;aIter
!= m_pMatrix
->end();++aIter
)
1744 if ( aIter
->is() && m_pCacheSet
->updateColumnValues((*aIter
)->get(),io_aRow
,o_ChangedColumns
))
1750 if ( aIter
== m_pMatrix
->end() )
1752 m_pCacheSet
->fillMissingValues(io_aRow
);
1756 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */