Update ooo320-m1
[ooovba.git] / dbaccess / source / core / api / RowSetCache.cxx
blob91ba4a0c7b429c565240a7f7ef3c001106710cf0
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 $
10 * $Revision: 1.100 $
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>
36 #endif
37 #ifndef _COMPHELPER_UNO3_HXX_
38 #include <comphelper/uno3.hxx>
39 #endif
40 #ifndef _COMPHELPER_EXTRACT_HXX_
41 #include <comphelper/extract.hxx>
42 #endif
43 #ifndef _COM_SUN_STAR_SDBCX_XKEYSSUPPLIER_HPP_
44 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
45 #endif
46 #ifndef _COM_SUN_STAR_SDBCX_XTABLESSUPPLIER_HPP_
47 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
48 #endif
49 #ifndef _COM_SUN_STAR_SDBCX_KEYTYPE_HPP_
50 #include <com/sun/star/sdbcx/KeyType.hpp>
51 #endif
52 #ifndef _COM_SUN_STAR_SDBC_RESULTSETCONCURRENCY_HPP_
53 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
54 #endif
55 #ifndef _COM_SUN_STAR_SDBC_COLUMNVALUE_HPP_
56 #include <com/sun/star/sdbc/ColumnValue.hpp>
57 #endif
58 #ifndef _COM_SUN_STAR_SDBCX_XCOLUMNSSUPPLIER_HPP_
59 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
60 #endif
61 #ifndef _COM_SUN_STAR_SDBCX_PRIVILEGE_HPP_
62 #include <com/sun/star/sdbcx/Privilege.hpp>
63 #endif
64 #ifndef _DBACORE_DATACOLUMN_HXX_
65 #include "CRowSetDataColumn.hxx"
66 #endif
67 #ifndef DBACCESS_CORE_API_CROWSETCOLUMN_HXX
68 #include "CRowSetColumn.hxx"
69 #endif
70 #ifndef DBACCESS_CORE_API_ROWSETBASE_HXX
71 #include "RowSetBase.hxx"
72 #endif
73 #ifndef _DBHELPER_DBEXCEPTION_HXX_
74 #include <connectivity/dbexception.hxx>
75 #endif
76 #ifndef _CONNECTIVITY_SQLPARSE_HXX
77 #include <connectivity/sqlparse.hxx>
78 #endif
79 #ifndef _CONNECTIVITY_SQLNODE_HXX
80 #include <connectivity/sqlnode.hxx>
81 #endif
82 #ifndef _CONNECTIVITY_PARSE_SQLITERATOR_HXX_
83 #include <connectivity/sqliterator.hxx>
84 #endif
85 #ifndef _COMPHELPER_PROPERTY_HXX_
86 #include <comphelper/property.hxx>
87 #endif
88 #ifndef _COM_SUN_STAR_SDBCX_COMPAREBOOKMARK_HPP_
89 #include <com/sun/star/sdbcx/CompareBookmark.hpp>
90 #endif
91 #ifndef _TOOLS_DEBUG_HXX
92 #include <tools/debug.hxx>
93 #endif
95 #include <algorithm>
96 #ifndef DBACCESS_CORE_API_ROWSETCACHE_HXX
97 #include "RowSetCache.hxx"
98 #endif
99 #ifndef _DBA_CORE_RESOURCE_HXX_
100 #include "core_resource.hxx"
101 #endif
102 #ifndef _DBA_CORE_RESOURCE_HRC_
103 #include "core_resource.hrc"
104 #endif
105 #ifndef DBACCESS_CORE_API_BOOKMARKSET_HXX
106 #include "BookmarkSet.hxx"
107 #endif
108 #ifndef DBACCESS_CORE_API_STATICSET_HXX
109 #include "StaticSet.hxx"
110 #endif
111 #ifndef DBACCESS_CORE_API_KEYSET_HXX
112 #include "KeySet.hxx"
113 #endif
114 #ifndef DBACCESS_SHARED_DBASTRINGS_HRC
115 #include "dbastrings.hrc"
116 #endif
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,
140 sal_Bool& _bNew,
141 const ORowSetValueVector& _aParameterValueForCache)
142 :m_xSet(_xRs)
143 ,m_xMetaData(Reference< XResultSetMetaDataSupplier >(_xRs,UNO_QUERY)->getMetaData())
144 ,m_aContext( _rContext )
145 ,m_pCacheSet(NULL)
146 ,m_pMatrix(NULL)
147 ,m_pInsertMatrix(NULL)
148 ,m_nLastColumnIndex(0)
149 ,m_nFetchSize(0)
150 ,m_nRowCount(0)
151 ,m_nPrivileges( Privilege::SELECT )
152 ,m_nPosition(0)
153 ,m_nStartPos(0)
154 ,m_nEndPos(0)
155 ,m_bRowCountFinal(sal_False)
156 ,m_bBeforeFirst(sal_True)
157 ,m_bAfterLast( sal_False )
158 ,m_bUpdated(sal_False)
159 ,m_bModified(_bModified)
160 ,m_bNew(_bNew)
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;
171 if(_xAnalyzer.is())
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();
190 else
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);
196 if(xKeys.is())
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);
212 break;
216 if(xColumnsSupplier.is())
218 // first we need a connection
219 Reference< XStatement> xStmt(_xRs->getStatement(),UNO_QUERY);
220 if(xStmt.is())
221 xConnection = xStmt->getConnection();
222 else
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);
231 if ( xColSup.is() )
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();
244 catch(Exception&)
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
256 if(!bNeedKeySet)
260 m_pCacheSet = new OBookmarkSet();
261 m_xCacheSet = m_pCacheSet;
262 m_pCacheSet->construct(_xRs);
264 // check privileges
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))
271 m_nPrivileges = 0;
272 xTable->getPropertyValue(PROPERTY_PRIVILEGES) >>= m_nPrivileges;
273 if(!m_nPrivileges)
274 m_nPrivileges = Privilege::SELECT;
278 catch(const SQLException&)
280 bNeedKeySet = sal_True;
284 if(bNeedKeySet)
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)
292 if(!bAllKeysFound )
294 m_pCacheSet = new OStaticSet();
295 m_xCacheSet = m_pCacheSet;
296 m_pCacheSet->construct(_xRs);
297 m_nPrivileges = Privilege::SELECT;
299 else
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);
308 // check privileges
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!");
320 if(xColumn.is())
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))
344 m_nPrivileges = 0;
345 xTable->getPropertyValue(PROPERTY_PRIVILEGES) >>= m_nPrivileges;
346 if(!m_nPrivileges)
347 m_nPrivileges = Privilege::SELECT;
350 if(bNoInsert)
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
356 if ( m_pCacheSet )
357 m_pCacheSet = NULL;
358 m_xCacheSet = NULL;
359 m_pCacheSet = new OStaticSet();
360 m_xCacheSet = m_pCacheSet;
361 m_pCacheSet->construct(_xRs);
362 m_nPrivileges = Privilege::SELECT;
367 // last check
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()
376 m_pCacheSet = NULL;
377 m_xCacheSet = NULL;
378 if(m_pMatrix)
380 m_pMatrix->clear();
381 delete m_pMatrix;
384 if(m_pInsertMatrix)
386 m_pInsertMatrix->clear();
387 delete m_pInsertMatrix;
389 m_xSet = WeakReference< XResultSet>();
390 m_xMetaData = NULL;
391 m_aUpdateTable = NULL;
393 DBG_DTOR(ORowSetCache,NULL);
396 // -------------------------------------------------------------------------
397 void ORowSetCache::setMaxRowSize(sal_Int32 _nSize)
400 if(_nSize == m_nFetchSize)
401 return;
403 m_nFetchSize = _nSize;
404 if(!m_pMatrix)
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();
413 else
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;
437 else
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++;
453 else
454 aCacheIter->second.aIterator = m_pMatrix->end();
458 if(!m_nPosition)
460 sal_Int32 nNewSt = 1;
461 fillMatrix(nNewSt,_nSize+1);
462 m_nStartPos = 0;
463 m_nEndPos = _nSize;
466 // -------------------------------------------------------------------------
468 // XResultSetMetaDataSupplier
469 Reference< XResultSetMetaData > ORowSetCache::getMetaData( )
471 return m_xMetaData;
473 // -------------------------------------------------------------------------
474 // ::com::sun::star::sdbcx::XRowLocate
475 Any ORowSetCache::getBookmark( )
478 if(m_bAfterLast)
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]);
492 default:
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();
508 if(!m_bAfterLast)
510 moveWindow();
511 checkPositionFlags();
512 if ( !m_bAfterLast )
514 m_aMatrixIter = calcPosition();
515 OSL_ENSURE(m_aMatrixIter->isValid(),"Iterator after moveToBookmark not valid");
517 else
518 m_aMatrixIter = m_pMatrix->end();
520 else
521 m_aMatrixIter = m_pMatrix->end();
523 else
524 return sal_False;
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 ) );
532 if ( bRet )
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();
541 return bRet;
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 // -------------------------------------------------------------------------
561 // XRowUpdate
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;
579 if(x.is())
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;
590 if(x.is())
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 // -------------------------------------------------------------------------
616 // XResultSet
617 sal_Bool ORowSetCache::next( )
621 if(!isAfterLast())
623 m_bBeforeFirst = sal_False;
624 ++m_nPosition;
626 // after we increment the position we have to check if we are already after the last row
627 checkPositionFlags();
628 if(!m_bAfterLast)
630 moveWindow();
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( )
651 return m_bAfterLast;
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( )
671 if(!m_bBeforeFirst)
673 m_bAfterLast = sal_False;
674 m_nPosition = 0;
675 m_bBeforeFirst = sal_True;
676 m_pCacheSet->beforeFirst();
677 moveWindow();
678 m_aMatrixIter = m_pMatrix->end();
680 return sal_True;
682 // -------------------------------------------------------------------------
683 sal_Bool ORowSetCache::afterLast( )
687 if(!m_bAfterLast)
689 m_bBeforeFirst = sal_False;
690 m_bAfterLast = sal_True;
692 if(!m_bRowCountFinal)
694 m_pCacheSet->last();
695 m_bRowCountFinal = sal_True;
696 m_nRowCount = m_pCacheSet->getRow();// + 1 removed
698 m_pCacheSet->afterLast();
700 m_nPosition = 0;
701 m_aMatrixIter = m_pMatrix->end();
703 return sal_True;
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)
716 if(bCheck)
718 if(!aIter->isValid())
719 *aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
720 m_pCacheSet->fillValueRow(*aIter,i);
722 else
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
729 if(!m_nRowCount)
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)
743 if(bCheck)
745 if(!aIter->isValid())
746 *aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
747 m_pCacheSet->fillValueRow(*aIter,nPos++);
749 bCheck = m_pCacheSet->next();
751 if(aIter != aEnd)
752 ::std::rotate(m_pMatrix->begin(),aEnd,aRealEnd);
754 break;
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;
769 else
770 m_nRowCount = std::max(i,m_nRowCount);
773 return bCheck;
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
788 if(!m_nStartPos)
789 return sal_False;
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);
805 aIter = aEnd;
806 m_nStartPos = 0;
808 else
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;
817 if ( bCheck )
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();
839 else
841 #if OSL_DEBUG_LEVEL > 0
842 ORowSetMatrix::iterator aOldPos;
843 aOldPos = aCacheIter->second.aIterator;
844 #endif
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;
850 #endif
851 OSL_ENSURE(aCacheIter->second.aIterator >= m_pMatrix->begin()
852 && aCacheIter->second.aIterator < m_pMatrix->end(),"Iterator out of area!");
857 else
858 { // normaly this should never happen
859 OSL_ENSURE(0,"What the hell is happen here!");
860 return sal_False;
863 else
864 {// no rows can be reused so fill again
865 if(nNewStartPos < 1) // special case
867 m_nStartPos = 0;
869 rotateCacheIterator(static_cast<sal_Int16>(m_nFetchSize+1)); // static_cast<sal_Int16>(m_nFetchSize+1)
871 m_pCacheSet->beforeFirst();
873 sal_Bool bCheck;
874 ORowSetMatrix::iterator aIter = m_pMatrix->begin();
875 for(sal_Int32 i=0;i<m_nFetchSize;++i,++aIter)
877 bCheck = m_pCacheSet->next();
878 if ( bCheck )
880 if(!aIter->isValid())
881 *aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
882 m_pCacheSet->fillValueRow(*aIter,i+1);
884 else
885 *aIter = NULL;
888 else
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 ) );
902 if ( bOk )
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 );
911 if ( bOk )
912 m_nRowCount = std::max(sal_Int32(m_nPosition+1),m_nRowCount);
915 if(!bOk)
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();
946 // bind end to front
947 if(bCheck)
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
954 if(!bOk)
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);
963 else
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;
979 // TODO check
980 // m_nStartPos = (nNewStartPos+m_nRowCount) - m_nFetchSize ;
981 if(m_nStartPos < 0)
982 m_nStartPos = 0;
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();
989 nPos = m_nStartPos;
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!");
1011 return bRet;
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();
1021 if(bRet)
1023 m_bBeforeFirst = m_bAfterLast = sal_False;
1024 m_nPosition = 1;
1025 moveWindow();
1026 m_aMatrixIter = m_pMatrix->begin();
1028 else
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();
1036 return bRet;
1038 // -------------------------------------------------------------------------
1039 sal_Bool ORowSetCache::last( )
1041 sal_Bool bRet = m_pCacheSet->last();
1042 if(bRet)
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();
1051 moveWindow();
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;
1056 // else
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();
1061 else
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
1069 if(bRet)
1071 OSL_ENSURE((*m_aMatrixIter).isValid(),"ORowSetCache::last: Row not valid!");
1073 #endif
1075 return bRet;
1077 // -------------------------------------------------------------------------
1078 sal_Int32 ORowSetCache::getRow( )
1080 return (isBeforeFirst() || isAfterLast()) ? 0 : m_nPosition;
1082 // -------------------------------------------------------------------------
1083 sal_Bool ORowSetCache::absolute( sal_Int32 row )
1085 if(!row )
1086 throw SQLException(DBACORE_RESSTRING(RID_STR_NO_ABS_ZERO),NULL,SQLSTATE_GENERAL,1000,Any() );
1088 if(row < 0)
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
1095 if(m_nPosition < 1)
1097 m_bBeforeFirst = sal_True;
1098 m_bAfterLast = sal_False;
1099 m_aMatrixIter = m_pMatrix->end();
1101 else
1103 m_bBeforeFirst = sal_False;
1104 m_bAfterLast = m_nPosition > m_nRowCount;
1105 moveWindow();
1106 OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
1107 m_aMatrixIter = calcPosition();
1110 else
1111 m_aMatrixIter = m_pMatrix->end();
1113 else
1115 m_nPosition = row;
1116 // the position flags
1117 m_bBeforeFirst = sal_False;
1118 checkPositionFlags();
1120 if(!m_bAfterLast)
1122 moveWindow();
1123 checkPositionFlags();
1124 if(!m_bAfterLast)
1125 m_aMatrixIter = calcPosition();
1126 else
1127 m_aMatrixIter = m_pMatrix->end();
1129 else
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;
1139 if(rows)
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;
1147 else
1148 if ( m_bBeforeFirst || ( m_bRowCountFinal && m_bAfterLast ) )
1149 throw SQLException( DBACORE_RESSTRING( RID_STR_NO_RELATIVE ), NULL, SQLSTATE_GENERAL, 1000, Any() );
1150 if ( nNewPosition )
1152 bErg = absolute( nNewPosition );
1153 bErg = bErg && !isAfterLast() && !isBeforeFirst();
1155 else
1157 m_bBeforeFirst = sal_True;
1158 bErg = sal_False;
1161 return bErg;
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
1170 bRet = last();
1171 else
1173 m_bAfterLast = sal_False;
1174 --m_nPosition;
1175 moveWindow();
1176 OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
1178 checkPositionFlags();
1180 if(!m_nPosition)
1182 m_bBeforeFirst = sal_True;
1183 m_aMatrixIter = m_pMatrix->end();
1185 else
1187 m_aMatrixIter = calcPosition();
1188 bRet = (*m_aMatrixIter).isValid();
1192 return bRet;
1194 // -------------------------------------------------------------------------
1195 void ORowSetCache::refreshRow( )
1197 if(isAfterLast())
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);
1202 if ( m_bNew )
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 // -------------------------------------------------------------------------
1218 // XResultSetUpdate
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() );
1227 if ( bRet )
1229 ++m_nRowCount;
1230 Any aBookmark = ((*m_aInsertRow)->get())[0].makeAny();
1231 m_bAfterLast = m_bBeforeFirst = sal_False;
1232 if(aBookmark.hasValue())
1233 moveToBookmark(aBookmark);
1234 else
1236 OSL_ENSURE(0,"There must be a bookmark after the row was inserted!");
1239 return bRet;
1241 // -------------------------------------------------------------------------
1242 void ORowSetCache::resetInsertRow(sal_Bool _bClearInsertRow)
1244 if ( _bClearInsertRow )
1245 clearInsertRow();
1246 m_bNew = sal_False;
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;
1283 // refreshRow( );
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() )
1294 return false;
1296 --m_nRowCount;
1297 OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!");
1298 ORowSetMatrix::iterator aPos = calcPosition();
1299 (*aPos) = NULL;
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)
1306 *(aPos-1) = *aPos;
1307 (*aPos) = NULL;
1309 m_aMatrixIter = m_pMatrix->end();
1311 --m_nPosition;
1312 return true;
1314 // -------------------------------------------------------------------------
1315 void ORowSetCache::cancelRowUpdates( )
1317 m_bNew = m_bModified = sal_False;
1318 if(!m_nPosition)
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);
1326 else
1328 OSL_ENSURE(0,"cancelRowUpdates couldn't position right with absolute");
1329 ::dbtools::throwFunctionSequenceException(NULL);
1332 // -------------------------------------------------------------------------
1333 void ORowSetCache::moveToInsertRow( )
1335 m_bNew = sal_True;
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);
1349 aIter->setNull();
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 )
1372 else
1373 ++aCacheIter;
1376 // -----------------------------------------------------------------------------
1377 void ORowSetCache::rotateCacheIterator(ORowSetMatrix::difference_type _nDist)
1379 if(_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());
1390 if(nDist < _nDist)
1392 aCacheIter->second.aIterator = m_pMatrix->end();
1394 else
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;
1425 if(m_bAfterLast)
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))
1461 bOk = sal_False;
1463 ::rtl::OUString sColumnName,sTableRange;
1464 OSQLParseTreeIterator::getColumnRange( pNode->getChild(0), _xConnection, sColumnName, sTableRange );
1465 bOk = sTableRange == _sUpdateTableName;
1466 if ( !bOk )
1468 OSQLParseTreeIterator::getColumnRange( pNode->getChild(2), _xConnection, sColumnName, sTableRange );
1469 bOk = sTableRange == _sUpdateTableName;
1472 return bOk;
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);
1492 if(pJoin)
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;
1503 if(pOuterType)
1504 { // found outer join
1505 bLeftSide = SQL_ISTOKEN(pOuterType->getChild(0),LEFT);
1506 bCheck = bLeftSide || SQL_ISTOKEN(pOuterType->getChild(0),RIGHT);
1509 if(bCheck)
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);
1512 if(bLeftSide)
1513 pTableRef = pJoin->getChild(0);
1514 else
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;
1525 else
1527 OSQLParseNode* pWhereOpt = pSqlParseNode->getChild(3)->getChild(1);
1528 if ( pWhereOpt && !pWhereOpt->isLeaf() )
1529 bOk = checkInnerJoin(pWhereOpt->getChild(1),_xConnection,_sUpdateTableName);
1532 return bOk;
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);
1546 aIter->setNull();
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);
1563 return 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);
1574 break;
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
1592 return bRet;
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);
1602 else
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();
1614 return _bCheck;
1616 // -----------------------------------------------------------------------------