/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include "cachedcontentresultset.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace com::sun::star::beans; using namespace com::sun::star::lang; using namespace com::sun::star::script; using namespace com::sun::star::sdbc; using namespace com::sun::star::ucb; using namespace com::sun::star::uno; using namespace com::sun::star::util; using namespace cppu; #define COMSUNSTARUCBCCRS_DEFAULT_FETCH_SIZE 256 #define COMSUNSTARUCBCCRS_DEFAULT_FETCH_DIRECTION FetchDirection::FORWARD //if you change this function template please pay attention to //function getObject, where this is similar implemented template T CachedContentResultSet::rowOriginGet( T (SAL_CALL css::sdbc::XRow::* f)(sal_Int32), sal_Int32 columnIndex) { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); sal_Int32 nRow = m_nRow; sal_Int32 nFetchSize = m_nFetchSize; sal_Int32 nFetchDirection = m_nFetchDirection; if( !m_aCache.hasRow( nRow ) ) { if( !m_aCache.hasCausedException( nRow ) ) { if( !m_xFetchProvider.is() ) { OSL_FAIL( "broadcaster was disposed already" ); throw SQLException(); } if( impl_isForwardOnly(aGuard) ) applyPositionToOrigin( aGuard, nRow ); impl_fetchData( aGuard, nRow, nFetchSize, nFetchDirection ); } if( !m_aCache.hasRow( nRow ) ) { m_bLastReadWasFromCache = false; applyPositionToOrigin( aGuard, nRow ); impl_init_xRowOrigin(aGuard); aGuard.unlock(); return (m_xRowOrigin.get()->*f)( columnIndex ); } } const Any& rValue = m_aCache.getAny( nRow, columnIndex ); T aRet = T(); m_bLastReadWasFromCache = true; m_bLastCachedReadWasNull = !( rValue >>= aRet ); /* Last chance. Try type converter service... */ if ( m_bLastCachedReadWasNull && rValue.hasValue() ) { Reference< XTypeConverter > xConverter = getTypeConverter(aGuard); if ( xConverter.is() ) { try { Any aConvAny = xConverter->convertTo( rValue, cppu::UnoType::get() ); m_bLastCachedReadWasNull = !( aConvAny >>= aRet ); } catch (const IllegalArgumentException&) { } catch (const CannotConvertException&) { } } } return aRet; } // CCRS_Cache methods CachedContentResultSet::CCRS_Cache::CCRS_Cache( const Reference< XContentIdentifierMapping > & xMapping ) : m_xContentIdentifierMapping( xMapping ) { } CachedContentResultSet::CCRS_Cache::~CCRS_Cache() { } void CachedContentResultSet::CCRS_Cache ::clear() { m_pResult.reset(); m_pMappedReminder.reset(); } void CachedContentResultSet::CCRS_Cache ::loadData( const FetchResult& rResult ) { clear(); m_pResult = rResult; } bool CachedContentResultSet::CCRS_Cache ::hasRow( sal_Int32 row ) const { if( !m_pResult ) return false; sal_Int32 nStart = m_pResult->StartIndex; sal_Int32 nEnd = nStart; if( m_pResult->Orientation ) nEnd += m_pResult->Rows.getLength() - 1; else nStart -= m_pResult->Rows.getLength() + 1; return nStart <= row && row <= nEnd; } sal_Int32 CachedContentResultSet::CCRS_Cache ::getMaxRow() const { if( !m_pResult ) return 0; sal_Int32 nEnd = m_pResult->StartIndex; if( m_pResult->Orientation ) return nEnd + m_pResult->Rows.getLength() - 1; else return nEnd; } bool CachedContentResultSet::CCRS_Cache ::hasKnownLast() const { if( !m_pResult ) return false; return ( m_pResult->FetchError & FetchError::ENDOFDATA ) && m_pResult->Orientation && m_pResult->Rows.hasElements(); } bool CachedContentResultSet::CCRS_Cache ::hasCausedException( sal_Int32 nRow ) const { if( !m_pResult ) return false; if( !( m_pResult->FetchError & FetchError::EXCEPTION ) ) return false; sal_Int32 nEnd = m_pResult->StartIndex; if( m_pResult->Orientation ) nEnd += m_pResult->Rows.getLength(); return nRow == nEnd+1; } Any& CachedContentResultSet::CCRS_Cache ::getRowAny( sal_Int32 nRow ) { if( !nRow ) throw SQLException(); if( !m_pResult ) throw SQLException(); if( !hasRow( nRow ) ) throw SQLException(); sal_Int32 nDiff = nRow - m_pResult->StartIndex; if( nDiff < 0 ) nDiff *= -1; return m_pResult->Rows.getArray()[nDiff]; } void CachedContentResultSet::CCRS_Cache ::remindMapped( sal_Int32 nRow ) { //remind that this row was mapped if( !m_pResult ) return; sal_Int32 nDiff = nRow - m_pResult->StartIndex; if( nDiff < 0 ) nDiff *= -1; Sequence< sal_Bool >& rMappedReminder = getMappedReminder(); if( nDiff < rMappedReminder.getLength() ) { sal_Bool* pMappedReminder = rMappedReminder.getArray(); pMappedReminder[nDiff] = true; } } bool CachedContentResultSet::CCRS_Cache ::isRowMapped( sal_Int32 nRow ) { if( !m_pMappedReminder || !m_pResult ) return false; sal_Int32 nDiff = nRow - m_pResult->StartIndex; if( nDiff < 0 ) nDiff *= -1; if( nDiff < m_pMappedReminder->getLength() ) return (*m_pMappedReminder)[nDiff]; return false; } Sequence< sal_Bool >& CachedContentResultSet::CCRS_Cache ::getMappedReminder() { if( !m_pMappedReminder ) { sal_Int32 nCount = m_pResult->Rows.getLength(); m_pMappedReminder.emplace( nCount ); std::fill_n(m_pMappedReminder->getArray(), m_pMappedReminder->getLength(), false); } return *m_pMappedReminder; } const Any& CachedContentResultSet::CCRS_Cache ::getAny( sal_Int32 nRow, sal_Int32 nColumnIndex ) { if( !nColumnIndex ) throw SQLException(); if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) ) { Any& rRow = getRowAny( nRow ); Sequence< Any > aValue; rRow >>= aValue; if( m_xContentIdentifierMapping->mapRow( aValue ) ) { rRow <<= aValue; remindMapped( nRow ); } else m_xContentIdentifierMapping.clear(); } auto & rowAny = getRowAny(nRow); auto rRow = o3tl::doAccess>(rowAny); if( nColumnIndex > rRow->getLength() ) throw SQLException(); return (*rRow)[nColumnIndex-1]; } OUString const & CachedContentResultSet::CCRS_Cache ::getContentIdentifierString( sal_Int32 nRow ) { try { if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) ) { Any& rRow = getRowAny( nRow ); OUString aValue; rRow >>= aValue; rRow <<= m_xContentIdentifierMapping->mapContentIdentifierString( aValue ); remindMapped( nRow ); } return *o3tl::doAccess(getRowAny(nRow)); } catch(const SQLException& ex) { css::uno::Any anyEx = cppu::getCaughtException(); throw css::lang::WrappedTargetRuntimeException( ex.Message, css::uno::Reference< css::uno::XInterface >(), anyEx ); } } Reference< XContentIdentifier > CachedContentResultSet::CCRS_Cache ::getContentIdentifier( sal_Int32 nRow ) { try { if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) ) { Any& rRow = getRowAny( nRow ); Reference< XContentIdentifier > aValue; rRow >>= aValue; rRow <<= m_xContentIdentifierMapping->mapContentIdentifier( aValue ); remindMapped( nRow ); } return *o3tl::doAccess>(getRowAny(nRow)); } catch(const SQLException& ex) { css::uno::Any anyEx = cppu::getCaughtException(); throw css::lang::WrappedTargetRuntimeException( ex.Message, css::uno::Reference< css::uno::XInterface >(), anyEx ); } } Reference< XContent > CachedContentResultSet::CCRS_Cache ::getContent( sal_Int32 nRow ) { try { if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) ) { Any& rRow = getRowAny( nRow ); Reference< XContent > aValue; rRow >>= aValue; rRow <<= m_xContentIdentifierMapping->mapContent( aValue ); remindMapped( nRow ); } return *o3tl::doAccess>(getRowAny(nRow)); } catch (const SQLException& ex) { css::uno::Any anyEx = cppu::getCaughtException(); throw css::lang::WrappedTargetRuntimeException( ex.Message, css::uno::Reference< css::uno::XInterface >(), anyEx ); } } class CCRS_PropertySetInfo : public cppu::OWeakObject, public css::lang::XTypeProvider, public css::beans::XPropertySetInfo { friend class CachedContentResultSet; //my Properties std::optional> m_xProperties; sal_Int32 m_nFetchSizePropertyHandle; sal_Int32 m_nFetchDirectionPropertyHandle; private: sal_Int32 impl_getRemainedHandle() const; bool impl_queryProperty( std::u16string_view rName , css::beans::Property& rProp ) const; sal_Int32 impl_getPos( std::u16string_view rName ) const; static bool impl_isMyPropertyName( std::u16string_view rName ); public: explicit CCRS_PropertySetInfo( Reference< XPropertySetInfo > const & xPropertySetInfoOrigin ); // XInterface virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; virtual void SAL_CALL acquire() noexcept override; virtual void SAL_CALL release() noexcept override; // XTypeProvider virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override; virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; // XPropertySetInfo virtual Sequence< css::beans::Property > SAL_CALL getProperties() override; virtual css::beans::Property SAL_CALL getPropertyByName( const OUString& aName ) override; virtual sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) override; }; //some helping variables ( names for my special properties ) const char16_t g_sPropertyNameForCount[] = u"RowCount"; const char16_t g_sPropertyNameForFinalCount[] = u"IsRowCountFinal"; constexpr OUString g_sPropertyNameForFetchSize(u"FetchSize"_ustr); constexpr OUString g_sPropertyNameForFetchDirection(u"FetchDirection"_ustr); CCRS_PropertySetInfo::CCRS_PropertySetInfo( Reference< XPropertySetInfo > const & xInfo ) : m_nFetchSizePropertyHandle( -1 ) , m_nFetchDirectionPropertyHandle( -1 ) { //initialize list of properties: // it is required, that the received xInfo contains the two // properties with names 'g_sPropertyNameForCount' and // 'g_sPropertyNameForFinalCount' if( xInfo.is() ) { m_xProperties = xInfo->getProperties(); } else { OSL_FAIL( "The received XPropertySetInfo doesn't contain required properties" ); m_xProperties.emplace(); } //ensure, that we haven't got the Properties 'FetchSize' and 'Direction' twice: sal_Int32 nFetchSize = impl_getPos( g_sPropertyNameForFetchSize ); sal_Int32 nFetchDirection = impl_getPos( g_sPropertyNameForFetchDirection ); sal_Int32 nDeleted = 0; if( nFetchSize != -1 ) nDeleted++; if( nFetchDirection != -1 ) nDeleted++; Sequence< Property > aOrigProps( *m_xProperties ); sal_Int32 nOrigProps = aOrigProps.getLength(); m_xProperties->realloc( nOrigProps + 2 - nDeleted );//note that nDeleted is <= 2 auto pProperties = m_xProperties->getArray(); for( sal_Int32 n = 0, m = 0; n < nOrigProps; n++, m++ ) { if( n == nFetchSize || n == nFetchDirection ) m--; else pProperties[ m ] = aOrigProps[ n ]; } { Property& rMyProp = pProperties[ nOrigProps - nDeleted ]; rMyProp.Name = g_sPropertyNameForFetchSize; rMyProp.Type = cppu::UnoType::get(); rMyProp.Attributes = PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT; if( nFetchSize != -1 ) m_nFetchSizePropertyHandle = aOrigProps[nFetchSize].Handle; else m_nFetchSizePropertyHandle = impl_getRemainedHandle(); rMyProp.Handle = m_nFetchSizePropertyHandle; } { Property& rMyProp = pProperties[ nOrigProps - nDeleted + 1 ]; rMyProp.Name = g_sPropertyNameForFetchDirection; rMyProp.Type = cppu::UnoType::get(); rMyProp.Attributes = PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT; m_nFetchDirectionPropertyHandle = rMyProp.Handle; } } // XInterface methods. void SAL_CALL CCRS_PropertySetInfo::acquire() noexcept { OWeakObject::acquire(); } void SAL_CALL CCRS_PropertySetInfo::release() noexcept { OWeakObject::release(); } css::uno::Any SAL_CALL CCRS_PropertySetInfo::queryInterface( const css::uno::Type & rType ) { css::uno::Any aRet = cppu::queryInterface( rType, static_cast< XTypeProvider* >(this), static_cast< XPropertySetInfo* >(this) ); return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); } // XTypeProvider methods. //list all interfaces exclusive baseclasses XTYPEPROVIDER_IMPL_2( CCRS_PropertySetInfo , XTypeProvider , XPropertySetInfo ); // XPropertySetInfo methods. //virtual Sequence< Property > SAL_CALL CCRS_PropertySetInfo ::getProperties() { return *m_xProperties; } //virtual Property SAL_CALL CCRS_PropertySetInfo ::getPropertyByName( const OUString& aName ) { Property aProp; if ( impl_queryProperty( aName, aProp ) ) return aProp; throw UnknownPropertyException(aName); } //virtual sal_Bool SAL_CALL CCRS_PropertySetInfo ::hasPropertyByName( const OUString& Name ) { return ( impl_getPos( Name ) != -1 ); } // impl_ methods. sal_Int32 CCRS_PropertySetInfo ::impl_getPos( std::u16string_view rName ) const { for( sal_Int32 nN = m_xProperties->getLength(); nN--; ) { const Property& rMyProp = (*m_xProperties)[nN]; if( rMyProp.Name == rName ) return nN; } return -1; } bool CCRS_PropertySetInfo ::impl_queryProperty( std::u16string_view rName, Property& rProp ) const { for (const Property& rMyProp : *m_xProperties) { if( rMyProp.Name == rName ) { rProp.Name = rMyProp.Name; rProp.Handle = rMyProp.Handle; rProp.Type = rMyProp.Type; rProp.Attributes = rMyProp.Attributes; return true; } } return false; } //static bool CCRS_PropertySetInfo ::impl_isMyPropertyName( std::u16string_view rPropertyName ) { return ( rPropertyName == g_sPropertyNameForCount || rPropertyName == g_sPropertyNameForFinalCount || rPropertyName == g_sPropertyNameForFetchSize || rPropertyName == g_sPropertyNameForFetchDirection ); } sal_Int32 CCRS_PropertySetInfo ::impl_getRemainedHandle( ) const { sal_Int32 nHandle = 1; if( !m_xProperties ) { OSL_FAIL( "Properties not initialized yet" ); return nHandle; } bool bFound = true; while( bFound ) { bFound = false; for (const auto& rProp : *m_xProperties) { if( nHandle == rProp.Handle ) { bFound = true; nHandle++; break; } } } return nHandle; } CachedContentResultSet::CachedContentResultSet( const Reference< XComponentContext > & rxContext , const Reference< XResultSet > & xOrigin , const Reference< XContentIdentifierMapping > & xContentIdentifierMapping ) : ContentResultSetWrapper( xOrigin ) , m_xContext( rxContext ) , m_xContentIdentifierMapping( xContentIdentifierMapping ) , m_nRow( 0 ) // Position is one-based. Zero means: before first element. , m_bAfterLast( false ) , m_nLastAppliedPos( 0 ) , m_bAfterLastApplied( false ) , m_nKnownCount( 0 ) , m_bFinalCount( false ) , m_nFetchSize( COMSUNSTARUCBCCRS_DEFAULT_FETCH_SIZE ) , m_nFetchDirection( COMSUNSTARUCBCCRS_DEFAULT_FETCH_DIRECTION ) , m_bLastReadWasFromCache( false ) , m_bLastCachedReadWasNull( true ) , m_aCache( m_xContentIdentifierMapping ) , m_aCacheContentIdentifierString( m_xContentIdentifierMapping ) , m_aCacheContentIdentifier( m_xContentIdentifierMapping ) , m_aCacheContent( m_xContentIdentifierMapping ) , m_bTriedToGetTypeConverter( false ) { m_xFetchProvider.set( m_xResultSetOrigin, UNO_QUERY ); OSL_ENSURE( m_xFetchProvider.is(), "interface XFetchProvider is required" ); m_xFetchProviderForContentAccess.set( m_xResultSetOrigin, UNO_QUERY ); OSL_ENSURE( m_xFetchProviderForContentAccess.is(), "interface XFetchProviderForContentAccess is required" ); impl_init(); }; CachedContentResultSet::~CachedContentResultSet() { impl_deinit(); //do not delete m_pMyPropSetInfo, cause it is hold via reference }; // impl_ methods. bool CachedContentResultSet ::applyPositionToOrigin( std::unique_lock& rGuard, sal_Int32 nRow ) { impl_EnsureNotDisposed(rGuard); /** @returns if the cursor is on a valid row; if it is off the result set. */ OSL_ENSURE( nRow >= 0, "only positive values supported" ); if( !m_xResultSetOrigin.is() ) { OSL_FAIL( "broadcaster was disposed already" ); return false; } // OSL_ENSURE( nRow <= m_nKnownCount, "don't step into regions you don't know with this method" ); sal_Int32 nLastAppliedPos = m_nLastAppliedPos; bool bAfterLastApplied = m_bAfterLastApplied; bool bAfterLast = m_bAfterLast; sal_Int32 nForwardOnly = m_nForwardOnly; rGuard.unlock(); if( bAfterLastApplied || nLastAppliedPos != nRow ) { if( nForwardOnly == 1 ) { if( bAfterLastApplied || bAfterLast || !nRow || nRow < nLastAppliedPos ) throw SQLException(); sal_Int32 nN = nRow - nLastAppliedPos; sal_Int32 nM; for( nM = 0; nN--; nM++ ) { if( !m_xResultSetOrigin->next() ) break; } rGuard.lock(); m_nLastAppliedPos += nM; m_bAfterLastApplied = nRow != m_nLastAppliedPos; return nRow == m_nLastAppliedPos; } if( !nRow ) //absolute( 0 ) will throw exception { m_xResultSetOrigin->beforeFirst(); rGuard.lock(); m_nLastAppliedPos = 0; m_bAfterLastApplied = false; return false; } try { //move absolute, if !nLastAppliedPos //because move relative would throw exception if( !nLastAppliedPos || bAfterLast || bAfterLastApplied ) { bool bValid = m_xResultSetOrigin->absolute( nRow ); rGuard.lock(); m_nLastAppliedPos = nRow; m_bAfterLastApplied = !bValid; return bValid; } else { bool bValid = m_xResultSetOrigin->relative( nRow - nLastAppliedPos ); rGuard.lock(); m_nLastAppliedPos += ( nRow - nLastAppliedPos ); m_bAfterLastApplied = !bValid; return bValid; } } catch (const SQLException&) { rGuard.lock(); if( !bAfterLastApplied && !bAfterLast && nRow > nLastAppliedPos && impl_isForwardOnly(rGuard) ) { sal_Int32 nN = nRow - nLastAppliedPos; sal_Int32 nM; for( nM = 0; nN--; nM++ ) { if( !m_xResultSetOrigin->next() ) break; } m_nLastAppliedPos += nM; m_bAfterLastApplied = nRow != m_nLastAppliedPos; } else throw; } return nRow == m_nLastAppliedPos; } return true; }; //define for fetching data #define FETCH_XXX( aCache, fetchInterface, fetchMethod ) \ bool bDirection = !!( \ nFetchDirection != FetchDirection::REVERSE ); \ FetchResult aResult = \ fetchInterface->fetchMethod( nRow, nFetchSize, bDirection ); \ aCache.loadData( aResult ); \ sal_Int32 nMax = aCache.getMaxRow(); \ sal_Int32 nCurCount = m_nKnownCount; \ bool bIsFinalCount = aCache.hasKnownLast(); \ bool bCurIsFinalCount = m_bFinalCount; \ if( nMax > nCurCount ) \ impl_changeRowCount( rGuard, nCurCount, nMax ); \ if( bIsFinalCount && !bCurIsFinalCount ) \ impl_changeIsRowCountFinal( rGuard, bCurIsFinalCount, bIsFinalCount ); void CachedContentResultSet ::impl_fetchData( std::unique_lock& rGuard, sal_Int32 nRow , sal_Int32 nFetchSize, sal_Int32 nFetchDirection ) { FETCH_XXX( m_aCache, m_xFetchProvider, fetch ); } void CachedContentResultSet ::impl_changeRowCount( std::unique_lock& rGuard, sal_Int32 nOld, sal_Int32 nNew ) { OSL_ENSURE( nNew > nOld, "RowCount only can grow" ); if( nNew <= nOld ) return; //create PropertyChangeEvent and set value PropertyChangeEvent aEvt; aEvt.Source = static_cast< XPropertySet * >( this ); aEvt.Further = false; aEvt.OldValue <<= nOld; aEvt.NewValue <<= nNew; m_nKnownCount = nNew; //send PropertyChangeEvent to listeners impl_notifyPropertyChangeListeners( rGuard, aEvt ); } void CachedContentResultSet ::impl_changeIsRowCountFinal( std::unique_lock& rGuard, bool bOld, bool bNew ) { OSL_ENSURE( !bOld && bNew, "This change is not allowed for IsRowCountFinal" ); if( bOld || !bNew ) return; //create PropertyChangeEvent and set value PropertyChangeEvent aEvt; aEvt.Source = static_cast< XPropertySet * >( this ); aEvt.Further = false; aEvt.OldValue <<= bOld; aEvt.NewValue <<= bNew; m_bFinalCount = bNew; //send PropertyChangeEvent to listeners impl_notifyPropertyChangeListeners( rGuard, aEvt ); } bool CachedContentResultSet ::impl_isKnownValidPosition( std::unique_lock& /*rGuard*/, sal_Int32 nRow ) const { return m_nKnownCount && nRow && nRow <= m_nKnownCount; } bool CachedContentResultSet ::impl_isKnownInvalidPosition( std::unique_lock& /*rGuard*/, sal_Int32 nRow ) const { if( !nRow ) return true; if( !m_bFinalCount ) return false; return nRow > m_nKnownCount; } //virtual void CachedContentResultSet ::impl_initPropertySetInfo(std::unique_lock& rGuard) { ContentResultSetWrapper::impl_initPropertySetInfo(rGuard); if( m_xMyPropertySetInfo.is() ) return; m_xMyPropertySetInfo = new CCRS_PropertySetInfo( m_xPropertySetInfo ); m_xPropertySetInfo = m_xMyPropertySetInfo.get(); } // XInterface methods. void SAL_CALL CachedContentResultSet::acquire() noexcept { OWeakObject::acquire(); } void SAL_CALL CachedContentResultSet::release() noexcept { OWeakObject::release(); } Any SAL_CALL CachedContentResultSet ::queryInterface( const Type& rType ) { //list all interfaces inclusive baseclasses of interfaces Any aRet = ContentResultSetWrapper::queryInterface( rType ); if( aRet.hasValue() ) return aRet; aRet = cppu::queryInterface( rType, static_cast< XTypeProvider* >( this ), static_cast< XServiceInfo* >( this ) ); return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); } // XTypeProvider methods. //list all interfaces exclusive baseclasses XTYPEPROVIDER_IMPL_11( CachedContentResultSet , XTypeProvider , XServiceInfo , XComponent , XCloseable , XResultSetMetaDataSupplier , XPropertySet , XPropertyChangeListener , XVetoableChangeListener , XContentAccess , XResultSet , XRow ); // XServiceInfo methods. OUString SAL_CALL CachedContentResultSet::getImplementationName() { return u"com.sun.star.comp.ucb.CachedContentResultSet"_ustr; } sal_Bool SAL_CALL CachedContentResultSet::supportsService( const OUString& ServiceName ) { return cppu::supportsService( this, ServiceName ); } css::uno::Sequence< OUString > SAL_CALL CachedContentResultSet::getSupportedServiceNames() { return { u"com.sun.star.ucb.CachedContentResultSet"_ustr }; } // XPropertySet methods. ( inherited ) // virtual void CachedContentResultSet ::setPropertyValueImpl( std::unique_lock& rGuard, const OUString& aPropertyName, const Any& aValue ) { impl_EnsureNotDisposed(rGuard); if( !getPropertySetInfoImpl(rGuard).is() ) { OSL_FAIL( "broadcaster was disposed already" ); throw UnknownPropertyException(); } Property aProp = m_xMyPropertySetInfo->getPropertyByName( aPropertyName ); //throws UnknownPropertyException, if so if( aProp.Attributes & PropertyAttribute::READONLY ) { //It is assumed, that the properties //'RowCount' and 'IsRowCountFinal' are readonly! throw IllegalArgumentException(); } if( aProp.Name == g_sPropertyNameForFetchDirection ) { //check value sal_Int32 nNew; if( !( aValue >>= nNew ) ) { throw IllegalArgumentException(); } if( nNew == FetchDirection::UNKNOWN ) { nNew = COMSUNSTARUCBCCRS_DEFAULT_FETCH_DIRECTION; } else if( nNew != FetchDirection::FORWARD && nNew != FetchDirection::REVERSE ) { throw IllegalArgumentException(); } //create PropertyChangeEvent and set value PropertyChangeEvent aEvt; aEvt.Source = static_cast< XPropertySet * >( this ); aEvt.PropertyName = aPropertyName; aEvt.Further = false; aEvt.PropertyHandle = m_xMyPropertySetInfo-> m_nFetchDirectionPropertyHandle; aEvt.OldValue <<= m_nFetchDirection; aEvt.NewValue <<= nNew; m_nFetchDirection = nNew; //send PropertyChangeEvent to listeners impl_notifyPropertyChangeListeners( rGuard, aEvt ); } else if( aProp.Name == g_sPropertyNameForFetchSize ) { //check value sal_Int32 nNew; if( !( aValue >>= nNew ) ) { throw IllegalArgumentException(); } if( nNew < 0 ) { nNew = COMSUNSTARUCBCCRS_DEFAULT_FETCH_SIZE; } //create PropertyChangeEvent and set value PropertyChangeEvent aEvt; aEvt.Source = static_cast< XPropertySet * >( this ); aEvt.PropertyName = aPropertyName; aEvt.Further = false; aEvt.PropertyHandle = m_xMyPropertySetInfo-> m_nFetchSizePropertyHandle; aEvt.OldValue <<= m_nFetchSize; aEvt.NewValue <<= nNew; m_nFetchSize = nNew; //send PropertyChangeEvent to listeners impl_notifyPropertyChangeListeners( rGuard, aEvt ); } else { impl_init_xPropertySetOrigin(rGuard); if( !m_xPropertySetOrigin.is() ) { OSL_FAIL( "broadcaster was disposed already" ); return; } m_xPropertySetOrigin->setPropertyValue( aPropertyName, aValue ); } } // virtual Any SAL_CALL CachedContentResultSet ::getPropertyValue( const OUString& rPropertyName ) { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); if( !getPropertySetInfoImpl(aGuard).is() ) { OSL_FAIL( "broadcaster was disposed already" ); throw UnknownPropertyException(); } m_xMyPropertySetInfo->getPropertyByName( rPropertyName ); //throws UnknownPropertyException, if so Any aValue; if( rPropertyName == g_sPropertyNameForCount ) { aValue <<= m_nKnownCount; } else if( rPropertyName == g_sPropertyNameForFinalCount ) { aValue <<= m_bFinalCount; } else if( rPropertyName == g_sPropertyNameForFetchSize ) { aValue <<= m_nFetchSize; } else if( rPropertyName == g_sPropertyNameForFetchDirection ) { aValue <<= m_nFetchDirection; } else { impl_init_xPropertySetOrigin(aGuard); if( !m_xPropertySetOrigin.is() ) { OSL_FAIL( "broadcaster was disposed already" ); throw UnknownPropertyException(); } aGuard.unlock(); aValue = m_xPropertySetOrigin->getPropertyValue( rPropertyName ); } return aValue; } // own methods. ( inherited ) //virtual, only called from ContentResultSetWrapperListener void CachedContentResultSet ::impl_disposing( const EventObject& rEventObject ) { { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); //release all references to the broadcaster: m_xFetchProvider.clear(); m_xFetchProviderForContentAccess.clear(); } ContentResultSetWrapper::impl_disposing( rEventObject ); } //virtual, only called from ContentResultSetWrapperListener void CachedContentResultSet ::impl_propertyChange( const PropertyChangeEvent& rEvt ) { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); PropertyChangeEvent aEvt( rEvt ); aEvt.Source = static_cast< XPropertySet * >( this ); aEvt.Further = false; if( CCRS_PropertySetInfo ::impl_isMyPropertyName( rEvt.PropertyName ) ) { //don't notify foreign events on fetchsize and fetchdirection if( aEvt.PropertyName == g_sPropertyNameForFetchSize || aEvt.PropertyName == g_sPropertyNameForFetchDirection ) return; //adjust my props 'RowCount' and 'IsRowCountFinal' if( aEvt.PropertyName == g_sPropertyNameForCount ) {//RowCount changed //check value sal_Int32 nNew = 0; if( !( aEvt.NewValue >>= nNew ) ) { OSL_FAIL( "PropertyChangeEvent contains wrong data" ); return; } impl_changeRowCount( aGuard, m_nKnownCount, nNew ); } else if( aEvt.PropertyName == g_sPropertyNameForFinalCount ) {//IsRowCountFinal changed //check value bool bNew = false; if( !( aEvt.NewValue >>= bNew ) ) { OSL_FAIL( "PropertyChangeEvent contains wrong data" ); return; } impl_changeIsRowCountFinal( aGuard, m_bFinalCount, bNew ); } return; } impl_notifyPropertyChangeListeners( aGuard, aEvt ); } //virtual, only called from ContentResultSetWrapperListener void CachedContentResultSet ::impl_vetoableChange( const PropertyChangeEvent& rEvt ) { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); //don't notify events on my properties, cause they are not vetoable if( CCRS_PropertySetInfo ::impl_isMyPropertyName( rEvt.PropertyName ) ) { return; } PropertyChangeEvent aEvt( rEvt ); aEvt.Source = static_cast< XPropertySet * >( this ); aEvt.Further = false; impl_notifyVetoableChangeListeners( aGuard, aEvt ); } // XContentAccess methods. ( inherited ) ( -- position dependent ) #define XCONTENTACCESS_queryXXX( queryXXX, XXX, TYPE ) \ impl_EnsureNotDisposed(rGuard); \ sal_Int32 nRow = m_nRow; \ sal_Int32 nFetchSize = m_nFetchSize; \ sal_Int32 nFetchDirection = m_nFetchDirection; \ if( !m_aCache##XXX.hasRow( nRow ) ) \ { \ try \ { \ if( !m_aCache##XXX.hasCausedException( nRow ) ) \ { \ if( !m_xFetchProviderForContentAccess.is() ) \ { \ OSL_FAIL( "broadcaster was disposed already" ); \ throw RuntimeException(); \ } \ if( impl_isForwardOnly(rGuard) ) \ applyPositionToOrigin( rGuard, nRow ); \ \ FETCH_XXX( m_aCache##XXX, m_xFetchProviderForContentAccess, fetch##XXX##s ); \ } \ if( !m_aCache##XXX.hasRow( nRow ) ) \ { \ applyPositionToOrigin( rGuard, nRow ); \ TYPE aRet = ContentResultSetWrapper::query##XXX();\ if( m_xContentIdentifierMapping.is() ) \ return m_xContentIdentifierMapping->map##XXX( aRet );\ return aRet; \ } \ } \ catch (const RuntimeException&) \ { \ throw; \ } \ catch (const Exception& e) \ { \ Any a(cppu::getCaughtException()); \ throw WrappedTargetRuntimeException( \ "wrapped Exception " + e.Message, \ Reference(), a); \ } \ } \ return m_aCache##XXX.get##XXX( nRow ); // virtual OUString CachedContentResultSet ::queryContentIdentifierStringImpl(std::unique_lock& rGuard) { XCONTENTACCESS_queryXXX( queryContentIdentifierString, ContentIdentifierString, OUString ) } // virtual Reference CachedContentResultSet ::queryContentIdentifierImpl(std::unique_lock& rGuard) { XCONTENTACCESS_queryXXX( queryContentIdentifier, ContentIdentifier, Reference< XContentIdentifier > ) } // virtual Reference CachedContentResultSet ::queryContentImpl(std::unique_lock& rGuard) { XCONTENTACCESS_queryXXX( queryContent, Content, Reference< XContent > ) } // XResultSet methods. ( inherited ) //virtual sal_Bool SAL_CALL CachedContentResultSet ::next() { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); //after last if( m_bAfterLast ) return false; //last aGuard.unlock(); if( isLast() ) { aGuard.lock(); m_nRow++; m_bAfterLast = true; return false; } aGuard.lock(); //known valid position if( impl_isKnownValidPosition( aGuard, m_nRow + 1 ) ) { m_nRow++; return true; } //unknown position sal_Int32 nRow = m_nRow; bool bValid = applyPositionToOrigin( aGuard, nRow + 1 ); m_nRow = nRow + 1; m_bAfterLast = !bValid; return bValid; } //virtual sal_Bool SAL_CALL CachedContentResultSet ::previous() { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); if( impl_isForwardOnly(aGuard) ) throw SQLException(); //before first ?: if( !m_bAfterLast && !m_nRow ) return false; //first ?: if( !m_bAfterLast && m_nKnownCount && m_nRow == 1 ) { m_nRow--; m_bAfterLast = false; return false; } //known valid position ?: if( impl_isKnownValidPosition( aGuard, m_nRow - 1 ) ) { m_nRow--; m_bAfterLast = false; return true; } //unknown position: sal_Int32 nRow = m_nRow; bool bValid = applyPositionToOrigin( aGuard, nRow - 1 ); m_nRow = nRow - 1; m_bAfterLast = false; return bValid; } //virtual sal_Bool SAL_CALL CachedContentResultSet ::absolute( sal_Int32 row ) { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); if( !row ) throw SQLException(); if( impl_isForwardOnly(aGuard) ) throw SQLException(); if( !m_xResultSetOrigin.is() ) { OSL_FAIL( "broadcaster was disposed already" ); return false; } if( row < 0 ) { if( m_bFinalCount ) { sal_Int32 nNewRow = m_nKnownCount + 1 + row; bool bValid = true; if( nNewRow <= 0 ) { nNewRow = 0; bValid = false; } m_nRow = nNewRow; m_bAfterLast = false; return bValid; } //unknown final count: aGuard.unlock(); bool bValid = m_xResultSetOrigin->absolute( row ); aGuard.lock(); if( m_bFinalCount ) { sal_Int32 nNewRow = m_nKnownCount + 1 + row; if( nNewRow < 0 ) nNewRow = 0; m_nLastAppliedPos = nNewRow; m_nRow = nNewRow; m_bAfterLastApplied = m_bAfterLast = false; return bValid; } aGuard.unlock(); sal_Int32 nCurRow = m_xResultSetOrigin->getRow(); aGuard.lock(); m_nLastAppliedPos = nCurRow; m_nRow = nCurRow; m_bAfterLast = false; return nCurRow != 0; } //row > 0: if( m_bFinalCount ) { if( row > m_nKnownCount ) { m_nRow = m_nKnownCount + 1; m_bAfterLast = true; return false; } m_nRow = row; m_bAfterLast = false; return true; } //unknown new position: aGuard.unlock(); bool bValid = m_xResultSetOrigin->absolute( row ); aGuard.lock(); if( m_bFinalCount ) { sal_Int32 nNewRow = row; if( nNewRow > m_nKnownCount ) { nNewRow = m_nKnownCount + 1; m_bAfterLastApplied = m_bAfterLast = true; } else m_bAfterLastApplied = m_bAfterLast = false; m_nLastAppliedPos = nNewRow; m_nRow = nNewRow; return bValid; } aGuard.unlock(); sal_Int32 nCurRow = m_xResultSetOrigin->getRow(); bool bIsAfterLast = m_xResultSetOrigin->isAfterLast(); aGuard.lock(); m_nLastAppliedPos = nCurRow; m_nRow = nCurRow; m_bAfterLastApplied = m_bAfterLast = bIsAfterLast; return nCurRow && !bIsAfterLast; } //virtual sal_Bool SAL_CALL CachedContentResultSet ::relative( sal_Int32 rows ) { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); if( impl_isForwardOnly(aGuard) ) throw SQLException(); if( m_bAfterLast || impl_isKnownInvalidPosition( aGuard, m_nRow ) ) throw SQLException(); if( !rows ) return true; sal_Int32 nNewRow = m_nRow + rows; if( nNewRow < 0 ) nNewRow = 0; if( impl_isKnownValidPosition( aGuard, nNewRow ) ) { m_nRow = nNewRow; m_bAfterLast = false; return true; } else { //known invalid new position: if( nNewRow == 0 ) { m_bAfterLast = false; m_nRow = 0; return false; } if( m_bFinalCount && nNewRow > m_nKnownCount ) { m_bAfterLast = true; m_nRow = m_nKnownCount + 1; return false; } //unknown new position: bool bValid = applyPositionToOrigin( aGuard, nNewRow ); m_nRow = nNewRow; m_bAfterLast = !bValid; // only nNewRow > 0 possible here return bValid; } } //virtual sal_Bool SAL_CALL CachedContentResultSet ::first() { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); if( impl_isForwardOnly(aGuard) ) throw SQLException(); if( impl_isKnownValidPosition( aGuard, 1 ) ) { m_nRow = 1; m_bAfterLast = false; return true; } if( impl_isKnownInvalidPosition( aGuard, 1 ) ) { m_nRow = 1; m_bAfterLast = false; return false; } //unknown position bool bValid = applyPositionToOrigin( aGuard, 1 ); m_nRow = 1; m_bAfterLast = false; return bValid; } //virtual sal_Bool SAL_CALL CachedContentResultSet ::last() { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); if( impl_isForwardOnly(aGuard) ) throw SQLException(); if( m_bFinalCount ) { m_nRow = m_nKnownCount; m_bAfterLast = false; return m_nKnownCount != 0; } //unknown position if( !m_xResultSetOrigin.is() ) { OSL_FAIL( "broadcaster was disposed already" ); return false; } aGuard.unlock(); bool bValid = m_xResultSetOrigin->last(); aGuard.lock(); m_bAfterLastApplied = m_bAfterLast = false; if( m_bFinalCount ) { m_nLastAppliedPos = m_nKnownCount; m_nRow = m_nKnownCount; return bValid; } aGuard.unlock(); sal_Int32 nCurRow = m_xResultSetOrigin->getRow(); aGuard.lock(); m_nLastAppliedPos = nCurRow; m_nRow = nCurRow; OSL_ENSURE( nCurRow >= m_nKnownCount, "position of last row < known Count, that could not be" ); m_nKnownCount = nCurRow; m_bFinalCount = true; return nCurRow != 0; } //virtual void SAL_CALL CachedContentResultSet ::beforeFirst() { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); if( impl_isForwardOnly(aGuard) ) throw SQLException(); m_nRow = 0; m_bAfterLast = false; } //virtual void SAL_CALL CachedContentResultSet ::afterLast() { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); if( impl_isForwardOnly(aGuard) ) throw SQLException(); m_nRow = 1; m_bAfterLast = true; } //virtual sal_Bool SAL_CALL CachedContentResultSet ::isAfterLast() { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); if( !m_bAfterLast ) return false; if( m_nKnownCount ) return m_bAfterLast; if( m_bFinalCount ) return false; if( !m_xResultSetOrigin.is() ) { OSL_FAIL( "broadcaster was disposed already" ); return false; } aGuard.unlock(); //find out whether the original resultset contains rows or not m_xResultSetOrigin->afterLast(); aGuard.lock(); m_bAfterLastApplied = true; aGuard.unlock(); return m_xResultSetOrigin->isAfterLast(); } //virtual sal_Bool SAL_CALL CachedContentResultSet ::isBeforeFirst() { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); if( m_bAfterLast ) return false; if( m_nRow ) return false; if( m_nKnownCount ) return true; if( m_bFinalCount ) return false; if( !m_xResultSetOrigin.is() ) { OSL_FAIL( "broadcaster was disposed already" ); return false; } aGuard.unlock(); //find out whether the original resultset contains rows or not m_xResultSetOrigin->beforeFirst(); aGuard.lock(); m_bAfterLastApplied = false; m_nLastAppliedPos = 0; aGuard.unlock(); return m_xResultSetOrigin->isBeforeFirst(); } //virtual sal_Bool SAL_CALL CachedContentResultSet ::isFirst() { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); sal_Int32 nRow = 0; Reference< XResultSet > xResultSetOrigin; if( m_bAfterLast ) return false; if( m_nRow != 1 ) return false; if( m_nKnownCount ) return true; if( m_bFinalCount ) return false; nRow = m_nRow; xResultSetOrigin = m_xResultSetOrigin; //need to ask origin if( !applyPositionToOrigin( aGuard, nRow ) ) return false; aGuard.unlock(); return xResultSetOrigin->isFirst(); } //virtual sal_Bool SAL_CALL CachedContentResultSet ::isLast() { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); sal_Int32 nRow = 0; Reference< XResultSet > xResultSetOrigin; if( m_bAfterLast ) return false; if( m_nRow < m_nKnownCount ) return false; if( m_bFinalCount ) return m_nKnownCount && m_nRow == m_nKnownCount; nRow = m_nRow; xResultSetOrigin = m_xResultSetOrigin; //need to ask origin if( !applyPositionToOrigin( aGuard, nRow ) ) return false; aGuard.unlock(); return xResultSetOrigin->isLast(); } //virtual sal_Int32 SAL_CALL CachedContentResultSet ::getRow() { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); if( m_bAfterLast ) return 0; return m_nRow; } //virtual void SAL_CALL CachedContentResultSet ::refreshRow() { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); //the ContentResultSet is static and will not change //therefore we don't need to reload anything } //virtual sal_Bool SAL_CALL CachedContentResultSet ::rowUpdated() { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); //the ContentResultSet is static and will not change return false; } //virtual sal_Bool SAL_CALL CachedContentResultSet ::rowInserted() { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); //the ContentResultSet is static and will not change return false; } //virtual sal_Bool SAL_CALL CachedContentResultSet ::rowDeleted() { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); //the ContentResultSet is static and will not change return false; } //virtual Reference< XInterface > SAL_CALL CachedContentResultSet ::getStatement() { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); //@todo ?return anything return Reference< XInterface >(); } // XRow methods. ( inherited ) //virtual sal_Bool SAL_CALL CachedContentResultSet ::wasNull() { std::unique_lock aGuard(m_aMutex); impl_EnsureNotDisposed(aGuard); impl_init_xRowOrigin(aGuard); if( m_bLastReadWasFromCache ) return m_bLastCachedReadWasNull; if( !m_xRowOrigin.is() ) { OSL_FAIL( "broadcaster was disposed already" ); return false; } aGuard.unlock(); return m_xRowOrigin->wasNull(); } //virtual OUString SAL_CALL CachedContentResultSet ::getString( sal_Int32 columnIndex ) { return rowOriginGet(&css::sdbc::XRow::getString, columnIndex); } //virtual sal_Bool SAL_CALL CachedContentResultSet ::getBoolean( sal_Int32 columnIndex ) { return rowOriginGet(&css::sdbc::XRow::getBoolean, columnIndex); } //virtual sal_Int8 SAL_CALL CachedContentResultSet ::getByte( sal_Int32 columnIndex ) { return rowOriginGet(&css::sdbc::XRow::getByte, columnIndex); } //virtual sal_Int16 SAL_CALL CachedContentResultSet ::getShort( sal_Int32 columnIndex ) { return rowOriginGet(&css::sdbc::XRow::getShort, columnIndex); } //virtual sal_Int32 SAL_CALL CachedContentResultSet ::getInt( sal_Int32 columnIndex ) { return rowOriginGet(&css::sdbc::XRow::getInt, columnIndex); } //virtual sal_Int64 SAL_CALL CachedContentResultSet ::getLong( sal_Int32 columnIndex ) { return rowOriginGet(&css::sdbc::XRow::getLong, columnIndex); } //virtual float SAL_CALL CachedContentResultSet ::getFloat( sal_Int32 columnIndex ) { return rowOriginGet(&css::sdbc::XRow::getFloat, columnIndex); } //virtual double SAL_CALL CachedContentResultSet ::getDouble( sal_Int32 columnIndex ) { return rowOriginGet(&css::sdbc::XRow::getDouble, columnIndex); } //virtual Sequence< sal_Int8 > SAL_CALL CachedContentResultSet ::getBytes( sal_Int32 columnIndex ) { return rowOriginGet< css::uno::Sequence >( &css::sdbc::XRow::getBytes, columnIndex); } //virtual Date SAL_CALL CachedContentResultSet ::getDate( sal_Int32 columnIndex ) { return rowOriginGet( &css::sdbc::XRow::getDate, columnIndex); } //virtual Time SAL_CALL CachedContentResultSet ::getTime( sal_Int32 columnIndex ) { return rowOriginGet( &css::sdbc::XRow::getTime, columnIndex); } //virtual DateTime SAL_CALL CachedContentResultSet ::getTimestamp( sal_Int32 columnIndex ) { return rowOriginGet( &css::sdbc::XRow::getTimestamp, columnIndex); } //virtual Reference< css::io::XInputStream > SAL_CALL CachedContentResultSet ::getBinaryStream( sal_Int32 columnIndex ) { return rowOriginGet< css::uno::Reference >( &css::sdbc::XRow::getBinaryStream, columnIndex); } //virtual Reference< css::io::XInputStream > SAL_CALL CachedContentResultSet ::getCharacterStream( sal_Int32 columnIndex ) { return rowOriginGet< css::uno::Reference >( &css::sdbc::XRow::getCharacterStream, columnIndex); } //virtual Any SAL_CALL CachedContentResultSet ::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& typeMap ) { //if you change this function please pay attention to //function template rowOriginGet, where this is similar implemented std::unique_lock aGuard(m_aMutex); sal_Int32 nRow = m_nRow; sal_Int32 nFetchSize = m_nFetchSize; sal_Int32 nFetchDirection = m_nFetchDirection; if( !m_aCache.hasRow( nRow ) ) { if( !m_aCache.hasCausedException( nRow ) ) { if( !m_xFetchProvider.is() ) { OSL_FAIL( "broadcaster was disposed already" ); return Any(); } impl_fetchData( aGuard, nRow, nFetchSize, nFetchDirection ); } if( !m_aCache.hasRow( nRow ) ) { m_bLastReadWasFromCache = false; applyPositionToOrigin( aGuard, nRow ); impl_init_xRowOrigin(aGuard); aGuard.unlock(); return m_xRowOrigin->getObject( columnIndex, typeMap ); } } //@todo: pay attention to typeMap const Any& rValue = m_aCache.getAny( nRow, columnIndex ); m_bLastReadWasFromCache = true; m_bLastCachedReadWasNull = !rValue.hasValue(); return rValue; } //virtual Reference< XRef > SAL_CALL CachedContentResultSet ::getRef( sal_Int32 columnIndex ) { return rowOriginGet< css::uno::Reference >( &css::sdbc::XRow::getRef, columnIndex); } //virtual Reference< XBlob > SAL_CALL CachedContentResultSet ::getBlob( sal_Int32 columnIndex ) { return rowOriginGet< css::uno::Reference >( &css::sdbc::XRow::getBlob, columnIndex); } //virtual Reference< XClob > SAL_CALL CachedContentResultSet ::getClob( sal_Int32 columnIndex ) { return rowOriginGet< css::uno::Reference >( &css::sdbc::XRow::getClob, columnIndex); } //virtual Reference< XArray > SAL_CALL CachedContentResultSet ::getArray( sal_Int32 columnIndex ) { return rowOriginGet< css::uno::Reference >( &css::sdbc::XRow::getArray, columnIndex); } // Type Converter Support const Reference< XTypeConverter >& CachedContentResultSet::getTypeConverter(std::unique_lock& ) { if ( !m_bTriedToGetTypeConverter && !m_xTypeConverter.is() ) { m_bTriedToGetTypeConverter = true; m_xTypeConverter.set( Converter::create(m_xContext) ); OSL_ENSURE( m_xTypeConverter.is(), "PropertyValueSet::getTypeConverter() - " "Service 'com.sun.star.script.Converter' n/a!" ); } return m_xTypeConverter; } CachedContentResultSetFactory::CachedContentResultSetFactory( const Reference< XComponentContext > & rxContext ) { m_xContext = rxContext; } CachedContentResultSetFactory::~CachedContentResultSetFactory() { } // CachedContentResultSetFactory XServiceInfo methods. OUString SAL_CALL CachedContentResultSetFactory::getImplementationName() { return u"com.sun.star.comp.ucb.CachedContentResultSetFactory"_ustr; } sal_Bool SAL_CALL CachedContentResultSetFactory::supportsService( const OUString& ServiceName ) { return cppu::supportsService( this, ServiceName ); } css::uno::Sequence< OUString > SAL_CALL CachedContentResultSetFactory::getSupportedServiceNames() { return { u"com.sun.star.ucb.CachedContentResultSetFactory"_ustr }; } // Service factory implementation. extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* ucb_CachedContentResultSetFactory_get_implementation( css::uno::XComponentContext* context , css::uno::Sequence const&) { return cppu::acquire(new CachedContentResultSetFactory(context)); } // CachedContentResultSetFactory XCachedContentResultSetFactory methods. //virtual Reference< XResultSet > SAL_CALL CachedContentResultSetFactory ::createCachedContentResultSet( const Reference< XResultSet > & xSource, const Reference< XContentIdentifierMapping > & xMapping ) { Reference< XResultSet > xRet = new CachedContentResultSet( m_xContext, xSource, xMapping ); return xRet; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */