cid#1607171 Data race condition
[LibreOffice.git] / ucb / source / cacher / cachedcontentresultset.cxx
blob4a554f7ff768a142d83fb6d86dd4a4fc47cd2fd8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "cachedcontentresultset.hxx"
22 #include <com/sun/star/sdbc/FetchDirection.hpp>
23 #include <com/sun/star/sdbc/SQLException.hpp>
24 #include <com/sun/star/ucb/FetchError.hpp>
25 #include <com/sun/star/beans/PropertyAttribute.hpp>
26 #include <com/sun/star/script/CannotConvertException.hpp>
27 #include <com/sun/star/script/Converter.hpp>
28 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
29 #include <rtl/ustring.hxx>
30 #include <o3tl/any.hxx>
31 #include <osl/diagnose.h>
32 #include <cppuhelper/exc_hlp.hxx>
33 #include <cppuhelper/queryinterface.hxx>
34 #include <ucbhelper/macros.hxx>
35 #include <optional>
36 #include <string_view>
38 using namespace com::sun::star::beans;
39 using namespace com::sun::star::lang;
40 using namespace com::sun::star::script;
41 using namespace com::sun::star::sdbc;
42 using namespace com::sun::star::ucb;
43 using namespace com::sun::star::uno;
44 using namespace com::sun::star::util;
45 using namespace cppu;
48 #define COMSUNSTARUCBCCRS_DEFAULT_FETCH_SIZE 256
49 #define COMSUNSTARUCBCCRS_DEFAULT_FETCH_DIRECTION FetchDirection::FORWARD
51 //if you change this function template please pay attention to
52 //function getObject, where this is similar implemented
54 template<typename T> T CachedContentResultSet::rowOriginGet(
55 T (SAL_CALL css::sdbc::XRow::* f)(sal_Int32), sal_Int32 columnIndex)
57 std::unique_lock aGuard(m_aMutex);
58 impl_EnsureNotDisposed(aGuard);
59 sal_Int32 nRow = m_nRow;
60 sal_Int32 nFetchSize = m_nFetchSize;
61 sal_Int32 nFetchDirection = m_nFetchDirection;
62 if( !m_aCache.hasRow( nRow ) )
64 if( !m_aCache.hasCausedException( nRow ) )
66 if( !m_xFetchProvider.is() )
68 OSL_FAIL( "broadcaster was disposed already" );
69 throw SQLException();
71 if( impl_isForwardOnly(aGuard) )
72 applyPositionToOrigin( aGuard, nRow );
74 impl_fetchData( aGuard, nRow, nFetchSize, nFetchDirection );
76 if( !m_aCache.hasRow( nRow ) )
78 m_bLastReadWasFromCache = false;
79 applyPositionToOrigin( aGuard, nRow );
80 impl_init_xRowOrigin(aGuard);
81 aGuard.unlock();
82 return (m_xRowOrigin.get()->*f)( columnIndex );
85 const Any& rValue = m_aCache.getAny( nRow, columnIndex );
86 T aRet = T();
87 m_bLastReadWasFromCache = true;
88 m_bLastCachedReadWasNull = !( rValue >>= aRet );
89 /* Last chance. Try type converter service... */
90 if ( m_bLastCachedReadWasNull && rValue.hasValue() )
92 Reference< XTypeConverter > xConverter = getTypeConverter(aGuard);
93 if ( xConverter.is() )
95 try
97 Any aConvAny = xConverter->convertTo(
98 rValue,
99 cppu::UnoType<T>::get() );
100 m_bLastCachedReadWasNull = !( aConvAny >>= aRet );
102 catch (const IllegalArgumentException&)
105 catch (const CannotConvertException&)
110 return aRet;
114 // CCRS_Cache methods
117 CachedContentResultSet::CCRS_Cache::CCRS_Cache(
118 const Reference< XContentIdentifierMapping > & xMapping )
119 : m_xContentIdentifierMapping( xMapping )
123 CachedContentResultSet::CCRS_Cache::~CCRS_Cache()
127 void CachedContentResultSet::CCRS_Cache
128 ::clear()
130 m_pResult.reset();
131 m_pMappedReminder.reset();
134 void CachedContentResultSet::CCRS_Cache
135 ::loadData( const FetchResult& rResult )
137 clear();
138 m_pResult = rResult;
141 bool CachedContentResultSet::CCRS_Cache
142 ::hasRow( sal_Int32 row ) const
144 if( !m_pResult )
145 return false;
146 sal_Int32 nStart = m_pResult->StartIndex;
147 sal_Int32 nEnd = nStart;
148 if( m_pResult->Orientation )
149 nEnd += m_pResult->Rows.getLength() - 1;
150 else
151 nStart -= m_pResult->Rows.getLength() + 1;
153 return nStart <= row && row <= nEnd;
156 sal_Int32 CachedContentResultSet::CCRS_Cache
157 ::getMaxRow() const
159 if( !m_pResult )
160 return 0;
161 sal_Int32 nEnd = m_pResult->StartIndex;
162 if( m_pResult->Orientation )
163 return nEnd + m_pResult->Rows.getLength() - 1;
164 else
165 return nEnd;
168 bool CachedContentResultSet::CCRS_Cache
169 ::hasKnownLast() const
171 if( !m_pResult )
172 return false;
174 return ( m_pResult->FetchError & FetchError::ENDOFDATA )
175 && m_pResult->Orientation
176 && m_pResult->Rows.hasElements();
179 bool CachedContentResultSet::CCRS_Cache
180 ::hasCausedException( sal_Int32 nRow ) const
182 if( !m_pResult )
183 return false;
184 if( !( m_pResult->FetchError & FetchError::EXCEPTION ) )
185 return false;
187 sal_Int32 nEnd = m_pResult->StartIndex;
188 if( m_pResult->Orientation )
189 nEnd += m_pResult->Rows.getLength();
191 return nRow == nEnd+1;
194 Any& CachedContentResultSet::CCRS_Cache
195 ::getRowAny( sal_Int32 nRow )
197 if( !nRow )
198 throw SQLException();
199 if( !m_pResult )
200 throw SQLException();
201 if( !hasRow( nRow ) )
202 throw SQLException();
204 sal_Int32 nDiff = nRow - m_pResult->StartIndex;
205 if( nDiff < 0 )
206 nDiff *= -1;
208 return m_pResult->Rows.getArray()[nDiff];
211 void CachedContentResultSet::CCRS_Cache
212 ::remindMapped( sal_Int32 nRow )
214 //remind that this row was mapped
215 if( !m_pResult )
216 return;
217 sal_Int32 nDiff = nRow - m_pResult->StartIndex;
218 if( nDiff < 0 )
219 nDiff *= -1;
220 Sequence< sal_Bool >& rMappedReminder = getMappedReminder();
221 if( nDiff < rMappedReminder.getLength() )
223 sal_Bool* pMappedReminder = rMappedReminder.getArray();
224 pMappedReminder[nDiff] = true;
228 bool CachedContentResultSet::CCRS_Cache
229 ::isRowMapped( sal_Int32 nRow )
231 if( !m_pMappedReminder || !m_pResult )
232 return false;
233 sal_Int32 nDiff = nRow - m_pResult->StartIndex;
234 if( nDiff < 0 )
235 nDiff *= -1;
236 if( nDiff < m_pMappedReminder->getLength() )
237 return (*m_pMappedReminder)[nDiff];
238 return false;
241 Sequence< sal_Bool >& CachedContentResultSet::CCRS_Cache
242 ::getMappedReminder()
244 if( !m_pMappedReminder )
246 sal_Int32 nCount = m_pResult->Rows.getLength();
247 m_pMappedReminder.emplace( nCount );
248 std::fill_n(m_pMappedReminder->getArray(), m_pMappedReminder->getLength(), false);
250 return *m_pMappedReminder;
253 const Any& CachedContentResultSet::CCRS_Cache
254 ::getAny( sal_Int32 nRow, sal_Int32 nColumnIndex )
256 if( !nColumnIndex )
257 throw SQLException();
258 if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) )
260 Any& rRow = getRowAny( nRow );
261 Sequence< Any > aValue;
262 rRow >>= aValue;
263 if( m_xContentIdentifierMapping->mapRow( aValue ) )
265 rRow <<= aValue;
266 remindMapped( nRow );
268 else
269 m_xContentIdentifierMapping.clear();
271 auto & rowAny = getRowAny(nRow);
272 auto rRow = o3tl::doAccess<Sequence<Any>>(rowAny);
274 if( nColumnIndex > rRow->getLength() )
275 throw SQLException();
276 return (*rRow)[nColumnIndex-1];
279 OUString const & CachedContentResultSet::CCRS_Cache
280 ::getContentIdentifierString( sal_Int32 nRow )
284 if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) )
286 Any& rRow = getRowAny( nRow );
287 OUString aValue;
288 rRow >>= aValue;
289 rRow <<= m_xContentIdentifierMapping->mapContentIdentifierString( aValue );
290 remindMapped( nRow );
292 return *o3tl::doAccess<OUString>(getRowAny(nRow));
294 catch(const SQLException& ex)
296 css::uno::Any anyEx = cppu::getCaughtException();
297 throw css::lang::WrappedTargetRuntimeException( ex.Message,
298 css::uno::Reference< css::uno::XInterface >(),
299 anyEx );
303 Reference< XContentIdentifier > CachedContentResultSet::CCRS_Cache
304 ::getContentIdentifier( sal_Int32 nRow )
308 if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) )
310 Any& rRow = getRowAny( nRow );
311 Reference< XContentIdentifier > aValue;
312 rRow >>= aValue;
313 rRow <<= m_xContentIdentifierMapping->mapContentIdentifier( aValue );
314 remindMapped( nRow );
316 return *o3tl::doAccess<Reference<XContentIdentifier>>(getRowAny(nRow));
318 catch(const SQLException& ex)
320 css::uno::Any anyEx = cppu::getCaughtException();
321 throw css::lang::WrappedTargetRuntimeException( ex.Message,
322 css::uno::Reference< css::uno::XInterface >(),
323 anyEx );
327 Reference< XContent > CachedContentResultSet::CCRS_Cache
328 ::getContent( sal_Int32 nRow )
332 if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) )
334 Any& rRow = getRowAny( nRow );
335 Reference< XContent > aValue;
336 rRow >>= aValue;
337 rRow <<= m_xContentIdentifierMapping->mapContent( aValue );
338 remindMapped( nRow );
340 return *o3tl::doAccess<Reference<XContent>>(getRowAny(nRow));
342 catch (const SQLException& ex)
344 css::uno::Any anyEx = cppu::getCaughtException();
345 throw css::lang::WrappedTargetRuntimeException( ex.Message,
346 css::uno::Reference< css::uno::XInterface >(),
347 anyEx );
354 class CCRS_PropertySetInfo :
355 public cppu::OWeakObject,
356 public css::lang::XTypeProvider,
357 public css::beans::XPropertySetInfo
359 friend class CachedContentResultSet;
361 //my Properties
362 std::optional<Sequence< css::beans::Property >>
363 m_xProperties;
365 sal_Int32 m_nFetchSizePropertyHandle;
366 sal_Int32 m_nFetchDirectionPropertyHandle;
368 private:
369 sal_Int32
370 impl_getRemainedHandle() const;
372 bool
373 impl_queryProperty(
374 std::u16string_view rName
375 , css::beans::Property& rProp ) const;
376 sal_Int32
377 impl_getPos( std::u16string_view rName ) const;
379 static bool
380 impl_isMyPropertyName( std::u16string_view rName );
382 public:
383 explicit CCRS_PropertySetInfo( Reference<
384 XPropertySetInfo > const & xPropertySetInfoOrigin );
386 // XInterface
387 virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
388 virtual void SAL_CALL acquire()
389 noexcept override;
390 virtual void SAL_CALL release()
391 noexcept override;
393 // XTypeProvider
394 virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
395 virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
397 // XPropertySetInfo
398 virtual Sequence< css::beans::Property > SAL_CALL
399 getProperties() override;
401 virtual css::beans::Property SAL_CALL
402 getPropertyByName( const OUString& aName ) override;
404 virtual sal_Bool SAL_CALL
405 hasPropertyByName( const OUString& Name ) override;
408 //some helping variables ( names for my special properties )
409 const char16_t g_sPropertyNameForCount[] = u"RowCount";
410 const char16_t g_sPropertyNameForFinalCount[] = u"IsRowCountFinal";
411 constexpr OUString g_sPropertyNameForFetchSize(u"FetchSize"_ustr);
412 constexpr OUString g_sPropertyNameForFetchDirection(u"FetchDirection"_ustr);
414 CCRS_PropertySetInfo::CCRS_PropertySetInfo(
415 Reference< XPropertySetInfo > const & xInfo )
416 : m_nFetchSizePropertyHandle( -1 )
417 , m_nFetchDirectionPropertyHandle( -1 )
419 //initialize list of properties:
421 // it is required, that the received xInfo contains the two
422 // properties with names 'g_sPropertyNameForCount' and
423 // 'g_sPropertyNameForFinalCount'
425 if( xInfo.is() )
427 m_xProperties = xInfo->getProperties();
429 else
431 OSL_FAIL( "The received XPropertySetInfo doesn't contain required properties" );
432 m_xProperties.emplace();
435 //ensure, that we haven't got the Properties 'FetchSize' and 'Direction' twice:
436 sal_Int32 nFetchSize = impl_getPos( g_sPropertyNameForFetchSize );
437 sal_Int32 nFetchDirection = impl_getPos( g_sPropertyNameForFetchDirection );
438 sal_Int32 nDeleted = 0;
439 if( nFetchSize != -1 )
440 nDeleted++;
441 if( nFetchDirection != -1 )
442 nDeleted++;
444 Sequence< Property > aOrigProps( *m_xProperties );
445 sal_Int32 nOrigProps = aOrigProps.getLength();
447 m_xProperties->realloc( nOrigProps + 2 - nDeleted );//note that nDeleted is <= 2
448 auto pProperties = m_xProperties->getArray();
449 for( sal_Int32 n = 0, m = 0; n < nOrigProps; n++, m++ )
451 if( n == nFetchSize || n == nFetchDirection )
452 m--;
453 else
454 pProperties[ m ] = aOrigProps[ n ];
457 Property& rMyProp = pProperties[ nOrigProps - nDeleted ];
458 rMyProp.Name = g_sPropertyNameForFetchSize;
459 rMyProp.Type = cppu::UnoType<sal_Int32>::get();
460 rMyProp.Attributes = PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT;
462 if( nFetchSize != -1 )
463 m_nFetchSizePropertyHandle = aOrigProps[nFetchSize].Handle;
464 else
465 m_nFetchSizePropertyHandle = impl_getRemainedHandle();
467 rMyProp.Handle = m_nFetchSizePropertyHandle;
471 Property& rMyProp = pProperties[ nOrigProps - nDeleted + 1 ];
472 rMyProp.Name = g_sPropertyNameForFetchDirection;
473 rMyProp.Type = cppu::UnoType<sal_Bool>::get();
474 rMyProp.Attributes = PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT;
476 m_nFetchDirectionPropertyHandle = rMyProp.Handle;
480 // XInterface methods.
482 void SAL_CALL CCRS_PropertySetInfo::acquire()
483 noexcept
485 OWeakObject::acquire();
488 void SAL_CALL CCRS_PropertySetInfo::release()
489 noexcept
491 OWeakObject::release();
494 css::uno::Any SAL_CALL CCRS_PropertySetInfo::queryInterface( const css::uno::Type & rType )
496 css::uno::Any aRet = cppu::queryInterface( rType,
497 static_cast< XTypeProvider* >(this),
498 static_cast< XPropertySetInfo* >(this)
500 return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
503 // XTypeProvider methods.
505 //list all interfaces exclusive baseclasses
506 XTYPEPROVIDER_IMPL_2( CCRS_PropertySetInfo
507 , XTypeProvider
508 , XPropertySetInfo
511 // XPropertySetInfo methods.
513 //virtual
514 Sequence< Property > SAL_CALL CCRS_PropertySetInfo
515 ::getProperties()
517 return *m_xProperties;
520 //virtual
521 Property SAL_CALL CCRS_PropertySetInfo
522 ::getPropertyByName( const OUString& aName )
524 Property aProp;
525 if ( impl_queryProperty( aName, aProp ) )
526 return aProp;
528 throw UnknownPropertyException(aName);
531 //virtual
532 sal_Bool SAL_CALL CCRS_PropertySetInfo
533 ::hasPropertyByName( const OUString& Name )
535 return ( impl_getPos( Name ) != -1 );
539 // impl_ methods.
542 sal_Int32 CCRS_PropertySetInfo
543 ::impl_getPos( std::u16string_view rName ) const
545 for( sal_Int32 nN = m_xProperties->getLength(); nN--; )
547 const Property& rMyProp = (*m_xProperties)[nN];
548 if( rMyProp.Name == rName )
549 return nN;
551 return -1;
554 bool CCRS_PropertySetInfo
555 ::impl_queryProperty( std::u16string_view rName, Property& rProp ) const
557 for (const Property& rMyProp : *m_xProperties)
559 if( rMyProp.Name == rName )
561 rProp.Name = rMyProp.Name;
562 rProp.Handle = rMyProp.Handle;
563 rProp.Type = rMyProp.Type;
564 rProp.Attributes = rMyProp.Attributes;
566 return true;
569 return false;
572 //static
573 bool CCRS_PropertySetInfo
574 ::impl_isMyPropertyName( std::u16string_view rPropertyName )
576 return ( rPropertyName == g_sPropertyNameForCount
577 || rPropertyName == g_sPropertyNameForFinalCount
578 || rPropertyName == g_sPropertyNameForFetchSize
579 || rPropertyName == g_sPropertyNameForFetchDirection );
582 sal_Int32 CCRS_PropertySetInfo
583 ::impl_getRemainedHandle( ) const
585 sal_Int32 nHandle = 1;
587 if( !m_xProperties )
589 OSL_FAIL( "Properties not initialized yet" );
590 return nHandle;
592 bool bFound = true;
593 while( bFound )
595 bFound = false;
596 for (const auto& rProp : *m_xProperties)
598 if( nHandle == rProp.Handle )
600 bFound = true;
601 nHandle++;
602 break;
606 return nHandle;
612 CachedContentResultSet::CachedContentResultSet(
613 const Reference< XComponentContext > & rxContext
614 , const Reference< XResultSet > & xOrigin
615 , const Reference< XContentIdentifierMapping > &
616 xContentIdentifierMapping )
617 : ContentResultSetWrapper( xOrigin )
619 , m_xContext( rxContext )
621 , m_xContentIdentifierMapping( xContentIdentifierMapping )
622 , m_nRow( 0 ) // Position is one-based. Zero means: before first element.
623 , m_bAfterLast( false )
624 , m_nLastAppliedPos( 0 )
625 , m_bAfterLastApplied( false )
626 , m_nKnownCount( 0 )
627 , m_bFinalCount( false )
628 , m_nFetchSize(
629 COMSUNSTARUCBCCRS_DEFAULT_FETCH_SIZE )
630 , m_nFetchDirection(
631 COMSUNSTARUCBCCRS_DEFAULT_FETCH_DIRECTION )
633 , m_bLastReadWasFromCache( false )
634 , m_bLastCachedReadWasNull( true )
635 , m_aCache( m_xContentIdentifierMapping )
636 , m_aCacheContentIdentifierString( m_xContentIdentifierMapping )
637 , m_aCacheContentIdentifier( m_xContentIdentifierMapping )
638 , m_aCacheContent( m_xContentIdentifierMapping )
639 , m_bTriedToGetTypeConverter( false )
641 m_xFetchProvider.set( m_xResultSetOrigin, UNO_QUERY );
642 OSL_ENSURE( m_xFetchProvider.is(), "interface XFetchProvider is required" );
644 m_xFetchProviderForContentAccess.set( m_xResultSetOrigin, UNO_QUERY );
645 OSL_ENSURE( m_xFetchProviderForContentAccess.is(), "interface XFetchProviderForContentAccess is required" );
647 impl_init();
650 CachedContentResultSet::~CachedContentResultSet()
652 impl_deinit();
653 //do not delete m_pMyPropSetInfo, cause it is hold via reference
657 // impl_ methods.
660 bool CachedContentResultSet
661 ::applyPositionToOrigin( std::unique_lock<std::mutex>& rGuard, sal_Int32 nRow )
663 impl_EnsureNotDisposed(rGuard);
666 @returns
667 <TRUE/> if the cursor is on a valid row; <FALSE/> if it is off
668 the result set.
671 OSL_ENSURE( nRow >= 0, "only positive values supported" );
672 if( !m_xResultSetOrigin.is() )
674 OSL_FAIL( "broadcaster was disposed already" );
675 return false;
677 // OSL_ENSURE( nRow <= m_nKnownCount, "don't step into regions you don't know with this method" );
679 sal_Int32 nLastAppliedPos = m_nLastAppliedPos;
680 bool bAfterLastApplied = m_bAfterLastApplied;
681 bool bAfterLast = m_bAfterLast;
682 sal_Int32 nForwardOnly = m_nForwardOnly;
684 rGuard.unlock();
686 if( bAfterLastApplied || nLastAppliedPos != nRow )
688 if( nForwardOnly == 1 )
690 if( bAfterLastApplied || bAfterLast || !nRow || nRow < nLastAppliedPos )
691 throw SQLException();
693 sal_Int32 nN = nRow - nLastAppliedPos;
694 sal_Int32 nM;
695 for( nM = 0; nN--; nM++ )
697 if( !m_xResultSetOrigin->next() )
698 break;
701 rGuard.lock();
702 m_nLastAppliedPos += nM;
703 m_bAfterLastApplied = nRow != m_nLastAppliedPos;
704 return nRow == m_nLastAppliedPos;
707 if( !nRow ) //absolute( 0 ) will throw exception
709 m_xResultSetOrigin->beforeFirst();
711 rGuard.lock();
712 m_nLastAppliedPos = 0;
713 m_bAfterLastApplied = false;
714 return false;
718 //move absolute, if !nLastAppliedPos
719 //because move relative would throw exception
720 if( !nLastAppliedPos || bAfterLast || bAfterLastApplied )
722 bool bValid = m_xResultSetOrigin->absolute( nRow );
724 rGuard.lock();
725 m_nLastAppliedPos = nRow;
726 m_bAfterLastApplied = !bValid;
727 return bValid;
729 else
731 bool bValid = m_xResultSetOrigin->relative( nRow - nLastAppliedPos );
733 rGuard.lock();
734 m_nLastAppliedPos += ( nRow - nLastAppliedPos );
735 m_bAfterLastApplied = !bValid;
736 return bValid;
739 catch (const SQLException&)
741 rGuard.lock();
742 if( !bAfterLastApplied && !bAfterLast && nRow > nLastAppliedPos && impl_isForwardOnly(rGuard) )
744 sal_Int32 nN = nRow - nLastAppliedPos;
745 sal_Int32 nM;
746 for( nM = 0; nN--; nM++ )
748 if( !m_xResultSetOrigin->next() )
749 break;
752 m_nLastAppliedPos += nM;
753 m_bAfterLastApplied = nRow != m_nLastAppliedPos;
755 else
756 throw;
759 return nRow == m_nLastAppliedPos;
761 return true;
765 //define for fetching data
768 #define FETCH_XXX( aCache, fetchInterface, fetchMethod ) \
769 bool bDirection = !!( \
770 nFetchDirection != FetchDirection::REVERSE ); \
771 FetchResult aResult = \
772 fetchInterface->fetchMethod( nRow, nFetchSize, bDirection ); \
773 aCache.loadData( aResult ); \
774 sal_Int32 nMax = aCache.getMaxRow(); \
775 sal_Int32 nCurCount = m_nKnownCount; \
776 bool bIsFinalCount = aCache.hasKnownLast(); \
777 bool bCurIsFinalCount = m_bFinalCount; \
778 if( nMax > nCurCount ) \
779 impl_changeRowCount( rGuard, nCurCount, nMax ); \
780 if( bIsFinalCount && !bCurIsFinalCount ) \
781 impl_changeIsRowCountFinal( rGuard, bCurIsFinalCount, bIsFinalCount );
783 void CachedContentResultSet
784 ::impl_fetchData( std::unique_lock<std::mutex>& rGuard, sal_Int32 nRow
785 , sal_Int32 nFetchSize, sal_Int32 nFetchDirection )
787 FETCH_XXX( m_aCache, m_xFetchProvider, fetch );
790 void CachedContentResultSet
791 ::impl_changeRowCount( std::unique_lock<std::mutex>& rGuard, sal_Int32 nOld, sal_Int32 nNew )
793 OSL_ENSURE( nNew > nOld, "RowCount only can grow" );
794 if( nNew <= nOld )
795 return;
797 //create PropertyChangeEvent and set value
798 PropertyChangeEvent aEvt;
799 aEvt.Source = static_cast< XPropertySet * >( this );
800 aEvt.Further = false;
801 aEvt.OldValue <<= nOld;
802 aEvt.NewValue <<= nNew;
804 m_nKnownCount = nNew;
806 //send PropertyChangeEvent to listeners
807 impl_notifyPropertyChangeListeners( rGuard, aEvt );
810 void CachedContentResultSet
811 ::impl_changeIsRowCountFinal( std::unique_lock<std::mutex>& rGuard, bool bOld, bool bNew )
813 OSL_ENSURE( !bOld && bNew, "This change is not allowed for IsRowCountFinal" );
814 if( bOld || !bNew )
815 return;
817 //create PropertyChangeEvent and set value
818 PropertyChangeEvent aEvt;
819 aEvt.Source = static_cast< XPropertySet * >( this );
820 aEvt.Further = false;
821 aEvt.OldValue <<= bOld;
822 aEvt.NewValue <<= bNew;
824 m_bFinalCount = bNew;
826 //send PropertyChangeEvent to listeners
827 impl_notifyPropertyChangeListeners( rGuard, aEvt );
830 bool CachedContentResultSet
831 ::impl_isKnownValidPosition( std::unique_lock<std::mutex>& /*rGuard*/, sal_Int32 nRow ) const
833 return m_nKnownCount && nRow
834 && nRow <= m_nKnownCount;
837 bool CachedContentResultSet
838 ::impl_isKnownInvalidPosition( std::unique_lock<std::mutex>& /*rGuard*/, sal_Int32 nRow ) const
840 if( !nRow )
841 return true;
842 if( !m_bFinalCount )
843 return false;
844 return nRow > m_nKnownCount;
848 //virtual
849 void CachedContentResultSet
850 ::impl_initPropertySetInfo(std::unique_lock<std::mutex>& rGuard)
852 ContentResultSetWrapper::impl_initPropertySetInfo(rGuard);
854 if( m_xMyPropertySetInfo.is() )
855 return;
856 m_xMyPropertySetInfo = new CCRS_PropertySetInfo( m_xPropertySetInfo );
857 m_xPropertySetInfo = m_xMyPropertySetInfo.get();
861 // XInterface methods.
862 void SAL_CALL CachedContentResultSet::acquire()
863 noexcept
865 OWeakObject::acquire();
868 void SAL_CALL CachedContentResultSet::release()
869 noexcept
871 OWeakObject::release();
874 Any SAL_CALL CachedContentResultSet
875 ::queryInterface( const Type& rType )
877 //list all interfaces inclusive baseclasses of interfaces
879 Any aRet = ContentResultSetWrapper::queryInterface( rType );
880 if( aRet.hasValue() )
881 return aRet;
883 aRet = cppu::queryInterface( rType,
884 static_cast< XTypeProvider* >( this ),
885 static_cast< XServiceInfo* >( this ) );
887 return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
891 // XTypeProvider methods.
893 //list all interfaces exclusive baseclasses
894 XTYPEPROVIDER_IMPL_11( CachedContentResultSet
895 , XTypeProvider
896 , XServiceInfo
897 , XComponent
898 , XCloseable
899 , XResultSetMetaDataSupplier
900 , XPropertySet
902 , XPropertyChangeListener
903 , XVetoableChangeListener
905 , XContentAccess
907 , XResultSet
908 , XRow );
911 // XServiceInfo methods.
913 OUString SAL_CALL CachedContentResultSet::getImplementationName()
915 return u"com.sun.star.comp.ucb.CachedContentResultSet"_ustr;
918 sal_Bool SAL_CALL CachedContentResultSet::supportsService( const OUString& ServiceName )
920 return cppu::supportsService( this, ServiceName );
923 css::uno::Sequence< OUString > SAL_CALL CachedContentResultSet::getSupportedServiceNames()
925 return { u"com.sun.star.ucb.CachedContentResultSet"_ustr };
930 // XPropertySet methods. ( inherited )
933 // virtual
934 void CachedContentResultSet
935 ::setPropertyValueImpl( std::unique_lock<std::mutex>& rGuard, const OUString& aPropertyName, const Any& aValue )
937 impl_EnsureNotDisposed(rGuard);
939 if( !getPropertySetInfoImpl(rGuard).is() )
941 OSL_FAIL( "broadcaster was disposed already" );
942 throw UnknownPropertyException();
945 Property aProp = m_xMyPropertySetInfo->getPropertyByName( aPropertyName );
946 //throws UnknownPropertyException, if so
948 if( aProp.Attributes & PropertyAttribute::READONLY )
950 //It is assumed, that the properties
951 //'RowCount' and 'IsRowCountFinal' are readonly!
952 throw IllegalArgumentException();
954 if( aProp.Name == g_sPropertyNameForFetchDirection )
956 //check value
957 sal_Int32 nNew;
958 if( !( aValue >>= nNew ) )
960 throw IllegalArgumentException();
963 if( nNew == FetchDirection::UNKNOWN )
965 nNew = COMSUNSTARUCBCCRS_DEFAULT_FETCH_DIRECTION;
967 else if( nNew != FetchDirection::FORWARD && nNew != FetchDirection::REVERSE )
969 throw IllegalArgumentException();
972 //create PropertyChangeEvent and set value
973 PropertyChangeEvent aEvt;
974 aEvt.Source = static_cast< XPropertySet * >( this );
975 aEvt.PropertyName = aPropertyName;
976 aEvt.Further = false;
977 aEvt.PropertyHandle = m_xMyPropertySetInfo->
978 m_nFetchDirectionPropertyHandle;
979 aEvt.OldValue <<= m_nFetchDirection;
980 aEvt.NewValue <<= nNew;
982 m_nFetchDirection = nNew;
984 //send PropertyChangeEvent to listeners
985 impl_notifyPropertyChangeListeners( rGuard, aEvt );
987 else if( aProp.Name == g_sPropertyNameForFetchSize )
989 //check value
990 sal_Int32 nNew;
991 if( !( aValue >>= nNew ) )
993 throw IllegalArgumentException();
996 if( nNew < 0 )
998 nNew = COMSUNSTARUCBCCRS_DEFAULT_FETCH_SIZE;
1001 //create PropertyChangeEvent and set value
1002 PropertyChangeEvent aEvt;
1003 aEvt.Source = static_cast< XPropertySet * >( this );
1004 aEvt.PropertyName = aPropertyName;
1005 aEvt.Further = false;
1006 aEvt.PropertyHandle = m_xMyPropertySetInfo->
1007 m_nFetchSizePropertyHandle;
1008 aEvt.OldValue <<= m_nFetchSize;
1009 aEvt.NewValue <<= nNew;
1011 m_nFetchSize = nNew;
1013 //send PropertyChangeEvent to listeners
1014 impl_notifyPropertyChangeListeners( rGuard, aEvt );
1016 else
1018 impl_init_xPropertySetOrigin(rGuard);
1019 if( !m_xPropertySetOrigin.is() )
1021 OSL_FAIL( "broadcaster was disposed already" );
1022 return;
1024 m_xPropertySetOrigin->setPropertyValue( aPropertyName, aValue );
1029 // virtual
1030 Any SAL_CALL CachedContentResultSet
1031 ::getPropertyValue( const OUString& rPropertyName )
1033 std::unique_lock aGuard(m_aMutex);
1034 impl_EnsureNotDisposed(aGuard);
1036 if( !getPropertySetInfoImpl(aGuard).is() )
1038 OSL_FAIL( "broadcaster was disposed already" );
1039 throw UnknownPropertyException();
1042 m_xMyPropertySetInfo->getPropertyByName( rPropertyName );
1043 //throws UnknownPropertyException, if so
1045 Any aValue;
1046 if( rPropertyName == g_sPropertyNameForCount )
1048 aValue <<= m_nKnownCount;
1050 else if( rPropertyName == g_sPropertyNameForFinalCount )
1052 aValue <<= m_bFinalCount;
1054 else if( rPropertyName == g_sPropertyNameForFetchSize )
1056 aValue <<= m_nFetchSize;
1058 else if( rPropertyName == g_sPropertyNameForFetchDirection )
1060 aValue <<= m_nFetchDirection;
1062 else
1064 impl_init_xPropertySetOrigin(aGuard);
1065 if( !m_xPropertySetOrigin.is() )
1067 OSL_FAIL( "broadcaster was disposed already" );
1068 throw UnknownPropertyException();
1070 aGuard.unlock();
1071 aValue = m_xPropertySetOrigin->getPropertyValue( rPropertyName );
1073 return aValue;
1077 // own methods. ( inherited )
1080 //virtual, only called from ContentResultSetWrapperListener
1081 void CachedContentResultSet
1082 ::impl_disposing( const EventObject& rEventObject )
1085 std::unique_lock aGuard(m_aMutex);
1086 impl_EnsureNotDisposed(aGuard);
1087 //release all references to the broadcaster:
1088 m_xFetchProvider.clear();
1089 m_xFetchProviderForContentAccess.clear();
1091 ContentResultSetWrapper::impl_disposing( rEventObject );
1094 //virtual, only called from ContentResultSetWrapperListener
1095 void CachedContentResultSet
1096 ::impl_propertyChange( const PropertyChangeEvent& rEvt )
1098 std::unique_lock aGuard(m_aMutex);
1099 impl_EnsureNotDisposed(aGuard);
1101 PropertyChangeEvent aEvt( rEvt );
1102 aEvt.Source = static_cast< XPropertySet * >( this );
1103 aEvt.Further = false;
1106 if( CCRS_PropertySetInfo
1107 ::impl_isMyPropertyName( rEvt.PropertyName ) )
1109 //don't notify foreign events on fetchsize and fetchdirection
1110 if( aEvt.PropertyName == g_sPropertyNameForFetchSize
1111 || aEvt.PropertyName == g_sPropertyNameForFetchDirection )
1112 return;
1114 //adjust my props 'RowCount' and 'IsRowCountFinal'
1115 if( aEvt.PropertyName == g_sPropertyNameForCount )
1116 {//RowCount changed
1118 //check value
1119 sal_Int32 nNew = 0;
1120 if( !( aEvt.NewValue >>= nNew ) )
1122 OSL_FAIL( "PropertyChangeEvent contains wrong data" );
1123 return;
1126 impl_changeRowCount( aGuard, m_nKnownCount, nNew );
1128 else if( aEvt.PropertyName == g_sPropertyNameForFinalCount )
1129 {//IsRowCountFinal changed
1131 //check value
1132 bool bNew = false;
1133 if( !( aEvt.NewValue >>= bNew ) )
1135 OSL_FAIL( "PropertyChangeEvent contains wrong data" );
1136 return;
1138 impl_changeIsRowCountFinal( aGuard, m_bFinalCount, bNew );
1140 return;
1144 impl_notifyPropertyChangeListeners( aGuard, aEvt );
1148 //virtual, only called from ContentResultSetWrapperListener
1149 void CachedContentResultSet
1150 ::impl_vetoableChange( const PropertyChangeEvent& rEvt )
1152 std::unique_lock aGuard(m_aMutex);
1153 impl_EnsureNotDisposed(aGuard);
1155 //don't notify events on my properties, cause they are not vetoable
1156 if( CCRS_PropertySetInfo
1157 ::impl_isMyPropertyName( rEvt.PropertyName ) )
1159 return;
1163 PropertyChangeEvent aEvt( rEvt );
1164 aEvt.Source = static_cast< XPropertySet * >( this );
1165 aEvt.Further = false;
1167 impl_notifyVetoableChangeListeners( aGuard, aEvt );
1171 // XContentAccess methods. ( inherited ) ( -- position dependent )
1174 #define XCONTENTACCESS_queryXXX( queryXXX, XXX, TYPE ) \
1175 impl_EnsureNotDisposed(rGuard); \
1176 sal_Int32 nRow = m_nRow; \
1177 sal_Int32 nFetchSize = m_nFetchSize; \
1178 sal_Int32 nFetchDirection = m_nFetchDirection; \
1179 if( !m_aCache##XXX.hasRow( nRow ) ) \
1181 try \
1183 if( !m_aCache##XXX.hasCausedException( nRow ) ) \
1185 if( !m_xFetchProviderForContentAccess.is() ) \
1187 OSL_FAIL( "broadcaster was disposed already" ); \
1188 throw RuntimeException(); \
1190 if( impl_isForwardOnly(rGuard) ) \
1191 applyPositionToOrigin( rGuard, nRow ); \
1193 FETCH_XXX( m_aCache##XXX, m_xFetchProviderForContentAccess, fetch##XXX##s ); \
1195 if( !m_aCache##XXX.hasRow( nRow ) ) \
1197 applyPositionToOrigin( rGuard, nRow ); \
1198 TYPE aRet = ContentResultSetWrapper::query##XXX();\
1199 if( m_xContentIdentifierMapping.is() ) \
1200 return m_xContentIdentifierMapping->map##XXX( aRet );\
1201 return aRet; \
1204 catch (const RuntimeException&) \
1206 throw; \
1208 catch (const Exception& e) \
1210 Any a(cppu::getCaughtException()); \
1211 throw WrappedTargetRuntimeException( \
1212 "wrapped Exception " + e.Message, \
1213 Reference<XInterface>(), a); \
1216 return m_aCache##XXX.get##XXX( nRow );
1218 // virtual
1219 OUString CachedContentResultSet
1220 ::queryContentIdentifierStringImpl(std::unique_lock<std::mutex>& rGuard)
1222 XCONTENTACCESS_queryXXX( queryContentIdentifierString, ContentIdentifierString, OUString )
1225 // virtual
1226 Reference<XContentIdentifier> CachedContentResultSet
1227 ::queryContentIdentifierImpl(std::unique_lock<std::mutex>& rGuard)
1229 XCONTENTACCESS_queryXXX( queryContentIdentifier, ContentIdentifier, Reference< XContentIdentifier > )
1232 // virtual
1233 Reference<XContent> CachedContentResultSet
1234 ::queryContentImpl(std::unique_lock<std::mutex>& rGuard)
1236 XCONTENTACCESS_queryXXX( queryContent, Content, Reference< XContent > )
1239 // XResultSet methods. ( inherited )
1241 //virtual
1243 sal_Bool SAL_CALL CachedContentResultSet
1244 ::next()
1246 std::unique_lock aGuard(m_aMutex);
1247 impl_EnsureNotDisposed(aGuard);
1249 //after last
1250 if( m_bAfterLast )
1251 return false;
1252 //last
1253 aGuard.unlock();
1254 if( isLast() )
1256 aGuard.lock();
1257 m_nRow++;
1258 m_bAfterLast = true;
1259 return false;
1261 aGuard.lock();
1262 //known valid position
1263 if( impl_isKnownValidPosition( aGuard, m_nRow + 1 ) )
1265 m_nRow++;
1266 return true;
1269 //unknown position
1270 sal_Int32 nRow = m_nRow;
1272 bool bValid = applyPositionToOrigin( aGuard, nRow + 1 );
1274 m_nRow = nRow + 1;
1275 m_bAfterLast = !bValid;
1276 return bValid;
1279 //virtual
1280 sal_Bool SAL_CALL CachedContentResultSet
1281 ::previous()
1283 std::unique_lock aGuard(m_aMutex);
1284 impl_EnsureNotDisposed(aGuard);
1286 if( impl_isForwardOnly(aGuard) )
1287 throw SQLException();
1289 //before first ?:
1290 if( !m_bAfterLast && !m_nRow )
1291 return false;
1292 //first ?:
1293 if( !m_bAfterLast && m_nKnownCount && m_nRow == 1 )
1295 m_nRow--;
1296 m_bAfterLast = false;
1297 return false;
1299 //known valid position ?:
1300 if( impl_isKnownValidPosition( aGuard, m_nRow - 1 ) )
1302 m_nRow--;
1303 m_bAfterLast = false;
1304 return true;
1306 //unknown position:
1307 sal_Int32 nRow = m_nRow;
1309 bool bValid = applyPositionToOrigin( aGuard, nRow - 1 );
1311 m_nRow = nRow - 1;
1312 m_bAfterLast = false;
1313 return bValid;
1316 //virtual
1317 sal_Bool SAL_CALL CachedContentResultSet
1318 ::absolute( sal_Int32 row )
1320 std::unique_lock aGuard(m_aMutex);
1321 impl_EnsureNotDisposed(aGuard);
1323 if( !row )
1324 throw SQLException();
1326 if( impl_isForwardOnly(aGuard) )
1327 throw SQLException();
1329 if( !m_xResultSetOrigin.is() )
1331 OSL_FAIL( "broadcaster was disposed already" );
1332 return false;
1334 if( row < 0 )
1336 if( m_bFinalCount )
1338 sal_Int32 nNewRow = m_nKnownCount + 1 + row;
1339 bool bValid = true;
1340 if( nNewRow <= 0 )
1342 nNewRow = 0;
1343 bValid = false;
1345 m_nRow = nNewRow;
1346 m_bAfterLast = false;
1347 return bValid;
1349 //unknown final count:
1350 aGuard.unlock();
1352 bool bValid = m_xResultSetOrigin->absolute( row );
1354 aGuard.lock();
1355 if( m_bFinalCount )
1357 sal_Int32 nNewRow = m_nKnownCount + 1 + row;
1358 if( nNewRow < 0 )
1359 nNewRow = 0;
1360 m_nLastAppliedPos = nNewRow;
1361 m_nRow = nNewRow;
1362 m_bAfterLastApplied = m_bAfterLast = false;
1363 return bValid;
1365 aGuard.unlock();
1367 sal_Int32 nCurRow = m_xResultSetOrigin->getRow();
1369 aGuard.lock();
1370 m_nLastAppliedPos = nCurRow;
1371 m_nRow = nCurRow;
1372 m_bAfterLast = false;
1373 return nCurRow != 0;
1375 //row > 0:
1376 if( m_bFinalCount )
1378 if( row > m_nKnownCount )
1380 m_nRow = m_nKnownCount + 1;
1381 m_bAfterLast = true;
1382 return false;
1384 m_nRow = row;
1385 m_bAfterLast = false;
1386 return true;
1388 //unknown new position:
1389 aGuard.unlock();
1391 bool bValid = m_xResultSetOrigin->absolute( row );
1393 aGuard.lock();
1394 if( m_bFinalCount )
1396 sal_Int32 nNewRow = row;
1397 if( nNewRow > m_nKnownCount )
1399 nNewRow = m_nKnownCount + 1;
1400 m_bAfterLastApplied = m_bAfterLast = true;
1402 else
1403 m_bAfterLastApplied = m_bAfterLast = false;
1405 m_nLastAppliedPos = nNewRow;
1406 m_nRow = nNewRow;
1407 return bValid;
1409 aGuard.unlock();
1411 sal_Int32 nCurRow = m_xResultSetOrigin->getRow();
1412 bool bIsAfterLast = m_xResultSetOrigin->isAfterLast();
1414 aGuard.lock();
1415 m_nLastAppliedPos = nCurRow;
1416 m_nRow = nCurRow;
1417 m_bAfterLastApplied = m_bAfterLast = bIsAfterLast;
1418 return nCurRow && !bIsAfterLast;
1421 //virtual
1422 sal_Bool SAL_CALL CachedContentResultSet
1423 ::relative( sal_Int32 rows )
1425 std::unique_lock aGuard(m_aMutex);
1426 impl_EnsureNotDisposed(aGuard);
1428 if( impl_isForwardOnly(aGuard) )
1429 throw SQLException();
1431 if( m_bAfterLast || impl_isKnownInvalidPosition( aGuard, m_nRow ) )
1432 throw SQLException();
1434 if( !rows )
1435 return true;
1437 sal_Int32 nNewRow = m_nRow + rows;
1438 if( nNewRow < 0 )
1439 nNewRow = 0;
1441 if( impl_isKnownValidPosition( aGuard, nNewRow ) )
1443 m_nRow = nNewRow;
1444 m_bAfterLast = false;
1445 return true;
1447 else
1449 //known invalid new position:
1450 if( nNewRow == 0 )
1452 m_bAfterLast = false;
1453 m_nRow = 0;
1454 return false;
1456 if( m_bFinalCount && nNewRow > m_nKnownCount )
1458 m_bAfterLast = true;
1459 m_nRow = m_nKnownCount + 1;
1460 return false;
1462 //unknown new position:
1463 bool bValid = applyPositionToOrigin( aGuard, nNewRow );
1464 m_nRow = nNewRow;
1465 m_bAfterLast = !bValid; // only nNewRow > 0 possible here
1466 return bValid;
1471 //virtual
1472 sal_Bool SAL_CALL CachedContentResultSet
1473 ::first()
1475 std::unique_lock aGuard(m_aMutex);
1476 impl_EnsureNotDisposed(aGuard);
1478 if( impl_isForwardOnly(aGuard) )
1479 throw SQLException();
1481 if( impl_isKnownValidPosition( aGuard, 1 ) )
1483 m_nRow = 1;
1484 m_bAfterLast = false;
1485 return true;
1487 if( impl_isKnownInvalidPosition( aGuard, 1 ) )
1489 m_nRow = 1;
1490 m_bAfterLast = false;
1491 return false;
1493 //unknown position
1494 bool bValid = applyPositionToOrigin( aGuard, 1 );
1495 m_nRow = 1;
1496 m_bAfterLast = false;
1497 return bValid;
1500 //virtual
1501 sal_Bool SAL_CALL CachedContentResultSet
1502 ::last()
1504 std::unique_lock aGuard(m_aMutex);
1505 impl_EnsureNotDisposed(aGuard);
1507 if( impl_isForwardOnly(aGuard) )
1508 throw SQLException();
1510 if( m_bFinalCount )
1512 m_nRow = m_nKnownCount;
1513 m_bAfterLast = false;
1514 return m_nKnownCount != 0;
1516 //unknown position
1517 if( !m_xResultSetOrigin.is() )
1519 OSL_FAIL( "broadcaster was disposed already" );
1520 return false;
1522 aGuard.unlock();
1524 bool bValid = m_xResultSetOrigin->last();
1526 aGuard.lock();
1527 m_bAfterLastApplied = m_bAfterLast = false;
1528 if( m_bFinalCount )
1530 m_nLastAppliedPos = m_nKnownCount;
1531 m_nRow = m_nKnownCount;
1532 return bValid;
1534 aGuard.unlock();
1536 sal_Int32 nCurRow = m_xResultSetOrigin->getRow();
1538 aGuard.lock();
1539 m_nLastAppliedPos = nCurRow;
1540 m_nRow = nCurRow;
1541 OSL_ENSURE( nCurRow >= m_nKnownCount, "position of last row < known Count, that could not be" );
1542 m_nKnownCount = nCurRow;
1543 m_bFinalCount = true;
1544 return nCurRow != 0;
1547 //virtual
1548 void SAL_CALL CachedContentResultSet
1549 ::beforeFirst()
1551 std::unique_lock aGuard(m_aMutex);
1552 impl_EnsureNotDisposed(aGuard);
1554 if( impl_isForwardOnly(aGuard) )
1555 throw SQLException();
1557 m_nRow = 0;
1558 m_bAfterLast = false;
1561 //virtual
1562 void SAL_CALL CachedContentResultSet
1563 ::afterLast()
1565 std::unique_lock aGuard(m_aMutex);
1566 impl_EnsureNotDisposed(aGuard);
1568 if( impl_isForwardOnly(aGuard) )
1569 throw SQLException();
1571 m_nRow = 1;
1572 m_bAfterLast = true;
1575 //virtual
1576 sal_Bool SAL_CALL CachedContentResultSet
1577 ::isAfterLast()
1579 std::unique_lock aGuard(m_aMutex);
1580 impl_EnsureNotDisposed(aGuard);
1582 if( !m_bAfterLast )
1583 return false;
1584 if( m_nKnownCount )
1585 return m_bAfterLast;
1586 if( m_bFinalCount )
1587 return false;
1589 if( !m_xResultSetOrigin.is() )
1591 OSL_FAIL( "broadcaster was disposed already" );
1592 return false;
1594 aGuard.unlock();
1596 //find out whether the original resultset contains rows or not
1597 m_xResultSetOrigin->afterLast();
1599 aGuard.lock();
1600 m_bAfterLastApplied = true;
1601 aGuard.unlock();
1603 return m_xResultSetOrigin->isAfterLast();
1606 //virtual
1607 sal_Bool SAL_CALL CachedContentResultSet
1608 ::isBeforeFirst()
1610 std::unique_lock aGuard(m_aMutex);
1611 impl_EnsureNotDisposed(aGuard);
1613 if( m_bAfterLast )
1614 return false;
1615 if( m_nRow )
1616 return false;
1617 if( m_nKnownCount )
1618 return true;
1619 if( m_bFinalCount )
1620 return false;
1622 if( !m_xResultSetOrigin.is() )
1624 OSL_FAIL( "broadcaster was disposed already" );
1625 return false;
1627 aGuard.unlock();
1629 //find out whether the original resultset contains rows or not
1630 m_xResultSetOrigin->beforeFirst();
1632 aGuard.lock();
1633 m_bAfterLastApplied = false;
1634 m_nLastAppliedPos = 0;
1635 aGuard.unlock();
1637 return m_xResultSetOrigin->isBeforeFirst();
1640 //virtual
1641 sal_Bool SAL_CALL CachedContentResultSet
1642 ::isFirst()
1644 std::unique_lock aGuard(m_aMutex);
1645 impl_EnsureNotDisposed(aGuard);
1647 sal_Int32 nRow = 0;
1648 Reference< XResultSet > xResultSetOrigin;
1650 if( m_bAfterLast )
1651 return false;
1652 if( m_nRow != 1 )
1653 return false;
1654 if( m_nKnownCount )
1655 return true;
1656 if( m_bFinalCount )
1657 return false;
1659 nRow = m_nRow;
1660 xResultSetOrigin = m_xResultSetOrigin;
1662 //need to ask origin
1663 if( !applyPositionToOrigin( aGuard, nRow ) )
1664 return false;
1665 aGuard.unlock();
1666 return xResultSetOrigin->isFirst();
1669 //virtual
1670 sal_Bool SAL_CALL CachedContentResultSet
1671 ::isLast()
1673 std::unique_lock aGuard(m_aMutex);
1674 impl_EnsureNotDisposed(aGuard);
1676 sal_Int32 nRow = 0;
1677 Reference< XResultSet > xResultSetOrigin;
1678 if( m_bAfterLast )
1679 return false;
1680 if( m_nRow < m_nKnownCount )
1681 return false;
1682 if( m_bFinalCount )
1683 return m_nKnownCount && m_nRow == m_nKnownCount;
1685 nRow = m_nRow;
1686 xResultSetOrigin = m_xResultSetOrigin;
1688 //need to ask origin
1689 if( !applyPositionToOrigin( aGuard, nRow ) )
1690 return false;
1691 aGuard.unlock();
1692 return xResultSetOrigin->isLast();
1696 //virtual
1697 sal_Int32 SAL_CALL CachedContentResultSet
1698 ::getRow()
1700 std::unique_lock aGuard(m_aMutex);
1701 impl_EnsureNotDisposed(aGuard);
1703 if( m_bAfterLast )
1704 return 0;
1705 return m_nRow;
1708 //virtual
1709 void SAL_CALL CachedContentResultSet
1710 ::refreshRow()
1712 std::unique_lock aGuard(m_aMutex);
1713 impl_EnsureNotDisposed(aGuard);
1715 //the ContentResultSet is static and will not change
1716 //therefore we don't need to reload anything
1719 //virtual
1720 sal_Bool SAL_CALL CachedContentResultSet
1721 ::rowUpdated()
1723 std::unique_lock aGuard(m_aMutex);
1724 impl_EnsureNotDisposed(aGuard);
1726 //the ContentResultSet is static and will not change
1727 return false;
1729 //virtual
1730 sal_Bool SAL_CALL CachedContentResultSet
1731 ::rowInserted()
1733 std::unique_lock aGuard(m_aMutex);
1734 impl_EnsureNotDisposed(aGuard);
1736 //the ContentResultSet is static and will not change
1737 return false;
1740 //virtual
1741 sal_Bool SAL_CALL CachedContentResultSet
1742 ::rowDeleted()
1744 std::unique_lock aGuard(m_aMutex);
1745 impl_EnsureNotDisposed(aGuard);
1747 //the ContentResultSet is static and will not change
1748 return false;
1751 //virtual
1752 Reference< XInterface > SAL_CALL CachedContentResultSet
1753 ::getStatement()
1755 std::unique_lock aGuard(m_aMutex);
1756 impl_EnsureNotDisposed(aGuard);
1757 //@todo ?return anything
1758 return Reference< XInterface >();
1762 // XRow methods. ( inherited )
1765 //virtual
1766 sal_Bool SAL_CALL CachedContentResultSet
1767 ::wasNull()
1769 std::unique_lock aGuard(m_aMutex);
1770 impl_EnsureNotDisposed(aGuard);
1771 impl_init_xRowOrigin(aGuard);
1772 if( m_bLastReadWasFromCache )
1773 return m_bLastCachedReadWasNull;
1774 if( !m_xRowOrigin.is() )
1776 OSL_FAIL( "broadcaster was disposed already" );
1777 return false;
1779 aGuard.unlock();
1780 return m_xRowOrigin->wasNull();
1783 //virtual
1784 OUString SAL_CALL CachedContentResultSet
1785 ::getString( sal_Int32 columnIndex )
1787 return rowOriginGet<OUString>(&css::sdbc::XRow::getString, columnIndex);
1790 //virtual
1791 sal_Bool SAL_CALL CachedContentResultSet
1792 ::getBoolean( sal_Int32 columnIndex )
1794 return rowOriginGet<sal_Bool>(&css::sdbc::XRow::getBoolean, columnIndex);
1797 //virtual
1798 sal_Int8 SAL_CALL CachedContentResultSet
1799 ::getByte( sal_Int32 columnIndex )
1801 return rowOriginGet<sal_Int8>(&css::sdbc::XRow::getByte, columnIndex);
1804 //virtual
1805 sal_Int16 SAL_CALL CachedContentResultSet
1806 ::getShort( sal_Int32 columnIndex )
1808 return rowOriginGet<sal_Int16>(&css::sdbc::XRow::getShort, columnIndex);
1811 //virtual
1812 sal_Int32 SAL_CALL CachedContentResultSet
1813 ::getInt( sal_Int32 columnIndex )
1815 return rowOriginGet<sal_Int32>(&css::sdbc::XRow::getInt, columnIndex);
1818 //virtual
1819 sal_Int64 SAL_CALL CachedContentResultSet
1820 ::getLong( sal_Int32 columnIndex )
1822 return rowOriginGet<sal_Int64>(&css::sdbc::XRow::getLong, columnIndex);
1825 //virtual
1826 float SAL_CALL CachedContentResultSet
1827 ::getFloat( sal_Int32 columnIndex )
1829 return rowOriginGet<float>(&css::sdbc::XRow::getFloat, columnIndex);
1832 //virtual
1833 double SAL_CALL CachedContentResultSet
1834 ::getDouble( sal_Int32 columnIndex )
1836 return rowOriginGet<double>(&css::sdbc::XRow::getDouble, columnIndex);
1839 //virtual
1840 Sequence< sal_Int8 > SAL_CALL CachedContentResultSet
1841 ::getBytes( sal_Int32 columnIndex )
1843 return rowOriginGet< css::uno::Sequence<sal_Int8> >(
1844 &css::sdbc::XRow::getBytes, columnIndex);
1847 //virtual
1848 Date SAL_CALL CachedContentResultSet
1849 ::getDate( sal_Int32 columnIndex )
1851 return rowOriginGet<css::util::Date>(
1852 &css::sdbc::XRow::getDate, columnIndex);
1855 //virtual
1856 Time SAL_CALL CachedContentResultSet
1857 ::getTime( sal_Int32 columnIndex )
1859 return rowOriginGet<css::util::Time>(
1860 &css::sdbc::XRow::getTime, columnIndex);
1863 //virtual
1864 DateTime SAL_CALL CachedContentResultSet
1865 ::getTimestamp( sal_Int32 columnIndex )
1867 return rowOriginGet<css::util::DateTime>(
1868 &css::sdbc::XRow::getTimestamp, columnIndex);
1871 //virtual
1872 Reference< css::io::XInputStream >
1873 SAL_CALL CachedContentResultSet
1874 ::getBinaryStream( sal_Int32 columnIndex )
1876 return rowOriginGet< css::uno::Reference<css::io::XInputStream> >(
1877 &css::sdbc::XRow::getBinaryStream, columnIndex);
1880 //virtual
1881 Reference< css::io::XInputStream >
1882 SAL_CALL CachedContentResultSet
1883 ::getCharacterStream( sal_Int32 columnIndex )
1885 return rowOriginGet< css::uno::Reference<css::io::XInputStream> >(
1886 &css::sdbc::XRow::getCharacterStream, columnIndex);
1889 //virtual
1890 Any SAL_CALL CachedContentResultSet
1891 ::getObject( sal_Int32 columnIndex,
1892 const Reference<
1893 css::container::XNameAccess >& typeMap )
1895 //if you change this function please pay attention to
1896 //function template rowOriginGet, where this is similar implemented
1898 std::unique_lock aGuard(m_aMutex);
1899 sal_Int32 nRow = m_nRow;
1900 sal_Int32 nFetchSize = m_nFetchSize;
1901 sal_Int32 nFetchDirection = m_nFetchDirection;
1902 if( !m_aCache.hasRow( nRow ) )
1904 if( !m_aCache.hasCausedException( nRow ) )
1906 if( !m_xFetchProvider.is() )
1908 OSL_FAIL( "broadcaster was disposed already" );
1909 return Any();
1911 impl_fetchData( aGuard, nRow, nFetchSize, nFetchDirection );
1913 if( !m_aCache.hasRow( nRow ) )
1915 m_bLastReadWasFromCache = false;
1916 applyPositionToOrigin( aGuard, nRow );
1917 impl_init_xRowOrigin(aGuard);
1918 aGuard.unlock();
1919 return m_xRowOrigin->getObject( columnIndex, typeMap );
1922 //@todo: pay attention to typeMap
1923 const Any& rValue = m_aCache.getAny( nRow, columnIndex );
1924 m_bLastReadWasFromCache = true;
1925 m_bLastCachedReadWasNull = !rValue.hasValue();
1926 return rValue;
1929 //virtual
1930 Reference< XRef > SAL_CALL CachedContentResultSet
1931 ::getRef( sal_Int32 columnIndex )
1933 return rowOriginGet< css::uno::Reference<css::sdbc::XRef> >(
1934 &css::sdbc::XRow::getRef, columnIndex);
1937 //virtual
1938 Reference< XBlob > SAL_CALL CachedContentResultSet
1939 ::getBlob( sal_Int32 columnIndex )
1941 return rowOriginGet< css::uno::Reference<css::sdbc::XBlob> >(
1942 &css::sdbc::XRow::getBlob, columnIndex);
1945 //virtual
1946 Reference< XClob > SAL_CALL CachedContentResultSet
1947 ::getClob( sal_Int32 columnIndex )
1949 return rowOriginGet< css::uno::Reference<css::sdbc::XClob> >(
1950 &css::sdbc::XRow::getClob, columnIndex);
1953 //virtual
1954 Reference< XArray > SAL_CALL CachedContentResultSet
1955 ::getArray( sal_Int32 columnIndex )
1957 return rowOriginGet< css::uno::Reference<css::sdbc::XArray> >(
1958 &css::sdbc::XRow::getArray, columnIndex);
1962 // Type Converter Support
1965 const Reference< XTypeConverter >& CachedContentResultSet::getTypeConverter(std::unique_lock<std::mutex>& )
1967 if ( !m_bTriedToGetTypeConverter && !m_xTypeConverter.is() )
1969 m_bTriedToGetTypeConverter = true;
1970 m_xTypeConverter.set( Converter::create(m_xContext) );
1972 OSL_ENSURE( m_xTypeConverter.is(),
1973 "PropertyValueSet::getTypeConverter() - "
1974 "Service 'com.sun.star.script.Converter' n/a!" );
1976 return m_xTypeConverter;
1982 CachedContentResultSetFactory::CachedContentResultSetFactory(
1983 const Reference< XComponentContext > & rxContext )
1985 m_xContext = rxContext;
1988 CachedContentResultSetFactory::~CachedContentResultSetFactory()
1992 // CachedContentResultSetFactory XServiceInfo methods.
1994 OUString SAL_CALL CachedContentResultSetFactory::getImplementationName()
1996 return u"com.sun.star.comp.ucb.CachedContentResultSetFactory"_ustr;
1998 sal_Bool SAL_CALL CachedContentResultSetFactory::supportsService( const OUString& ServiceName )
2000 return cppu::supportsService( this, ServiceName );
2002 css::uno::Sequence< OUString > SAL_CALL CachedContentResultSetFactory::getSupportedServiceNames()
2004 return { u"com.sun.star.ucb.CachedContentResultSetFactory"_ustr };
2007 // Service factory implementation.
2011 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
2012 ucb_CachedContentResultSetFactory_get_implementation(
2013 css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
2015 return cppu::acquire(new CachedContentResultSetFactory(context));
2019 // CachedContentResultSetFactory XCachedContentResultSetFactory methods.
2022 //virtual
2023 Reference< XResultSet > SAL_CALL CachedContentResultSetFactory
2024 ::createCachedContentResultSet(
2025 const Reference< XResultSet > & xSource,
2026 const Reference< XContentIdentifierMapping > & xMapping )
2028 Reference< XResultSet > xRet = new CachedContentResultSet( m_xContext, xSource, xMapping );
2029 return xRet;
2032 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */