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