Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / ucb / source / cacher / cachedcontentresultset.cxx
blob7c1f316d1c65b3fcb6e00fc15e52907d372e22e5
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 OUStringLiteral g_sPropertyNameForFetchSize(u"FetchSize");
412 constexpr OUStringLiteral g_sPropertyNameForFetchDirection(u"FetchDirection");
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 : std::as_const(*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 : std::as_const(*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 "com.sun.star.comp.ucb.CachedContentResultSet";
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 { "com.sun.star.ucb.CachedContentResultSet" };
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 )
1226 // virtual
1227 Reference< XContentIdentifier > SAL_CALL CachedContentResultSet
1228 ::queryContentIdentifier()
1230 std::unique_lock rGuard(m_aMutex);
1231 XCONTENTACCESS_queryXXX( queryContentIdentifier, ContentIdentifier, Reference< XContentIdentifier > )
1235 // virtual
1236 Reference< XContent > SAL_CALL CachedContentResultSet
1237 ::queryContent()
1239 std::unique_lock rGuard(m_aMutex);
1240 XCONTENTACCESS_queryXXX( queryContent, Content, Reference< XContent > )
1244 // XResultSet methods. ( inherited )
1246 //virtual
1248 sal_Bool SAL_CALL CachedContentResultSet
1249 ::next()
1251 std::unique_lock aGuard(m_aMutex);
1252 impl_EnsureNotDisposed(aGuard);
1254 //after last
1255 if( m_bAfterLast )
1256 return false;
1257 //last
1258 aGuard.unlock();
1259 if( isLast() )
1261 aGuard.lock();
1262 m_nRow++;
1263 m_bAfterLast = true;
1264 return false;
1266 aGuard.lock();
1267 //known valid position
1268 if( impl_isKnownValidPosition( aGuard, m_nRow + 1 ) )
1270 m_nRow++;
1271 return true;
1274 //unknown position
1275 sal_Int32 nRow = m_nRow;
1277 bool bValid = applyPositionToOrigin( aGuard, nRow + 1 );
1279 m_nRow = nRow + 1;
1280 m_bAfterLast = !bValid;
1281 return bValid;
1284 //virtual
1285 sal_Bool SAL_CALL CachedContentResultSet
1286 ::previous()
1288 std::unique_lock aGuard(m_aMutex);
1289 impl_EnsureNotDisposed(aGuard);
1291 if( impl_isForwardOnly(aGuard) )
1292 throw SQLException();
1294 //before first ?:
1295 if( !m_bAfterLast && !m_nRow )
1296 return false;
1297 //first ?:
1298 if( !m_bAfterLast && m_nKnownCount && m_nRow == 1 )
1300 m_nRow--;
1301 m_bAfterLast = false;
1302 return false;
1304 //known valid position ?:
1305 if( impl_isKnownValidPosition( aGuard, m_nRow - 1 ) )
1307 m_nRow--;
1308 m_bAfterLast = false;
1309 return true;
1311 //unknown position:
1312 sal_Int32 nRow = m_nRow;
1314 bool bValid = applyPositionToOrigin( aGuard, nRow - 1 );
1316 m_nRow = nRow - 1;
1317 m_bAfterLast = false;
1318 return bValid;
1321 //virtual
1322 sal_Bool SAL_CALL CachedContentResultSet
1323 ::absolute( sal_Int32 row )
1325 std::unique_lock aGuard(m_aMutex);
1326 impl_EnsureNotDisposed(aGuard);
1328 if( !row )
1329 throw SQLException();
1331 if( impl_isForwardOnly(aGuard) )
1332 throw SQLException();
1334 if( !m_xResultSetOrigin.is() )
1336 OSL_FAIL( "broadcaster was disposed already" );
1337 return false;
1339 if( row < 0 )
1341 if( m_bFinalCount )
1343 sal_Int32 nNewRow = m_nKnownCount + 1 + row;
1344 bool bValid = true;
1345 if( nNewRow <= 0 )
1347 nNewRow = 0;
1348 bValid = false;
1350 m_nRow = nNewRow;
1351 m_bAfterLast = false;
1352 return bValid;
1354 //unknown final count:
1355 aGuard.unlock();
1357 bool bValid = m_xResultSetOrigin->absolute( row );
1359 aGuard.lock();
1360 if( m_bFinalCount )
1362 sal_Int32 nNewRow = m_nKnownCount + 1 + row;
1363 if( nNewRow < 0 )
1364 nNewRow = 0;
1365 m_nLastAppliedPos = nNewRow;
1366 m_nRow = nNewRow;
1367 m_bAfterLastApplied = m_bAfterLast = false;
1368 return bValid;
1370 aGuard.unlock();
1372 sal_Int32 nCurRow = m_xResultSetOrigin->getRow();
1374 aGuard.lock();
1375 m_nLastAppliedPos = nCurRow;
1376 m_nRow = nCurRow;
1377 m_bAfterLast = false;
1378 return nCurRow != 0;
1380 //row > 0:
1381 if( m_bFinalCount )
1383 if( row > m_nKnownCount )
1385 m_nRow = m_nKnownCount + 1;
1386 m_bAfterLast = true;
1387 return false;
1389 m_nRow = row;
1390 m_bAfterLast = false;
1391 return true;
1393 //unknown new position:
1394 aGuard.unlock();
1396 bool bValid = m_xResultSetOrigin->absolute( row );
1398 aGuard.lock();
1399 if( m_bFinalCount )
1401 sal_Int32 nNewRow = row;
1402 if( nNewRow > m_nKnownCount )
1404 nNewRow = m_nKnownCount + 1;
1405 m_bAfterLastApplied = m_bAfterLast = true;
1407 else
1408 m_bAfterLastApplied = m_bAfterLast = false;
1410 m_nLastAppliedPos = nNewRow;
1411 m_nRow = nNewRow;
1412 return bValid;
1414 aGuard.unlock();
1416 sal_Int32 nCurRow = m_xResultSetOrigin->getRow();
1417 bool bIsAfterLast = m_xResultSetOrigin->isAfterLast();
1419 aGuard.lock();
1420 m_nLastAppliedPos = nCurRow;
1421 m_nRow = nCurRow;
1422 m_bAfterLastApplied = m_bAfterLast = bIsAfterLast;
1423 return nCurRow && !bIsAfterLast;
1426 //virtual
1427 sal_Bool SAL_CALL CachedContentResultSet
1428 ::relative( sal_Int32 rows )
1430 std::unique_lock aGuard(m_aMutex);
1431 impl_EnsureNotDisposed(aGuard);
1433 if( impl_isForwardOnly(aGuard) )
1434 throw SQLException();
1436 if( m_bAfterLast || impl_isKnownInvalidPosition( aGuard, m_nRow ) )
1437 throw SQLException();
1439 if( !rows )
1440 return true;
1442 sal_Int32 nNewRow = m_nRow + rows;
1443 if( nNewRow < 0 )
1444 nNewRow = 0;
1446 if( impl_isKnownValidPosition( aGuard, nNewRow ) )
1448 m_nRow = nNewRow;
1449 m_bAfterLast = false;
1450 return true;
1452 else
1454 //known invalid new position:
1455 if( nNewRow == 0 )
1457 m_bAfterLast = false;
1458 m_nRow = 0;
1459 return false;
1461 if( m_bFinalCount && nNewRow > m_nKnownCount )
1463 m_bAfterLast = true;
1464 m_nRow = m_nKnownCount + 1;
1465 return false;
1467 //unknown new position:
1468 bool bValid = applyPositionToOrigin( aGuard, nNewRow );
1469 m_nRow = nNewRow;
1470 m_bAfterLast = !bValid; // only nNewRow > 0 possible here
1471 return bValid;
1476 //virtual
1477 sal_Bool SAL_CALL CachedContentResultSet
1478 ::first()
1480 std::unique_lock aGuard(m_aMutex);
1481 impl_EnsureNotDisposed(aGuard);
1483 if( impl_isForwardOnly(aGuard) )
1484 throw SQLException();
1486 if( impl_isKnownValidPosition( aGuard, 1 ) )
1488 m_nRow = 1;
1489 m_bAfterLast = false;
1490 return true;
1492 if( impl_isKnownInvalidPosition( aGuard, 1 ) )
1494 m_nRow = 1;
1495 m_bAfterLast = false;
1496 return false;
1498 //unknown position
1499 bool bValid = applyPositionToOrigin( aGuard, 1 );
1500 m_nRow = 1;
1501 m_bAfterLast = false;
1502 return bValid;
1505 //virtual
1506 sal_Bool SAL_CALL CachedContentResultSet
1507 ::last()
1509 std::unique_lock aGuard(m_aMutex);
1510 impl_EnsureNotDisposed(aGuard);
1512 if( impl_isForwardOnly(aGuard) )
1513 throw SQLException();
1515 if( m_bFinalCount )
1517 m_nRow = m_nKnownCount;
1518 m_bAfterLast = false;
1519 return m_nKnownCount != 0;
1521 //unknown position
1522 if( !m_xResultSetOrigin.is() )
1524 OSL_FAIL( "broadcaster was disposed already" );
1525 return false;
1527 aGuard.unlock();
1529 bool bValid = m_xResultSetOrigin->last();
1531 aGuard.lock();
1532 m_bAfterLastApplied = m_bAfterLast = false;
1533 if( m_bFinalCount )
1535 m_nLastAppliedPos = m_nKnownCount;
1536 m_nRow = m_nKnownCount;
1537 return bValid;
1539 aGuard.unlock();
1541 sal_Int32 nCurRow = m_xResultSetOrigin->getRow();
1543 aGuard.lock();
1544 m_nLastAppliedPos = nCurRow;
1545 m_nRow = nCurRow;
1546 OSL_ENSURE( nCurRow >= m_nKnownCount, "position of last row < known Count, that could not be" );
1547 m_nKnownCount = nCurRow;
1548 m_bFinalCount = true;
1549 return nCurRow != 0;
1552 //virtual
1553 void SAL_CALL CachedContentResultSet
1554 ::beforeFirst()
1556 std::unique_lock aGuard(m_aMutex);
1557 impl_EnsureNotDisposed(aGuard);
1559 if( impl_isForwardOnly(aGuard) )
1560 throw SQLException();
1562 m_nRow = 0;
1563 m_bAfterLast = false;
1566 //virtual
1567 void SAL_CALL CachedContentResultSet
1568 ::afterLast()
1570 std::unique_lock aGuard(m_aMutex);
1571 impl_EnsureNotDisposed(aGuard);
1573 if( impl_isForwardOnly(aGuard) )
1574 throw SQLException();
1576 m_nRow = 1;
1577 m_bAfterLast = true;
1580 //virtual
1581 sal_Bool SAL_CALL CachedContentResultSet
1582 ::isAfterLast()
1584 std::unique_lock aGuard(m_aMutex);
1585 impl_EnsureNotDisposed(aGuard);
1587 if( !m_bAfterLast )
1588 return false;
1589 if( m_nKnownCount )
1590 return m_bAfterLast;
1591 if( m_bFinalCount )
1592 return false;
1594 if( !m_xResultSetOrigin.is() )
1596 OSL_FAIL( "broadcaster was disposed already" );
1597 return false;
1599 aGuard.unlock();
1601 //find out whether the original resultset contains rows or not
1602 m_xResultSetOrigin->afterLast();
1604 aGuard.lock();
1605 m_bAfterLastApplied = true;
1606 aGuard.unlock();
1608 return m_xResultSetOrigin->isAfterLast();
1611 //virtual
1612 sal_Bool SAL_CALL CachedContentResultSet
1613 ::isBeforeFirst()
1615 std::unique_lock aGuard(m_aMutex);
1616 impl_EnsureNotDisposed(aGuard);
1618 if( m_bAfterLast )
1619 return false;
1620 if( m_nRow )
1621 return false;
1622 if( m_nKnownCount )
1623 return true;
1624 if( m_bFinalCount )
1625 return false;
1627 if( !m_xResultSetOrigin.is() )
1629 OSL_FAIL( "broadcaster was disposed already" );
1630 return false;
1632 aGuard.unlock();
1634 //find out whether the original resultset contains rows or not
1635 m_xResultSetOrigin->beforeFirst();
1637 aGuard.lock();
1638 m_bAfterLastApplied = false;
1639 m_nLastAppliedPos = 0;
1640 aGuard.unlock();
1642 return m_xResultSetOrigin->isBeforeFirst();
1645 //virtual
1646 sal_Bool SAL_CALL CachedContentResultSet
1647 ::isFirst()
1649 std::unique_lock aGuard(m_aMutex);
1650 impl_EnsureNotDisposed(aGuard);
1652 sal_Int32 nRow = 0;
1653 Reference< XResultSet > xResultSetOrigin;
1655 if( m_bAfterLast )
1656 return false;
1657 if( m_nRow != 1 )
1658 return false;
1659 if( m_nKnownCount )
1660 return true;
1661 if( m_bFinalCount )
1662 return false;
1664 nRow = m_nRow;
1665 xResultSetOrigin = m_xResultSetOrigin;
1667 //need to ask origin
1668 if( !applyPositionToOrigin( aGuard, nRow ) )
1669 return false;
1670 aGuard.unlock();
1671 return xResultSetOrigin->isFirst();
1674 //virtual
1675 sal_Bool SAL_CALL CachedContentResultSet
1676 ::isLast()
1678 std::unique_lock aGuard(m_aMutex);
1679 impl_EnsureNotDisposed(aGuard);
1681 sal_Int32 nRow = 0;
1682 Reference< XResultSet > xResultSetOrigin;
1683 if( m_bAfterLast )
1684 return false;
1685 if( m_nRow < m_nKnownCount )
1686 return false;
1687 if( m_bFinalCount )
1688 return m_nKnownCount && m_nRow == m_nKnownCount;
1690 nRow = m_nRow;
1691 xResultSetOrigin = m_xResultSetOrigin;
1693 //need to ask origin
1694 if( !applyPositionToOrigin( aGuard, nRow ) )
1695 return false;
1696 aGuard.unlock();
1697 return xResultSetOrigin->isLast();
1701 //virtual
1702 sal_Int32 SAL_CALL CachedContentResultSet
1703 ::getRow()
1705 std::unique_lock aGuard(m_aMutex);
1706 impl_EnsureNotDisposed(aGuard);
1708 if( m_bAfterLast )
1709 return 0;
1710 return m_nRow;
1713 //virtual
1714 void SAL_CALL CachedContentResultSet
1715 ::refreshRow()
1717 std::unique_lock aGuard(m_aMutex);
1718 impl_EnsureNotDisposed(aGuard);
1720 //the ContentResultSet is static and will not change
1721 //therefore we don't need to reload anything
1724 //virtual
1725 sal_Bool SAL_CALL CachedContentResultSet
1726 ::rowUpdated()
1728 std::unique_lock aGuard(m_aMutex);
1729 impl_EnsureNotDisposed(aGuard);
1731 //the ContentResultSet is static and will not change
1732 return false;
1734 //virtual
1735 sal_Bool SAL_CALL CachedContentResultSet
1736 ::rowInserted()
1738 std::unique_lock aGuard(m_aMutex);
1739 impl_EnsureNotDisposed(aGuard);
1741 //the ContentResultSet is static and will not change
1742 return false;
1745 //virtual
1746 sal_Bool SAL_CALL CachedContentResultSet
1747 ::rowDeleted()
1749 std::unique_lock aGuard(m_aMutex);
1750 impl_EnsureNotDisposed(aGuard);
1752 //the ContentResultSet is static and will not change
1753 return false;
1756 //virtual
1757 Reference< XInterface > SAL_CALL CachedContentResultSet
1758 ::getStatement()
1760 std::unique_lock aGuard(m_aMutex);
1761 impl_EnsureNotDisposed(aGuard);
1762 //@todo ?return anything
1763 return Reference< XInterface >();
1767 // XRow methods. ( inherited )
1770 //virtual
1771 sal_Bool SAL_CALL CachedContentResultSet
1772 ::wasNull()
1774 std::unique_lock aGuard(m_aMutex);
1775 impl_EnsureNotDisposed(aGuard);
1776 impl_init_xRowOrigin(aGuard);
1777 if( m_bLastReadWasFromCache )
1778 return m_bLastCachedReadWasNull;
1779 if( !m_xRowOrigin.is() )
1781 OSL_FAIL( "broadcaster was disposed already" );
1782 return false;
1784 aGuard.unlock();
1785 return m_xRowOrigin->wasNull();
1788 //virtual
1789 OUString SAL_CALL CachedContentResultSet
1790 ::getString( sal_Int32 columnIndex )
1792 return rowOriginGet<OUString>(&css::sdbc::XRow::getString, columnIndex);
1795 //virtual
1796 sal_Bool SAL_CALL CachedContentResultSet
1797 ::getBoolean( sal_Int32 columnIndex )
1799 return rowOriginGet<sal_Bool>(&css::sdbc::XRow::getBoolean, columnIndex);
1802 //virtual
1803 sal_Int8 SAL_CALL CachedContentResultSet
1804 ::getByte( sal_Int32 columnIndex )
1806 return rowOriginGet<sal_Int8>(&css::sdbc::XRow::getByte, columnIndex);
1809 //virtual
1810 sal_Int16 SAL_CALL CachedContentResultSet
1811 ::getShort( sal_Int32 columnIndex )
1813 return rowOriginGet<sal_Int16>(&css::sdbc::XRow::getShort, columnIndex);
1816 //virtual
1817 sal_Int32 SAL_CALL CachedContentResultSet
1818 ::getInt( sal_Int32 columnIndex )
1820 return rowOriginGet<sal_Int32>(&css::sdbc::XRow::getInt, columnIndex);
1823 //virtual
1824 sal_Int64 SAL_CALL CachedContentResultSet
1825 ::getLong( sal_Int32 columnIndex )
1827 return rowOriginGet<sal_Int64>(&css::sdbc::XRow::getLong, columnIndex);
1830 //virtual
1831 float SAL_CALL CachedContentResultSet
1832 ::getFloat( sal_Int32 columnIndex )
1834 return rowOriginGet<float>(&css::sdbc::XRow::getFloat, columnIndex);
1837 //virtual
1838 double SAL_CALL CachedContentResultSet
1839 ::getDouble( sal_Int32 columnIndex )
1841 return rowOriginGet<double>(&css::sdbc::XRow::getDouble, columnIndex);
1844 //virtual
1845 Sequence< sal_Int8 > SAL_CALL CachedContentResultSet
1846 ::getBytes( sal_Int32 columnIndex )
1848 return rowOriginGet< css::uno::Sequence<sal_Int8> >(
1849 &css::sdbc::XRow::getBytes, columnIndex);
1852 //virtual
1853 Date SAL_CALL CachedContentResultSet
1854 ::getDate( sal_Int32 columnIndex )
1856 return rowOriginGet<css::util::Date>(
1857 &css::sdbc::XRow::getDate, columnIndex);
1860 //virtual
1861 Time SAL_CALL CachedContentResultSet
1862 ::getTime( sal_Int32 columnIndex )
1864 return rowOriginGet<css::util::Time>(
1865 &css::sdbc::XRow::getTime, columnIndex);
1868 //virtual
1869 DateTime SAL_CALL CachedContentResultSet
1870 ::getTimestamp( sal_Int32 columnIndex )
1872 return rowOriginGet<css::util::DateTime>(
1873 &css::sdbc::XRow::getTimestamp, columnIndex);
1876 //virtual
1877 Reference< css::io::XInputStream >
1878 SAL_CALL CachedContentResultSet
1879 ::getBinaryStream( sal_Int32 columnIndex )
1881 return rowOriginGet< css::uno::Reference<css::io::XInputStream> >(
1882 &css::sdbc::XRow::getBinaryStream, columnIndex);
1885 //virtual
1886 Reference< css::io::XInputStream >
1887 SAL_CALL CachedContentResultSet
1888 ::getCharacterStream( sal_Int32 columnIndex )
1890 return rowOriginGet< css::uno::Reference<css::io::XInputStream> >(
1891 &css::sdbc::XRow::getCharacterStream, columnIndex);
1894 //virtual
1895 Any SAL_CALL CachedContentResultSet
1896 ::getObject( sal_Int32 columnIndex,
1897 const Reference<
1898 css::container::XNameAccess >& typeMap )
1900 //if you change this function please pay attention to
1901 //function template rowOriginGet, where this is similar implemented
1903 std::unique_lock aGuard(m_aMutex);
1904 sal_Int32 nRow = m_nRow;
1905 sal_Int32 nFetchSize = m_nFetchSize;
1906 sal_Int32 nFetchDirection = m_nFetchDirection;
1907 if( !m_aCache.hasRow( nRow ) )
1909 if( !m_aCache.hasCausedException( nRow ) )
1911 if( !m_xFetchProvider.is() )
1913 OSL_FAIL( "broadcaster was disposed already" );
1914 return Any();
1916 impl_fetchData( aGuard, nRow, nFetchSize, nFetchDirection );
1918 if( !m_aCache.hasRow( nRow ) )
1920 m_bLastReadWasFromCache = false;
1921 applyPositionToOrigin( aGuard, nRow );
1922 impl_init_xRowOrigin(aGuard);
1923 aGuard.unlock();
1924 return m_xRowOrigin->getObject( columnIndex, typeMap );
1927 //@todo: pay attention to typeMap
1928 const Any& rValue = m_aCache.getAny( nRow, columnIndex );
1929 m_bLastReadWasFromCache = true;
1930 m_bLastCachedReadWasNull = !rValue.hasValue();
1931 return rValue;
1934 //virtual
1935 Reference< XRef > SAL_CALL CachedContentResultSet
1936 ::getRef( sal_Int32 columnIndex )
1938 return rowOriginGet< css::uno::Reference<css::sdbc::XRef> >(
1939 &css::sdbc::XRow::getRef, columnIndex);
1942 //virtual
1943 Reference< XBlob > SAL_CALL CachedContentResultSet
1944 ::getBlob( sal_Int32 columnIndex )
1946 return rowOriginGet< css::uno::Reference<css::sdbc::XBlob> >(
1947 &css::sdbc::XRow::getBlob, columnIndex);
1950 //virtual
1951 Reference< XClob > SAL_CALL CachedContentResultSet
1952 ::getClob( sal_Int32 columnIndex )
1954 return rowOriginGet< css::uno::Reference<css::sdbc::XClob> >(
1955 &css::sdbc::XRow::getClob, columnIndex);
1958 //virtual
1959 Reference< XArray > SAL_CALL CachedContentResultSet
1960 ::getArray( sal_Int32 columnIndex )
1962 return rowOriginGet< css::uno::Reference<css::sdbc::XArray> >(
1963 &css::sdbc::XRow::getArray, columnIndex);
1967 // Type Converter Support
1970 const Reference< XTypeConverter >& CachedContentResultSet::getTypeConverter(std::unique_lock<std::mutex>& )
1972 if ( !m_bTriedToGetTypeConverter && !m_xTypeConverter.is() )
1974 m_bTriedToGetTypeConverter = true;
1975 m_xTypeConverter.set( Converter::create(m_xContext) );
1977 OSL_ENSURE( m_xTypeConverter.is(),
1978 "PropertyValueSet::getTypeConverter() - "
1979 "Service 'com.sun.star.script.Converter' n/a!" );
1981 return m_xTypeConverter;
1987 CachedContentResultSetFactory::CachedContentResultSetFactory(
1988 const Reference< XComponentContext > & rxContext )
1990 m_xContext = rxContext;
1993 CachedContentResultSetFactory::~CachedContentResultSetFactory()
1997 // CachedContentResultSetFactory XServiceInfo methods.
1999 OUString SAL_CALL CachedContentResultSetFactory::getImplementationName()
2001 return "com.sun.star.comp.ucb.CachedContentResultSetFactory";
2003 sal_Bool SAL_CALL CachedContentResultSetFactory::supportsService( const OUString& ServiceName )
2005 return cppu::supportsService( this, ServiceName );
2007 css::uno::Sequence< OUString > SAL_CALL CachedContentResultSetFactory::getSupportedServiceNames()
2009 return { "com.sun.star.ucb.CachedContentResultSetFactory" };
2012 // Service factory implementation.
2016 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
2017 ucb_CachedContentResultSetFactory_get_implementation(
2018 css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
2020 return cppu::acquire(new CachedContentResultSetFactory(context));
2024 // CachedContentResultSetFactory XCachedContentResultSetFactory methods.
2027 //virtual
2028 Reference< XResultSet > SAL_CALL CachedContentResultSetFactory
2029 ::createCachedContentResultSet(
2030 const Reference< XResultSet > & xSource,
2031 const Reference< XContentIdentifierMapping > & xMapping )
2033 Reference< XResultSet > xRet = new CachedContentResultSet( m_xContext, xSource, xMapping );
2034 return xRet;
2037 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */