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