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