diff options
Diffstat (limited to 'dbaccess/source/core/api/RowSetCache.cxx')
-rw-r--r-- | dbaccess/source/core/api/RowSetCache.cxx | 323 |
1 files changed, 203 insertions, 120 deletions
diff --git a/dbaccess/source/core/api/RowSetCache.cxx b/dbaccess/source/core/api/RowSetCache.cxx index 924fd881346e..dba67c045f9d 100644 --- a/dbaccess/source/core/api/RowSetCache.cxx +++ b/dbaccess/source/core/api/RowSetCache.cxx @@ -70,18 +70,11 @@ #ifndef DBACCESS_CORE_API_ROWSETBASE_HXX #include "RowSetBase.hxx" #endif -#ifndef _DBHELPER_DBEXCEPTION_HXX_ #include <connectivity/dbexception.hxx> -#endif -#ifndef _CONNECTIVITY_SQLPARSE_HXX #include <connectivity/sqlparse.hxx> -#endif -#ifndef _CONNECTIVITY_SQLNODE_HXX #include <connectivity/sqlnode.hxx> -#endif -#ifndef _CONNECTIVITY_PARSE_SQLITERATOR_HXX_ +#include <connectivity/dbtools.hxx> #include <connectivity/sqliterator.hxx> -#endif #ifndef _COMPHELPER_PROPERTY_HXX_ #include <comphelper/property.hxx> #endif @@ -114,6 +107,8 @@ #ifndef DBACCESS_SHARED_DBASTRINGS_HRC #include "dbastrings.hrc" #endif +#include "WrappedResultSet.hxx" +#include "OptimisticSet.hxx" using namespace dbaccess; using namespace dbtools; @@ -162,10 +157,34 @@ ORowSetCache::ORowSetCache(const Reference< XResultSet >& _xRs, { DBG_CTOR(ORowSetCache,NULL); + // first try if the result can be used to do inserts and updates + try + { + Reference< XResultSetUpdate> xUp(_xRs,UNO_QUERY_THROW); + xUp->moveToInsertRow(); + xUp->cancelRowUpdates(); + _xRs->beforeFirst(); + m_nPrivileges = Privilege::SELECT|Privilege::DELETE|Privilege::INSERT|Privilege::UPDATE; + m_pCacheSet = new WrappedResultSet(); + m_xCacheSet = m_pCacheSet; + m_pCacheSet->construct(_xRs,i_sRowSetFilter); + return; + } + catch(const Exception&) + { + } + // check if all keys of the updateable table are fetched sal_Bool bAllKeysFound = sal_False; sal_Int32 nTablesCount = 0; + Reference< XPropertySet> xProp(_xRs,UNO_QUERY); + Reference< XPropertySetInfo > xPropInfo = xProp->getPropertySetInfo(); + sal_Bool bNeedKeySet = !(xPropInfo->hasPropertyByName(PROPERTY_ISBOOKMARKABLE) && + any2bool(xProp->getPropertyValue(PROPERTY_ISBOOKMARKABLE)) && Reference< XRowLocate >(_xRs, UNO_QUERY).is() ); + bNeedKeySet = bNeedKeySet || (xPropInfo->hasPropertyByName(PROPERTY_RESULTSETCONCURRENCY) && + ::comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY)) == ResultSetConcurrency::READ_ONLY); + Reference< XIndexAccess> xUpdateTableKeys; ::rtl::OUString aUpdateTableName = _rUpdateTableName; Reference< XConnection> xConnection; @@ -186,58 +205,54 @@ ORowSetCache::ORowSetCache(const Reference< XResultSet >& _xRs, Reference<XTablesSupplier> xTabSup(_xAnalyzer,UNO_QUERY); OSL_ENSURE(xTabSup.is(),"ORowSet::execute composer isn't a tablesupplier!"); Reference<XNameAccess> xTables = xTabSup->getTables(); - - - if(_rUpdateTableName.getLength() && xTables->hasByName(_rUpdateTableName)) - xTables->getByName(_rUpdateTableName) >>= m_aUpdateTable; - else if(xTables->getElementNames().getLength()) - { - aUpdateTableName = xTables->getElementNames()[0]; - xTables->getByName(aUpdateTableName) >>= m_aUpdateTable; + Sequence< ::rtl::OUString> aTableNames = xTables->getElementNames(); + if ( aTableNames.getLength() > 1 && !_rUpdateTableName.getLength() && bNeedKeySet ) + {// here we have a join or union and nobody told us which table to update, so we update them all + m_nPrivileges = Privilege::SELECT|Privilege::DELETE|Privilege::INSERT|Privilege::UPDATE; + OptimisticSet* pCursor = new OptimisticSet(m_aContext,xConnection,_xAnalyzer,_aParameterValueForCache); + m_pCacheSet = pCursor; + m_xCacheSet = m_pCacheSet; + try + { + m_pCacheSet->construct(_xRs,i_sRowSetFilter); + if ( pCursor->isReadOnly() ) + m_nPrivileges = Privilege::SELECT; + m_aKeyColumns = pCursor->getJoinedKeyColumns(); + return; + } + catch(const Exception&) + { + } } - Reference<XIndexAccess> xIndexAccess(xTables,UNO_QUERY); - if(xIndexAccess.is()) - nTablesCount = xIndexAccess->getCount(); else - nTablesCount = xTables->getElementNames().getLength(); - - if(m_aUpdateTable.is() && nTablesCount < 3) // for we can't handle more than 2 tables in our keyset { - Reference<XKeysSupplier> xKeys(m_aUpdateTable,UNO_QUERY); - if(xKeys.is()) + if(_rUpdateTableName.getLength() && xTables->hasByName(_rUpdateTableName)) + xTables->getByName(_rUpdateTableName) >>= m_aUpdateTable; + else if(xTables->getElementNames().getLength()) { - xUpdateTableKeys = xKeys->getKeys(); - if ( xUpdateTableKeys.is() ) - { - Reference<XColumnsSupplier> xColumnsSupplier; - // search the one and only primary key - const sal_Int32 nCount = xUpdateTableKeys->getCount(); - for(sal_Int32 i = 0 ; i < nCount ; ++i) - { - Reference<XPropertySet> xProp(xUpdateTableKeys->getByIndex(i),UNO_QUERY); - sal_Int32 nKeyType = 0; - xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType; - if(KeyType::PRIMARY == nKeyType) - { - xColumnsSupplier.set(xProp,UNO_QUERY); - break; - } - } + aUpdateTableName = xTables->getElementNames()[0]; + xTables->getByName(aUpdateTableName) >>= m_aUpdateTable; + } + Reference<XIndexAccess> xIndexAccess(xTables,UNO_QUERY); + if(xIndexAccess.is()) + nTablesCount = xIndexAccess->getCount(); + else + nTablesCount = xTables->getElementNames().getLength(); - if(xColumnsSupplier.is()) + if(m_aUpdateTable.is() && nTablesCount < 3) // for we can't handle more than 2 tables in our keyset + { + Reference<XPropertySet> xSet(m_aUpdateTable,UNO_QUERY); + const Reference<XNameAccess> xPrimaryKeyColumns = dbtools::getPrimaryKeyColumns_throw(xSet); + if ( xPrimaryKeyColumns.is() ) + { + Reference<XColumnsSupplier> xColSup(_xAnalyzer,UNO_QUERY); + if ( xColSup.is() ) { - - - Reference<XNameAccess> xColumns = xColumnsSupplier->getColumns(); - Reference<XColumnsSupplier> xColSup(_xAnalyzer,UNO_QUERY); - if ( xColSup.is() ) - { - Reference<XNameAccess> xSelColumns = xColSup->getColumns(); - Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData(); - SelectColumnsMetaData aColumnNames(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers() ? true : false); - ::dbaccess::getColumnPositions(xSelColumns,xColumns->getElementNames(),aUpdateTableName,aColumnNames); - bAllKeysFound = !aColumnNames.empty() && sal_Int32(aColumnNames.size()) == xColumns->getElementNames().getLength(); - } + Reference<XNameAccess> xSelColumns = xColSup->getColumns(); + Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData(); + SelectColumnsMetaData aColumnNames(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers() ? true : false); + ::dbaccess::getColumnPositions(xSelColumns,xPrimaryKeyColumns->getElementNames(),aUpdateTableName,aColumnNames); + bAllKeysFound = !aColumnNames.empty() && sal_Int32(aColumnNames.size()) == xPrimaryKeyColumns->getElementNames().getLength(); } } } @@ -247,12 +262,6 @@ ORowSetCache::ORowSetCache(const Reference< XResultSet >& _xRs, { } } - Reference< XPropertySet> xProp(_xRs,UNO_QUERY); - - sal_Bool bNeedKeySet = !(xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_ISBOOKMARKABLE) && - any2bool(xProp->getPropertyValue(PROPERTY_ISBOOKMARKABLE)) && Reference< XRowLocate >(_xRs, UNO_QUERY).is() ); - bNeedKeySet = bNeedKeySet || (xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_RESULTSETCONCURRENCY) && - ::comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY)) == ResultSetConcurrency::READ_ONLY); // first check if resultset is bookmarkable if(!bNeedKeySet) @@ -316,8 +325,7 @@ ORowSetCache::ORowSetCache(const Reference< XResultSet >& _xRs, const ::rtl::OUString* pEnd = pIter + aNames.getLength(); for(;pIter != pEnd;++pIter) { - Reference<XPropertySet> xColumn; - ::cppu::extractInterface(xColumn,xColumns->getByName(*pIter)); + Reference<XPropertySet> xColumn(xColumns->getByName(*pIter),UNO_QUERY); OSL_ENSURE(xColumn.is(),"Column in table is null!"); if(xColumn.is()) { @@ -473,6 +481,21 @@ Reference< XResultSetMetaData > ORowSetCache::getMetaData( ) return m_xMetaData; } // ------------------------------------------------------------------------- +Any lcl_getBookmark(ORowSetValue& i_aValue,OCacheSet* i_pCacheSet) +{ + switch ( i_aValue.getTypeKind() ) + { + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + return makeAny((sal_Int32)i_aValue); + default: + if ( i_pCacheSet && i_aValue.isNull()) + i_aValue = i_pCacheSet->getBookmark(); + return i_aValue.getAny(); + } +} +// ------------------------------------------------------------------------- // ::com::sun::star::sdbcx::XRowLocate Any ORowSetCache::getBookmark( ) { @@ -485,17 +508,7 @@ Any ORowSetCache::getBookmark( ) return Any(); // this is allowed here because the rowset knowns what it is doing } - switch(((*m_aMatrixIter)->get())[0].getTypeKind()) - { - case DataType::TINYINT: - case DataType::SMALLINT: - case DataType::INTEGER: - return makeAny((sal_Int32)((*m_aMatrixIter)->get())[0]); - default: - if(((*m_aMatrixIter)->get())[0].isNull()) - ((*m_aMatrixIter)->get())[0] = m_pCacheSet->getBookmark(); - return ((*m_aMatrixIter)->get())[0].getAny(); - } + return lcl_getBookmark(((*m_aMatrixIter)->get())[0],m_pCacheSet); } // ------------------------------------------------------------------------- sal_Bool ORowSetCache::moveToBookmark( const Any& bookmark ) @@ -550,84 +563,106 @@ sal_Int32 ORowSetCache::compareBookmarks( const Any& _first, const Any& _second // ------------------------------------------------------------------------- sal_Bool ORowSetCache::hasOrderedBookmarks( ) { - return m_pCacheSet->hasOrderedBookmarks(); } // ------------------------------------------------------------------------- sal_Int32 ORowSetCache::hashBookmark( const Any& bookmark ) { - return m_pCacheSet->hashBookmark(bookmark); } -// ------------------------------------------------------------------------- // XRowUpdate // ----------------------------------------------------------------------------- -void ORowSetCache::updateNull(sal_Int32 columnIndex) +void ORowSetCache::updateNull(sal_Int32 columnIndex,ORowSetValueVector::Vector& io_aRow + ,::std::vector<sal_Int32>& o_ChangedColumns + ) { checkUpdateConditions(columnIndex); - ((*m_aInsertRow)->get())[columnIndex].setBound(sal_True); - ((*m_aInsertRow)->get())[columnIndex].setNull(); - ((*m_aInsertRow)->get())[columnIndex].setModified(); -} -// ----------------------------------------------------------------------------- -void ORowSetCache::updateValue(sal_Int32 columnIndex,const ORowSetValue& x) -{ - checkUpdateConditions(columnIndex); + ORowSetValueVector::Vector& rInsert = ((*m_aInsertRow)->get()); + rInsert[columnIndex].setBound(sal_True); + rInsert[columnIndex].setNull(); + rInsert[columnIndex].setModified(); + io_aRow[columnIndex].setNull(); - ((*m_aInsertRow)->get())[columnIndex].setBound(sal_True); - ((*m_aInsertRow)->get())[columnIndex] = x; - ((*m_aInsertRow)->get())[columnIndex].setModified(); + m_pCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns); + impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns); } -// ------------------------------------------------------------------------- -void ORowSetCache::updateBinaryStream( sal_Int32 columnIndex, const Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ) +// ----------------------------------------------------------------------------- +void ORowSetCache::updateValue(sal_Int32 columnIndex,const ORowSetValue& x + ,ORowSetValueVector::Vector& io_aRow + ,::std::vector<sal_Int32>& o_ChangedColumns + ) { checkUpdateConditions(columnIndex); + ORowSetValueVector::Vector& rInsert = ((*m_aInsertRow)->get()); + rInsert[columnIndex].setBound(sal_True); + rInsert[columnIndex] = x; + rInsert[columnIndex].setModified(); + io_aRow[columnIndex] = rInsert[columnIndex]; - Sequence<sal_Int8> aSeq; - if(x.is()) - x->readBytes(aSeq,length); - updateValue(columnIndex,aSeq); + m_pCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns); + impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns); } // ------------------------------------------------------------------------- -void ORowSetCache::updateCharacterStream( sal_Int32 columnIndex, const Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ) +void ORowSetCache::updateCharacterStream( sal_Int32 columnIndex, const Reference< ::com::sun::star::io::XInputStream >& x + , sal_Int32 length,ORowSetValueVector::Vector& io_aRow + ,::std::vector<sal_Int32>& o_ChangedColumns + ) { checkUpdateConditions(columnIndex); - Sequence<sal_Int8> aSeq; if(x.is()) x->readBytes(aSeq,length); - updateValue(columnIndex,aSeq); + ORowSetValueVector::Vector& rInsert = ((*m_aInsertRow)->get()); + rInsert[columnIndex].setBound(sal_True); + rInsert[columnIndex] = aSeq; + rInsert[columnIndex].setModified(); + io_aRow[columnIndex] = makeAny(x); + + m_pCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns); + impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns); } // ------------------------------------------------------------------------- -void ORowSetCache::updateObject( sal_Int32 columnIndex, const Any& x ) +void ORowSetCache::updateObject( sal_Int32 columnIndex, const Any& x + ,ORowSetValueVector::Vector& io_aRow + ,::std::vector<sal_Int32>& o_ChangedColumns + ) { checkUpdateConditions(columnIndex); + ORowSetValueVector::Vector& rInsert = ((*m_aInsertRow)->get()); + rInsert[columnIndex].setBound(sal_True); + rInsert[columnIndex] = x; + rInsert[columnIndex].setModified(); + io_aRow[columnIndex] = rInsert[columnIndex]; - ((*m_aInsertRow)->get())[columnIndex].setBound(sal_True); - ((*m_aInsertRow)->get())[columnIndex] = x; - ((*m_aInsertRow)->get())[columnIndex].setModified(); + m_pCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns); + impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns); } // ------------------------------------------------------------------------- -void ORowSetCache::updateNumericObject( sal_Int32 columnIndex, const Any& x, sal_Int32 /*scale*/ ) +void ORowSetCache::updateNumericObject( sal_Int32 columnIndex, const Any& x, sal_Int32 /*scale*/ + ,ORowSetValueVector::Vector& io_aRow + ,::std::vector<sal_Int32>& o_ChangedColumns + ) { checkUpdateConditions(columnIndex); + ORowSetValueVector::Vector& rInsert = ((*m_aInsertRow)->get()); + rInsert[columnIndex].setBound(sal_True); + rInsert[columnIndex] = x; + rInsert[columnIndex].setModified(); + io_aRow[columnIndex] = rInsert[columnIndex]; - ((*m_aInsertRow)->get())[columnIndex].setBound(sal_True); - ((*m_aInsertRow)->get())[columnIndex] = x; - ((*m_aInsertRow)->get())[columnIndex].setModified(); + m_pCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns); + impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns); } // ------------------------------------------------------------------------- // XResultSet sal_Bool ORowSetCache::next( ) { - - if(!isAfterLast()) { m_bBeforeFirst = sal_False; @@ -1226,7 +1261,7 @@ sal_Bool ORowSetCache::rowInserted( ) } // ------------------------------------------------------------------------- // XResultSetUpdate -sal_Bool ORowSetCache::insertRow( ) +sal_Bool ORowSetCache::insertRow(::std::vector< Any >& o_aBookmarks) { if ( !m_bNew || !m_aInsertRow->isValid() ) throw SQLException(DBACORE_RESSTRING(RID_STR_NO_MOVETOINSERTROW_CALLED),NULL,SQLSTATE_GENERAL,1000,Any() ); @@ -1240,7 +1275,19 @@ sal_Bool ORowSetCache::insertRow( ) Any aBookmark = ((*m_aInsertRow)->get())[0].makeAny(); m_bAfterLast = m_bBeforeFirst = sal_False; if(aBookmark.hasValue()) + { moveToBookmark(aBookmark); + // update the cached values + ORowSetValueVector::Vector& rCurrentRow = ((*m_aMatrixIter))->get(); + ORowSetMatrix::iterator aIter = m_pMatrix->begin(); + for(;aIter != m_pMatrix->end();++aIter) + { + if ( m_aMatrixIter != aIter && aIter->isValid() && m_pCacheSet->columnValuesUpdated((*aIter)->get(),rCurrentRow) ) + { + o_aBookmarks.push_back(lcl_getBookmark((*aIter)->get()[0],m_pCacheSet)); + } + } + } else { OSL_ENSURE(0,"There must be a bookmark after the row was inserted!"); @@ -1270,7 +1317,7 @@ void ORowSetCache::cancelRowModification() resetInsertRow(sal_False); } // ------------------------------------------------------------------------- -void ORowSetCache::updateRow( ORowSetMatrix::iterator& _rUpdateRow ) +void ORowSetCache::updateRow( ORowSetMatrix::iterator& _rUpdateRow,::std::vector< Any >& o_aBookmarks ) { if(isAfterLast() || isBeforeFirst()) throw SQLException(DBACORE_RESSTRING(RID_STR_NO_UPDATEROW),NULL,SQLSTATE_GENERAL,1000,Any() ); @@ -1281,16 +1328,23 @@ void ORowSetCache::updateRow( ORowSetMatrix::iterator& _rUpdateRow ) // the row was already fetched moveToBookmark(aBookmark); m_pCacheSet->updateRow(*_rUpdateRow,*m_aMatrixIter,m_aUpdateTable); - // *(*m_aMatrixIter) = *(*_rUpdateRow); // refetch the whole row (*m_aMatrixIter) = NULL; - moveToBookmark(aBookmark); - // moveToBookmark((*(*m_aInsertRow))[0].makeAny()); -// if(m_pCacheSet->rowUpdated()) -// *m_aMatrixIter = m_aInsertRow; + if ( moveToBookmark(aBookmark) ) + { + // update the cached values + ORowSetValueVector::Vector& rCurrentRow = ((*m_aMatrixIter))->get(); + ORowSetMatrix::iterator aIter = m_pMatrix->begin(); + for(;aIter != m_pMatrix->end();++aIter) + { + if ( m_aMatrixIter != aIter && aIter->isValid() && m_pCacheSet->columnValuesUpdated((*aIter)->get(),rCurrentRow) ) + { + o_aBookmarks.push_back(lcl_getBookmark((*aIter)->get()[0],m_pCacheSet)); + } + } + } m_bModified = sal_False; - // refreshRow( ); } // ------------------------------------------------------------------------- bool ORowSetCache::deleteRow( ) @@ -1307,8 +1361,6 @@ bool ORowSetCache::deleteRow( ) OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < (sal_Int32)m_pMatrix->size(),"Position is behind end()!"); ORowSetMatrix::iterator aPos = calcPosition(); (*aPos) = NULL; - // (*m_pMatrix)[(m_nPosition - m_nStartPos)] = NULL; // set the deleted row to NULL - ORowSetMatrix::iterator aEnd = m_pMatrix->end(); for(++aPos;aPos != aEnd && aPos->isValid();++aPos) @@ -1625,8 +1677,39 @@ sal_Bool ORowSetCache::fill(ORowSetMatrix::iterator& _aIter,const ORowSetMatrix: return _bCheck; } // ----------------------------------------------------------------------------- +bool ORowSetCache::isResultSetChanged() const +{ + return m_pCacheSet->isResultSetChanged(); +} +// ----------------------------------------------------------------------------- +void ORowSetCache::reset(const Reference< XResultSet>& _xDriverSet) +{ + m_xMetaData.set(Reference< XResultSetMetaDataSupplier >(_xDriverSet,UNO_QUERY)->getMetaData()); + m_pCacheSet->reset(_xDriverSet); + m_bRowCountFinal = sal_False; + m_nRowCount = 0; + reFillMatrix(m_nStartPos+1,m_nEndPos+1); +} +// ----------------------------------------------------------------------------- +void ORowSetCache::impl_updateRowFromCache_throw(ORowSetValueVector::Vector& io_aRow + ,::std::vector<sal_Int32>& o_ChangedColumns) +{ + if ( o_ChangedColumns.size() > 1 ) + { + ORowSetMatrix::iterator aIter = m_pMatrix->begin(); + for(;aIter != m_pMatrix->end();++aIter) + { + if ( aIter->isValid() && m_pCacheSet->updateColumnValues((*aIter)->get(),io_aRow,o_ChangedColumns)) + { + break; + } + } - - - + if ( aIter == m_pMatrix->end() ) + { + m_pCacheSet->fillMissingValues(io_aRow); + } + } +} +// ----------------------------------------------------------------------------- |