1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: RowSetCache.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_dbaccess.hxx"
34 #ifndef _COMPHELPER_SEQSTREAM_HXX
35 #include <comphelper/seqstream.hxx>
37 #ifndef _COMPHELPER_UNO3_HXX_
38 #include <comphelper/uno3.hxx>
40 #ifndef _COMPHELPER_EXTRACT_HXX_
41 #include <comphelper/extract.hxx>
43 #ifndef _COM_SUN_STAR_SDBCX_XKEYSSUPPLIER_HPP_
44 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
46 #ifndef _COM_SUN_STAR_SDBCX_XTABLESSUPPLIER_HPP_
47 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
49 #ifndef _COM_SUN_STAR_SDBCX_KEYTYPE_HPP_
50 #include <com/sun/star/sdbcx/KeyType.hpp>
52 #ifndef _COM_SUN_STAR_SDBC_RESULTSETCONCURRENCY_HPP_
53 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
55 #ifndef _COM_SUN_STAR_SDBC_COLUMNVALUE_HPP_
56 #include <com/sun/star/sdbc/ColumnValue.hpp>
58 #ifndef _COM_SUN_STAR_SDBCX_XCOLUMNSSUPPLIER_HPP_
59 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
61 #ifndef _COM_SUN_STAR_SDBCX_PRIVILEGE_HPP_
62 #include <com/sun/star/sdbcx/Privilege.hpp>
64 #ifndef _DBACORE_DATACOLUMN_HXX_
65 #include "CRowSetDataColumn.hxx"
67 #ifndef DBACCESS_CORE_API_CROWSETCOLUMN_HXX
68 #include "CRowSetColumn.hxx"
70 #ifndef DBACCESS_CORE_API_ROWSETBASE_HXX
71 #include "RowSetBase.hxx"
73 #ifndef _DBHELPER_DBEXCEPTION_HXX_
74 #include <connectivity/dbexception.hxx>
76 #ifndef _CONNECTIVITY_SQLPARSE_HXX
77 #include <connectivity/sqlparse.hxx>
79 #ifndef _CONNECTIVITY_SQLNODE_HXX
80 #include <connectivity/sqlnode.hxx>
82 #ifndef _CONNECTIVITY_PARSE_SQLITERATOR_HXX_
83 #include <connectivity/sqliterator.hxx>
85 #ifndef _COMPHELPER_PROPERTY_HXX_
86 #include <comphelper/property.hxx>
88 #ifndef _COM_SUN_STAR_SDBCX_COMPAREBOOKMARK_HPP_
89 #include <com/sun/star/sdbcx/CompareBookmark.hpp>
91 #ifndef _TOOLS_DEBUG_HXX
92 #include <tools/debug.hxx>
96 #ifndef DBACCESS_CORE_API_ROWSETCACHE_HXX
97 #include "RowSetCache.hxx"
99 #ifndef _DBA_CORE_RESOURCE_HXX_
100 #include "core_resource.hxx"
102 #ifndef _DBA_CORE_RESOURCE_HRC_
103 #include "core_resource.hrc"
105 #ifndef DBACCESS_CORE_API_BOOKMARKSET_HXX
106 #include "BookmarkSet.hxx"
108 #ifndef DBACCESS_CORE_API_STATICSET_HXX
109 #include "StaticSet.hxx"
111 #ifndef DBACCESS_CORE_API_KEYSET_HXX
112 #include "KeySet.hxx"
114 #ifndef DBACCESS_SHARED_DBASTRINGS_HRC
115 #include "dbastrings.hrc"
118 using namespace dbaccess
;
119 using namespace dbtools
;
120 using namespace connectivity
;
121 using namespace ::com::sun::star::uno
;
122 using namespace ::com::sun::star::beans
;
123 using namespace ::com::sun::star::sdbc
;
124 using namespace ::com::sun::star::sdb
;
125 using namespace ::com::sun::star::sdbcx
;
126 using namespace ::com::sun::star::container
;
127 using namespace ::com::sun::star::lang
;
128 using namespace ::cppu
;
129 using namespace ::osl
;
131 #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!")
133 DBG_NAME(ORowSetCache
)
134 // -------------------------------------------------------------------------
135 ORowSetCache::ORowSetCache(const Reference
< XResultSet
>& _xRs
,
136 const Reference
< XSingleSelectQueryAnalyzer
>& _xAnalyzer
,
137 const ::comphelper::ComponentContext
& _rContext
,
138 const ::rtl::OUString
& _rUpdateTableName
,
139 sal_Bool
& _bModified
,
141 const ORowSetValueVector
& _aParameterValueForCache
)
143 ,m_xMetaData(Reference
< XResultSetMetaDataSupplier
>(_xRs
,UNO_QUERY
)->getMetaData())
144 ,m_aContext( _rContext
)
147 ,m_pInsertMatrix(NULL
)
148 ,m_nLastColumnIndex(0)
151 ,m_nPrivileges( Privilege::SELECT
)
155 ,m_bRowCountFinal(sal_False
)
156 ,m_bBeforeFirst(sal_True
)
157 ,m_bAfterLast( sal_False
)
158 ,m_bUpdated(sal_False
)
159 ,m_bModified(_bModified
)
162 DBG_CTOR(ORowSetCache
,NULL
);
164 // check if all keys of the updateable table are fetched
165 sal_Bool bAllKeysFound
= sal_False
;
166 sal_Int32 nTablesCount
= 0;
168 Reference
< XIndexAccess
> xUpdateTableKeys
;
169 ::rtl::OUString aUpdateTableName
= _rUpdateTableName
;
170 Reference
< XConnection
> xConnection
;
175 Reference
<XTablesSupplier
> xTabSup(_xAnalyzer
,UNO_QUERY
);
176 OSL_ENSURE(xTabSup
.is(),"ORowSet::execute composer isn't a tablesupplier!");
177 Reference
<XNameAccess
> xTables
= xTabSup
->getTables();
180 if(_rUpdateTableName
.getLength() && xTables
->hasByName(_rUpdateTableName
))
181 xTables
->getByName(_rUpdateTableName
) >>= m_aUpdateTable
;
182 else if(xTables
->getElementNames().getLength())
184 aUpdateTableName
= xTables
->getElementNames()[0];
185 xTables
->getByName(aUpdateTableName
) >>= m_aUpdateTable
;
187 Reference
<XIndexAccess
> xIndexAccess(xTables
,UNO_QUERY
);
188 if(xIndexAccess
.is())
189 nTablesCount
= xIndexAccess
->getCount();
191 nTablesCount
= xTables
->getElementNames().getLength();
193 if(m_aUpdateTable
.is() && nTablesCount
< 3) // for we can't handle more than 2 tables in our keyset
195 Reference
<XKeysSupplier
> xKeys(m_aUpdateTable
,UNO_QUERY
);
198 xUpdateTableKeys
= xKeys
->getKeys();
199 if ( xUpdateTableKeys
.is() )
201 Reference
<XColumnsSupplier
> xColumnsSupplier
;
202 // search the one and only primary key
203 const sal_Int32 nCount
= xUpdateTableKeys
->getCount();
204 for(sal_Int32 i
= 0 ; i
< nCount
; ++i
)
206 Reference
<XPropertySet
> xProp(xUpdateTableKeys
->getByIndex(i
),UNO_QUERY
);
207 sal_Int32 nKeyType
= 0;
208 xProp
->getPropertyValue(PROPERTY_TYPE
) >>= nKeyType
;
209 if(KeyType::PRIMARY
== nKeyType
)
211 xColumnsSupplier
.set(xProp
,UNO_QUERY
);
216 if(xColumnsSupplier
.is())
218 // first we need a connection
219 Reference
< XStatement
> xStmt(_xRs
->getStatement(),UNO_QUERY
);
221 xConnection
= xStmt
->getConnection();
224 Reference
< XPreparedStatement
> xPrepStmt(_xRs
->getStatement(),UNO_QUERY
);
225 xConnection
= xPrepStmt
->getConnection();
227 OSL_ENSURE(xConnection
.is(),"No connection!");
229 Reference
<XNameAccess
> xColumns
= xColumnsSupplier
->getColumns();
230 Reference
<XColumnsSupplier
> xColSup(_xAnalyzer
,UNO_QUERY
);
233 Reference
<XNameAccess
> xSelColumns
= xColSup
->getColumns();
234 Reference
<XDatabaseMetaData
> xMeta
= xConnection
->getMetaData();
235 SelectColumnsMetaData
aColumnNames(xMeta
.is() && xMeta
->supportsMixedCaseQuotedIdentifiers() ? true : false);
236 ::dbaccess::getColumnPositions(xSelColumns
,xColumns
,aUpdateTableName
,aColumnNames
);
237 bAllKeysFound
= !aColumnNames
.empty() && sal_Int32(aColumnNames
.size()) == xColumns
->getElementNames().getLength();
248 Reference
< XPropertySet
> xProp(_xRs
,UNO_QUERY
);
250 sal_Bool bNeedKeySet
= !(xProp
->getPropertySetInfo()->hasPropertyByName(PROPERTY_ISBOOKMARKABLE
) &&
251 any2bool(xProp
->getPropertyValue(PROPERTY_ISBOOKMARKABLE
)) && Reference
< XRowLocate
>(_xRs
, UNO_QUERY
).is() );
252 bNeedKeySet
= bNeedKeySet
|| (xProp
->getPropertySetInfo()->hasPropertyByName(PROPERTY_RESULTSETCONCURRENCY
) &&
253 ::comphelper::getINT32(xProp
->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY
)) == ResultSetConcurrency::READ_ONLY
);
255 // first check if resultset is bookmarkable
260 m_pCacheSet
= new OBookmarkSet();
261 m_xCacheSet
= m_pCacheSet
;
262 m_pCacheSet
->construct(_xRs
);
265 m_nPrivileges
= Privilege::SELECT
;
266 if(Reference
<XResultSetUpdate
>(_xRs
,UNO_QUERY
).is()) // this interface is optional so we have to check it
268 Reference
<XPropertySet
> xTable(m_aUpdateTable
,UNO_QUERY
);
269 if(xTable
.is() && xTable
->getPropertySetInfo()->hasPropertyByName(PROPERTY_PRIVILEGES
))
272 xTable
->getPropertyValue(PROPERTY_PRIVILEGES
) >>= m_nPrivileges
;
274 m_nPrivileges
= Privilege::SELECT
;
278 catch(const SQLException
&)
280 bNeedKeySet
= sal_True
;
286 // need to check if we could handle this select clause
287 bAllKeysFound
= bAllKeysFound
&& (nTablesCount
== 1 || checkJoin(xConnection
,_xAnalyzer
,aUpdateTableName
));
289 // || !(comphelper::hasProperty(PROPERTY_CANUPDATEINSERTEDROWS,xProp) && any2bool(xProp->getPropertyValue(PROPERTY_CANUPDATEINSERTEDROWS)))
291 // oj removed because keyset uses only the next// || (xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_RESULTSETTYPE) && comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETTYPE)) == ResultSetType::FORWARD_ONLY)
294 m_pCacheSet
= new OStaticSet();
295 m_xCacheSet
= m_pCacheSet
;
296 m_pCacheSet
->construct(_xRs
);
297 m_nPrivileges
= Privilege::SELECT
;
301 Reference
<XDatabaseMetaData
> xMeta
= xConnection
->getMetaData();
302 SelectColumnsMetaData
aColumnNames(xMeta
.is() && xMeta
->supportsMixedCaseQuotedIdentifiers() ? true : false);
303 Reference
<XColumnsSupplier
> xColSup(_xAnalyzer
,UNO_QUERY
);
304 Reference
<XNameAccess
> xSelColumns
= xColSup
->getColumns();
305 Reference
<XNameAccess
> xColumns
= m_aUpdateTable
->getColumns();
306 ::dbaccess::getColumnPositions(xSelColumns
,xColumns
,aUpdateTableName
,aColumnNames
);
309 m_nPrivileges
= Privilege::SELECT
;
310 sal_Bool bNoInsert
= sal_False
;
312 Sequence
< ::rtl::OUString
> aNames(xColumns
->getElementNames());
313 const ::rtl::OUString
* pIter
= aNames
.getConstArray();
314 const ::rtl::OUString
* pEnd
= pIter
+ aNames
.getLength();
315 for(;pIter
!= pEnd
;++pIter
)
317 Reference
<XPropertySet
> xColumn
;
318 ::cppu::extractInterface(xColumn
,xColumns
->getByName(*pIter
));
319 OSL_ENSURE(xColumn
.is(),"Column in table is null!");
322 sal_Int32 nNullable
= 0;
323 xColumn
->getPropertyValue(PROPERTY_ISNULLABLE
) >>= nNullable
;
324 if(nNullable
== ColumnValue::NO_NULLS
&& aColumnNames
.find(*pIter
) == aColumnNames
.end())
325 { // we found a column where null is not allowed so we can't insert new values
326 bNoInsert
= sal_True
;
327 break; // one column is enough
332 OKeySet
* pKeySet
= new OKeySet(m_aUpdateTable
,xUpdateTableKeys
,aUpdateTableName
,_xAnalyzer
,_aParameterValueForCache
);
335 m_pCacheSet
= pKeySet
;
336 m_xCacheSet
= m_pCacheSet
;
337 pKeySet
->construct(_xRs
);
339 if(Reference
<XResultSetUpdate
>(_xRs
,UNO_QUERY
).is()) // this interface is optional so we have to check it
341 Reference
<XPropertySet
> xTable(m_aUpdateTable
,UNO_QUERY
);
342 if(xTable
.is() && xTable
->getPropertySetInfo()->hasPropertyByName(PROPERTY_PRIVILEGES
))
345 xTable
->getPropertyValue(PROPERTY_PRIVILEGES
) >>= m_nPrivileges
;
347 m_nPrivileges
= Privilege::SELECT
;
351 m_nPrivileges
|= ~Privilege::INSERT
; // remove the insert privilege
353 catch(const SQLException
&)
355 // we couldn't create a keyset here so we have to create a static cache
359 m_pCacheSet
= new OStaticSet();
360 m_xCacheSet
= m_pCacheSet
;
361 m_pCacheSet
->construct(_xRs
);
362 m_nPrivileges
= Privilege::SELECT
;
368 if(!bAllKeysFound
&& xProp
->getPropertySetInfo()->hasPropertyByName(PROPERTY_RESULTSETCONCURRENCY
) &&
369 ::comphelper::getINT32(xProp
->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY
)) == ResultSetConcurrency::READ_ONLY
)
370 m_nPrivileges
= Privilege::SELECT
;
373 // -------------------------------------------------------------------------
374 ORowSetCache::~ORowSetCache()
386 m_pInsertMatrix
->clear();
387 delete m_pInsertMatrix
;
389 m_xSet
= WeakReference
< XResultSet
>();
391 m_aUpdateTable
= NULL
;
393 DBG_DTOR(ORowSetCache
,NULL
);
396 // -------------------------------------------------------------------------
397 void ORowSetCache::setMaxRowSize(sal_Int32 _nSize
)
400 if(_nSize
== m_nFetchSize
)
403 m_nFetchSize
= _nSize
;
406 m_pMatrix
= new ORowSetMatrix(_nSize
);
407 m_aMatrixIter
= m_pMatrix
->end();
408 m_aMatrixEnd
= m_pMatrix
->end();
410 m_pInsertMatrix
= new ORowSetMatrix(1); // a little bit overkill but ??? :-)
411 m_aInsertRow
= m_pInsertMatrix
->end();
415 // now correct the iterator in our iterator vector
416 ::std::vector
<sal_Int32
> aPositions
;
417 ::std::map
<sal_Int32
,sal_Bool
> aCacheIterToChange
;
418 // first get the positions where they stand now
419 ORowSetCacheMap::iterator aCacheIter
= m_aCacheIterators
.begin();
420 ORowSetCacheMap::iterator aCacheEnd
= m_aCacheIterators
.end();
421 for(;aCacheIter
!= aCacheEnd
;++aCacheIter
)
423 aCacheIterToChange
[aCacheIter
->first
] = sal_False
;
424 if ( !aCacheIter
->second
.pRowSet
->isInsertRow()
425 /*&& aCacheIter->second.aIterator != m_pMatrix->end()*/ && !m_bModified
)
427 ptrdiff_t nDist
= (aCacheIter
->second
.aIterator
- m_pMatrix
->begin());
428 aPositions
.push_back(nDist
);
429 aCacheIterToChange
[aCacheIter
->first
] = sal_True
;
432 sal_Int32 nKeyPos
= (m_aMatrixIter
- m_pMatrix
->begin());
433 m_pMatrix
->resize(_nSize
);
435 if ( nKeyPos
< _nSize
)
436 m_aMatrixIter
= m_pMatrix
->begin() + nKeyPos
;
438 m_aMatrixIter
= m_pMatrix
->end();
439 m_aMatrixEnd
= m_pMatrix
->end();
441 // now adjust their positions because a resize invalid all iterators
442 ::std::vector
<sal_Int32
>::const_iterator aIter
= aPositions
.begin();
443 ::std::map
<sal_Int32
,sal_Bool
>::const_iterator aPosChangeIter
= aCacheIterToChange
.begin();
444 for( aCacheIter
= m_aCacheIterators
.begin();
445 aPosChangeIter
!= aCacheIterToChange
.end();
446 ++aPosChangeIter
,++aCacheIter
)
448 if ( aPosChangeIter
->second
)
450 CHECK_MATRIX_POS(*aIter
);
451 if ( *aIter
< _nSize
)
452 aCacheIter
->second
.aIterator
= m_pMatrix
->begin() + *aIter
++;
454 aCacheIter
->second
.aIterator
= m_pMatrix
->end();
460 sal_Int32 nNewSt
= 1;
461 fillMatrix(nNewSt
,_nSize
+1);
466 // -------------------------------------------------------------------------
468 // XResultSetMetaDataSupplier
469 Reference
< XResultSetMetaData
> ORowSetCache::getMetaData( )
473 // -------------------------------------------------------------------------
474 // ::com::sun::star::sdbcx::XRowLocate
475 Any
ORowSetCache::getBookmark( )
479 throwFunctionSequenceException(m_xSet
.get());
481 if ( m_aMatrixIter
>= m_pMatrix
->end() || m_aMatrixIter
< m_pMatrix
->begin() || !(*m_aMatrixIter
).isValid())
483 return Any(); // this is allowed here because the rowset knowns what it is doing
486 switch(((*m_aMatrixIter
)->get())[0].getTypeKind())
488 case DataType::TINYINT
:
489 case DataType::SMALLINT
:
490 case DataType::INTEGER
:
491 return makeAny((sal_Int32
)((*m_aMatrixIter
)->get())[0]);
493 if(((*m_aMatrixIter
)->get())[0].isNull())
494 ((*m_aMatrixIter
)->get())[0] = m_pCacheSet
->getBookmark();
495 return ((*m_aMatrixIter
)->get())[0].getAny();
498 // -------------------------------------------------------------------------
499 sal_Bool
ORowSetCache::moveToBookmark( const Any
& bookmark
)
501 if ( m_pCacheSet
->moveToBookmark(bookmark
) )
503 m_bBeforeFirst
= sal_False
;
504 m_nPosition
= m_pCacheSet
->getRow();
506 checkPositionFlags();
511 checkPositionFlags();
514 m_aMatrixIter
= calcPosition();
515 OSL_ENSURE(m_aMatrixIter
->isValid(),"Iterator after moveToBookmark not valid");
518 m_aMatrixIter
= m_pMatrix
->end();
521 m_aMatrixIter
= m_pMatrix
->end();
526 return m_aMatrixIter
!= m_pMatrix
->end() && (*m_aMatrixIter
).isValid();
528 // -------------------------------------------------------------------------
529 sal_Bool
ORowSetCache::moveRelativeToBookmark( const Any
& bookmark
, sal_Int32 rows
)
531 sal_Bool
bRet( moveToBookmark( bookmark
) );
534 m_nPosition
= m_pCacheSet
->getRow() + rows
;
535 absolute(m_nPosition
);
536 // for(sal_Int32 i=0;i<rows && m_aMatrixIter != m_pMatrix->end();++i,++m_aMatrixIter) ;
538 bRet
= m_aMatrixIter
!= m_pMatrix
->end() && (*m_aMatrixIter
).isValid();
543 // -------------------------------------------------------------------------
544 sal_Int32
ORowSetCache::compareBookmarks( const Any
& _first
, const Any
& _second
)
546 return (!_first
.hasValue() || !_second
.hasValue()) ? CompareBookmark::NOT_COMPARABLE
: m_pCacheSet
->compareBookmarks(_first
,_second
);
548 // -------------------------------------------------------------------------
549 sal_Bool
ORowSetCache::hasOrderedBookmarks( )
552 return m_pCacheSet
->hasOrderedBookmarks();
554 // -------------------------------------------------------------------------
555 sal_Int32
ORowSetCache::hashBookmark( const Any
& bookmark
)
558 return m_pCacheSet
->hashBookmark(bookmark
);
560 // -------------------------------------------------------------------------
562 // -----------------------------------------------------------------------------
563 void ORowSetCache::updateValue(sal_Int32 columnIndex
,const ORowSetValue
& x
)
565 checkUpdateConditions(columnIndex
);
568 ((*m_aInsertRow
)->get())[columnIndex
].setBound(sal_True
);
569 ((*m_aInsertRow
)->get())[columnIndex
] = x
;
570 ((*m_aInsertRow
)->get())[columnIndex
].setModified();
572 // -------------------------------------------------------------------------
573 void ORowSetCache::updateBinaryStream( sal_Int32 columnIndex
, const Reference
< ::com::sun::star::io::XInputStream
>& x
, sal_Int32 length
)
575 checkUpdateConditions(columnIndex
);
578 Sequence
<sal_Int8
> aSeq
;
580 x
->readBytes(aSeq
,length
);
581 updateValue(columnIndex
,aSeq
);
583 // -------------------------------------------------------------------------
584 void ORowSetCache::updateCharacterStream( sal_Int32 columnIndex
, const Reference
< ::com::sun::star::io::XInputStream
>& x
, sal_Int32 length
)
586 checkUpdateConditions(columnIndex
);
589 Sequence
<sal_Int8
> aSeq
;
591 x
->readBytes(aSeq
,length
);
593 updateValue(columnIndex
,aSeq
);
595 // -------------------------------------------------------------------------
596 void ORowSetCache::updateObject( sal_Int32 columnIndex
, const Any
& x
)
598 checkUpdateConditions(columnIndex
);
601 ((*m_aInsertRow
)->get())[columnIndex
].setBound(sal_True
);
602 ((*m_aInsertRow
)->get())[columnIndex
] = x
;
603 ((*m_aInsertRow
)->get())[columnIndex
].setModified();
605 // -------------------------------------------------------------------------
606 void ORowSetCache::updateNumericObject( sal_Int32 columnIndex
, const Any
& x
, sal_Int32
/*scale*/ )
608 checkUpdateConditions(columnIndex
);
611 ((*m_aInsertRow
)->get())[columnIndex
].setBound(sal_True
);
612 ((*m_aInsertRow
)->get())[columnIndex
] = x
;
613 ((*m_aInsertRow
)->get())[columnIndex
].setModified();
615 // -------------------------------------------------------------------------
617 sal_Bool
ORowSetCache::next( )
623 m_bBeforeFirst
= sal_False
;
626 // after we increment the position we have to check if we are already after the last row
627 checkPositionFlags();
632 OSL_ENSURE(((m_nPosition
- m_nStartPos
) - 1) < (sal_Int32
)m_pMatrix
->size(),"Position is behind end()!");
633 m_aMatrixIter
= calcPosition();
634 checkPositionFlags();
638 return !m_bAfterLast
;
640 // -------------------------------------------------------------------------
641 sal_Bool
ORowSetCache::isBeforeFirst( )
643 // return !m_nPosition;
645 return m_bBeforeFirst
;
647 // -------------------------------------------------------------------------
648 sal_Bool
ORowSetCache::isAfterLast( )
653 // -------------------------------------------------------------------------
654 sal_Bool
ORowSetCache::isFirst( )
657 return m_nPosition
== 1; // ask resultset for
659 // -------------------------------------------------------------------------
660 sal_Bool
ORowSetCache::isLast( )
662 // return m_bRowCountFinal ? (m_nPosition==m_nRowCount) : m_pCacheSet->isLast();
664 return m_nPosition
== m_nRowCount
;
666 // -------------------------------------------------------------------------
667 sal_Bool
ORowSetCache::beforeFirst( )
673 m_bAfterLast
= sal_False
;
675 m_bBeforeFirst
= sal_True
;
676 m_pCacheSet
->beforeFirst();
678 m_aMatrixIter
= m_pMatrix
->end();
682 // -------------------------------------------------------------------------
683 sal_Bool
ORowSetCache::afterLast( )
689 m_bBeforeFirst
= sal_False
;
690 m_bAfterLast
= sal_True
;
692 if(!m_bRowCountFinal
)
695 m_bRowCountFinal
= sal_True
;
696 m_nRowCount
= m_pCacheSet
->getRow();// + 1 removed
698 m_pCacheSet
->afterLast();
701 m_aMatrixIter
= m_pMatrix
->end();
705 // -------------------------------------------------------------------------
706 sal_Bool
ORowSetCache::fillMatrix(sal_Int32
& _nNewStartPos
,sal_Int32 _nNewEndPos
)
708 OSL_ENSURE(_nNewStartPos
!= _nNewEndPos
,"ORowSetCache::fillMatrix: StartPos and EndPos can not be equal!");
709 // fill the whole window with new data
710 ORowSetMatrix::iterator aIter
= m_pMatrix
->begin();
711 sal_Bool bCheck
= m_pCacheSet
->absolute(_nNewStartPos
); // -1 no need to
713 sal_Int32 i
=_nNewStartPos
;
714 for(;i
<_nNewEndPos
;++i
,++aIter
)
718 if(!aIter
->isValid())
719 *aIter
= new ORowSetValueVector(m_xMetaData
->getColumnCount());
720 m_pCacheSet
->fillValueRow(*aIter
,i
);
723 { // there are no more rows found so we can fetch some before start
725 if(!m_bRowCountFinal
)
727 if(m_pCacheSet
->previous()) // because we stand after the last row
728 m_nRowCount
= m_pCacheSet
->getRow(); // here we have the row count
730 m_nRowCount
= i
-1; // it can be that getRow return zero
731 m_bRowCountFinal
= sal_True
;
733 if(m_nRowCount
> m_nFetchSize
)
735 ORowSetMatrix::iterator aEnd
= aIter
;
736 ORowSetMatrix::iterator aRealEnd
= m_pMatrix
->end();
737 sal_Int32 nPos
= m_nRowCount
- m_nFetchSize
+ 1;
738 _nNewStartPos
= nPos
;
739 bCheck
= m_pCacheSet
->absolute(_nNewStartPos
);
741 for(;bCheck
&& aIter
!= aRealEnd
;++aIter
)
745 if(!aIter
->isValid())
746 *aIter
= new ORowSetValueVector(m_xMetaData
->getColumnCount());
747 m_pCacheSet
->fillValueRow(*aIter
,nPos
++);
749 bCheck
= m_pCacheSet
->next();
752 ::std::rotate(m_pMatrix
->begin(),aEnd
,aRealEnd
);
756 bCheck
= m_pCacheSet
->next();
758 // m_nStartPos = _nNewStartPos;
759 // we have to read one row forward to enshure that we know when we are on last row
760 // but only when we don't know it already
761 if(!m_bRowCountFinal
)
763 if(!m_pCacheSet
->next())
765 if(m_pCacheSet
->previous()) // because we stand after the last row
766 m_nRowCount
= m_pCacheSet
->getRow(); // here we have the row count
767 m_bRowCountFinal
= sal_True
;
770 m_nRowCount
= std::max(i
,m_nRowCount
);
775 // -------------------------------------------------------------------------
776 sal_Bool
ORowSetCache::moveWindow()
779 sal_Bool bRet
= sal_True
;
781 sal_Int32 nDiff
= (sal_Int32
)(m_nFetchSize
*0.5 -0.5);
782 sal_Int32 nNewStartPos
= (m_nPosition
- nDiff
);
783 // sal_Int32 nNewEndPos = (m_nPosition+m_nFetchSize*0.5);
784 sal_Int32 nNewEndPos
= nNewStartPos
+ m_nFetchSize
;
786 if ( m_nPosition
<= m_nStartPos
)
787 { // the window is behind the new start pos
790 // the new position should be the nPos - nFetchSize/2
791 if ( nNewEndPos
> m_nStartPos
)
792 { // but the two regions are overlapping
793 // fill the rows behind the new end
795 ORowSetMatrix::iterator aEnd
; // the iterator we need for rotate
796 ORowSetMatrix::iterator aIter
; // the iterator we fill with new values
798 sal_Bool bCheck
= sal_True
;
799 if ( nNewStartPos
< 1 )
801 bCheck
= m_pCacheSet
->first();
802 // aEnd = m_pMatrix->begin() + (sal_Int32)(m_nFetchSize*0.5);
803 OSL_ENSURE((nNewEndPos
- m_nStartPos
- nNewStartPos
) < (sal_Int32
)m_pMatrix
->size(),"Position is behind end()!");
804 aEnd
= m_pMatrix
->begin() + (nNewEndPos
- m_nStartPos
- nNewStartPos
);
810 OSL_ENSURE((nNewEndPos
- m_nStartPos
-1) < (sal_Int32
)m_pMatrix
->size(),"Position is behind end()!");
811 aEnd
= m_pMatrix
->begin() + ((nNewEndPos
- m_nStartPos
)-1);
812 aIter
= m_pMatrix
->begin() + ((nNewEndPos
- m_nStartPos
)-1);
813 bCheck
= m_pCacheSet
->absolute(nNewStartPos
);
814 m_nStartPos
= nNewStartPos
-1;
819 sal_Int32 nPos
= m_nStartPos
;
820 bCheck
= fill(aIter
,m_pMatrix
->end(),nPos
,bCheck
);
822 ::std::rotate(m_pMatrix
->begin(),aEnd
,m_pMatrix
->end());
823 // now correct the iterator in our iterator vector
824 // rotateCacheIterator(aEnd-m_pMatrix->begin()); //can't be used because they decrement and here we need to increment
825 ptrdiff_t nNewDist
= aEnd
- m_pMatrix
->begin();
826 ptrdiff_t nOffSet
= m_pMatrix
->end() - aEnd
;
827 ORowSetCacheMap::iterator aCacheIter
= m_aCacheIterators
.begin();
828 ORowSetCacheMap::iterator aCacheEnd
= m_aCacheIterators
.end();
829 for(;aCacheIter
!= aCacheEnd
;++aCacheIter
)
831 if ( !aCacheIter
->second
.pRowSet
->isInsertRow()
832 && aCacheIter
->second
.aIterator
!= m_pMatrix
->end() && !m_bModified
)
834 ptrdiff_t nDist
= (aCacheIter
->second
.aIterator
- m_pMatrix
->begin());
835 if ( nDist
>= nNewDist
)
837 aCacheIter
->second
.aIterator
= m_pMatrix
->end();
841 #if OSL_DEBUG_LEVEL > 0
842 ORowSetMatrix::iterator aOldPos
;
843 aOldPos
= aCacheIter
->second
.aIterator
;
845 CHECK_MATRIX_POS( ((aOldPos
- m_pMatrix
->begin()) + nOffSet
) );
846 aCacheIter
->second
.aIterator
+= nOffSet
;
847 #if OSL_DEBUG_LEVEL > 0
848 ORowSetMatrix::iterator aCurrentPos
;
849 aCurrentPos
= aCacheIter
->second
.aIterator
;
851 OSL_ENSURE(aCacheIter
->second
.aIterator
>= m_pMatrix
->begin()
852 && aCacheIter
->second
.aIterator
< m_pMatrix
->end(),"Iterator out of area!");
858 { // normaly this should never happen
859 OSL_ENSURE(0,"What the hell is happen here!");
864 {// no rows can be reused so fill again
865 if(nNewStartPos
< 1) // special case
869 rotateCacheIterator(static_cast<sal_Int16
>(m_nFetchSize
+1)); // static_cast<sal_Int16>(m_nFetchSize+1)
871 m_pCacheSet
->beforeFirst();
874 ORowSetMatrix::iterator aIter
= m_pMatrix
->begin();
875 for(sal_Int32 i
=0;i
<m_nFetchSize
;++i
,++aIter
)
877 bCheck
= m_pCacheSet
->next();
880 if(!aIter
->isValid())
881 *aIter
= new ORowSetValueVector(m_xMetaData
->getColumnCount());
882 m_pCacheSet
->fillValueRow(*aIter
,i
+1);
889 bRet
= reFillMatrix(nNewStartPos
,nNewEndPos
);
892 else if(m_nPosition
> m_nStartPos
)
893 { // the new start pos is above the startpos of the window
895 if(m_nPosition
<= (m_nStartPos
+m_nFetchSize
))
896 { // position in window
897 OSL_ENSURE((m_nPosition
- m_nStartPos
-1) < (sal_Int32
)m_pMatrix
->size(),"Position is behind end()!");
898 m_aMatrixIter
= calcPosition();
899 if(!m_aMatrixIter
->isValid())
901 sal_Bool
bOk( m_pCacheSet
->absolute( m_nPosition
) );
904 *m_aMatrixIter
= new ORowSetValueVector(m_xMetaData
->getColumnCount());
905 m_pCacheSet
->fillValueRow(*m_aMatrixIter
,m_nPosition
);
906 // we have to read one row forward to enshure that we know when we are on last row
907 // but only when we don't know it already
908 if ( !m_bRowCountFinal
)
910 bOk
= m_pCacheSet
->absolute( m_nPosition
+ 1 );
912 m_nRowCount
= std::max(sal_Int32(m_nPosition
+1),m_nRowCount
);
917 if(!m_bRowCountFinal
)
919 // because we stand after the last row
920 m_nRowCount
= m_pCacheSet
->previous() ? m_pCacheSet
->getRow() : 0;// + 1 removed
921 m_bRowCountFinal
= sal_True
;
926 else if(nNewStartPos
< (m_nStartPos
+m_nFetchSize
))
927 { // position behind window but the region is overlapping
928 // the rows from begin() to (begin + nNewStartPos - m_nStartPos) can be refilled with the new rows
929 // the rows behind this can be reused
930 ORowSetMatrix::iterator aIter
= m_pMatrix
->begin();
931 CHECK_MATRIX_POS(nNewStartPos
- m_nStartPos
- 1);
932 ORowSetMatrix::iterator aEnd
= m_pMatrix
->begin() + (nNewStartPos
- m_nStartPos
- 1);
934 sal_Int32 nPos
= m_nStartPos
+ m_nFetchSize
+ 1;
935 sal_Bool bCheck
= m_pCacheSet
->absolute(nPos
);
936 bCheck
= fill(aIter
,aEnd
,nPos
,bCheck
); // refill the region wew don't need anymore
938 // // we know that this is the current maximal rowcount here
939 // if ( !m_bRowCountFinal && bCheck )
940 // m_nRowCount = std::max(nPos,m_nRowCount);
941 // we have to read one row forward to enshure that we know when we are on last row
942 // but only when we don't know it already
943 sal_Bool bOk
= sal_True
;
944 if(bCheck
&& !m_bRowCountFinal
)
945 bOk
= m_pCacheSet
->next();
948 { // rotate the end to the front
949 ::std::rotate(m_pMatrix
->begin(),aIter
,m_pMatrix
->end());
950 // now correct the iterator in our iterator vector
951 rotateCacheIterator( (sal_Int16
)( aIter
- m_pMatrix
->begin() ) );
952 m_nStartPos
= nNewStartPos
- 1; // must be -1
953 // now I can say how many rows we have
956 m_pCacheSet
->previous(); // because we stand after the last row
957 m_nRowCount
= nPos
; // here we have the row count
958 m_bRowCountFinal
= sal_True
;
960 else if(!m_bRowCountFinal
)
961 m_nRowCount
= std::max(++nPos
,m_nRowCount
);
964 { // the end was reached before end() so we can set the start before nNewStartPos
966 m_nStartPos
+= (aIter
- m_pMatrix
->begin());
967 // m_nStartPos = (aIter - m_pMatrix->begin());
968 ::std::rotate(m_pMatrix
->begin(),aIter
,m_pMatrix
->end());
969 // now correct the iterator in our iterator vector
970 rotateCacheIterator( (sal_Int16
)( aIter
- m_pMatrix
->begin() ) );
972 if ( !m_bRowCountFinal
)
974 m_pCacheSet
->previous(); // because we stand after the last row
975 m_nRowCount
= std::max(m_nRowCount
,--nPos
); // here we have the row count
976 OSL_ENSURE(nPos
== m_pCacheSet
->getRow(),"nPos isn't valid!");
977 m_bRowCountFinal
= sal_True
;
980 // m_nStartPos = (nNewStartPos+m_nRowCount) - m_nFetchSize ;
984 // here we need only to check if the begining row is valid. If not we have to fetch it.
985 if(!m_pMatrix
->begin()->isValid())
987 aIter
= m_pMatrix
->begin();
990 bCheck
= m_pCacheSet
->absolute(m_nStartPos
);
991 for(; !aIter
->isValid() && bCheck
;++aIter
)
993 OSL_ENSURE(aIter
!= m_pMatrix
->end(),"Invalid iterator");
994 bCheck
= m_pCacheSet
->next();
995 if ( bCheck
) // resultset stands on right position
997 *aIter
= new ORowSetValueVector(m_xMetaData
->getColumnCount());
998 m_pCacheSet
->fillValueRow(*aIter
,++nPos
);
1003 else // no rows can be reused so fill again
1004 bRet
= reFillMatrix(nNewStartPos
,nNewEndPos
);
1007 if(!m_bRowCountFinal
)
1008 m_nRowCount
= std::max(m_nPosition
,m_nRowCount
);
1009 OSL_ENSURE(m_nStartPos
>= 0,"ORowSetCache::moveWindow: m_nStartPos is less than 0!");
1013 // -------------------------------------------------------------------------
1014 sal_Bool
ORowSetCache::first( )
1016 // first move to the first row
1017 // then check if the cache window is at the begining
1018 // when not postionize the window and fill it with data
1019 // smart moving of the window -> clear only the rows whom are out of range
1020 sal_Bool bRet
= m_pCacheSet
->first();
1023 m_bBeforeFirst
= m_bAfterLast
= sal_False
;
1026 m_aMatrixIter
= m_pMatrix
->begin();
1030 m_bRowCountFinal
= m_bBeforeFirst
= m_bAfterLast
= sal_True
;
1031 m_nRowCount
= m_nPosition
= 0;
1033 OSL_ENSURE(m_bBeforeFirst
|| m_bNew
,"ORowSetCache::first return false and BeforeFirst isn't true");
1034 m_aMatrixIter
= m_pMatrix
->end();
1038 // -------------------------------------------------------------------------
1039 sal_Bool
ORowSetCache::last( )
1041 sal_Bool bRet
= m_pCacheSet
->last();
1044 m_bBeforeFirst
= m_bAfterLast
= sal_False
;
1045 if(!m_bRowCountFinal
)
1047 m_bRowCountFinal
= sal_True
;
1048 m_nRowCount
= m_nPosition
= m_pCacheSet
->getRow(); // not + 1
1050 m_nPosition
= m_pCacheSet
->getRow();
1052 // we have to repositioning because moveWindow can modify the cache
1053 m_pCacheSet
->last();
1054 // if(m_nPosition > m_nFetchSize)
1055 // m_aMatrixIter = m_pMatrix->end() -1;
1057 // m_aMatrixIter = m_pMatrix->begin() + m_nPosition - 1;
1058 OSL_ENSURE(((m_nPosition
- m_nStartPos
) - 1) < (sal_Int32
)m_pMatrix
->size(),"Position is behind end()!");
1059 m_aMatrixIter
= calcPosition();
1063 m_bRowCountFinal
= m_bBeforeFirst
= m_bAfterLast
= sal_True
;
1064 m_nRowCount
= m_nPosition
= 0;
1065 OSL_ENSURE(m_bBeforeFirst
,"ORowSetCache::last return false and BeforeFirst isn't true");
1066 m_aMatrixIter
= m_pMatrix
->end();
1068 #if OSL_DEBUG_LEVEL > 1
1071 OSL_ENSURE((*m_aMatrixIter
).isValid(),"ORowSetCache::last: Row not valid!");
1077 // -------------------------------------------------------------------------
1078 sal_Int32
ORowSetCache::getRow( )
1080 return (isBeforeFirst() || isAfterLast()) ? 0 : m_nPosition
;
1082 // -------------------------------------------------------------------------
1083 sal_Bool
ORowSetCache::absolute( sal_Int32 row
)
1086 throw SQLException(DBACORE_RESSTRING(RID_STR_NO_ABS_ZERO
),NULL
,SQLSTATE_GENERAL
,1000,Any() );
1090 // here we have to scroll from the last row to backward so we have to go to last row and
1091 // and two the previous
1092 if(m_bRowCountFinal
|| last())
1094 m_nPosition
= m_nRowCount
+ row
+ 1; // + row because row is negative and +1 because row==-1 means last row
1097 m_bBeforeFirst
= sal_True
;
1098 m_bAfterLast
= sal_False
;
1099 m_aMatrixIter
= m_pMatrix
->end();
1103 m_bBeforeFirst
= sal_False
;
1104 m_bAfterLast
= m_nPosition
> m_nRowCount
;
1106 OSL_ENSURE(((m_nPosition
- m_nStartPos
) - 1) < (sal_Int32
)m_pMatrix
->size(),"Position is behind end()!");
1107 m_aMatrixIter
= calcPosition();
1111 m_aMatrixIter
= m_pMatrix
->end();
1116 // the position flags
1117 m_bBeforeFirst
= sal_False
;
1118 checkPositionFlags();
1123 checkPositionFlags();
1125 m_aMatrixIter
= calcPosition();
1127 m_aMatrixIter
= m_pMatrix
->end();
1130 m_aMatrixIter
= m_pMatrix
->end();
1133 return !(m_bAfterLast
|| m_bBeforeFirst
);
1135 // -------------------------------------------------------------------------
1136 sal_Bool
ORowSetCache::relative( sal_Int32 rows
)
1138 sal_Bool bErg
= sal_True
;
1141 sal_Int32 nNewPosition
= m_nPosition
+ rows
;
1143 if ( m_bBeforeFirst
&& rows
> 0 )
1144 nNewPosition
= rows
;
1145 else if ( m_bRowCountFinal
&& m_bAfterLast
&& rows
< 0 )
1146 nNewPosition
= m_nRowCount
+ 1 + rows
;
1148 if ( m_bBeforeFirst
|| ( m_bRowCountFinal
&& m_bAfterLast
) )
1149 throw SQLException( DBACORE_RESSTRING( RID_STR_NO_RELATIVE
), NULL
, SQLSTATE_GENERAL
, 1000, Any() );
1152 bErg
= absolute( nNewPosition
);
1153 bErg
= bErg
&& !isAfterLast() && !isBeforeFirst();
1157 m_bBeforeFirst
= sal_True
;
1163 // -------------------------------------------------------------------------
1164 sal_Bool
ORowSetCache::previous( )
1166 sal_Bool bRet
= sal_False
;
1167 if(!isBeforeFirst())
1169 if(m_bAfterLast
) // we stand after the last row so one before is the last row
1173 m_bAfterLast
= sal_False
;
1176 OSL_ENSURE(((m_nPosition
- m_nStartPos
) - 1) < (sal_Int32
)m_pMatrix
->size(),"Position is behind end()!");
1178 checkPositionFlags();
1182 m_bBeforeFirst
= sal_True
;
1183 m_aMatrixIter
= m_pMatrix
->end();
1187 m_aMatrixIter
= calcPosition();
1188 bRet
= (*m_aMatrixIter
).isValid();
1194 // -------------------------------------------------------------------------
1195 void ORowSetCache::refreshRow( )
1198 throw SQLException(DBACORE_RESSTRING(RID_STR_NO_REFESH_AFTERLAST
),NULL
,SQLSTATE_GENERAL
,1000,Any() );
1199 OSL_ENSURE(m_aMatrixIter
!= m_pMatrix
->end(),"refreshRow() called for invalid row!");
1200 m_pCacheSet
->refreshRow();
1201 m_pCacheSet
->fillValueRow(*m_aMatrixIter
,m_nPosition
);
1204 cancelRowModification();
1207 // -------------------------------------------------------------------------
1208 sal_Bool
ORowSetCache::rowUpdated( )
1210 return m_pCacheSet
->rowUpdated();
1212 // -------------------------------------------------------------------------
1213 sal_Bool
ORowSetCache::rowInserted( )
1215 return m_pCacheSet
->rowInserted();
1217 // -------------------------------------------------------------------------
1219 sal_Bool
ORowSetCache::insertRow( )
1221 if ( !m_bNew
|| !m_aInsertRow
->isValid() )
1222 throw SQLException(DBACORE_RESSTRING(RID_STR_NO_MOVETOINSERTROW_CALLED
),NULL
,SQLSTATE_GENERAL
,1000,Any() );
1224 m_pCacheSet
->insertRow(*m_aInsertRow
,m_aUpdateTable
);
1226 sal_Bool
bRet( rowInserted() );
1230 Any aBookmark
= ((*m_aInsertRow
)->get())[0].makeAny();
1231 m_bAfterLast
= m_bBeforeFirst
= sal_False
;
1232 if(aBookmark
.hasValue())
1233 moveToBookmark(aBookmark
);
1236 OSL_ENSURE(0,"There must be a bookmark after the row was inserted!");
1241 // -------------------------------------------------------------------------
1242 void ORowSetCache::resetInsertRow(sal_Bool _bClearInsertRow
)
1244 if ( _bClearInsertRow
)
1247 m_bModified
= sal_False
;
1249 // -------------------------------------------------------------------------
1250 void ORowSetCache::cancelRowModification()
1252 // clear the insertrow references -> implies that the current row of the rowset changes as well
1253 ORowSetCacheMap::iterator aCacheIter
= m_aCacheIterators
.begin();
1254 ORowSetCacheMap::iterator aCacheEnd
= m_aCacheIterators
.end();
1255 for(;aCacheIter
!= aCacheEnd
;++aCacheIter
)
1257 if ( aCacheIter
->second
.pRowSet
->isInsertRow() && aCacheIter
->second
.aIterator
== m_aInsertRow
)
1258 aCacheIter
->second
.aIterator
= m_pMatrix
->end();
1259 } // for(;aCacheIter != aCacheEnd;++aCacheIter)
1260 resetInsertRow(sal_False
);
1262 // -------------------------------------------------------------------------
1263 void ORowSetCache::updateRow( ORowSetMatrix::iterator
& _rUpdateRow
)
1265 if(isAfterLast() || isBeforeFirst())
1266 throw SQLException(DBACORE_RESSTRING(RID_STR_NO_UPDATEROW
),NULL
,SQLSTATE_GENERAL
,1000,Any() );
1268 Any aBookmark
= ((*_rUpdateRow
)->get())[0].makeAny();
1269 OSL_ENSURE(aBookmark
.hasValue(),"Bookmark must have a value!");
1270 // here we don't have to reposition our CacheSet, when we try to update a row,
1271 // the row was already fetched
1272 moveToBookmark(aBookmark
);
1273 m_pCacheSet
->updateRow(*_rUpdateRow
,*m_aMatrixIter
,m_aUpdateTable
);
1274 // *(*m_aMatrixIter) = *(*_rUpdateRow);
1275 // refetch the whole row
1276 (*m_aMatrixIter
) = NULL
;
1277 moveToBookmark(aBookmark
);
1279 // moveToBookmark((*(*m_aInsertRow))[0].makeAny());
1280 // if(m_pCacheSet->rowUpdated())
1281 // *m_aMatrixIter = m_aInsertRow;
1282 m_bModified
= sal_False
;
1285 // -------------------------------------------------------------------------
1286 bool ORowSetCache::deleteRow( )
1288 if(isAfterLast() || isBeforeFirst())
1289 throw SQLException(DBACORE_RESSTRING(RID_STR_NO_DELETEROW
),NULL
,SQLSTATE_GENERAL
,1000,Any() );
1291 // m_pCacheSet->absolute(m_nPosition);
1292 m_pCacheSet
->deleteRow(*m_aMatrixIter
,m_aUpdateTable
);
1293 if ( !m_pCacheSet
->rowDeleted() )
1297 OSL_ENSURE(((m_nPosition
- m_nStartPos
) - 1) < (sal_Int32
)m_pMatrix
->size(),"Position is behind end()!");
1298 ORowSetMatrix::iterator aPos
= calcPosition();
1300 // (*m_pMatrix)[(m_nPosition - m_nStartPos)] = NULL; // set the deleted row to NULL
1303 ORowSetMatrix::iterator aEnd
= m_pMatrix
->end();
1304 for(++aPos
;aPos
!= aEnd
&& aPos
->isValid();++aPos
)
1309 m_aMatrixIter
= m_pMatrix
->end();
1314 // -------------------------------------------------------------------------
1315 void ORowSetCache::cancelRowUpdates( )
1317 m_bNew
= m_bModified
= sal_False
;
1320 OSL_ENSURE(0,"cancelRowUpdates:Invalid positions pos == 0");
1321 ::dbtools::throwFunctionSequenceException(NULL
);
1324 if(m_pCacheSet
->absolute(m_nPosition
))
1325 m_pCacheSet
->fillValueRow(*m_aMatrixIter
,m_nPosition
);
1328 OSL_ENSURE(0,"cancelRowUpdates couldn't position right with absolute");
1329 ::dbtools::throwFunctionSequenceException(NULL
);
1332 // -------------------------------------------------------------------------
1333 void ORowSetCache::moveToInsertRow( )
1336 m_bUpdated
= m_bAfterLast
= sal_False
;
1338 m_aInsertRow
= m_pInsertMatrix
->begin();
1339 if(!m_aInsertRow
->isValid())
1340 *m_aInsertRow
= new ORowSetValueVector(m_xMetaData
->getColumnCount());
1342 // we don't unbound the bookmark column
1343 ORowSetValueVector::Vector::iterator aIter
= (*m_aInsertRow
)->get().begin()+1;
1344 ORowSetValueVector::Vector::iterator aEnd
= (*m_aInsertRow
)->get().end();
1345 for(;aIter
!= aEnd
;++aIter
)
1347 aIter
->setBound(sal_False
);
1348 aIter
->setModified(sal_False
);
1352 // -------------------------------------------------------------------------
1353 ORowSetCacheIterator
ORowSetCache::createIterator(ORowSetBase
* _pRowSet
)
1356 ORowSetCacheIterator_Helper aHelper
;
1357 aHelper
.aIterator
= m_pMatrix
->end();
1358 aHelper
.pRowSet
= _pRowSet
;
1359 return ORowSetCacheIterator(m_aCacheIterators
.insert(m_aCacheIterators
.begin(),ORowSetCacheMap::value_type(m_aCacheIterators
.size()+1,aHelper
)),this,_pRowSet
);
1361 // -----------------------------------------------------------------------------
1362 void ORowSetCache::deleteIterator(const ORowSetBase
* _pRowSet
)
1364 ORowSetCacheMap::iterator aCacheIter
= m_aCacheIterators
.begin();
1365 for(;aCacheIter
!= m_aCacheIterators
.end();)
1367 if ( aCacheIter
->second
.pRowSet
== _pRowSet
)
1369 m_aCacheIterators
.erase(aCacheIter
);
1370 aCacheIter
= m_aCacheIterators
.begin();
1371 } // if ( aCacheIter->second.pRowSet == _pRowSet )
1376 // -----------------------------------------------------------------------------
1377 void ORowSetCache::rotateCacheIterator(ORowSetMatrix::difference_type _nDist
)
1381 // now correct the iterator in our iterator vector
1382 ORowSetCacheMap::iterator aCacheIter
= m_aCacheIterators
.begin();
1383 ORowSetCacheMap::iterator aCacheEnd
= m_aCacheIterators
.end();
1384 for(;aCacheIter
!= aCacheEnd
;++aCacheIter
)
1386 if ( !aCacheIter
->second
.pRowSet
->isInsertRow()
1387 && aCacheIter
->second
.aIterator
!= m_pMatrix
->end() && !m_bModified
)
1389 ptrdiff_t nDist
= (aCacheIter
->second
.aIterator
- m_pMatrix
->begin());
1392 aCacheIter
->second
.aIterator
= m_pMatrix
->end();
1396 OSL_ENSURE((aCacheIter
->second
.aIterator
- m_pMatrix
->begin()) >= _nDist
,"Invalid Dist value!");
1397 aCacheIter
->second
.aIterator
-= _nDist
;
1398 OSL_ENSURE(aCacheIter
->second
.aIterator
>= m_pMatrix
->begin()
1399 && aCacheIter
->second
.aIterator
< m_pMatrix
->end(),"Iterator out of area!");
1405 // -------------------------------------------------------------------------
1406 void ORowSetCache::setUpdateIterator(const ORowSetMatrix::iterator
& _rOriginalRow
)
1408 m_aInsertRow
= m_pInsertMatrix
->begin();
1409 if(!m_aInsertRow
->isValid())
1410 *m_aInsertRow
= new ORowSetValueVector(m_xMetaData
->getColumnCount());
1412 (*(*m_aInsertRow
)) = (*(*_rOriginalRow
));
1413 // we don't unbound the bookmark column
1414 ORowSetValueVector::Vector::iterator aIter
= (*m_aInsertRow
)->get().begin();
1415 ORowSetValueVector::Vector::iterator aEnd
= (*m_aInsertRow
)->get().end();
1416 for(;aIter
!= aEnd
;++aIter
)
1417 aIter
->setModified(sal_False
);
1419 // -----------------------------------------------------------------------------
1420 void ORowSetCache::checkPositionFlags()
1422 if(m_bRowCountFinal
)
1424 m_bAfterLast
= m_nPosition
> m_nRowCount
;
1426 m_nPosition
= 0;//m_nRowCount;
1429 // -----------------------------------------------------------------------------
1430 void ORowSetCache::checkUpdateConditions(sal_Int32 columnIndex
)
1432 if(m_bAfterLast
|| columnIndex
>= (sal_Int32
)(*m_aInsertRow
)->get().size())
1433 throwFunctionSequenceException(m_xSet
.get());
1435 //------------------------------------------------------------------------------
1436 sal_Bool
ORowSetCache::checkInnerJoin(const ::connectivity::OSQLParseNode
*pNode
,const Reference
< XConnection
>& _xConnection
,const ::rtl::OUString
& _sUpdateTableName
)
1438 sal_Bool bOk
= sal_False
;
1439 if (pNode
->count() == 3 && // Ausdruck is geklammert
1440 SQL_ISPUNCTUATION(pNode
->getChild(0),"(") &&
1441 SQL_ISPUNCTUATION(pNode
->getChild(2),")"))
1443 bOk
= checkInnerJoin(pNode
->getChild(1),_xConnection
,_sUpdateTableName
);
1445 else if ((SQL_ISRULE(pNode
,search_condition
) || SQL_ISRULE(pNode
,boolean_term
)) && // AND/OR-Verknuepfung:
1446 pNode
->count() == 3)
1448 // nur AND Verknüpfung zulassen
1449 if ( SQL_ISTOKEN(pNode
->getChild(1),AND
) )
1450 bOk
= checkInnerJoin(pNode
->getChild(0),_xConnection
,_sUpdateTableName
)
1451 && checkInnerJoin(pNode
->getChild(2),_xConnection
,_sUpdateTableName
);
1453 else if (SQL_ISRULE(pNode
,comparison_predicate
))
1455 // only the comparison of columns is allowed
1456 DBG_ASSERT(pNode
->count() == 3,"checkInnerJoin: Fehler im Parse Tree");
1457 if (!(SQL_ISRULE(pNode
->getChild(0),column_ref
) &&
1458 SQL_ISRULE(pNode
->getChild(2),column_ref
) &&
1459 pNode
->getChild(1)->getNodeType() == SQL_NODE_EQUAL
))
1463 ::rtl::OUString sColumnName
,sTableRange
;
1464 OSQLParseTreeIterator::getColumnRange( pNode
->getChild(0), _xConnection
, sColumnName
, sTableRange
);
1465 bOk
= sTableRange
== _sUpdateTableName
;
1468 OSQLParseTreeIterator::getColumnRange( pNode
->getChild(2), _xConnection
, sColumnName
, sTableRange
);
1469 bOk
= sTableRange
== _sUpdateTableName
;
1474 // -----------------------------------------------------------------------------
1475 sal_Bool
ORowSetCache::checkJoin(const Reference
< XConnection
>& _xConnection
,
1476 const Reference
< XSingleSelectQueryAnalyzer
>& _xAnalyzer
,
1477 const ::rtl::OUString
& _sUpdateTableName
)
1479 sal_Bool bOk
= sal_False
;
1480 ::rtl::OUString sSql
= _xAnalyzer
->getQuery();
1481 ::rtl::OUString sErrorMsg
;
1482 ::connectivity::OSQLParser
aSqlParser( m_aContext
.getLegacyServiceFactory() );
1483 ::std::auto_ptr
< ::connectivity::OSQLParseNode
> pSqlParseNode( aSqlParser
.parseTree(sErrorMsg
,sSql
));
1484 if ( pSqlParseNode
.get() && SQL_ISRULE(pSqlParseNode
, select_statement
) )
1486 OSQLParseNode
* pTableRefCommalist
= pSqlParseNode
->getByRule(::connectivity::OSQLParseNode::table_ref_commalist
);
1487 OSL_ENSURE(pTableRefCommalist
,"NO tables why!?");
1488 if(pTableRefCommalist
&& pTableRefCommalist
->count() == 1)
1490 // we found only one element so it must some kind of join here
1491 OSQLParseNode
* pJoin
= pTableRefCommalist
->getByRule(::connectivity::OSQLParseNode::qualified_join
);
1493 { // we are only intereseted in qualified joins like RIGHT or LEFT
1494 OSQLParseNode
* pJoinType
= pJoin
->getChild(1);
1495 OSQLParseNode
* pOuterType
= NULL
;
1496 if(SQL_ISRULE(pJoinType
,join_type
) && pJoinType
->count() == 2)
1497 pOuterType
= pJoinType
->getChild(0);
1498 else if(SQL_ISRULE(pJoinType
,outer_join_type
))
1499 pOuterType
= pJoinType
;
1501 sal_Bool bCheck
= sal_False
;
1502 sal_Bool bLeftSide
= sal_False
;
1504 { // found outer join
1505 bLeftSide
= SQL_ISTOKEN(pOuterType
->getChild(0),LEFT
);
1506 bCheck
= bLeftSide
|| SQL_ISTOKEN(pOuterType
->getChild(0),RIGHT
);
1510 { // here we know that we have to check on which side our table resides
1511 const OSQLParseNode
* pTableRef
= pJoin
->getByRule(::connectivity::OSQLParseNode::qualified_join
);
1513 pTableRef
= pJoin
->getChild(0);
1515 pTableRef
= pJoin
->getChild(3);
1516 OSL_ENSURE(SQL_ISRULE(pTableRef
,table_ref
),"Must be a tableref here!");
1518 ::rtl::OUString sTableRange
= OSQLParseNode::getTableRange(pTableRef
);
1519 if(!sTableRange
.getLength())
1520 pTableRef
->getChild(0)->parseNodeToStr( sTableRange
, _xConnection
, NULL
, sal_False
, sal_False
);
1521 bOk
= sTableRange
== _sUpdateTableName
;
1527 OSQLParseNode
* pWhereOpt
= pSqlParseNode
->getChild(3)->getChild(1);
1528 if ( pWhereOpt
&& !pWhereOpt
->isLeaf() )
1529 bOk
= checkInnerJoin(pWhereOpt
->getChild(1),_xConnection
,_sUpdateTableName
);
1534 // -----------------------------------------------------------------------------
1535 void ORowSetCache::clearInsertRow()
1537 // we don't unbound the bookmark column
1538 if ( m_aInsertRow
!= m_pInsertMatrix
->end() && m_aInsertRow
->isValid() )
1540 ORowSetValueVector::Vector::iterator aIter
= (*m_aInsertRow
)->get().begin()+1;
1541 ORowSetValueVector::Vector::iterator aEnd
= (*m_aInsertRow
)->get().end();
1542 for(;aIter
!= aEnd
;++aIter
)
1544 aIter
->setBound(sal_False
);
1545 aIter
->setModified(sal_False
);
1547 } // for(;aIter != (*m_aInsertRow)->end();++aIter)
1550 // -----------------------------------------------------------------------------
1551 ORowSetMatrix::iterator
ORowSetCache::calcPosition() const
1553 sal_Int32 nValue
= (m_nPosition
- m_nStartPos
) - 1;
1554 CHECK_MATRIX_POS(nValue
);
1555 return ( nValue
< 0 || nValue
>= static_cast<sal_Int32
>(m_pMatrix
->size()) ) ? m_pMatrix
->end() : (m_pMatrix
->begin() + nValue
);
1557 // -----------------------------------------------------------------------------
1559 TORowSetOldRowHelperRef
ORowSetCache::registerOldRow()
1561 TORowSetOldRowHelperRef pRef
= new ORowSetOldRowHelper(ORowSetRow());
1562 m_aOldRows
.push_back(pRef
);
1565 // -----------------------------------------------------------------------------
1566 void ORowSetCache::deregisterOldRow(const TORowSetOldRowHelperRef
& _rRow
)
1568 TOldRowSetRows::iterator aOldRowEnd
= m_aOldRows
.end();
1569 for (TOldRowSetRows::iterator aOldRowIter
= m_aOldRows
.begin(); aOldRowIter
!= aOldRowEnd
; ++aOldRowIter
)
1571 if ( aOldRowIter
->getBodyPtr() == _rRow
.getBodyPtr() )
1573 m_aOldRows
.erase(aOldRowIter
);
1579 // -----------------------------------------------------------------------------
1580 sal_Bool
ORowSetCache::reFillMatrix(sal_Int32 _nNewStartPos
,sal_Int32 _nNewEndPos
)
1582 TOldRowSetRows::iterator aOldRowEnd
= m_aOldRows
.end();
1583 for (TOldRowSetRows::iterator aOldRowIter
= m_aOldRows
.begin(); aOldRowIter
!= aOldRowEnd
; ++aOldRowIter
)
1585 if ( aOldRowIter
->isValid() && aOldRowIter
->getBody().getRow().isValid() )
1586 aOldRowIter
->getBody().setRow(new ORowSetValueVector(aOldRowIter
->getBody().getRow().getBody()) );
1588 sal_Int32 nNewSt
= _nNewStartPos
;
1589 sal_Bool bRet
= fillMatrix(nNewSt
,_nNewEndPos
);
1590 m_nStartPos
= nNewSt
- 1;
1591 rotateCacheIterator(static_cast<sal_Int16
>(m_nFetchSize
+1)); // forces that every iterator will be set to null
1594 // -----------------------------------------------------------------------------
1595 sal_Bool
ORowSetCache::fill(ORowSetMatrix::iterator
& _aIter
,const ORowSetMatrix::iterator
& _aEnd
,sal_Int32
& _nPos
,sal_Bool _bCheck
)
1597 sal_Int32 nColumnCount
= m_xMetaData
->getColumnCount();
1598 for(; _bCheck
&& _aIter
!= _aEnd
;)
1600 if ( !_aIter
->isValid() )
1601 *_aIter
= new ORowSetValueVector(nColumnCount
);
1604 TOldRowSetRows::iterator aOldRowEnd
= m_aOldRows
.end();
1605 for (TOldRowSetRows::iterator aOldRowIter
= m_aOldRows
.begin(); aOldRowIter
!= aOldRowEnd
; ++aOldRowIter
)
1607 if ( aOldRowIter
->getBody().getRow().isEqualBody(*_aIter
) )
1608 *_aIter
= new ORowSetValueVector(nColumnCount
);
1611 m_pCacheSet
->fillValueRow(*_aIter
++,++_nPos
);
1612 _bCheck
= m_pCacheSet
->next();
1616 // -----------------------------------------------------------------------------