LibreOffice Module ucb (master)  1
cachedcontentresultset.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 
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>
34 #include <ucbhelper/macros.hxx>
35 #include <memory>
36 #include <string_view>
37 
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;
46 
47 
48 #define COMSUNSTARUCBCCRS_DEFAULT_FETCH_SIZE 256
49 #define COMSUNSTARUCBCCRS_DEFAULT_FETCH_DIRECTION FetchDirection::FORWARD
50 
51 //if you change this function template please pay attention to
52 //function getObject, where this is similar implemented
53 
54 template<typename T> T CachedContentResultSet::rowOriginGet(
55  T (SAL_CALL css::sdbc::XRow::* f)(sal_Int32), sal_Int32 columnIndex)
56 {
57  impl_EnsureNotDisposed();
58  osl::ResettableMutexGuard aGuard(m_aMutex);
59  sal_Int32 nRow = m_nRow;
60  sal_Int32 nFetchSize = m_nFetchSize;
61  sal_Int32 nFetchDirection = m_nFetchDirection;
62  if( !m_aCache.hasRow( nRow ) )
63  {
64  bool isCleared = false;
65  if( !m_aCache.hasCausedException( nRow ) )
66  {
67  if( !m_xFetchProvider.is() )
68  {
69  OSL_FAIL( "broadcaster was disposed already" );
70  throw SQLException();
71  }
72  aGuard.clear();
73  isCleared = true;
74  if( impl_isForwardOnly() )
75  applyPositionToOrigin( nRow );
76 
77  impl_fetchData( nRow, nFetchSize, nFetchDirection );
78  }
79  if (isCleared)
80  {
81  aGuard.reset();
82  }
83  if( !m_aCache.hasRow( nRow ) )
84  {
85  m_bLastReadWasFromCache = false;
86  aGuard.clear();
87  applyPositionToOrigin( nRow );
88  impl_init_xRowOrigin();
89  return (m_xRowOrigin.get()->*f)( columnIndex );
90  }
91  }
92  const Any& rValue = m_aCache.getAny( nRow, columnIndex );
93  T aRet = T();
94  m_bLastReadWasFromCache = true;
95  m_bLastCachedReadWasNull = !( rValue >>= aRet );
96  /* Last chance. Try type converter service... */
97  if ( m_bLastCachedReadWasNull && rValue.hasValue() )
98  {
100  if ( xConverter.is() )
101  {
102  try
103  {
104  Any aConvAny = xConverter->convertTo(
105  rValue,
107  m_bLastCachedReadWasNull = !( aConvAny >>= aRet );
108  }
109  catch (const IllegalArgumentException&)
110  {
111  }
112  catch (const CannotConvertException&)
113  {
114  }
115  }
116  }
117  return aRet;
118 }
119 
120 
121 // CCRS_Cache methods
122 
123 
125  const Reference< XContentIdentifierMapping > & xMapping )
126  : m_xContentIdentifierMapping( xMapping )
127 {
128 }
129 
131 {
132 }
133 
134 void CachedContentResultSet::CCRS_Cache
135  ::clear()
136 {
137  m_pResult.reset();
138  m_pMappedReminder.reset();
139 }
140 
141 void CachedContentResultSet::CCRS_Cache
142  ::loadData( const FetchResult& rResult )
143 {
144  clear();
145  m_pResult.reset( new FetchResult( rResult ) );
146 }
147 
148 bool CachedContentResultSet::CCRS_Cache
149  ::hasRow( sal_Int32 row )
150 {
151  if( !m_pResult )
152  return false;
153  sal_Int32 nStart = m_pResult->StartIndex;
154  sal_Int32 nEnd = nStart;
155  if( m_pResult->Orientation )
156  nEnd += m_pResult->Rows.getLength() - 1;
157  else
158  nStart -= m_pResult->Rows.getLength() + 1;
159 
160  return nStart <= row && row <= nEnd;
161 }
162 
163 sal_Int32 CachedContentResultSet::CCRS_Cache
164  ::getMaxRow() const
165 {
166  if( !m_pResult )
167  return 0;
168  sal_Int32 nEnd = m_pResult->StartIndex;
169  if( m_pResult->Orientation )
170  return nEnd + m_pResult->Rows.getLength() - 1;
171  else
172  return nEnd;
173 }
174 
175 bool CachedContentResultSet::CCRS_Cache
176  ::hasKnownLast() const
177 {
178  if( !m_pResult )
179  return false;
180 
181  return ( m_pResult->FetchError & FetchError::ENDOFDATA )
182  && m_pResult->Orientation
183  && m_pResult->Rows.hasElements();
184 }
185 
186 bool CachedContentResultSet::CCRS_Cache
187  ::hasCausedException( sal_Int32 nRow )
188 {
189  if( !m_pResult )
190  return false;
191  if( !( m_pResult->FetchError & FetchError::EXCEPTION ) )
192  return false;
193 
194  sal_Int32 nEnd = m_pResult->StartIndex;
195  if( m_pResult->Orientation )
196  nEnd += m_pResult->Rows.getLength();
197 
198  return nRow == nEnd+1;
199 }
200 
201 Any& CachedContentResultSet::CCRS_Cache
202  ::getRowAny( sal_Int32 nRow )
203 {
204  if( !nRow )
205  throw SQLException();
206  if( !m_pResult )
207  throw SQLException();
208  if( !hasRow( nRow ) )
209  throw SQLException();
210 
211  sal_Int32 nDiff = nRow - m_pResult->StartIndex;
212  if( nDiff < 0 )
213  nDiff *= -1;
214 
215  return (m_pResult->Rows)[nDiff];
216 }
217 
218 void CachedContentResultSet::CCRS_Cache
219  ::remindMapped( sal_Int32 nRow )
220 {
221  //remind that this row was mapped
222  if( !m_pResult )
223  return;
224  sal_Int32 nDiff = nRow - m_pResult->StartIndex;
225  if( nDiff < 0 )
226  nDiff *= -1;
227  Sequence< sal_Bool >* pMappedReminder = getMappedReminder();
228  if( nDiff < pMappedReminder->getLength() )
229  (*pMappedReminder)[nDiff] = true;
230 }
231 
232 bool CachedContentResultSet::CCRS_Cache
233  ::isRowMapped( sal_Int32 nRow )
234 {
235  if( !m_pMappedReminder || !m_pResult )
236  return false;
237  sal_Int32 nDiff = nRow - m_pResult->StartIndex;
238  if( nDiff < 0 )
239  nDiff *= -1;
240  if( nDiff < m_pMappedReminder->getLength() )
241  return (*m_pMappedReminder)[nDiff];
242  return false;
243 }
244 
245 Sequence< sal_Bool >* CachedContentResultSet::CCRS_Cache
246  ::getMappedReminder()
247 {
248  if( !m_pMappedReminder )
249  {
250  sal_Int32 nCount = m_pResult->Rows.getLength();
251  m_pMappedReminder.reset(new Sequence< sal_Bool >( nCount ));
252  std::fill(m_pMappedReminder->begin(), m_pMappedReminder->end(), false);
253  }
254  return m_pMappedReminder.get();
255 }
256 
257 const Any& CachedContentResultSet::CCRS_Cache
258  ::getAny( sal_Int32 nRow, sal_Int32 nColumnIndex )
259 {
260  if( !nColumnIndex )
261  throw SQLException();
262  if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) )
263  {
264  Any& rRow = getRowAny( nRow );
265  Sequence< Any > aValue;
266  rRow >>= aValue;
267  if( m_xContentIdentifierMapping->mapRow( aValue ) )
268  {
269  rRow <<= aValue;
270  remindMapped( nRow );
271  }
272  else
274  }
275  auto & rowAny = getRowAny(nRow);
276  auto rRow = o3tl::doAccess<Sequence<Any>>(rowAny);
277 
278  if( nColumnIndex > rRow->getLength() )
279  throw SQLException();
280  return (*rRow)[nColumnIndex-1];
281 }
282 
283 OUString const & CachedContentResultSet::CCRS_Cache
284  ::getContentIdentifierString( sal_Int32 nRow )
285 {
286  try
287  {
288  if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) )
289  {
290  Any& rRow = getRowAny( nRow );
291  OUString aValue;
292  rRow >>= aValue;
293  rRow <<= m_xContentIdentifierMapping->mapContentIdentifierString( aValue );
294  remindMapped( nRow );
295  }
296  return *o3tl::doAccess<OUString>(getRowAny(nRow));
297  }
298  catch(const SQLException& ex)
299  {
300  css::uno::Any anyEx = cppu::getCaughtException();
301  throw css::lang::WrappedTargetRuntimeException( ex.Message,
302  css::uno::Reference< css::uno::XInterface >(),
303  anyEx );
304  }
305 }
306 
307 Reference< XContentIdentifier > CachedContentResultSet::CCRS_Cache
308  ::getContentIdentifier( sal_Int32 nRow )
309 {
310  try
311  {
312  if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) )
313  {
314  Any& rRow = getRowAny( nRow );
316  rRow >>= aValue;
317  rRow <<= m_xContentIdentifierMapping->mapContentIdentifier( aValue );
318  remindMapped( nRow );
319  }
320  return *o3tl::doAccess<Reference<XContentIdentifier>>(getRowAny(nRow));
321  }
322  catch(const SQLException& ex)
323  {
324  css::uno::Any anyEx = cppu::getCaughtException();
325  throw css::lang::WrappedTargetRuntimeException( ex.Message,
326  css::uno::Reference< css::uno::XInterface >(),
327  anyEx );
328  }
329 }
330 
331 Reference< XContent > CachedContentResultSet::CCRS_Cache
332  ::getContent( sal_Int32 nRow )
333 {
334  try
335  {
336  if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) )
337  {
338  Any& rRow = getRowAny( nRow );
339  Reference< XContent > aValue;
340  rRow >>= aValue;
341  rRow <<= m_xContentIdentifierMapping->mapContent( aValue );
342  remindMapped( nRow );
343  }
344  return *o3tl::doAccess<Reference<XContent>>(getRowAny(nRow));
345  }
346  catch (const SQLException& ex)
347  {
348  css::uno::Any anyEx = cppu::getCaughtException();
349  throw css::lang::WrappedTargetRuntimeException( ex.Message,
350  css::uno::Reference< css::uno::XInterface >(),
351  anyEx );
352  }
353 }
354 
355 
356 
357 
359  public cppu::OWeakObject,
360  public css::lang::XTypeProvider,
361  public css::beans::XPropertySetInfo
362 {
364 
365  //my Properties
366  std::unique_ptr<Sequence< css::beans::Property >>
368 
371 
372 private:
373  sal_Int32
374  impl_getRemainedHandle() const;
375 
376  bool
377  impl_queryProperty(
378  std::u16string_view rName
379  , css::beans::Property& rProp ) const;
380  sal_Int32
381  impl_getPos( std::u16string_view rName ) const;
382 
383  static bool
384  impl_isMyPropertyName( std::u16string_view rName );
385 
386 public:
388  XPropertySetInfo > const & xPropertySetInfoOrigin );
389 
390  // XInterface
391  virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
392  virtual void SAL_CALL acquire()
393  throw() override;
394  virtual void SAL_CALL release()
395  throw() override;
396 
397  // XTypeProvider
398  virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
399  virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
400 
401  // XPropertySetInfo
402  virtual Sequence< css::beans::Property > SAL_CALL
403  getProperties() override;
404 
405  virtual css::beans::Property SAL_CALL
406  getPropertyByName( const OUString& aName ) override;
407 
408  virtual sal_Bool SAL_CALL
409  hasPropertyByName( const OUString& Name ) override;
410 };
411 
412 //some helping variables ( names for my special properties )
413 const char16_t g_sPropertyNameForCount[] = u"RowCount";
414 const char16_t g_sPropertyNameForFinalCount[] = u"IsRowCountFinal";
415 constexpr OUStringLiteral g_sPropertyNameForFetchSize(u"FetchSize");
416 constexpr OUStringLiteral g_sPropertyNameForFetchDirection(u"FetchDirection");
417 
419  Reference< XPropertySetInfo > const & xInfo )
420  : m_nFetchSizePropertyHandle( -1 )
421  , m_nFetchDirectionPropertyHandle( -1 )
422 {
423  //initialize list of properties:
424 
425  // it is required, that the received xInfo contains the two
426  // properties with names 'g_sPropertyNameForCount' and
427  // 'g_sPropertyNameForFinalCount'
428 
429  if( xInfo.is() )
430  {
431  Sequence<Property> aProps = xInfo->getProperties();
432  m_pProperties.reset( new Sequence<Property> ( aProps ) );
433  }
434  else
435  {
436  OSL_FAIL( "The received XPropertySetInfo doesn't contain required properties" );
437  m_pProperties.reset( new Sequence<Property> );
438  }
439 
440  //ensure, that we haven't got the Properties 'FetchSize' and 'Direction' twice:
441  sal_Int32 nFetchSize = impl_getPos( g_sPropertyNameForFetchSize );
442  sal_Int32 nFetchDirection = impl_getPos( g_sPropertyNameForFetchDirection );
443  sal_Int32 nDeleted = 0;
444  if( nFetchSize != -1 )
445  nDeleted++;
446  if( nFetchDirection != -1 )
447  nDeleted++;
448 
449  std::unique_ptr<Sequence< Property > > pOrigProps(new Sequence<Property> ( *m_pProperties ));
450  sal_Int32 nOrigProps = pOrigProps->getLength();
451 
452  m_pProperties->realloc( nOrigProps + 2 - nDeleted );//note that nDeleted is <= 2
453  for( sal_Int32 n = 0, m = 0; n < nOrigProps; n++, m++ )
454  {
455  if( n == nFetchSize || n == nFetchDirection )
456  m--;
457  else
458  (*m_pProperties)[ m ] = (*pOrigProps)[ n ];
459  }
460  {
461  Property& rMyProp = (*m_pProperties)[ nOrigProps - nDeleted ];
462  rMyProp.Name = g_sPropertyNameForFetchSize;
463  rMyProp.Type = cppu::UnoType<sal_Int32>::get();
464  rMyProp.Attributes = PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT;
465 
466  if( nFetchSize != -1 )
467  m_nFetchSizePropertyHandle = (*pOrigProps)[nFetchSize].Handle;
468  else
469  m_nFetchSizePropertyHandle = impl_getRemainedHandle();
470 
471  rMyProp.Handle = m_nFetchSizePropertyHandle;
472 
473  }
474  {
475  Property& rMyProp = (*m_pProperties)[ nOrigProps - nDeleted + 1 ];
476  rMyProp.Name = g_sPropertyNameForFetchDirection;
477  rMyProp.Type = cppu::UnoType<sal_Bool>::get();
478  rMyProp.Attributes = PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT;
479 
480  m_nFetchDirectionPropertyHandle = rMyProp.Handle;
481  }
482 }
483 
484 // XInterface methods.
485 
487  throw()
488 {
489  OWeakObject::acquire();
490 }
491 
493  throw()
494 {
495  OWeakObject::release();
496 }
497 
498 css::uno::Any SAL_CALL CCRS_PropertySetInfo::queryInterface( const css::uno::Type & rType )
499 {
500  css::uno::Any aRet = cppu::queryInterface( rType,
501  static_cast< XTypeProvider* >(this),
502  static_cast< XPropertySetInfo* >(this)
503  );
504  return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
505 }
506 
507 // XTypeProvider methods.
508 
509 //list all interfaces exclusive baseclasses
511  , XTypeProvider
512  , XPropertySetInfo
513  );
514 
515 // XPropertySetInfo methods.
516 
517 //virtual
518 Sequence< Property > SAL_CALL CCRS_PropertySetInfo
519  ::getProperties()
520 {
521  return *m_pProperties;
522 }
523 
524 //virtual
525 Property SAL_CALL CCRS_PropertySetInfo
526  ::getPropertyByName( const OUString& aName )
527 {
528  Property aProp;
529  if ( impl_queryProperty( aName, aProp ) )
530  return aProp;
531 
532  throw UnknownPropertyException(aName);
533 }
534 
535 //virtual
536 sal_Bool SAL_CALL CCRS_PropertySetInfo
537  ::hasPropertyByName( const OUString& Name )
538 {
539  return ( impl_getPos( Name ) != -1 );
540 }
541 
542 
543 // impl_ methods.
544 
545 
546 sal_Int32 CCRS_PropertySetInfo
547  ::impl_getPos( std::u16string_view rName ) const
548 {
549  for( sal_Int32 nN = m_pProperties->getLength(); nN--; )
550  {
551  const Property& rMyProp = (*m_pProperties)[nN];
552  if( rMyProp.Name == rName )
553  return nN;
554  }
555  return -1;
556 }
557 
558 bool CCRS_PropertySetInfo
559  ::impl_queryProperty( std::u16string_view rName, Property& rProp ) const
560 {
561  for( const Property& rMyProp : std::as_const(*m_pProperties) )
562  {
563  if( rMyProp.Name == rName )
564  {
565  rProp.Name = rMyProp.Name;
566  rProp.Handle = rMyProp.Handle;
567  rProp.Type = rMyProp.Type;
568  rProp.Attributes = rMyProp.Attributes;
569 
570  return true;
571  }
572  }
573  return false;
574 }
575 
576 //static
577 bool CCRS_PropertySetInfo
578  ::impl_isMyPropertyName( std::u16string_view rPropertyName )
579 {
580  return ( rPropertyName == g_sPropertyNameForCount
581  || rPropertyName == g_sPropertyNameForFinalCount
582  || rPropertyName == g_sPropertyNameForFetchSize
583  || rPropertyName == g_sPropertyNameForFetchDirection );
584 }
585 
586 sal_Int32 CCRS_PropertySetInfo
587  ::impl_getRemainedHandle( ) const
588 {
589  sal_Int32 nHandle = 1;
590 
591  if( !m_pProperties )
592  {
593  OSL_FAIL( "Properties not initialized yet" );
594  return nHandle;
595  }
596  bool bFound = true;
597  while( bFound )
598  {
599  bFound = false;
600  for( const auto & rProp : std::as_const(*m_pProperties) )
601  {
602  if( nHandle == rProp.Handle )
603  {
604  bFound = true;
605  nHandle++;
606  break;
607  }
608  }
609  }
610  return nHandle;
611 }
612 
613 
614 
615 
617  const Reference< XComponentContext > & rxContext
618  , const Reference< XResultSet > & xOrigin
620  xContentIdentifierMapping )
621  : ContentResultSetWrapper( xOrigin )
622 
623  , m_xContext( rxContext )
624 
625  , m_xContentIdentifierMapping( xContentIdentifierMapping )
626  , m_nRow( 0 ) // Position is one-based. Zero means: before first element.
627  , m_bAfterLast( false )
628  , m_nLastAppliedPos( 0 )
629  , m_bAfterLastApplied( false )
630  , m_nKnownCount( 0 )
631  , m_bFinalCount( false )
632  , m_nFetchSize(
636 
637  , m_bLastReadWasFromCache( false )
638  , m_bLastCachedReadWasNull( true )
643  , m_bTriedToGetTypeConverter( false )
644 {
645  m_xFetchProvider.set( m_xResultSetOrigin, UNO_QUERY );
646  OSL_ENSURE( m_xFetchProvider.is(), "interface XFetchProvider is required" );
647 
649  OSL_ENSURE( m_xFetchProviderForContentAccess.is(), "interface XFetchProviderForContentAccess is required" );
650 
651  impl_init();
652 };
653 
655 {
656  impl_deinit();
657  //do not delete m_pMyPropSetInfo, cause it is hold via reference
658 };
659 
660 
661 // impl_ methods.
662 
663 
664 bool CachedContentResultSet
665  ::applyPositionToOrigin( sal_Int32 nRow )
666 {
668 
675  osl::ResettableMutexGuard aGuard(m_aMutex);
676  OSL_ENSURE( nRow >= 0, "only positive values supported" );
677  if( !m_xResultSetOrigin.is() )
678  {
679  OSL_FAIL( "broadcaster was disposed already" );
680  return false;
681  }
682 // OSL_ENSURE( nRow <= m_nKnownCount, "don't step into regions you don't know with this method" );
683 
684  sal_Int32 nLastAppliedPos = m_nLastAppliedPos;
685  bool bAfterLastApplied = m_bAfterLastApplied;
686  bool bAfterLast = m_bAfterLast;
687  sal_Int32 nForwardOnly = m_nForwardOnly;
688 
689  aGuard.clear();
690 
691  if( bAfterLastApplied || nLastAppliedPos != nRow )
692  {
693  if( nForwardOnly == 1 )
694  {
695  if( bAfterLastApplied || bAfterLast || !nRow || nRow < nLastAppliedPos )
696  throw SQLException();
697 
698  sal_Int32 nN = nRow - nLastAppliedPos;
699  sal_Int32 nM;
700  for( nM = 0; nN--; nM++ )
701  {
702  if( !m_xResultSetOrigin->next() )
703  break;
704  }
705 
706  aGuard.reset();
707  m_nLastAppliedPos += nM;
709  return nRow == m_nLastAppliedPos;
710  }
711 
712  if( !nRow ) //absolute( 0 ) will throw exception
713  {
714  m_xResultSetOrigin->beforeFirst();
715 
716  aGuard.reset();
717  m_nLastAppliedPos = 0;
718  m_bAfterLastApplied = false;
719  return false;
720  }
721  try
722  {
723  //move absolute, if !nLastAppliedPos
724  //because move relative would throw exception
725  if( !nLastAppliedPos || bAfterLast || bAfterLastApplied )
726  {
727  bool bValid = m_xResultSetOrigin->absolute( nRow );
728 
729  aGuard.reset();
730  m_nLastAppliedPos = nRow;
731  m_bAfterLastApplied = !bValid;
732  return bValid;
733  }
734  else
735  {
736  bool bValid = m_xResultSetOrigin->relative( nRow - nLastAppliedPos );
737 
738  aGuard.reset();
739  m_nLastAppliedPos += ( nRow - nLastAppliedPos );
740  m_bAfterLastApplied = !bValid;
741  return bValid;
742  }
743  }
744  catch (const SQLException&)
745  {
746  if( !bAfterLastApplied && !bAfterLast && nRow > nLastAppliedPos && impl_isForwardOnly() )
747  {
748  sal_Int32 nN = nRow - nLastAppliedPos;
749  sal_Int32 nM;
750  for( nM = 0; nN--; nM++ )
751  {
752  if( !m_xResultSetOrigin->next() )
753  break;
754  }
755 
756  aGuard.reset();
757  m_nLastAppliedPos += nM;
759  }
760  else
761  throw;
762  }
763 
764  return nRow == m_nLastAppliedPos;
765  }
766  return true;
767 };
768 
769 
770 //define for fetching data
771 
772 
773 #define FETCH_XXX( aCache, fetchInterface, fetchMethod ) \
774 bool bDirection = !!( \
775  nFetchDirection != FetchDirection::REVERSE ); \
776 FetchResult aResult = \
777  fetchInterface->fetchMethod( nRow, nFetchSize, bDirection ); \
778 osl::ClearableGuard< osl::Mutex > aGuard2( m_aMutex ); \
779 aCache.loadData( aResult ); \
780 sal_Int32 nMax = aCache.getMaxRow(); \
781 sal_Int32 nCurCount = m_nKnownCount; \
782 bool bIsFinalCount = aCache.hasKnownLast(); \
783 bool bCurIsFinalCount = m_bFinalCount; \
784 aGuard2.clear(); \
785 if( nMax > nCurCount ) \
786  impl_changeRowCount( nCurCount, nMax ); \
787 if( bIsFinalCount && !bCurIsFinalCount ) \
788  impl_changeIsRowCountFinal( bCurIsFinalCount, bIsFinalCount );
789 
790 void CachedContentResultSet
791  ::impl_fetchData( sal_Int32 nRow
792  , sal_Int32 nFetchSize, sal_Int32 nFetchDirection )
793 {
795 }
796 
797 void CachedContentResultSet
798  ::impl_changeRowCount( sal_Int32 nOld, sal_Int32 nNew )
799 {
800  OSL_ENSURE( nNew > nOld, "RowCount only can grow" );
801  if( nNew <= nOld )
802  return;
803 
804  //create PropertyChangeEvent and set value
805  PropertyChangeEvent aEvt;
806  {
807  osl::Guard< osl::Mutex > aGuard( m_aMutex );
808  aEvt.Source = static_cast< XPropertySet * >( this );
809  aEvt.Further = false;
810  aEvt.OldValue <<= nOld;
811  aEvt.NewValue <<= nNew;
812 
813  m_nKnownCount = nNew;
814  }
815 
816  //send PropertyChangeEvent to listeners
818 }
819 
820 void CachedContentResultSet
821  ::impl_changeIsRowCountFinal( bool bOld, bool bNew )
822 {
823  OSL_ENSURE( !bOld && bNew, "This change is not allowed for IsRowCountFinal" );
824  if( bOld || !bNew )
825  return;
826 
827  //create PropertyChangeEvent and set value
828  PropertyChangeEvent aEvt;
829  {
830  osl::Guard< osl::Mutex > aGuard( m_aMutex );
831  aEvt.Source = static_cast< XPropertySet * >( this );
832  aEvt.Further = false;
833  aEvt.OldValue <<= bOld;
834  aEvt.NewValue <<= bNew;
835 
836  m_bFinalCount = bNew;
837  }
838 
839  //send PropertyChangeEvent to listeners
841 }
842 
843 bool CachedContentResultSet
844  ::impl_isKnownValidPosition( sal_Int32 nRow )
845 {
846  return m_nKnownCount && nRow
847  && nRow <= m_nKnownCount;
848 }
849 
850 bool CachedContentResultSet
851  ::impl_isKnownInvalidPosition( sal_Int32 nRow )
852 {
853  if( !nRow )
854  return true;
855  if( !m_bFinalCount )
856  return false;
857  return nRow > m_nKnownCount;
858 }
859 
860 
861 //virtual
862 void CachedContentResultSet
863  ::impl_initPropertySetInfo()
864 {
866 
867  osl::Guard< osl::Mutex > aGuard( m_aMutex );
868  if( m_xMyPropertySetInfo.is() )
869  return;
872 }
873 
874 
875 // XInterface methods.
877  throw()
878 {
879  OWeakObject::acquire();
880 }
881 
883  throw()
884 {
885  OWeakObject::release();
886 }
887 
888 Any SAL_CALL CachedContentResultSet
889  ::queryInterface( const Type& rType )
890 {
891  //list all interfaces inclusive baseclasses of interfaces
892 
894  if( aRet.hasValue() )
895  return aRet;
896 
897  aRet = cppu::queryInterface( rType,
898  static_cast< XTypeProvider* >( this ),
899  static_cast< XServiceInfo* >( this ) );
900 
901  return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
902 }
903 
904 
905 // XTypeProvider methods.
906 
907 //list all interfaces exclusive baseclasses
909  , XTypeProvider
910  , XServiceInfo
911  , XComponent
912  , XCloseable
913  , XResultSetMetaDataSupplier
914  , XPropertySet
915 
916  , XPropertyChangeListener
917  , XVetoableChangeListener
918 
919  , XContentAccess
920 
921  , XResultSet
922  , XRow );
923 
924 
925 // XServiceInfo methods.
926 
928 {
929  return "com.sun.star.comp.ucb.CachedContentResultSet";
930 }
931 
932 sal_Bool SAL_CALL CachedContentResultSet::supportsService( const OUString& ServiceName )
933 {
934  return cppu::supportsService( this, ServiceName );
935 }
936 
937 css::uno::Sequence< OUString > SAL_CALL CachedContentResultSet::getSupportedServiceNames()
938 {
939  return { "com.sun.star.ucb.CachedContentResultSet" };
940 }
941 
942 
943 
944 // XPropertySet methods. ( inherited )
945 
946 
947 // virtual
948 void SAL_CALL CachedContentResultSet
949  ::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
950 {
952 
953  if( !getPropertySetInfo().is() )
954  {
955  OSL_FAIL( "broadcaster was disposed already" );
956  throw UnknownPropertyException();
957  }
958 
959  Property aProp = m_xMyPropertySetInfo->getPropertyByName( aPropertyName );
960  //throws UnknownPropertyException, if so
961 
962  if( aProp.Attributes & PropertyAttribute::READONLY )
963  {
964  //It is assumed, that the properties
965  //'RowCount' and 'IsRowCountFinal' are readonly!
966  throw IllegalArgumentException();
967  }
968  if( aProp.Name == g_sPropertyNameForFetchDirection )
969  {
970  //check value
971  sal_Int32 nNew;
972  if( !( aValue >>= nNew ) )
973  {
974  throw IllegalArgumentException();
975  }
976 
977  if( nNew == FetchDirection::UNKNOWN )
978  {
980  }
981  else if( nNew != FetchDirection::FORWARD && nNew != FetchDirection::REVERSE )
982  {
983  throw IllegalArgumentException();
984  }
985 
986  //create PropertyChangeEvent and set value
987  PropertyChangeEvent aEvt;
988  {
989  osl::Guard< osl::Mutex > aGuard( m_aMutex );
990  aEvt.Source = static_cast< XPropertySet * >( this );
991  aEvt.PropertyName = aPropertyName;
992  aEvt.Further = false;
993  aEvt.PropertyHandle = m_xMyPropertySetInfo->
994  m_nFetchDirectionPropertyHandle;
995  aEvt.OldValue <<= m_nFetchDirection;
996  aEvt.NewValue <<= nNew;
997 
998  m_nFetchDirection = nNew;
999  }
1000 
1001  //send PropertyChangeEvent to listeners
1003  }
1004  else if( aProp.Name == g_sPropertyNameForFetchSize )
1005  {
1006  //check value
1007  sal_Int32 nNew;
1008  if( !( aValue >>= nNew ) )
1009  {
1010  throw IllegalArgumentException();
1011  }
1012 
1013  if( nNew < 0 )
1014  {
1016  }
1017 
1018  //create PropertyChangeEvent and set value
1019  PropertyChangeEvent aEvt;
1020  {
1021  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1022  aEvt.Source = static_cast< XPropertySet * >( this );
1023  aEvt.PropertyName = aPropertyName;
1024  aEvt.Further = false;
1025  aEvt.PropertyHandle = m_xMyPropertySetInfo->
1026  m_nFetchSizePropertyHandle;
1027  aEvt.OldValue <<= m_nFetchSize;
1028  aEvt.NewValue <<= nNew;
1029 
1030  m_nFetchSize = nNew;
1031  }
1032 
1033  //send PropertyChangeEvent to listeners
1035  }
1036  else
1037  {
1039  {
1040  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1041  if( !m_xPropertySetOrigin.is() )
1042  {
1043  OSL_FAIL( "broadcaster was disposed already" );
1044  return;
1045  }
1046  }
1047  m_xPropertySetOrigin->setPropertyValue( aPropertyName, aValue );
1048  }
1049 }
1050 
1051 
1052 // virtual
1053 Any SAL_CALL CachedContentResultSet
1054  ::getPropertyValue( const OUString& rPropertyName )
1055 {
1057 
1058  if( !getPropertySetInfo().is() )
1059  {
1060  OSL_FAIL( "broadcaster was disposed already" );
1061  throw UnknownPropertyException();
1062  }
1063 
1064  m_xMyPropertySetInfo->getPropertyByName( rPropertyName );
1065  //throws UnknownPropertyException, if so
1066 
1067  Any aValue;
1068  if( rPropertyName == g_sPropertyNameForCount )
1069  {
1070  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1071  aValue <<= m_nKnownCount;
1072  }
1073  else if( rPropertyName == g_sPropertyNameForFinalCount )
1074  {
1075  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1076  aValue <<= m_bFinalCount;
1077  }
1078  else if( rPropertyName == g_sPropertyNameForFetchSize )
1079  {
1080  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1081  aValue <<= m_nFetchSize;
1082  }
1083  else if( rPropertyName == g_sPropertyNameForFetchDirection )
1084  {
1085  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1086  aValue <<= m_nFetchDirection;
1087  }
1088  else
1089  {
1091  {
1092  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1093  if( !m_xPropertySetOrigin.is() )
1094  {
1095  OSL_FAIL( "broadcaster was disposed already" );
1096  throw UnknownPropertyException();
1097  }
1098  }
1099  aValue = m_xPropertySetOrigin->getPropertyValue( rPropertyName );
1100  }
1101  return aValue;
1102 }
1103 
1104 
1105 // own methods. ( inherited )
1106 
1107 
1108 //virtual
1109 void CachedContentResultSet
1110  ::impl_disposing( const EventObject& rEventObject )
1111 {
1112  {
1114  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1115  //release all references to the broadcaster:
1116  m_xFetchProvider.clear();
1118  }
1120 }
1121 
1122 //virtual
1123 void CachedContentResultSet
1124  ::impl_propertyChange( const PropertyChangeEvent& rEvt )
1125 {
1127 
1128  PropertyChangeEvent aEvt( rEvt );
1129  aEvt.Source = static_cast< XPropertySet * >( this );
1130  aEvt.Further = false;
1131 
1132 
1134  ::impl_isMyPropertyName( rEvt.PropertyName ) )
1135  {
1136  //don't notify foreign events on fetchsize and fetchdirection
1137  if( aEvt.PropertyName == g_sPropertyNameForFetchSize
1138  || aEvt.PropertyName == g_sPropertyNameForFetchDirection )
1139  return;
1140 
1141  //adjust my props 'RowCount' and 'IsRowCountFinal'
1142  if( aEvt.PropertyName == g_sPropertyNameForCount )
1143  {//RowCount changed
1144 
1145  //check value
1146  sal_Int32 nNew = 0;
1147  if( !( aEvt.NewValue >>= nNew ) )
1148  {
1149  OSL_FAIL( "PropertyChangeEvent contains wrong data" );
1150  return;
1151  }
1152 
1154  }
1155  else if( aEvt.PropertyName == g_sPropertyNameForFinalCount )
1156  {//IsRowCountFinal changed
1157 
1158  //check value
1159  bool bNew = false;
1160  if( !( aEvt.NewValue >>= bNew ) )
1161  {
1162  OSL_FAIL( "PropertyChangeEvent contains wrong data" );
1163  return;
1164  }
1166  }
1167  return;
1168  }
1169 
1170 
1172 }
1173 
1174 
1175 //virtual
1176 void CachedContentResultSet
1177  ::impl_vetoableChange( const PropertyChangeEvent& rEvt )
1178 {
1180 
1181  //don't notify events on my properties, cause they are not vetoable
1183  ::impl_isMyPropertyName( rEvt.PropertyName ) )
1184  {
1185  return;
1186  }
1187 
1188 
1189  PropertyChangeEvent aEvt( rEvt );
1190  aEvt.Source = static_cast< XPropertySet * >( this );
1191  aEvt.Further = false;
1192 
1194 }
1195 
1196 
1197 // XContentAccess methods. ( inherited ) ( -- position dependent )
1198 
1199 
1200 #define XCONTENTACCESS_queryXXX( queryXXX, XXX, TYPE ) \
1201 impl_EnsureNotDisposed(); \
1202 osl::ResettableMutexGuard aGuard(m_aMutex); \
1203 sal_Int32 nRow = m_nRow; \
1204 sal_Int32 nFetchSize = m_nFetchSize; \
1205 sal_Int32 nFetchDirection = m_nFetchDirection; \
1206 if( !m_aCache##XXX.hasRow( nRow ) ) \
1207 { \
1208  try \
1209  { \
1210  bool isCleared = false; \
1211  if( !m_aCache##XXX.hasCausedException( nRow ) ) \
1212  { \
1213  if( !m_xFetchProviderForContentAccess.is() ) \
1214  { \
1215  OSL_FAIL( "broadcaster was disposed already" ); \
1216  throw RuntimeException(); \
1217  } \
1218  aGuard.clear(); \
1219  isCleared = true; \
1220  if( impl_isForwardOnly() ) \
1221  applyPositionToOrigin( nRow ); \
1222  \
1223  FETCH_XXX( m_aCache##XXX, m_xFetchProviderForContentAccess, fetch##XXX##s ); \
1224  } \
1225  if (isCleared) \
1226  { \
1227  aGuard.reset(); \
1228  } \
1229  if( !m_aCache##XXX.hasRow( nRow ) ) \
1230  { \
1231  aGuard.clear(); \
1232  applyPositionToOrigin( nRow ); \
1233  TYPE aRet = ContentResultSetWrapper::queryXXX();\
1234  if( m_xContentIdentifierMapping.is() ) \
1235  return m_xContentIdentifierMapping->map##XXX( aRet );\
1236  return aRet; \
1237  } \
1238  } \
1239  catch (const RuntimeException&) \
1240  { \
1241  throw; \
1242  } \
1243  catch (const Exception& e) \
1244  { \
1245  Any a(cppu::getCaughtException()); \
1246  throw WrappedTargetRuntimeException( \
1247  "wrapped Exception " + e.Message, \
1248  Reference<XInterface>(), a); \
1249  } \
1250 } \
1251 return m_aCache##XXX.get##XXX( nRow );
1252 
1253 // virtual
1254 OUString SAL_CALL CachedContentResultSet
1255  ::queryContentIdentifierString()
1256 {
1257  XCONTENTACCESS_queryXXX( queryContentIdentifierString, ContentIdentifierString, OUString )
1258 }
1259 
1260 
1261 // virtual
1262 Reference< XContentIdentifier > SAL_CALL CachedContentResultSet
1263  ::queryContentIdentifier()
1264 {
1266 }
1267 
1268 
1269 // virtual
1270 Reference< XContent > SAL_CALL CachedContentResultSet
1271  ::queryContent()
1272 {
1274 }
1275 
1276 
1277 // XResultSet methods. ( inherited )
1278 
1279 //virtual
1280 
1281 sal_Bool SAL_CALL CachedContentResultSet
1282  ::next()
1283 {
1285 
1286  osl::ResettableMutexGuard aGuard(m_aMutex);
1287  //after last
1288  if( m_bAfterLast )
1289  return false;
1290  //last
1291  aGuard.clear();
1292  if( isLast() )
1293  {
1294  aGuard.reset();
1295  m_nRow++;
1296  m_bAfterLast = true;
1297  return false;
1298  }
1299  aGuard.reset();
1300  //known valid position
1301  if( impl_isKnownValidPosition( m_nRow + 1 ) )
1302  {
1303  m_nRow++;
1304  return true;
1305  }
1306 
1307  //unknown position
1308  sal_Int32 nRow = m_nRow;
1309  aGuard.clear();
1310 
1311  bool bValid = applyPositionToOrigin( nRow + 1 );
1312 
1313  aGuard.reset();
1314  m_nRow = nRow + 1;
1315  m_bAfterLast = !bValid;
1316  return bValid;
1317 }
1318 
1319 //virtual
1320 sal_Bool SAL_CALL CachedContentResultSet
1321  ::previous()
1322 {
1324 
1325  if( impl_isForwardOnly() )
1326  throw SQLException();
1327 
1328  osl::ResettableMutexGuard aGuard(m_aMutex);
1329  //before first ?:
1330  if( !m_bAfterLast && !m_nRow )
1331  return false;
1332  //first ?:
1333  if( !m_bAfterLast && m_nKnownCount && m_nRow == 1 )
1334  {
1335  m_nRow--;
1336  m_bAfterLast = false;
1337  return false;
1338  }
1339  //known valid position ?:
1340  if( impl_isKnownValidPosition( m_nRow - 1 ) )
1341  {
1342  m_nRow--;
1343  m_bAfterLast = false;
1344  return true;
1345  }
1346  //unknown position:
1347  sal_Int32 nRow = m_nRow;
1348  aGuard.clear();
1349 
1350  bool bValid = applyPositionToOrigin( nRow - 1 );
1351 
1352  aGuard.reset();
1353  m_nRow = nRow - 1;
1354  m_bAfterLast = false;
1355  return bValid;
1356 }
1357 
1358 //virtual
1359 sal_Bool SAL_CALL CachedContentResultSet
1360  ::absolute( sal_Int32 row )
1361 {
1363 
1364  if( !row )
1365  throw SQLException();
1366 
1367  if( impl_isForwardOnly() )
1368  throw SQLException();
1369 
1370  osl::ResettableMutexGuard aGuard(m_aMutex);
1371 
1372  if( !m_xResultSetOrigin.is() )
1373  {
1374  OSL_FAIL( "broadcaster was disposed already" );
1375  return false;
1376  }
1377  if( row < 0 )
1378  {
1379  if( m_bFinalCount )
1380  {
1381  sal_Int32 nNewRow = m_nKnownCount + 1 + row;
1382  bool bValid = true;
1383  if( nNewRow <= 0 )
1384  {
1385  nNewRow = 0;
1386  bValid = false;
1387  }
1388  m_nRow = nNewRow;
1389  m_bAfterLast = false;
1390  return bValid;
1391  }
1392  //unknown final count:
1393  aGuard.clear();
1394 
1395  bool bValid = m_xResultSetOrigin->absolute( row );
1396 
1397  aGuard.reset();
1398  if( m_bFinalCount )
1399  {
1400  sal_Int32 nNewRow = m_nKnownCount + 1 + row;
1401  if( nNewRow < 0 )
1402  nNewRow = 0;
1403  m_nLastAppliedPos = nNewRow;
1404  m_nRow = nNewRow;
1406  return bValid;
1407  }
1408  aGuard.clear();
1409 
1410  sal_Int32 nCurRow = m_xResultSetOrigin->getRow();
1411 
1412  aGuard.reset();
1413  m_nLastAppliedPos = nCurRow;
1414  m_nRow = nCurRow;
1415  m_bAfterLast = false;
1416  return nCurRow != 0;
1417  }
1418  //row > 0:
1419  if( m_bFinalCount )
1420  {
1421  if( row > m_nKnownCount )
1422  {
1423  m_nRow = m_nKnownCount + 1;
1424  m_bAfterLast = true;
1425  return false;
1426  }
1427  m_nRow = row;
1428  m_bAfterLast = false;
1429  return true;
1430  }
1431  //unknown new position:
1432  aGuard.clear();
1433 
1434  bool bValid = m_xResultSetOrigin->absolute( row );
1435 
1436  aGuard.reset();
1437  if( m_bFinalCount )
1438  {
1439  sal_Int32 nNewRow = row;
1440  if( nNewRow > m_nKnownCount )
1441  {
1442  nNewRow = m_nKnownCount + 1;
1444  }
1445  else
1447 
1448  m_nLastAppliedPos = nNewRow;
1449  m_nRow = nNewRow;
1450  return bValid;
1451  }
1452  aGuard.clear();
1453 
1454  sal_Int32 nCurRow = m_xResultSetOrigin->getRow();
1455  bool bIsAfterLast = m_xResultSetOrigin->isAfterLast();
1456 
1457  aGuard.reset();
1458  m_nLastAppliedPos = nCurRow;
1459  m_nRow = nCurRow;
1460  m_bAfterLastApplied = m_bAfterLast = bIsAfterLast;
1461  return nCurRow && !bIsAfterLast;
1462 }
1463 
1464 //virtual
1465 sal_Bool SAL_CALL CachedContentResultSet
1466  ::relative( sal_Int32 rows )
1467 {
1469 
1470  if( impl_isForwardOnly() )
1471  throw SQLException();
1472 
1473  osl::ResettableMutexGuard aGuard(m_aMutex);
1475  throw SQLException();
1476 
1477  if( !rows )
1478  return true;
1479 
1480  sal_Int32 nNewRow = m_nRow + rows;
1481  if( nNewRow < 0 )
1482  nNewRow = 0;
1483 
1484  if( impl_isKnownValidPosition( nNewRow ) )
1485  {
1486  m_nRow = nNewRow;
1487  m_bAfterLast = false;
1488  return true;
1489  }
1490  else
1491  {
1492  //known invalid new position:
1493  if( nNewRow == 0 )
1494  {
1495  m_bAfterLast = false;
1496  m_nRow = 0;
1497  return false;
1498  }
1499  if( m_bFinalCount && nNewRow > m_nKnownCount )
1500  {
1501  m_bAfterLast = true;
1502  m_nRow = m_nKnownCount + 1;
1503  return false;
1504  }
1505  //unknown new position:
1506  aGuard.clear();
1507  bool bValid = applyPositionToOrigin( nNewRow );
1508 
1509  aGuard.reset();
1510  m_nRow = nNewRow;
1511  m_bAfterLast = !bValid; // only nNewRow > 0 possible here
1512  return bValid;
1513  }
1514 }
1515 
1516 
1517 //virtual
1518 sal_Bool SAL_CALL CachedContentResultSet
1519  ::first()
1520 {
1522 
1523  if( impl_isForwardOnly() )
1524  throw SQLException();
1525 
1526  osl::ResettableMutexGuard aGuard(m_aMutex);
1527  if( impl_isKnownValidPosition( 1 ) )
1528  {
1529  m_nRow = 1;
1530  m_bAfterLast = false;
1531  return true;
1532  }
1533  if( impl_isKnownInvalidPosition( 1 ) )
1534  {
1535  m_nRow = 1;
1536  m_bAfterLast = false;
1537  return false;
1538  }
1539  //unknown position
1540  aGuard.clear();
1541 
1542  bool bValid = applyPositionToOrigin( 1 );
1543 
1544  aGuard.reset();
1545  m_nRow = 1;
1546  m_bAfterLast = false;
1547  return bValid;
1548 }
1549 
1550 //virtual
1551 sal_Bool SAL_CALL CachedContentResultSet
1552  ::last()
1553 {
1555 
1556  if( impl_isForwardOnly() )
1557  throw SQLException();
1558 
1559  osl::ResettableMutexGuard aGuard(m_aMutex);
1560  if( m_bFinalCount )
1561  {
1563  m_bAfterLast = false;
1564  return m_nKnownCount != 0;
1565  }
1566  //unknown position
1567  if( !m_xResultSetOrigin.is() )
1568  {
1569  OSL_FAIL( "broadcaster was disposed already" );
1570  return false;
1571  }
1572  aGuard.clear();
1573 
1574  bool bValid = m_xResultSetOrigin->last();
1575 
1576  aGuard.reset();
1578  if( m_bFinalCount )
1579  {
1582  return bValid;
1583  }
1584  aGuard.clear();
1585 
1586  sal_Int32 nCurRow = m_xResultSetOrigin->getRow();
1587 
1588  aGuard.reset();
1589  m_nLastAppliedPos = nCurRow;
1590  m_nRow = nCurRow;
1591  OSL_ENSURE( nCurRow >= m_nKnownCount, "position of last row < known Count, that could not be" );
1592  m_nKnownCount = nCurRow;
1593  m_bFinalCount = true;
1594  return nCurRow != 0;
1595 }
1596 
1597 //virtual
1598 void SAL_CALL CachedContentResultSet
1599  ::beforeFirst()
1600 {
1602 
1603  if( impl_isForwardOnly() )
1604  throw SQLException();
1605 
1606  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1607  m_nRow = 0;
1608  m_bAfterLast = false;
1609 }
1610 
1611 //virtual
1612 void SAL_CALL CachedContentResultSet
1613  ::afterLast()
1614 {
1616 
1617  if( impl_isForwardOnly() )
1618  throw SQLException();
1619 
1620  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1621  m_nRow = 1;
1622  m_bAfterLast = true;
1623 }
1624 
1625 //virtual
1626 sal_Bool SAL_CALL CachedContentResultSet
1627  ::isAfterLast()
1628 {
1630 
1631  osl::ResettableMutexGuard aGuard(m_aMutex);
1632  if( !m_bAfterLast )
1633  return false;
1634  if( m_nKnownCount )
1635  return m_bAfterLast;
1636  if( m_bFinalCount )
1637  return false;
1638 
1639  if( !m_xResultSetOrigin.is() )
1640  {
1641  OSL_FAIL( "broadcaster was disposed already" );
1642  return false;
1643  }
1644  aGuard.clear();
1645 
1646  //find out whether the original resultset contains rows or not
1647  m_xResultSetOrigin->afterLast();
1648 
1649  aGuard.reset();
1650  m_bAfterLastApplied = true;
1651  aGuard.clear();
1652 
1653  return m_xResultSetOrigin->isAfterLast();
1654 }
1655 
1656 //virtual
1657 sal_Bool SAL_CALL CachedContentResultSet
1658  ::isBeforeFirst()
1659 {
1661 
1662  osl::ResettableMutexGuard aGuard(m_aMutex);
1663  if( m_bAfterLast )
1664  return false;
1665  if( m_nRow )
1666  return false;
1667  if( m_nKnownCount )
1668  return true;
1669  if( m_bFinalCount )
1670  return false;
1671 
1672  if( !m_xResultSetOrigin.is() )
1673  {
1674  OSL_FAIL( "broadcaster was disposed already" );
1675  return false;
1676  }
1677  aGuard.clear();
1678 
1679  //find out whether the original resultset contains rows or not
1680  m_xResultSetOrigin->beforeFirst();
1681 
1682  aGuard.reset();
1683  m_bAfterLastApplied = false;
1684  m_nLastAppliedPos = 0;
1685  aGuard.clear();
1686 
1687  return m_xResultSetOrigin->isBeforeFirst();
1688 }
1689 
1690 //virtual
1691 sal_Bool SAL_CALL CachedContentResultSet
1692  ::isFirst()
1693 {
1695 
1696  sal_Int32 nRow = 0;
1697  Reference< XResultSet > xResultSetOrigin;
1698 
1699  {
1700  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1701  if( m_bAfterLast )
1702  return false;
1703  if( m_nRow != 1 )
1704  return false;
1705  if( m_nKnownCount )
1706  return true;
1707  if( m_bFinalCount )
1708  return false;
1709 
1710  nRow = m_nRow;
1711  xResultSetOrigin = m_xResultSetOrigin;
1712  }
1713 
1714  //need to ask origin
1715  {
1716  if( applyPositionToOrigin( nRow ) )
1717  return xResultSetOrigin->isFirst();
1718  else
1719  return false;
1720  }
1721 }
1722 
1723 //virtual
1724 sal_Bool SAL_CALL CachedContentResultSet
1725  ::isLast()
1726 {
1728 
1729  sal_Int32 nRow = 0;
1730  Reference< XResultSet > xResultSetOrigin;
1731  {
1732  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1733  if( m_bAfterLast )
1734  return false;
1735  if( m_nRow < m_nKnownCount )
1736  return false;
1737  if( m_bFinalCount )
1738  return m_nKnownCount && m_nRow == m_nKnownCount;
1739 
1740  nRow = m_nRow;
1741  xResultSetOrigin = m_xResultSetOrigin;
1742  }
1743 
1744  //need to ask origin
1745  {
1746  if( applyPositionToOrigin( nRow ) )
1747  return xResultSetOrigin->isLast();
1748  else
1749  return false;
1750  }
1751 }
1752 
1753 
1754 //virtual
1755 sal_Int32 SAL_CALL CachedContentResultSet
1756  ::getRow()
1757 {
1759 
1760  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1761  if( m_bAfterLast )
1762  return 0;
1763  return m_nRow;
1764 }
1765 
1766 //virtual
1767 void SAL_CALL CachedContentResultSet
1768  ::refreshRow()
1769 {
1771 
1772  //the ContentResultSet is static and will not change
1773  //therefore we don't need to reload anything
1774 }
1775 
1776 //virtual
1777 sal_Bool SAL_CALL CachedContentResultSet
1778  ::rowUpdated()
1779 {
1781 
1782  //the ContentResultSet is static and will not change
1783  return false;
1784 }
1785 //virtual
1786 sal_Bool SAL_CALL CachedContentResultSet
1787  ::rowInserted()
1788 {
1790 
1791  //the ContentResultSet is static and will not change
1792  return false;
1793 }
1794 
1795 //virtual
1796 sal_Bool SAL_CALL CachedContentResultSet
1797  ::rowDeleted()
1798 {
1800 
1801  //the ContentResultSet is static and will not change
1802  return false;
1803 }
1804 
1805 //virtual
1806 Reference< XInterface > SAL_CALL CachedContentResultSet
1807  ::getStatement()
1808 {
1810  //@todo ?return anything
1811  return Reference< XInterface >();
1812 }
1813 
1814 
1815 // XRow methods. ( inherited )
1816 
1817 
1818 //virtual
1819 sal_Bool SAL_CALL CachedContentResultSet
1820  ::wasNull()
1821 {
1824  {
1825  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1827  return m_bLastCachedReadWasNull;
1828  if( !m_xRowOrigin.is() )
1829  {
1830  OSL_FAIL( "broadcaster was disposed already" );
1831  return false;
1832  }
1833  }
1834  return m_xRowOrigin->wasNull();
1835 }
1836 
1837 //virtual
1838 OUString SAL_CALL CachedContentResultSet
1839  ::getString( sal_Int32 columnIndex )
1840 {
1841  return rowOriginGet<OUString>(&css::sdbc::XRow::getString, columnIndex);
1842 }
1843 
1844 //virtual
1845 sal_Bool SAL_CALL CachedContentResultSet
1846  ::getBoolean( sal_Int32 columnIndex )
1847 {
1848  return rowOriginGet<sal_Bool>(&css::sdbc::XRow::getBoolean, columnIndex);
1849 }
1850 
1851 //virtual
1852 sal_Int8 SAL_CALL CachedContentResultSet
1853  ::getByte( sal_Int32 columnIndex )
1854 {
1855  return rowOriginGet<sal_Int8>(&css::sdbc::XRow::getByte, columnIndex);
1856 }
1857 
1858 //virtual
1859 sal_Int16 SAL_CALL CachedContentResultSet
1860  ::getShort( sal_Int32 columnIndex )
1861 {
1862  return rowOriginGet<sal_Int16>(&css::sdbc::XRow::getShort, columnIndex);
1863 }
1864 
1865 //virtual
1866 sal_Int32 SAL_CALL CachedContentResultSet
1867  ::getInt( sal_Int32 columnIndex )
1868 {
1869  return rowOriginGet<sal_Int32>(&css::sdbc::XRow::getInt, columnIndex);
1870 }
1871 
1872 //virtual
1873 sal_Int64 SAL_CALL CachedContentResultSet
1874  ::getLong( sal_Int32 columnIndex )
1875 {
1876  return rowOriginGet<sal_Int64>(&css::sdbc::XRow::getLong, columnIndex);
1877 }
1878 
1879 //virtual
1880 float SAL_CALL CachedContentResultSet
1881  ::getFloat( sal_Int32 columnIndex )
1882 {
1883  return rowOriginGet<float>(&css::sdbc::XRow::getFloat, columnIndex);
1884 }
1885 
1886 //virtual
1887 double SAL_CALL CachedContentResultSet
1888  ::getDouble( sal_Int32 columnIndex )
1889 {
1890  return rowOriginGet<double>(&css::sdbc::XRow::getDouble, columnIndex);
1891 }
1892 
1893 //virtual
1894 Sequence< sal_Int8 > SAL_CALL CachedContentResultSet
1895  ::getBytes( sal_Int32 columnIndex )
1896 {
1897  return rowOriginGet< css::uno::Sequence<sal_Int8> >(
1898  &css::sdbc::XRow::getBytes, columnIndex);
1899 }
1900 
1901 //virtual
1902 Date SAL_CALL CachedContentResultSet
1903  ::getDate( sal_Int32 columnIndex )
1904 {
1905  return rowOriginGet<css::util::Date>(
1906  &css::sdbc::XRow::getDate, columnIndex);
1907 }
1908 
1909 //virtual
1910 Time SAL_CALL CachedContentResultSet
1911  ::getTime( sal_Int32 columnIndex )
1912 {
1913  return rowOriginGet<css::util::Time>(
1914  &css::sdbc::XRow::getTime, columnIndex);
1915 }
1916 
1917 //virtual
1918 DateTime SAL_CALL CachedContentResultSet
1919  ::getTimestamp( sal_Int32 columnIndex )
1920 {
1921  return rowOriginGet<css::util::DateTime>(
1922  &css::sdbc::XRow::getTimestamp, columnIndex);
1923 }
1924 
1925 //virtual
1927  SAL_CALL CachedContentResultSet
1928  ::getBinaryStream( sal_Int32 columnIndex )
1929 {
1930  return rowOriginGet< css::uno::Reference<css::io::XInputStream> >(
1931  &css::sdbc::XRow::getBinaryStream, columnIndex);
1932 }
1933 
1934 //virtual
1936  SAL_CALL CachedContentResultSet
1937  ::getCharacterStream( sal_Int32 columnIndex )
1938 {
1939  return rowOriginGet< css::uno::Reference<css::io::XInputStream> >(
1940  &css::sdbc::XRow::getCharacterStream, columnIndex);
1941 }
1942 
1943 //virtual
1944 Any SAL_CALL CachedContentResultSet
1945  ::getObject( sal_Int32 columnIndex,
1946  const Reference<
1947  css::container::XNameAccess >& typeMap )
1948 {
1949  //if you change this function please pay attention to
1950  //function template rowOriginGet, where this is similar implemented
1951 
1952  osl::ResettableMutexGuard aGuard(m_aMutex);
1953  sal_Int32 nRow = m_nRow;
1954  sal_Int32 nFetchSize = m_nFetchSize;
1955  sal_Int32 nFetchDirection = m_nFetchDirection;
1956  if( !m_aCache.hasRow( nRow ) )
1957  {
1958  bool isCleared = false;
1959  if( !m_aCache.hasCausedException( nRow ) )
1960  {
1961  if( !m_xFetchProvider.is() )
1962  {
1963  OSL_FAIL( "broadcaster was disposed already" );
1964  return Any();
1965  }
1966  isCleared = true;
1967  aGuard.clear();
1968 
1969  impl_fetchData( nRow, nFetchSize, nFetchDirection );
1970  }
1971  if (isCleared)
1972  {
1973  aGuard.reset();
1974  }
1975  if( !m_aCache.hasRow( nRow ) )
1976  {
1977  m_bLastReadWasFromCache = false;
1978  aGuard.clear();
1979  applyPositionToOrigin( nRow );
1981  return m_xRowOrigin->getObject( columnIndex, typeMap );
1982  }
1983  }
1984  //@todo: pay attention to typeMap
1985  const Any& rValue = m_aCache.getAny( nRow, columnIndex );
1986  m_bLastReadWasFromCache = true;
1987  m_bLastCachedReadWasNull = !rValue.hasValue();
1988  return rValue;
1989 }
1990 
1991 //virtual
1992 Reference< XRef > SAL_CALL CachedContentResultSet
1993  ::getRef( sal_Int32 columnIndex )
1994 {
1995  return rowOriginGet< css::uno::Reference<css::sdbc::XRef> >(
1996  &css::sdbc::XRow::getRef, columnIndex);
1997 }
1998 
1999 //virtual
2000 Reference< XBlob > SAL_CALL CachedContentResultSet
2001  ::getBlob( sal_Int32 columnIndex )
2002 {
2003  return rowOriginGet< css::uno::Reference<css::sdbc::XBlob> >(
2004  &css::sdbc::XRow::getBlob, columnIndex);
2005 }
2006 
2007 //virtual
2008 Reference< XClob > SAL_CALL CachedContentResultSet
2009  ::getClob( sal_Int32 columnIndex )
2010 {
2011  return rowOriginGet< css::uno::Reference<css::sdbc::XClob> >(
2012  &css::sdbc::XRow::getClob, columnIndex);
2013 }
2014 
2015 //virtual
2016 Reference< XArray > SAL_CALL CachedContentResultSet
2017  ::getArray( sal_Int32 columnIndex )
2018 {
2019  return rowOriginGet< css::uno::Reference<css::sdbc::XArray> >(
2020  &css::sdbc::XRow::getArray, columnIndex);
2021 }
2022 
2023 
2024 // Type Converter Support
2025 
2026 
2028 {
2029  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2030 
2032  {
2034  m_xTypeConverter.set( Converter::create(m_xContext) );
2035 
2036  OSL_ENSURE( m_xTypeConverter.is(),
2037  "PropertyValueSet::getTypeConverter() - "
2038  "Service 'com.sun.star.script.Converter' n/a!" );
2039  }
2040  return m_xTypeConverter;
2041 }
2042 
2043 
2044 
2045 
2047  const Reference< XComponentContext > & rxContext )
2048 {
2049  m_xContext = rxContext;
2050 }
2051 
2053 {
2054 }
2055 
2056 // CachedContentResultSetFactory XServiceInfo methods.
2057 
2059 {
2060  return "com.sun.star.comp.ucb.CachedContentResultSetFactory";
2061 }
2062 sal_Bool SAL_CALL CachedContentResultSetFactory::supportsService( const OUString& ServiceName )
2063 {
2064  return cppu::supportsService( this, ServiceName );
2065 }
2066 css::uno::Sequence< OUString > SAL_CALL CachedContentResultSetFactory::getSupportedServiceNames()
2067 {
2068  return { "com.sun.star.ucb.CachedContentResultSetFactory" };
2069 }
2070 
2071 // Service factory implementation.
2072 
2073 
2074 
2075 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
2077  css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
2078 {
2079  return cppu::acquire(new CachedContentResultSetFactory(context));
2080 }
2081 
2082 
2083 // CachedContentResultSetFactory XCachedContentResultSetFactory methods.
2084 
2085 
2086  //virtual
2087 Reference< XResultSet > SAL_CALL CachedContentResultSetFactory
2088  ::createCachedContentResultSet(
2089  const Reference< XResultSet > & xSource,
2090  const Reference< XContentIdentifierMapping > & xMapping )
2091 {
2092  Reference< XResultSet > xRet = new CachedContentResultSet( m_xContext, xSource, xMapping );
2093  return xRet;
2094 }
2095 
2096 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XTypeConverter > xConverter
Type
virtual css::uno::Reference< css::ucb::XContentIdentifier > SAL_CALL queryContentIdentifier() override
virtual void SAL_CALL acquire() override
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType) override
osl::Mutex m_aMutex
virtual void impl_disposing(const css::lang::EventObject &Source)
virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override
void impl_notifyPropertyChangeListeners(const css::beans::PropertyChangeEvent &rEvt)
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
constexpr OUStringLiteral g_sPropertyNameForFetchDirection(u"FetchDirection")
signed char sal_Int8
css::uno::Reference< css::uno::XComponentContext > m_xContext
void impl_notifyVetoableChangeListeners(const css::beans::PropertyChangeEvent &rEvt)
css::uno::Reference< css::script::XTypeConverter > m_xTypeConverter
sal_Int64 n
bool impl_isKnownInvalidPosition(sal_Int32 nRow)
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
rtl::Reference< CCRS_PropertySetInfo > m_xMyPropertySetInfo
T rowOriginGet(T(SAL_CALL css::sdbc::XRow::*f)(sal_Int32), sal_Int32 columnIndex)
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType) override
bool applyPositionToOrigin(sal_Int32 nRow)
const css::uno::Any & getAny(sal_Int32 nRow, sal_Int32 nColumnIndex)
const css::uno::Reference< css::script::XTypeConverter > & getTypeConverter()
CachedContentResultSetFactory(const css::uno::Reference< css::uno::XComponentContext > &rxContext)
std::unique_ptr< Sequence< css::beans::Property > > m_pProperties
virtual void SAL_CALL release() override
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
#define COMSUNSTARUCBCCRS_DEFAULT_FETCH_SIZE
css::uno::Reference< css::ucb::XFetchProvider > m_xFetchProvider
css::uno::Any const & rValue
Any SAL_CALL getCaughtException()
int nCount
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
sal_Int32 nHandle
void impl_fetchData(sal_Int32 nRow, sal_Int32 nCount, sal_Int32 nFetchDirection)
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
virtual sal_Bool SAL_CALL isLast() override
css::uno::Reference< css::ucb::XFetchProviderForContentAccess > m_xFetchProviderForContentAccess
XTYPEPROVIDER_IMPL_2(CCRS_PropertySetInfo, XTypeProvider, XPropertySetInfo)
css::uno::Reference< css::ucb::XContentIdentifierMapping > m_xContentIdentifierMapping
virtual OUString SAL_CALL getImplementationName() override
class SAL_NO_VTABLE XPropertySet
virtual OUString SAL_CALL queryContentIdentifierString() override
#define XCONTENTACCESS_queryXXX(queryXXX, XXX, TYPE)
virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override
virtual OUString SAL_CALL getImplementationName() override
const char16_t g_sPropertyNameForCount[]
css::uno::Reference< css::sdbc::XRow > m_xRowOrigin
unsigned char sal_Bool
void impl_changeRowCount(sal_Int32 nOld, sal_Int32 nNew)
css::uno::Reference< css::uno::XComponentContext > m_xContext
XTYPEPROVIDER_IMPL_11(CachedContentResultSet, XTypeProvider, XServiceInfo, XComponent, XCloseable, XResultSetMetaDataSupplier, XPropertySet, XPropertyChangeListener, XVetoableChangeListener, XContentAccess, XResultSet, XRow)
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * ucb_CachedContentResultSetFactory_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
css::uno::Type const & get()
bool impl_isKnownValidPosition(sal_Int32 nRow)
constexpr OUStringLiteral g_sPropertyNameForFetchSize(u"FetchSize")
virtual void SAL_CALL release() override
virtual void SAL_CALL acquire() override
CCRS_Cache(const css::uno::Reference< css::ucb::XContentIdentifierMapping > &xMapping)
#define FETCH_XXX(aCache, fetchInterface, fetchMethod)
double getLength(const B2DPolygon &rCandidate)
css::uno::Reference< css::beans::XPropertySet > m_xPropertySetOrigin
! call impl_init_xContentAccessOrigin() bevor you access this member
virtual ~CachedContentResultSet() override
css::uno::Reference< css::sdbc::XResultSet > m_xResultSetOrigin
css::uno::Reference< css::beans::XPropertySetInfo > m_xPropertySetInfo
! call impl_init_xPropertySetOrigin() bevor you access this member
uno::Reference< script::XTypeConverter > const & getTypeConverter(const uno::Reference< uno::XComponentContext > &xContext)
const char16_t g_sPropertyNameForFinalCount[]
tuple m
virtual css::uno::Reference< css::ucb::XContent > SAL_CALL queryContent() override
#define COMSUNSTARUCBCCRS_DEFAULT_FETCH_DIRECTION
css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType, Interface1 *p1)
CachedContentResultSet(const css::uno::Reference< css::uno::XComponentContext > &rxContext, const css::uno::Reference< css::sdbc::XResultSet > &xOrigin, const css::uno::Reference< css::ucb::XContentIdentifierMapping > &xContentIdentifierMapping)
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType) override
void impl_changeIsRowCountFinal(bool bOld, bool bNew)
virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override