blob: e54d00f2d7fb63cdf0512f18fc3067f0eec429b6 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_ucb.hxx"
#include <cachedcontentresultset.hxx>
#include <com/sun/star/sdbc/FetchDirection.hpp>
#include <com/sun/star/ucb/FetchError.hpp>
#include <com/sun/star/ucb/ResultSetException.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/script/XTypeConverter.hpp>
#include <com/sun/star/sdbc/ResultSetType.hpp>
#include <rtl/ustring.hxx>
#include <osl/diagnose.h>
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;
using namespace rtl;
#define COMSUNSTARUCBCCRS_DEFAULT_FETCH_SIZE 256
#define COMSUNSTARUCBCCRS_DEFAULT_FETCH_DIRECTION FetchDirection::FORWARD
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
//define for getXXX methods of interface XRow
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
//if you change this macro please pay attention to
//function ::getObject, where this is similar implemented
#define XROW_GETXXX( getXXX, Type ) \
impl_EnsureNotDisposed(); \
ReacquireableGuard 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_ENSURE( sal_False, "broadcaster was disposed already" ); \
throw SQLException(); \
} \
aGuard.clear(); \
if( impl_isForwardOnly() ) \
applyPositionToOrigin( nRow ); \
\
impl_fetchData( nRow, nFetchSize, nFetchDirection ); \
} \
aGuard.reacquire(); \
if( !m_aCache.hasRow( nRow ) ) \
{ \
m_bLastReadWasFromCache = sal_False; \
aGuard.clear(); \
applyPositionToOrigin( nRow ); \
impl_init_xRowOrigin(); \
return m_xRowOrigin->getXXX( columnIndex ); \
} \
} \
const Any& rValue = m_aCache.getAny( nRow, columnIndex );\
Type aRet = Type(); \
m_bLastReadWasFromCache = sal_True; \
m_bLastCachedReadWasNull = !( rValue >>= aRet ); \
/* Last chance. Try type converter service... */ \
if ( m_bLastCachedReadWasNull && rValue.hasValue() ) \
{ \
Reference< XTypeConverter > xConverter \
= getTypeConverter(); \
if ( xConverter.is() ) \
{ \
try \
{ \
Any aConvAny = xConverter->convertTo( \
rValue, \
getCppuType( static_cast< \
const Type * >( 0 ) ) ); \
m_bLastCachedReadWasNull = !( aConvAny >>= aRet ); \
} \
catch ( IllegalArgumentException ) \
{ \
} \
catch ( CannotConvertException ) \
{ \
} \
} \
} \
return aRet;
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// CCRS_Cache methoeds.
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
CachedContentResultSet::CCRS_Cache::CCRS_Cache(
const Reference< XContentIdentifierMapping > & xMapping )
: m_pResult( NULL )
, m_xContentIdentifierMapping( xMapping )
, m_pMappedReminder( NULL )
{
}
CachedContentResultSet::CCRS_Cache::~CCRS_Cache()
{
delete m_pResult;
}
void SAL_CALL CachedContentResultSet::CCRS_Cache
::clear()
{
if( m_pResult )
{
delete m_pResult;
m_pResult = NULL;
}
clearMappedReminder();
}
void SAL_CALL CachedContentResultSet::CCRS_Cache
::loadData( const FetchResult& rResult )
{
clear();
m_pResult = new FetchResult( rResult );
}
sal_Bool SAL_CALL CachedContentResultSet::CCRS_Cache
::hasRow( sal_Int32 row )
{
if( !m_pResult )
return sal_False;
long nStart = m_pResult->StartIndex;
long 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 SAL_CALL CachedContentResultSet::CCRS_Cache
::getMaxRow()
{
if( !m_pResult )
return 0;
long nEnd = m_pResult->StartIndex;
if( m_pResult->Orientation )
return nEnd += m_pResult->Rows.getLength() - 1;
else
return nEnd;
}
sal_Bool SAL_CALL CachedContentResultSet::CCRS_Cache
::hasKnownLast()
{
if( !m_pResult )
return sal_False;
if( ( m_pResult->FetchError & FetchError::ENDOFDATA )
&& m_pResult->Orientation
&& m_pResult->Rows.getLength() )
return sal_True;
return sal_False;
}
sal_Bool SAL_CALL CachedContentResultSet::CCRS_Cache
::hasCausedException( sal_Int32 nRow )
{
if( !m_pResult )
return sal_False;
if( !( m_pResult->FetchError & FetchError::EXCEPTION ) )
return sal_False;
long nEnd = m_pResult->StartIndex;
if( m_pResult->Orientation )
nEnd += m_pResult->Rows.getLength();
return nRow == nEnd+1;
}
Any& SAL_CALL CachedContentResultSet::CCRS_Cache
::getRowAny( sal_Int32 nRow )
throw( SQLException,
RuntimeException )
{
if( !nRow )
throw SQLException();
if( !m_pResult )
throw SQLException();
if( !hasRow( nRow ) )
throw SQLException();
long nDiff = nRow - m_pResult->StartIndex;
if( nDiff < 0 )
nDiff *= -1;
return (m_pResult->Rows)[nDiff];
}
void SAL_CALL CachedContentResultSet::CCRS_Cache
::remindMapped( sal_Int32 nRow )
{
//remind that this row was mapped
if( !m_pResult )
return;
long nDiff = nRow - m_pResult->StartIndex;
if( nDiff < 0 )
nDiff *= -1;
Sequence< sal_Bool >* pMappedReminder = getMappedReminder();
if( nDiff < pMappedReminder->getLength() )
(*pMappedReminder)[nDiff] = sal_True;
}
sal_Bool SAL_CALL CachedContentResultSet::CCRS_Cache
::isRowMapped( sal_Int32 nRow )
{
if( !m_pMappedReminder || !m_pResult )
return sal_False;
long nDiff = nRow - m_pResult->StartIndex;
if( nDiff < 0 )
nDiff *= -1;
if( nDiff < m_pMappedReminder->getLength() )
return (*m_pMappedReminder)[nDiff];
return sal_False;
}
void SAL_CALL CachedContentResultSet::CCRS_Cache
::clearMappedReminder()
{
delete m_pMappedReminder;
m_pMappedReminder = NULL;
}
Sequence< sal_Bool >* SAL_CALL CachedContentResultSet::CCRS_Cache
::getMappedReminder()
{
if( !m_pMappedReminder )
{
sal_Int32 nCount = m_pResult->Rows.getLength();
m_pMappedReminder = new Sequence< sal_Bool >( nCount );
for( ;nCount; nCount-- )
(*m_pMappedReminder)[nCount] = sal_False;
}
return m_pMappedReminder;
}
const Any& SAL_CALL CachedContentResultSet::CCRS_Cache
::getAny( sal_Int32 nRow, sal_Int32 nColumnIndex )
throw( SQLException,
RuntimeException )
{
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();
}
const Sequence< Any >& rRow =
(* reinterpret_cast< const Sequence< Any > * >
(getRowAny( nRow ).getValue() ));
if( nColumnIndex > rRow.getLength() )
throw SQLException();
return rRow[nColumnIndex-1];
}
const rtl::OUString& SAL_CALL CachedContentResultSet::CCRS_Cache
::getContentIdentifierString( sal_Int32 nRow )
throw( com::sun::star::uno::RuntimeException )
{
try
{
if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) )
{
Any& rRow = getRowAny( nRow );
rtl::OUString aValue;
rRow >>= aValue;
rRow <<= m_xContentIdentifierMapping->mapContentIdentifierString( aValue );
remindMapped( nRow );
}
return (* reinterpret_cast< const rtl::OUString * >
(getRowAny( nRow ).getValue() ));
}
catch( SQLException )
{
throw RuntimeException();
}
}
const Reference< XContentIdentifier >& SAL_CALL CachedContentResultSet::CCRS_Cache
::getContentIdentifier( sal_Int32 nRow )
throw( com::sun::star::uno::RuntimeException )
{
try
{
if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) )
{
Any& rRow = getRowAny( nRow );
Reference< XContentIdentifier > aValue;
rRow >>= aValue;
rRow <<= m_xContentIdentifierMapping->mapContentIdentifier( aValue );
remindMapped( nRow );
}
return (* reinterpret_cast< const Reference< XContentIdentifier > * >
(getRowAny( nRow ).getValue() ));
}
catch( SQLException )
{
throw RuntimeException();
}
}
const Reference< XContent >& SAL_CALL CachedContentResultSet::CCRS_Cache
::getContent( sal_Int32 nRow )
throw( com::sun::star::uno::RuntimeException )
{
try
{
if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) )
{
Any& rRow = getRowAny( nRow );
Reference< XContent > aValue;
rRow >>= aValue;
rRow <<= m_xContentIdentifierMapping->mapContent( aValue );
remindMapped( nRow );
}
return (* reinterpret_cast< const Reference< XContent > * >
(getRowAny( nRow ).getValue() ));
}
catch( SQLException )
{
throw RuntimeException();
}
}
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// class CCRS_PropertySetInfo
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
class CCRS_PropertySetInfo :
public cppu::OWeakObject,
public com::sun::star::lang::XTypeProvider,
public com::sun::star::beans::XPropertySetInfo
{
friend class CachedContentResultSet;
//my Properties
Sequence< com::sun::star::beans::Property >*
m_pProperties;
//some helping variables ( names for my special properties )
static rtl::OUString m_aPropertyNameForCount;
static rtl::OUString m_aPropertyNameForFinalCount;
static rtl::OUString m_aPropertyNameForFetchSize;
static rtl::OUString m_aPropertyNameForFetchDirection;
long m_nFetchSizePropertyHandle;
long m_nFetchDirectionPropertyHandle;
private:
sal_Int32 SAL_CALL
impl_getRemainedHandle() const;
sal_Bool SAL_CALL
impl_queryProperty(
const rtl::OUString& rName
, com::sun::star::beans::Property& rProp ) const;
sal_Int32 SAL_CALL
impl_getPos( const rtl::OUString& rName ) const;
static sal_Bool SAL_CALL
impl_isMyPropertyName( const rtl::OUString& rName );
public:
CCRS_PropertySetInfo( Reference<
XPropertySetInfo > xPropertySetInfoOrigin );
virtual ~CCRS_PropertySetInfo();
// XInterface
XINTERFACE_DECL()
// XTypeProvider
XTYPEPROVIDER_DECL()
// XPropertySetInfo
virtual Sequence< com::sun::star::beans::Property > SAL_CALL
getProperties()
throw( RuntimeException );
virtual com::sun::star::beans::Property SAL_CALL
getPropertyByName( const rtl::OUString& aName )
throw( com::sun::star::beans::UnknownPropertyException, RuntimeException );
virtual sal_Bool SAL_CALL
hasPropertyByName( const rtl::OUString& Name )
throw( RuntimeException );
};
OUString CCRS_PropertySetInfo::m_aPropertyNameForCount( OUString::createFromAscii( "RowCount" ) );
OUString CCRS_PropertySetInfo::m_aPropertyNameForFinalCount( OUString::createFromAscii( "IsRowCountFinal" ) );
OUString CCRS_PropertySetInfo::m_aPropertyNameForFetchSize( OUString::createFromAscii( "FetchSize" ) );
OUString CCRS_PropertySetInfo::m_aPropertyNameForFetchDirection( OUString::createFromAscii( "FetchDirection" ) );
CCRS_PropertySetInfo::CCRS_PropertySetInfo(
Reference< XPropertySetInfo > xInfo )
: m_pProperties( NULL )
, m_nFetchSizePropertyHandle( -1 )
, m_nFetchDirectionPropertyHandle( -1 )
{
//initialize list of properties:
// it is required, that the received xInfo contains the two
// properties with names 'm_aPropertyNameForCount' and
// 'm_aPropertyNameForFinalCount'
if( xInfo.is() )
{
Sequence<Property> aProps = xInfo->getProperties();
m_pProperties = new Sequence<Property> ( aProps );
}
else
{
OSL_ENSURE( sal_False, "The received XPropertySetInfo doesn't contain required properties" );
m_pProperties = new Sequence<Property>;
}
//ensure, that we haven't got the Properties 'FetchSize' and 'Direction' twice:
sal_Int32 nFetchSize = impl_getPos( m_aPropertyNameForFetchSize );
sal_Int32 nFetchDirection = impl_getPos( m_aPropertyNameForFetchDirection );
sal_Int32 nDeleted = 0;
if( nFetchSize != -1 )
nDeleted++;
if( nFetchDirection != -1 )
nDeleted++;
Sequence< Property >* pOrigProps = new Sequence<Property> ( *m_pProperties );
sal_Int32 nOrigProps = pOrigProps->getLength();
m_pProperties->realloc( nOrigProps + 2 - nDeleted );//note that nDeleted is <= 2
for( sal_Int32 n = 0, m = 0; n < nOrigProps; n++, m++ )
{
if( n == nFetchSize || n == nFetchDirection )
m--;
else
(*m_pProperties)[ m ] = (*pOrigProps)[ n ];
}
{
Property& rMyProp = (*m_pProperties)[ nOrigProps - nDeleted ];
rMyProp.Name = m_aPropertyNameForFetchSize;
rMyProp.Type = getCppuType( static_cast< const sal_Int32 * >( 0 ) );
rMyProp.Attributes = PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT;
if( nFetchSize != -1 )
m_nFetchSizePropertyHandle = (*pOrigProps)[nFetchSize].Handle;
else
m_nFetchSizePropertyHandle = impl_getRemainedHandle();
rMyProp.Handle = m_nFetchSizePropertyHandle;
}
{
Property& rMyProp = (*m_pProperties)[ nOrigProps - nDeleted + 1 ];
rMyProp.Name = m_aPropertyNameForFetchDirection;
rMyProp.Type = getCppuType( static_cast< const sal_Bool * >( 0 ) );
rMyProp.Attributes = PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT;
if( nFetchSize != -1 )
m_nFetchDirectionPropertyHandle = (*pOrigProps)[nFetchDirection].Handle;
else
m_nFetchDirectionPropertyHandle = impl_getRemainedHandle();
m_nFetchDirectionPropertyHandle = rMyProp.Handle;
}
delete pOrigProps;
}
CCRS_PropertySetInfo::~CCRS_PropertySetInfo()
{
delete m_pProperties;
}
//--------------------------------------------------------------------------
// XInterface methods.
//--------------------------------------------------------------------------
//list all interfaces inclusive baseclasses of interfaces
XINTERFACE_IMPL_2( CCRS_PropertySetInfo
, XTypeProvider
, XPropertySetInfo
);
//--------------------------------------------------------------------------
// XTypeProvider methods.
//--------------------------------------------------------------------------
//list all interfaces exclusive baseclasses
XTYPEPROVIDER_IMPL_2( CCRS_PropertySetInfo
, XTypeProvider
, XPropertySetInfo
);
//--------------------------------------------------------------------------
// XPropertySetInfo methods.
//--------------------------------------------------------------------------
//virtual
Sequence< Property > SAL_CALL CCRS_PropertySetInfo
::getProperties() throw( RuntimeException )
{
return *m_pProperties;
}
//virtual
Property SAL_CALL CCRS_PropertySetInfo
::getPropertyByName( const rtl::OUString& aName )
throw( UnknownPropertyException, RuntimeException )
{
if ( !aName.getLength() )
throw UnknownPropertyException();
Property aProp;
if ( impl_queryProperty( aName, aProp ) )
return aProp;
throw UnknownPropertyException();
}
//virtual
sal_Bool SAL_CALL CCRS_PropertySetInfo
::hasPropertyByName( const rtl::OUString& Name )
throw( RuntimeException )
{
return ( impl_getPos( Name ) != -1 );
}
//--------------------------------------------------------------------------
// impl_ methods.
//--------------------------------------------------------------------------
sal_Int32 SAL_CALL CCRS_PropertySetInfo
::impl_getPos( const OUString& rName ) const
{
for( sal_Int32 nN = m_pProperties->getLength(); nN--; )
{
const Property& rMyProp = (*m_pProperties)[nN];
if( rMyProp.Name == rName )
return nN;
}
return -1;
}
sal_Bool SAL_CALL CCRS_PropertySetInfo
::impl_queryProperty( const OUString& rName, Property& rProp ) const
{
for( sal_Int32 nN = m_pProperties->getLength(); nN--; )
{
const Property& rMyProp = (*m_pProperties)[nN];
if( rMyProp.Name == rName )
{
rProp.Name = rMyProp.Name;
rProp.Handle = rMyProp.Handle;
rProp.Type = rMyProp.Type;
rProp.Attributes = rMyProp.Attributes;
return sal_True;
}
}
return sal_False;
}
//static
sal_Bool SAL_CALL CCRS_PropertySetInfo
::impl_isMyPropertyName( const OUString& rPropertyName )
{
return ( rPropertyName == m_aPropertyNameForCount
|| rPropertyName == m_aPropertyNameForFinalCount
|| rPropertyName == m_aPropertyNameForFetchSize
|| rPropertyName == m_aPropertyNameForFetchDirection );
}
sal_Int32 SAL_CALL CCRS_PropertySetInfo
::impl_getRemainedHandle( ) const
{
sal_Int32 nHandle = 1;
if( !m_pProperties )
{
OSL_ENSURE( sal_False, "Properties not initialized yet" );
return nHandle;
}
sal_Bool bFound = sal_True;
while( bFound )
{
bFound = sal_False;
for( sal_Int32 nN = m_pProperties->getLength(); nN--; )
{
if( nHandle == (*m_pProperties)[nN].Handle )
{
bFound = sal_True;
nHandle++;
break;
}
}
}
return nHandle;
}
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// class CachedContentResultSet
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
CachedContentResultSet::CachedContentResultSet(
const Reference< XMultiServiceFactory > & xSMgr
, const Reference< XResultSet > & xOrigin
, const Reference< XContentIdentifierMapping > &
xContentIdentifierMapping )
: ContentResultSetWrapper( xOrigin )
, m_xSMgr( xSMgr )
, m_xFetchProvider( NULL )
, m_xFetchProviderForContentAccess( NULL )
, m_xMyPropertySetInfo( NULL )
, m_pMyPropSetInfo( NULL )
, m_xContentIdentifierMapping( xContentIdentifierMapping )
, m_nRow( 0 ) // Position is one-based. Zero means: before first element.
, m_bAfterLast( sal_False )
, m_nLastAppliedPos( 0 )
, m_bAfterLastApplied( sal_False )
, m_nKnownCount( 0 )
, m_bFinalCount( sal_False )
, m_nFetchSize(
COMSUNSTARUCBCCRS_DEFAULT_FETCH_SIZE )
, m_nFetchDirection(
COMSUNSTARUCBCCRS_DEFAULT_FETCH_DIRECTION )
, m_bLastReadWasFromCache( sal_False )
, m_bLastCachedReadWasNull( sal_True )
, m_aCache( m_xContentIdentifierMapping )
, m_aCacheContentIdentifierString( m_xContentIdentifierMapping )
, m_aCacheContentIdentifier( m_xContentIdentifierMapping )
, m_aCacheContent( m_xContentIdentifierMapping )
, m_bTriedToGetTypeConverter( sal_False )
, m_xTypeConverter( NULL )
{
m_xFetchProvider = Reference< XFetchProvider >( m_xResultSetOrigin, UNO_QUERY );
OSL_ENSURE( m_xFetchProvider.is(), "interface XFetchProvider is required" );
m_xFetchProviderForContentAccess = Reference< XFetchProviderForContentAccess >( 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.
//--------------------------------------------------------------------------
sal_Bool SAL_CALL CachedContentResultSet
::applyPositionToOrigin( sal_Int32 nRow )
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
//-------------------------------------------------------------------------
/**
@returns
<TRUE/> if the cursor is on a valid row; <FALSE/> if it is off
the result set.
*/
ReacquireableGuard aGuard( m_aMutex );
OSL_ENSURE( nRow >= 0, "only positive values supported" );
if( !m_xResultSetOrigin.is() )
{
OSL_ENSURE( sal_False, "broadcaster was disposed already" );
return sal_False;
}
// OSL_ENSURE( nRow <= m_nKnownCount, "don't step into regions you don't know with this method" );
sal_Int32 nLastAppliedPos = m_nLastAppliedPos;
sal_Bool bAfterLastApplied = m_bAfterLastApplied;
sal_Bool bAfterLast = m_bAfterLast;
sal_Int32 nForwardOnly = m_nForwardOnly;
aGuard.clear();
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;
}
aGuard.reacquire();
m_nLastAppliedPos += nM;
m_bAfterLastApplied = nRow != m_nLastAppliedPos;
return nRow == m_nLastAppliedPos;
}
if( !nRow ) //absolute( 0 ) will throw exception
{
m_xResultSetOrigin->beforeFirst();
aGuard.reacquire();
m_nLastAppliedPos = 0;
m_bAfterLastApplied = sal_False;
return sal_False;
}
try
{
//move absolute, if !nLastAppliedPos
//because move relative would throw exception
if( !nLastAppliedPos || bAfterLast || bAfterLastApplied )
{
sal_Bool bValid = m_xResultSetOrigin->absolute( nRow );
aGuard.reacquire();
m_nLastAppliedPos = nRow;
m_bAfterLastApplied = !bValid;
return bValid;
}
else
{
sal_Bool bValid = m_xResultSetOrigin->relative( nRow - nLastAppliedPos );
aGuard.reacquire();
m_nLastAppliedPos += ( nRow - nLastAppliedPos );
m_bAfterLastApplied = !bValid;
return bValid;
}
}
catch( SQLException& rEx )
{
if( !bAfterLastApplied && !bAfterLast && nRow > nLastAppliedPos && impl_isForwardOnly() )
{
sal_Int32 nN = nRow - nLastAppliedPos;
sal_Int32 nM;
for( nM = 0; nN--; nM++ )
{
if( !m_xResultSetOrigin->next() )
break;
}
aGuard.reacquire();
m_nLastAppliedPos += nM;
m_bAfterLastApplied = nRow != m_nLastAppliedPos;
}
else
throw rEx;
}
return nRow == m_nLastAppliedPos;
}
return sal_True;
};
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
//define for fetching data
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
#define FETCH_XXX( aCache, fetchInterface, fetchMethod ) \
sal_Bool bDirection = !!( \
nFetchDirection != FetchDirection::REVERSE ); \
FetchResult aResult = \
fetchInterface->fetchMethod( nRow, nFetchSize, bDirection ); \
osl::ClearableGuard< osl::Mutex > aGuard2( m_aMutex ); \
aCache.loadData( aResult ); \
sal_Int32 nMax = aCache.getMaxRow(); \
sal_Int32 nCurCount = m_nKnownCount; \
sal_Bool bIsFinalCount = aCache.hasKnownLast(); \
sal_Bool bCurIsFinalCount = m_bFinalCount; \
aGuard2.clear(); \
if( nMax > nCurCount ) \
impl_changeRowCount( nCurCount, nMax ); \
if( bIsFinalCount && !bCurIsFinalCount ) \
impl_changeIsRowCountFinal( bCurIsFinalCount, bIsFinalCount );
void SAL_CALL CachedContentResultSet
::impl_fetchData( sal_Int32 nRow
, sal_Int32 nFetchSize, sal_Int32 nFetchDirection )
throw( com::sun::star::uno::RuntimeException )
{
FETCH_XXX( m_aCache, m_xFetchProvider, fetch );
}
void SAL_CALL CachedContentResultSet
::impl_changeRowCount( 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;
{
osl::Guard< osl::Mutex > aGuard( m_aMutex );
aEvt.Source = static_cast< XPropertySet * >( this );
aEvt.Further = sal_False;
aEvt.OldValue <<= nOld;
aEvt.NewValue <<= nNew;
m_nKnownCount = nNew;
}
//send PropertyChangeEvent to listeners
impl_notifyPropertyChangeListeners( aEvt );
}
void SAL_CALL CachedContentResultSet
::impl_changeIsRowCountFinal( sal_Bool bOld, sal_Bool bNew )
{
OSL_ENSURE( !bOld && bNew, "This change is not allowed for IsRowCountFinal" );
if( ! (!bOld && bNew ) )
return;
//create PropertyChangeEvent and set value
PropertyChangeEvent aEvt;
{
osl::Guard< osl::Mutex > aGuard( m_aMutex );
aEvt.Source = static_cast< XPropertySet * >( this );
aEvt.Further = sal_False;
aEvt.OldValue <<= bOld;
aEvt.NewValue <<= bNew;
m_bFinalCount = bNew;
}
//send PropertyChangeEvent to listeners
impl_notifyPropertyChangeListeners( aEvt );
}
sal_Bool SAL_CALL CachedContentResultSet
::impl_isKnownValidPosition( sal_Int32 nRow )
{
return m_nKnownCount && nRow
&& nRow <= m_nKnownCount;
}
sal_Bool SAL_CALL CachedContentResultSet
::impl_isKnownInvalidPosition( sal_Int32 nRow )
{
if( !nRow )
return sal_True;
if( !m_bFinalCount )
return sal_False;
return nRow > m_nKnownCount;
}
//virtual
void SAL_CALL CachedContentResultSet
::impl_initPropertySetInfo()
{
ContentResultSetWrapper::impl_initPropertySetInfo();
osl::Guard< osl::Mutex > aGuard( m_aMutex );
if( m_pMyPropSetInfo )
return;
m_pMyPropSetInfo = new CCRS_PropertySetInfo( m_xPropertySetInfo );
m_xMyPropertySetInfo = m_pMyPropSetInfo;
m_xPropertySetInfo = m_xMyPropertySetInfo;
}
//--------------------------------------------------------------------------
// XInterface methods. ( inherited )
//--------------------------------------------------------------------------
XINTERFACE_COMMON_IMPL( CachedContentResultSet )
Any SAL_CALL CachedContentResultSet
::queryInterface( const Type& rType )
throw ( RuntimeException )
{
//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.
//--------------------------------------------------------------------------
XSERVICEINFO_NOFACTORY_IMPL_1( CachedContentResultSet,
OUString::createFromAscii(
"com.sun.star.comp.ucb.CachedContentResultSet" ),
OUString::createFromAscii(
CACHED_CONTENT_RESULTSET_SERVICE_NAME ) );
//--------------------------------------------------------------------------
// XPropertySet methods. ( inherited )
//--------------------------------------------------------------------------
// virtual
void SAL_CALL CachedContentResultSet
::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
throw( UnknownPropertyException,
PropertyVetoException,
IllegalArgumentException,
WrappedTargetException,
RuntimeException )
{
impl_EnsureNotDisposed();
if( !getPropertySetInfo().is() )
{
OSL_ENSURE( sal_False, "broadcaster was disposed already" );
throw UnknownPropertyException();
}
Property aProp = m_pMyPropSetInfo->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 == CCRS_PropertySetInfo
::m_aPropertyNameForFetchDirection )
{
//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;
{
osl::Guard< osl::Mutex > aGuard( m_aMutex );
aEvt.Source = static_cast< XPropertySet * >( this );
aEvt.PropertyName = aPropertyName;
aEvt.Further = sal_False;
aEvt.PropertyHandle = m_pMyPropSetInfo->
m_nFetchDirectionPropertyHandle;
aEvt.OldValue <<= m_nFetchDirection;
aEvt.NewValue <<= nNew;
m_nFetchDirection = nNew;
}
//send PropertyChangeEvent to listeners
impl_notifyPropertyChangeListeners( aEvt );
}
else if( aProp.Name == CCRS_PropertySetInfo
::m_aPropertyNameForFetchSize )
{
//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;
{
osl::Guard< osl::Mutex > aGuard( m_aMutex );
aEvt.Source = static_cast< XPropertySet * >( this );
aEvt.PropertyName = aPropertyName;
aEvt.Further = sal_False;
aEvt.PropertyHandle = m_pMyPropSetInfo->
m_nFetchSizePropertyHandle;
aEvt.OldValue <<= m_nFetchSize;
aEvt.NewValue <<= nNew;
m_nFetchSize = nNew;
}
//send PropertyChangeEvent to listeners
impl_notifyPropertyChangeListeners( aEvt );
}
else
{
impl_init_xPropertySetOrigin();
{
osl::Guard< osl::Mutex > aGuard( m_aMutex );
if( !m_xPropertySetOrigin.is() )
{
OSL_ENSURE( sal_False, "broadcaster was disposed already" );
return;
}
}
m_xPropertySetOrigin->setPropertyValue( aPropertyName, aValue );
}
}
//--------------------------------------------------------------------------
// virtual
Any SAL_CALL CachedContentResultSet
::getPropertyValue( const OUString& rPropertyName )
throw( UnknownPropertyException,
WrappedTargetException,
RuntimeException )
{
impl_EnsureNotDisposed();
if( !getPropertySetInfo().is() )
{
OSL_ENSURE( sal_False, "broadcaster was disposed already" );
throw UnknownPropertyException();
}
Property aProp = m_pMyPropSetInfo->getPropertyByName( rPropertyName );
//throws UnknownPropertyException, if so
Any aValue;
if( rPropertyName == CCRS_PropertySetInfo
::m_aPropertyNameForCount )
{
osl::Guard< osl::Mutex > aGuard( m_aMutex );
aValue <<= m_nKnownCount;
}
else if( rPropertyName == CCRS_PropertySetInfo
::m_aPropertyNameForFinalCount )
{
osl::Guard< osl::Mutex > aGuard( m_aMutex );
aValue <<= m_bFinalCount;
}
else if( rPropertyName == CCRS_PropertySetInfo
::m_aPropertyNameForFetchSize )
{
osl::Guard< osl::Mutex > aGuard( m_aMutex );
aValue <<= m_nFetchSize;
}
else if( rPropertyName == CCRS_PropertySetInfo
::m_aPropertyNameForFetchDirection )
{
osl::Guard< osl::Mutex > aGuard( m_aMutex );
aValue <<= m_nFetchDirection;
}
else
{
impl_init_xPropertySetOrigin();
{
osl::Guard< osl::Mutex > aGuard( m_aMutex );
if( !m_xPropertySetOrigin.is() )
{
OSL_ENSURE( sal_False, "broadcaster was disposed already" );
throw UnknownPropertyException();
}
}
aValue = m_xPropertySetOrigin->getPropertyValue( rPropertyName );
}
return aValue;
}
//--------------------------------------------------------------------------
// own methods. ( inherited )
//--------------------------------------------------------------------------
//virtual
void SAL_CALL CachedContentResultSet
::impl_disposing( const EventObject& rEventObject )
throw( RuntimeException )
{
{
impl_EnsureNotDisposed();
osl::Guard< osl::Mutex > aGuard( m_aMutex );
//release all references to the broadcaster:
m_xFetchProvider.clear();
m_xFetchProviderForContentAccess.clear();
}
ContentResultSetWrapper::impl_disposing( rEventObject );
}
//virtual
void SAL_CALL CachedContentResultSet
::impl_propertyChange( const PropertyChangeEvent& rEvt )
throw( RuntimeException )
{
impl_EnsureNotDisposed();
PropertyChangeEvent aEvt( rEvt );
aEvt.Source = static_cast< XPropertySet * >( this );
aEvt.Further = sal_False;
//---------
if( CCRS_PropertySetInfo
::impl_isMyPropertyName( rEvt.PropertyName ) )
{
//don't notify foreign events on fetchsize and fetchdirection
if( aEvt.PropertyName == CCRS_PropertySetInfo
::m_aPropertyNameForFetchSize
|| aEvt.PropertyName == CCRS_PropertySetInfo
::m_aPropertyNameForFetchDirection )
return;
//adjust my props 'RowCount' and 'IsRowCountFinal'
if( aEvt.PropertyName == CCRS_PropertySetInfo
::m_aPropertyNameForCount )
{//RowCount changed
//check value
sal_Int32 nNew = 0;
if( !( aEvt.NewValue >>= nNew ) )
{
OSL_ENSURE( sal_False, "PropertyChangeEvent contains wrong data" );
return;
}
impl_changeRowCount( m_nKnownCount, nNew );
}
else if( aEvt.PropertyName == CCRS_PropertySetInfo
::m_aPropertyNameForFinalCount )
{//IsRowCountFinal changed
//check value
sal_Bool bNew = sal_False;
if( !( aEvt.NewValue >>= bNew ) )
{
OSL_ENSURE( sal_False, "PropertyChangeEvent contains wrong data" );
return;
}
impl_changeIsRowCountFinal( m_bFinalCount, bNew );
}
return;
}
//-----------
impl_notifyPropertyChangeListeners( aEvt );
}
//virtual
void SAL_CALL CachedContentResultSet
::impl_vetoableChange( const PropertyChangeEvent& rEvt )
throw( PropertyVetoException,
RuntimeException )
{
impl_EnsureNotDisposed();
//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 = sal_False;
impl_notifyVetoableChangeListeners( aEvt );
}
//--------------------------------------------------------------------------
// XContentAccess methods. ( inherited ) ( -- position dependent )
//--------------------------------------------------------------------------
#define XCONTENTACCESS_queryXXX( queryXXX, XXX, TYPE ) \
impl_EnsureNotDisposed(); \
ReacquireableGuard aGuard( m_aMutex ); \
sal_Int32 nRow = m_nRow; \
sal_Int32 nFetchSize = m_nFetchSize; \
sal_Int32 nFetchDirection = m_nFetchDirection; \
if( !m_aCache##XXX.hasRow( nRow ) ) \
{ \
if( !m_aCache##XXX.hasCausedException( nRow ) ) \
{ \
if( !m_xFetchProviderForContentAccess.is() ) \
{ \
OSL_ENSURE( sal_False, "broadcaster was disposed already" );\
throw RuntimeException(); \
} \
aGuard.clear(); \
if( impl_isForwardOnly() ) \
applyPositionToOrigin( nRow ); \
\
FETCH_XXX( m_aCache##XXX, m_xFetchProviderForContentAccess, fetch##XXX##s ); \
} \
aGuard.reacquire(); \
if( !m_aCache##XXX.hasRow( nRow ) ) \
{ \
aGuard.clear(); \
applyPositionToOrigin( nRow ); \
TYPE aRet = ContentResultSetWrapper::queryXXX(); \
if( m_xContentIdentifierMapping.is() ) \
return m_xContentIdentifierMapping->map##XXX( aRet );\
return aRet; \
} \
} \
return m_aCache##XXX.get##XXX( nRow );
//--------------------------------------------------------------------------
// virtual
OUString SAL_CALL CachedContentResultSet
::queryContentIdentifierString()
throw( RuntimeException )
{
XCONTENTACCESS_queryXXX( queryContentIdentifierString, ContentIdentifierString, OUString )
}
//--------------------------------------------------------------------------
// virtual
Reference< XContentIdentifier > SAL_CALL CachedContentResultSet
::queryContentIdentifier()
throw( RuntimeException )
{
XCONTENTACCESS_queryXXX( queryContentIdentifier, ContentIdentifier, Reference< XContentIdentifier > )
}
//--------------------------------------------------------------------------
// virtual
Reference< XContent > SAL_CALL CachedContentResultSet
::queryContent()
throw( RuntimeException )
{
XCONTENTACCESS_queryXXX( queryContent, Content, Reference< XContent > )
}
//-----------------------------------------------------------------
// XResultSet methods. ( inherited )
//-----------------------------------------------------------------
//virtual
sal_Bool SAL_CALL CachedContentResultSet
::next()
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
ReacquireableGuard aGuard( m_aMutex );
//after last
if( m_bAfterLast )
return sal_False;
//last
aGuard.clear();
if( isLast() )
{
aGuard.reacquire();
m_nRow++;
m_bAfterLast = sal_True;
return sal_False;
}
aGuard.reacquire();
//known valid position
if( impl_isKnownValidPosition( m_nRow + 1 ) )
{
m_nRow++;
return sal_True;
}
//unknown position
sal_Int32 nRow = m_nRow;
aGuard.clear();
sal_Bool bValid = applyPositionToOrigin( nRow + 1 );
aGuard.reacquire();
m_nRow = nRow + 1;
m_bAfterLast = !bValid;
return bValid;
}
//virtual
sal_Bool SAL_CALL CachedContentResultSet
::previous()
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
if( impl_isForwardOnly() )
throw SQLException();
ReacquireableGuard aGuard( m_aMutex );
//before first ?:
if( !m_bAfterLast && !m_nRow )
return sal_False;
//first ?:
if( !m_bAfterLast && m_nKnownCount && m_nRow == 1 )
{
m_nRow--;
m_bAfterLast = sal_False;
return sal_False;
}
//known valid position ?:
if( impl_isKnownValidPosition( m_nRow - 1 ) )
{
m_nRow--;
m_bAfterLast = sal_False;
return sal_True;
}
//unknown position:
sal_Int32 nRow = m_nRow;
aGuard.clear();
sal_Bool bValid = applyPositionToOrigin( nRow - 1 );
aGuard.reacquire();
m_nRow = nRow - 1;
m_bAfterLast = sal_False;
return bValid;
}
//virtual
sal_Bool SAL_CALL CachedContentResultSet
::absolute( sal_Int32 row )
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
if( !row )
throw SQLException();
if( impl_isForwardOnly() )
throw SQLException();
ReacquireableGuard aGuard( m_aMutex );
if( !m_xResultSetOrigin.is() )
{
OSL_ENSURE( sal_False, "broadcaster was disposed already" );
return sal_False;
}
if( row < 0 )
{
if( m_bFinalCount )
{
sal_Int32 nNewRow = m_nKnownCount + 1 + row;
sal_Bool bValid = sal_True;
if( nNewRow <= 0 )
{
nNewRow = 0;
bValid = sal_False;
}
m_nRow = nNewRow;
m_bAfterLast = sal_False;
return bValid;
}
//unknown final count:
aGuard.clear();
// Solaris has problems catching or propagating derived exceptions
// when only the base class is known, so make ResultSetException
// (derived from SQLException) known here:
sal_Bool bValid;
try
{
bValid = m_xResultSetOrigin->absolute( row );
}
catch (ResultSetException &)
{
throw;
}
aGuard.reacquire();
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 = sal_False;
return bValid;
}
aGuard.clear();
sal_Int32 nCurRow = m_xResultSetOrigin->getRow();
aGuard.reacquire();
m_nLastAppliedPos = nCurRow;
m_nRow = nCurRow;
m_bAfterLast = sal_False;
return nCurRow != 0;
}
//row > 0:
if( m_bFinalCount )
{
if( row > m_nKnownCount )
{
m_nRow = m_nKnownCount + 1;
m_bAfterLast = sal_True;
return sal_False;
}
m_nRow = row;
m_bAfterLast = sal_False;
return sal_True;
}
//unknown new position:
aGuard.clear();
sal_Bool bValid = m_xResultSetOrigin->absolute( row );
aGuard.reacquire();
if( m_bFinalCount )
{
sal_Int32 nNewRow = row;
if( nNewRow > m_nKnownCount )
{
nNewRow = m_nKnownCount + 1;
m_bAfterLastApplied = m_bAfterLast = sal_True;
}
else
m_bAfterLastApplied = m_bAfterLast = sal_False;
m_nLastAppliedPos = nNewRow;
m_nRow = nNewRow;
return bValid;
}
aGuard.clear();
sal_Int32 nCurRow = m_xResultSetOrigin->getRow();
sal_Bool bIsAfterLast = m_xResultSetOrigin->isAfterLast();
aGuard.reacquire();
m_nLastAppliedPos = nCurRow;
m_nRow = nCurRow;
m_bAfterLastApplied = m_bAfterLast = bIsAfterLast;
return nCurRow && !bIsAfterLast;
}
//virtual
sal_Bool SAL_CALL CachedContentResultSet
::relative( sal_Int32 rows )
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
if( impl_isForwardOnly() )
throw SQLException();
ReacquireableGuard aGuard( m_aMutex );
if( m_bAfterLast || impl_isKnownInvalidPosition( m_nRow ) )
throw SQLException();
if( !rows )
return sal_True;
sal_Int32 nNewRow = m_nRow + rows;
if( nNewRow < 0 )
nNewRow = 0;
if( impl_isKnownValidPosition( nNewRow ) )
{
m_nRow = nNewRow;
m_bAfterLast = sal_False;
return sal_True;
}
else
{
//known invalid new position:
if( nNewRow == 0 )
{
m_bAfterLast = sal_False;
m_nRow = 0;
return sal_False;
}
if( m_bFinalCount && nNewRow > m_nKnownCount )
{
m_bAfterLast = sal_True;
m_nRow = m_nKnownCount + 1;
return sal_False;
}
//unknown new position:
aGuard.clear();
sal_Bool bValid = applyPositionToOrigin( nNewRow );
aGuard.reacquire();
m_nRow = nNewRow;
m_bAfterLast = !bValid && nNewRow > 0;
return bValid;
}
}
//virtual
sal_Bool SAL_CALL CachedContentResultSet
::first()
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
if( impl_isForwardOnly() )
throw SQLException();
ReacquireableGuard aGuard( m_aMutex );
if( impl_isKnownValidPosition( 1 ) )
{
m_nRow = 1;
m_bAfterLast = sal_False;
return sal_True;
}
if( impl_isKnownInvalidPosition( 1 ) )
{
m_nRow = 1;
m_bAfterLast = sal_False;
return sal_False;
}
//unknown position
aGuard.clear();
sal_Bool bValid = applyPositionToOrigin( 1 );
aGuard.reacquire();
m_nRow = 1;
m_bAfterLast = sal_False;
return bValid;
}
//virtual
sal_Bool SAL_CALL CachedContentResultSet
::last()
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
if( impl_isForwardOnly() )
throw SQLException();
ReacquireableGuard aGuard( m_aMutex );
if( m_bFinalCount )
{
m_nRow = m_nKnownCount;
m_bAfterLast = sal_False;
return m_nKnownCount != 0;
}
//unknown position
if( !m_xResultSetOrigin.is() )
{
OSL_ENSURE( sal_False, "broadcaster was disposed already" );
return sal_False;
}
aGuard.clear();
sal_Bool bValid = m_xResultSetOrigin->last();
aGuard.reacquire();
m_bAfterLastApplied = m_bAfterLast = sal_False;
if( m_bFinalCount )
{
m_nLastAppliedPos = m_nKnownCount;
m_nRow = m_nKnownCount;
return bValid;
}
aGuard.clear();
sal_Int32 nCurRow = m_xResultSetOrigin->getRow();
aGuard.reacquire();
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 = sal_True;
return nCurRow != 0;
}
//virtual
void SAL_CALL CachedContentResultSet
::beforeFirst()
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
if( impl_isForwardOnly() )
throw SQLException();
osl::Guard< osl::Mutex > aGuard( m_aMutex );
m_nRow = 0;
m_bAfterLast = sal_False;
}
//virtual
void SAL_CALL CachedContentResultSet
::afterLast()
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
if( impl_isForwardOnly() )
throw SQLException();
osl::Guard< osl::Mutex > aGuard( m_aMutex );
m_nRow = 1;
m_bAfterLast = sal_True;
}
//virtual
sal_Bool SAL_CALL CachedContentResultSet
::isAfterLast()
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
ReacquireableGuard aGuard( m_aMutex );
if( !m_bAfterLast )
return sal_False;
if( m_nKnownCount )
return m_bAfterLast;
if( m_bFinalCount )
return sal_False;
if( !m_xResultSetOrigin.is() )
{
OSL_ENSURE( sal_False, "broadcaster was disposed already" );
return sal_False;
}
aGuard.clear();
//find out whethter the original resultset contains rows or not
m_xResultSetOrigin->afterLast();
aGuard.reacquire();
m_bAfterLastApplied = sal_True;
aGuard.clear();
return m_xResultSetOrigin->isAfterLast();
}
//virtual
sal_Bool SAL_CALL CachedContentResultSet
::isBeforeFirst()
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
ReacquireableGuard aGuard( m_aMutex );
if( m_bAfterLast )
return sal_False;
if( m_nRow )
return sal_False;
if( m_nKnownCount )
return !m_nRow;
if( m_bFinalCount )
return sal_False;
if( !m_xResultSetOrigin.is() )
{
OSL_ENSURE( sal_False, "broadcaster was disposed already" );
return sal_False;
}
aGuard.clear();
//find out whethter the original resultset contains rows or not
m_xResultSetOrigin->beforeFirst();
aGuard.reacquire();
m_bAfterLastApplied = sal_False;
m_nLastAppliedPos = 0;
aGuard.clear();
return m_xResultSetOrigin->isBeforeFirst();
}
//virtual
sal_Bool SAL_CALL CachedContentResultSet
::isFirst()
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
sal_Int32 nRow = 0;
Reference< XResultSet > xResultSetOrigin;
{
osl::Guard< osl::Mutex > aGuard( m_aMutex );
if( m_bAfterLast )
return sal_False;
if( m_nRow != 1 )
return sal_False;
if( m_nKnownCount )
return m_nRow == 1;
if( m_bFinalCount )
return sal_False;
nRow = m_nRow;
xResultSetOrigin = m_xResultSetOrigin;
}
//need to ask origin
{
if( applyPositionToOrigin( nRow ) )
return xResultSetOrigin->isFirst();
else
return sal_False;
}
}
//virtual
sal_Bool SAL_CALL CachedContentResultSet
::isLast()
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
sal_Int32 nRow = 0;
Reference< XResultSet > xResultSetOrigin;
{
osl::Guard< osl::Mutex > aGuard( m_aMutex );
if( m_bAfterLast )
return sal_False;
if( m_nRow < m_nKnownCount )
return sal_False;
if( m_bFinalCount )
return m_nKnownCount && m_nRow == m_nKnownCount;
nRow = m_nRow;
xResultSetOrigin = m_xResultSetOrigin;
}
//need to ask origin
{
if( applyPositionToOrigin( nRow ) )
return xResultSetOrigin->isLast();
else
return sal_False;
}
}
//virtual
sal_Int32 SAL_CALL CachedContentResultSet
::getRow()
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
osl::Guard< osl::Mutex > aGuard( m_aMutex );
if( m_bAfterLast )
return 0;
return m_nRow;
}
//virtual
void SAL_CALL CachedContentResultSet
::refreshRow()
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
//the ContentResultSet is static and will not change
//therefore we don't need to reload anything
}
//virtual
sal_Bool SAL_CALL CachedContentResultSet
::rowUpdated()
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
//the ContentResultSet is static and will not change
return sal_False;
}
//virtual
sal_Bool SAL_CALL CachedContentResultSet
::rowInserted()
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
//the ContentResultSet is static and will not change
return sal_False;
}
//virtual
sal_Bool SAL_CALL CachedContentResultSet
::rowDeleted()
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
//the ContentResultSet is static and will not change
return sal_False;
}
//virtual
Reference< XInterface > SAL_CALL CachedContentResultSet
::getStatement()
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
//@todo ?return anything
return Reference< XInterface >();
}
//-----------------------------------------------------------------
// XRow methods. ( inherited )
//-----------------------------------------------------------------
//virtual
sal_Bool SAL_CALL CachedContentResultSet
::wasNull()
throw( SQLException,
RuntimeException )
{
impl_EnsureNotDisposed();
impl_init_xRowOrigin();
{
osl::Guard< osl::Mutex > aGuard( m_aMutex );
if( m_bLastReadWasFromCache )
return m_bLastCachedReadWasNull;
if( !m_xRowOrigin.is() )
{
OSL_ENSURE( sal_False, "broadcaster was disposed already" );
return sal_False;
}
}
return m_xRowOrigin->wasNull();
}
//virtual
rtl::OUString SAL_CALL CachedContentResultSet
::getString( sal_Int32 columnIndex )
throw( SQLException,
RuntimeException )
{
XROW_GETXXX( getString, OUString );
}
//virtual
sal_Bool SAL_CALL CachedContentResultSet
::getBoolean( sal_Int32 columnIndex )
throw( SQLException,
RuntimeException )
{
XROW_GETXXX( getBoolean, sal_Bool );
}
//virtual
sal_Int8 SAL_CALL CachedContentResultSet
::getByte( sal_Int32 columnIndex )
throw( SQLException,
RuntimeException )
{
XROW_GETXXX( getByte, sal_Int8 );
}
//virtual
sal_Int16 SAL_CALL CachedContentResultSet
::getShort( sal_Int32 columnIndex )
throw( SQLException,
RuntimeException )
{
XROW_GETXXX( getShort, sal_Int16 );
}
//virtual
sal_Int32 SAL_CALL CachedContentResultSet
::getInt( sal_Int32 columnIndex )
throw( SQLException,
RuntimeException )
{
XROW_GETXXX( getInt, sal_Int32 );
}
//virtual
sal_Int64 SAL_CALL CachedContentResultSet
::getLong( sal_Int32 columnIndex )
throw( SQLException,
RuntimeException )
{
XROW_GETXXX( getLong, sal_Int64 );
}
//virtual
float SAL_CALL CachedContentResultSet
::getFloat( sal_Int32 columnIndex )
throw( SQLException,
RuntimeException )
{
XROW_GETXXX( getFloat, float );
}
//virtual
double SAL_CALL CachedContentResultSet
::getDouble( sal_Int32 columnIndex )
throw( SQLException,
RuntimeException )
{
XROW_GETXXX( getDouble, double );
}
//virtual
Sequence< sal_Int8 > SAL_CALL CachedContentResultSet
::getBytes( sal_Int32 columnIndex )
throw( SQLException,
RuntimeException )
{
XROW_GETXXX( getBytes, Sequence< sal_Int8 > );
}
//virtual
Date SAL_CALL CachedContentResultSet
::getDate( sal_Int32 columnIndex )
throw( SQLException,
RuntimeException )
{
XROW_GETXXX( getDate, Date );
}
//virtual
Time SAL_CALL CachedContentResultSet
::getTime( sal_Int32 columnIndex )
throw( SQLException,
RuntimeException )
{
XROW_GETXXX( getTime, Time );
}
//virtual
DateTime SAL_CALL CachedContentResultSet
::getTimestamp( sal_Int32 columnIndex )
throw( SQLException,
RuntimeException )
{
XROW_GETXXX( getTimestamp, DateTime );
}
//virtual
Reference< com::sun::star::io::XInputStream >
SAL_CALL CachedContentResultSet
::getBinaryStream( sal_Int32 columnIndex )
throw( SQLException,
RuntimeException )
{
XROW_GETXXX( getBinaryStream, Reference< com::sun::star::io::XInputStream > );
}
//virtual
Reference< com::sun::star::io::XInputStream >
SAL_CALL CachedContentResultSet
::getCharacterStream( sal_Int32 columnIndex )
throw( SQLException,
RuntimeException )
{
XROW_GETXXX( getCharacterStream, Reference< com::sun::star::io::XInputStream > );
}
//virtual
Any SAL_CALL CachedContentResultSet
::getObject( sal_Int32 columnIndex,
const Reference<
com::sun::star::container::XNameAccess >& typeMap )
throw( SQLException,
RuntimeException )
{
//if you change this macro please pay attention to
//define XROW_GETXXX, where this is similar implemented
ReacquireableGuard 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_ENSURE( sal_False, "broadcaster was disposed already" );
return Any();
}
aGuard.clear();
impl_fetchData( nRow, nFetchSize, nFetchDirection );
}
aGuard.reacquire();
if( !m_aCache.hasRow( nRow ) )
{
m_bLastReadWasFromCache = sal_False;
aGuard.clear();
applyPositionToOrigin( nRow );
impl_init_xRowOrigin();
return m_xRowOrigin->getObject( columnIndex, typeMap );
}
}
//@todo: pay attention to typeMap
const Any& rValue = m_aCache.getAny( nRow, columnIndex );
Any aRet;
m_bLastReadWasFromCache = sal_True;
m_bLastCachedReadWasNull = !( rValue >>= aRet );
return aRet;
}
//virtual
Reference< XRef > SAL_CALL CachedContentResultSet
::getRef( sal_Int32 columnIndex )
throw( SQLException,
RuntimeException )
{
XROW_GETXXX( getRef, Reference< XRef > );
}
//virtual
Reference< XBlob > SAL_CALL CachedContentResultSet
::getBlob( sal_Int32 columnIndex )
throw( SQLException,
RuntimeException )
{
XROW_GETXXX( getBlob, Reference< XBlob > );
}
//virtual
Reference< XClob > SAL_CALL CachedContentResultSet
::getClob( sal_Int32 columnIndex )
throw( SQLException,
RuntimeException )
{
XROW_GETXXX( getClob, Reference< XClob > );
}
//virtual
Reference< XArray > SAL_CALL CachedContentResultSet
::getArray( sal_Int32 columnIndex )
throw( SQLException,
RuntimeException )
{
XROW_GETXXX( getArray, Reference< XArray > );
}
//-----------------------------------------------------------------
// Type Converter Support
//-----------------------------------------------------------------
const Reference< XTypeConverter >& CachedContentResultSet::getTypeConverter()
{
osl::Guard< osl::Mutex > aGuard( m_aMutex );
if ( !m_bTriedToGetTypeConverter && !m_xTypeConverter.is() )
{
m_bTriedToGetTypeConverter = sal_True;
m_xTypeConverter = Reference< XTypeConverter >(
m_xSMgr->createInstance(
OUString::createFromAscii(
"com.sun.star.script.Converter" ) ),
UNO_QUERY );
OSL_ENSURE( m_xTypeConverter.is(),
"PropertyValueSet::getTypeConverter() - "
"Service 'com.sun.star.script.Converter' n/a!" );
}
return m_xTypeConverter;
}
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// class CachedContentResultSetFactory
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
CachedContentResultSetFactory::CachedContentResultSetFactory(
const Reference< XMultiServiceFactory > & rSMgr )
{
m_xSMgr = rSMgr;
}
CachedContentResultSetFactory::~CachedContentResultSetFactory()
{
}
//--------------------------------------------------------------------------
// CachedContentResultSetFactory XInterface methods.
//--------------------------------------------------------------------------
XINTERFACE_IMPL_3( CachedContentResultSetFactory,
XTypeProvider,
XServiceInfo,
XCachedContentResultSetFactory );
//--------------------------------------------------------------------------
// CachedContentResultSetFactory XTypeProvider methods.
//--------------------------------------------------------------------------
XTYPEPROVIDER_IMPL_3( CachedContentResultSetFactory,
XTypeProvider,
XServiceInfo,
XCachedContentResultSetFactory );
//--------------------------------------------------------------------------
// CachedContentResultSetFactory XServiceInfo methods.
//--------------------------------------------------------------------------
XSERVICEINFO_IMPL_1( CachedContentResultSetFactory,
OUString::createFromAscii(
"com.sun.star.comp.ucb.CachedContentResultSetFactory" ),
OUString::createFromAscii(
CACHED_CONTENT_RESULTSET_FACTORY_NAME ) );
//--------------------------------------------------------------------------
// Service factory implementation.
//--------------------------------------------------------------------------
ONE_INSTANCE_SERVICE_FACTORY_IMPL( CachedContentResultSetFactory );
//--------------------------------------------------------------------------
// CachedContentResultSetFactory XCachedContentResultSetFactory methods.
//--------------------------------------------------------------------------
//virtual
Reference< XResultSet > SAL_CALL CachedContentResultSetFactory
::createCachedContentResultSet(
const Reference< XResultSet > & xSource,
const Reference< XContentIdentifierMapping > & xMapping )
throw( com::sun::star::uno::RuntimeException )
{
Reference< XResultSet > xRet;
xRet = new CachedContentResultSet( m_xSMgr, xSource, xMapping );
return xRet;
}