Bump version to 5.0-14
[LibreOffice.git] / dbaccess / source / core / dataaccess / datasource.cxx
blob4b8d579be89573913844e515b738f9576720b6fa
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "datasource.hxx"
21 #include "module_dba.hxx"
22 #include "services.hxx"
23 #include "userinformation.hxx"
24 #include "commandcontainer.hxx"
25 #include "dbastrings.hrc"
26 #include "core_resource.hxx"
27 #include "core_resource.hrc"
28 #include "connection.hxx"
29 #include "SharedConnection.hxx"
30 #include "databasedocument.hxx"
31 #include "OAuthenticationContinuation.hxx"
33 #include <com/sun/star/beans/NamedValue.hpp>
34 #include <com/sun/star/beans/PropertyAttribute.hpp>
35 #include <com/sun/star/beans/PropertyState.hpp>
36 #include <com/sun/star/beans/XPropertyContainer.hpp>
37 #include <com/sun/star/document/XDocumentSubStorageSupplier.hpp>
38 #include <com/sun/star/embed/XTransactedObject.hpp>
39 #include <com/sun/star/lang/DisposedException.hpp>
40 #include <com/sun/star/reflection/ProxyFactory.hpp>
41 #include <com/sun/star/sdb/DatabaseContext.hpp>
42 #include <com/sun/star/sdbc/ConnectionPool.hpp>
43 #include <com/sun/star/sdbc/XDriverAccess.hpp>
44 #include <com/sun/star/sdbc/XDriverManager.hpp>
45 #include <com/sun/star/sdbc/DriverManager.hpp>
46 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
47 #include <com/sun/star/ucb/AuthenticationRequest.hpp>
48 #include <com/sun/star/ucb/XInteractionSupplyAuthentication.hpp>
49 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
50 #include <com/sun/star/view/XPrintable.hpp>
52 #include <comphelper/guarding.hxx>
53 #include <comphelper/interaction.hxx>
54 #include <comphelper/namedvaluecollection.hxx>
55 #include <comphelper/property.hxx>
56 #include <comphelper/seqstream.hxx>
57 #include <comphelper/sequence.hxx>
58 #include <cppuhelper/supportsservice.hxx>
59 #include <connectivity/dbexception.hxx>
60 #include <connectivity/dbtools.hxx>
61 #include <cppuhelper/typeprovider.hxx>
62 #include <tools/debug.hxx>
63 #include <tools/diagnose_ex.h>
64 #include <osl/diagnose.h>
65 #include <tools/urlobj.hxx>
66 #include <typelib/typedescription.hxx>
67 #include <unotools/confignode.hxx>
68 #include <unotools/sharedunocomponent.hxx>
69 #include <rtl/digest.h>
71 #include <algorithm>
72 #include <iterator>
73 #include <set>
75 using namespace ::com::sun::star::sdbc;
76 using namespace ::com::sun::star::sdbcx;
77 using namespace ::com::sun::star::sdb;
78 using namespace ::com::sun::star::beans;
79 using namespace ::com::sun::star::uno;
80 using namespace ::com::sun::star::lang;
81 using namespace ::com::sun::star::embed;
82 using namespace ::com::sun::star::container;
83 using namespace ::com::sun::star::util;
84 using namespace ::com::sun::star::io;
85 using namespace ::com::sun::star::task;
86 using namespace ::com::sun::star::ucb;
87 using namespace ::com::sun::star::frame;
88 using namespace ::com::sun::star::reflection;
89 using namespace ::cppu;
90 using namespace ::osl;
91 using namespace ::dbtools;
92 using namespace ::comphelper;
94 namespace dbaccess
97 // FlushNotificationAdapter
98 typedef ::cppu::WeakImplHelper1< XFlushListener > FlushNotificationAdapter_Base;
99 /** helper class which implements a XFlushListener, and forwards all
100 notification events to another XFlushListener
102 The speciality is that the foreign XFlushListener instance, to which
103 the notifications are forwarded, is held weak.
105 Thus, the class can be used with XFlushable instance which hold
106 their listeners with a hard reference, if you simply do not *want*
107 to be held hard-ref-wise.
109 class FlushNotificationAdapter : public FlushNotificationAdapter_Base
111 private:
112 WeakReference< XFlushable > m_aBroadcaster;
113 WeakReference< XFlushListener > m_aListener;
115 public:
116 static void installAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener )
118 Reference< XFlushListener > xAdapter( new FlushNotificationAdapter( _rxBroadcaster, _rxListener ) );
121 protected:
122 FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener );
123 virtual ~FlushNotificationAdapter();
125 void SAL_CALL impl_dispose( bool _bRevokeListener );
127 protected:
128 // XFlushListener
129 virtual void SAL_CALL flushed( const ::com::sun::star::lang::EventObject& rEvent ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
130 // XEventListener
131 virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
134 FlushNotificationAdapter::FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener )
135 :m_aBroadcaster( _rxBroadcaster )
136 ,m_aListener( _rxListener )
138 OSL_ENSURE( _rxBroadcaster.is(), "FlushNotificationAdapter::FlushNotificationAdapter: invalid flushable!" );
140 osl_atomic_increment( &m_refCount );
142 if ( _rxBroadcaster.is() )
143 _rxBroadcaster->addFlushListener( this );
145 osl_atomic_decrement( &m_refCount );
146 OSL_ENSURE( m_refCount == 1, "FlushNotificationAdapter::FlushNotificationAdapter: broadcaster isn't holding by hard ref!?" );
149 FlushNotificationAdapter::~FlushNotificationAdapter()
153 void SAL_CALL FlushNotificationAdapter::impl_dispose( bool _bRevokeListener )
155 Reference< XFlushListener > xKeepAlive( this );
157 if ( _bRevokeListener )
159 Reference< XFlushable > xFlushable( m_aBroadcaster );
160 if ( xFlushable.is() )
161 xFlushable->removeFlushListener( this );
164 m_aListener.clear();
165 m_aBroadcaster.clear();
168 void SAL_CALL FlushNotificationAdapter::flushed( const EventObject& rEvent ) throw (RuntimeException, std::exception)
170 Reference< XFlushListener > xListener( m_aListener );
171 if ( xListener.is() )
172 xListener->flushed( rEvent );
173 else
174 impl_dispose( true );
177 void SAL_CALL FlushNotificationAdapter::disposing( const EventObject& Source ) throw (RuntimeException, std::exception)
179 Reference< XFlushListener > xListener( m_aListener );
180 if ( xListener.is() )
181 xListener->disposing( Source );
183 impl_dispose( true );
186 OAuthenticationContinuation::OAuthenticationContinuation()
187 :m_bRemberPassword(true), // TODO: a meaningful default
188 m_bCanSetUserName(true)
192 sal_Bool SAL_CALL OAuthenticationContinuation::canSetRealm( ) throw(RuntimeException, std::exception)
194 return sal_False;
197 void SAL_CALL OAuthenticationContinuation::setRealm( const OUString& /*Realm*/ ) throw(RuntimeException, std::exception)
199 SAL_WARN("dbaccess","OAuthenticationContinuation::setRealm: not supported!");
202 sal_Bool SAL_CALL OAuthenticationContinuation::canSetUserName( ) throw(RuntimeException, std::exception)
204 // we always allow this, even if the database document is read-only. In this case,
205 // it's simply that the user cannot store the new user name.
206 return m_bCanSetUserName;
209 void SAL_CALL OAuthenticationContinuation::setUserName( const OUString& _rUser ) throw(RuntimeException, std::exception)
211 m_sUser = _rUser;
214 sal_Bool SAL_CALL OAuthenticationContinuation::canSetPassword( ) throw(RuntimeException, std::exception)
216 return sal_True;
219 void SAL_CALL OAuthenticationContinuation::setPassword( const OUString& _rPassword ) throw(RuntimeException, std::exception)
221 m_sPassword = _rPassword;
224 Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberPasswordModes( RememberAuthentication& _reDefault ) throw(RuntimeException, std::exception)
226 Sequence< RememberAuthentication > aReturn(1);
227 _reDefault = aReturn[0] = RememberAuthentication_SESSION;
228 return aReturn;
231 void SAL_CALL OAuthenticationContinuation::setRememberPassword( RememberAuthentication _eRemember ) throw(RuntimeException, std::exception)
233 m_bRemberPassword = (RememberAuthentication_NO != _eRemember);
236 sal_Bool SAL_CALL OAuthenticationContinuation::canSetAccount( ) throw(RuntimeException, std::exception)
238 return sal_False;
241 void SAL_CALL OAuthenticationContinuation::setAccount( const OUString& ) throw(RuntimeException, std::exception)
243 SAL_WARN("dbaccess","OAuthenticationContinuation::setAccount: not supported!");
246 Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberAccountModes( RememberAuthentication& _reDefault ) throw(RuntimeException, std::exception)
248 Sequence < RememberAuthentication > aReturn(1);
249 aReturn[0] = RememberAuthentication_NO;
250 _reDefault = RememberAuthentication_NO;
251 return aReturn;
254 void SAL_CALL OAuthenticationContinuation::setRememberAccount( RememberAuthentication /*Remember*/ ) throw(RuntimeException, std::exception)
256 SAL_WARN("dbaccess","OAuthenticationContinuation::setRememberAccount: not supported!");
259 /** The class OSharedConnectionManager implements a structure to share connections.
260 It owns the master connections which will be disposed when the last connection proxy is gone.
262 typedef ::cppu::WeakImplHelper1< XEventListener > OConnectionHelper_BASE;
263 // need to hold the digest
264 struct TDigestHolder
266 sal_uInt8 m_pBuffer[RTL_DIGEST_LENGTH_SHA1];
267 TDigestHolder()
269 m_pBuffer[0] = 0;
274 class OSharedConnectionManager : public OConnectionHelper_BASE
277 // contains the currently used master connections
278 typedef struct
280 Reference< XConnection > xMasterConnection;
281 oslInterlockedCount nALiveCount;
282 } TConnectionHolder;
284 // the less-compare functor, used for the stl::map
285 struct TDigestLess : public ::std::binary_function< TDigestHolder, TDigestHolder, bool>
287 bool operator() (const TDigestHolder& x, const TDigestHolder& y) const
289 sal_uInt32 i;
290 for(i=0;i < RTL_DIGEST_LENGTH_SHA1 && (x.m_pBuffer[i] >= y.m_pBuffer[i]); ++i)
292 return i < RTL_DIGEST_LENGTH_SHA1;
296 typedef ::std::map< TDigestHolder,TConnectionHolder,TDigestLess> TConnectionMap; // holds the master connections
297 typedef ::std::map< Reference< XConnection >,TConnectionMap::iterator> TSharedConnectionMap;// holds the shared connections
299 ::osl::Mutex m_aMutex;
300 TConnectionMap m_aConnections; // remember the master connection in conjunction with the digest
301 TSharedConnectionMap m_aSharedConnection; // the shared connections with conjunction with an iterator into the connections map
302 Reference< XProxyFactory > m_xProxyFactory;
304 protected:
305 virtual ~OSharedConnectionManager();
307 public:
308 OSharedConnectionManager(const Reference< XComponentContext >& _rxContext);
310 void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw(RuntimeException, std::exception) SAL_OVERRIDE;
311 Reference<XConnection> getConnection( const OUString& url,
312 const OUString& user,
313 const OUString& password,
314 const Sequence< PropertyValue >& _aInfo,
315 ODatabaseSource* _pDataSource);
316 void addEventListener(const Reference<XConnection>& _rxConnection,TConnectionMap::iterator& _rIter);
319 OSharedConnectionManager::OSharedConnectionManager(const Reference< XComponentContext >& _rxContext)
321 m_xProxyFactory.set( ProxyFactory::create( _rxContext ) );
324 OSharedConnectionManager::~OSharedConnectionManager()
328 void SAL_CALL OSharedConnectionManager::disposing( const ::com::sun::star::lang::EventObject& Source ) throw(RuntimeException, std::exception)
330 MutexGuard aGuard(m_aMutex);
331 Reference<XConnection> xConnection(Source.Source,UNO_QUERY);
332 TSharedConnectionMap::iterator aFind = m_aSharedConnection.find(xConnection);
333 if ( m_aSharedConnection.end() != aFind )
335 osl_atomic_decrement(&aFind->second->second.nALiveCount);
336 if ( !aFind->second->second.nALiveCount )
338 ::comphelper::disposeComponent(aFind->second->second.xMasterConnection);
339 m_aConnections.erase(aFind->second);
341 m_aSharedConnection.erase(aFind);
345 Reference<XConnection> OSharedConnectionManager::getConnection( const OUString& url,
346 const OUString& user,
347 const OUString& password,
348 const Sequence< PropertyValue >& _aInfo,
349 ODatabaseSource* _pDataSource)
351 MutexGuard aGuard(m_aMutex);
352 TConnectionMap::key_type nId;
353 Sequence< PropertyValue > aInfoCopy(_aInfo);
354 sal_Int32 nPos = aInfoCopy.getLength();
355 aInfoCopy.realloc( nPos + 2 );
356 aInfoCopy[nPos].Name = "TableFilter";
357 aInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableFilter;
358 aInfoCopy[nPos].Name = "TableTypeFilter";
359 aInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableTypeFilter;
361 OUString sUser = user;
362 OUString sPassword = password;
363 if ((sUser.isEmpty()) && (sPassword.isEmpty()) && (!_pDataSource->m_pImpl->m_sUser.isEmpty()))
364 { // ease the usage of this method. data source which are intended to have a user automatically
365 // fill in the user/password combination if the caller of this method does not specify otherwise
366 sUser = _pDataSource->m_pImpl->m_sUser;
367 if (!_pDataSource->m_pImpl->m_aPassword.isEmpty())
368 sPassword = _pDataSource->m_pImpl->m_aPassword;
371 ::connectivity::OConnectionWrapper::createUniqueId(url,aInfoCopy,nId.m_pBuffer,sUser,sPassword);
372 TConnectionMap::iterator aIter = m_aConnections.find(nId);
374 if ( m_aConnections.end() == aIter )
376 TConnectionHolder aHolder;
377 aHolder.nALiveCount = 0; // will be incremented by addListener
378 aHolder.xMasterConnection = _pDataSource->buildIsolatedConnection(user,password);
379 aIter = m_aConnections.insert(TConnectionMap::value_type(nId,aHolder)).first;
382 Reference<XConnection> xRet;
383 if ( aIter->second.xMasterConnection.is() )
385 Reference< XAggregation > xConProxy = m_xProxyFactory->createProxy(aIter->second.xMasterConnection.get());
386 xRet = new OSharedConnection(xConProxy);
387 m_aSharedConnection.insert(TSharedConnectionMap::value_type(xRet,aIter));
388 addEventListener(xRet,aIter);
391 return xRet;
394 void OSharedConnectionManager::addEventListener(const Reference<XConnection>& _rxConnection,TConnectionMap::iterator& _rIter)
396 Reference<XComponent> xComp(_rxConnection,UNO_QUERY);
397 xComp->addEventListener(this);
398 OSL_ENSURE( m_aConnections.end() != _rIter , "Iterator is end!");
399 osl_atomic_increment(&_rIter->second.nALiveCount);
402 namespace
404 Sequence< PropertyValue > lcl_filterDriverProperties( const Reference< XDriver >& _xDriver, const OUString& _sUrl,
405 const Sequence< PropertyValue >& _rDataSourceSettings, const AsciiPropertyValue* _pKnownSettings )
407 if ( _xDriver.is() )
409 Sequence< DriverPropertyInfo > aDriverInfo(_xDriver->getPropertyInfo(_sUrl,_rDataSourceSettings));
411 const PropertyValue* pDataSourceSetting = _rDataSourceSettings.getConstArray();
412 const PropertyValue* pEnd = pDataSourceSetting + _rDataSourceSettings.getLength();
414 ::std::vector< PropertyValue > aRet;
416 for ( ; pDataSourceSetting != pEnd ; ++pDataSourceSetting )
418 bool bAllowSetting = false;
419 const AsciiPropertyValue* pSetting = _pKnownSettings;
420 for ( ; pSetting->AsciiName; ++pSetting )
422 if ( pDataSourceSetting->Name.equalsAscii( pSetting->AsciiName ) )
423 { // the particular data source setting is known
425 const DriverPropertyInfo* pAllowedDriverSetting = aDriverInfo.getConstArray();
426 const DriverPropertyInfo* pDriverSettingsEnd = pAllowedDriverSetting + aDriverInfo.getLength();
427 for ( ; pAllowedDriverSetting != pDriverSettingsEnd; ++pAllowedDriverSetting )
429 if ( pAllowedDriverSetting->Name.equalsAscii( pSetting->AsciiName ) )
430 { // the driver also allows this setting
431 bAllowSetting = true;
432 break;
435 break;
438 if ( bAllowSetting || !pSetting->AsciiName )
439 { // if the driver allows this particular setting, or if the setting is completely unknown,
440 // we pass it to the driver
441 aRet.push_back( *pDataSourceSetting );
444 if ( !aRet.empty() )
445 return Sequence< PropertyValue >(&(*aRet.begin()),aRet.size());
447 return Sequence< PropertyValue >();
450 typedef ::std::map< OUString, sal_Int32 > PropertyAttributeCache;
452 struct IsDefaultAndNotRemoveable : public ::std::unary_function< PropertyValue, bool >
454 private:
455 const PropertyAttributeCache& m_rAttribs;
457 public:
458 IsDefaultAndNotRemoveable( const PropertyAttributeCache& _rAttribs ) : m_rAttribs( _rAttribs ) { }
460 bool operator()( const PropertyValue& _rProp )
462 if ( _rProp.State != PropertyState_DEFAULT_VALUE )
463 return false;
465 bool bRemoveable = true;
467 PropertyAttributeCache::const_iterator pos = m_rAttribs.find( _rProp.Name );
468 OSL_ENSURE( pos != m_rAttribs.end(), "IsDefaultAndNotRemoveable: illegal property name!" );
469 if ( pos != m_rAttribs.end() )
470 bRemoveable = ( ( pos->second & PropertyAttribute::REMOVABLE ) != 0 );
472 return !bRemoveable;
477 } // namespace dbaccess
479 // ODatabaseContext
481 extern "C" void SAL_CALL createRegistryInfo_ODatabaseSource()
483 static ::dba::OAutoRegistration< ::dbaccess::ODatabaseSource > aAutoRegistration;
486 namespace dbaccess
489 ODatabaseSource::ODatabaseSource(const ::rtl::Reference<ODatabaseModelImpl>& _pImpl)
490 :ModelDependentComponent( _pImpl )
491 ,ODatabaseSource_Base( getMutex() )
492 ,OPropertySetHelper( ODatabaseSource_Base::rBHelper )
493 ,m_aBookmarks( *this, getMutex() )
494 ,m_aFlushListeners( getMutex() )
496 // some kind of default
497 SAL_INFO("dbaccess", "DS: ctor: " << std::hex << this << ": " << std::hex << m_pImpl.get() );
500 ODatabaseSource::~ODatabaseSource()
502 SAL_INFO("dbaccess", "DS: dtor: " << std::hex << this << ": " << std::hex << m_pImpl.get() );
503 if ( !ODatabaseSource_Base::rBHelper.bInDispose && !ODatabaseSource_Base::rBHelper.bDisposed )
505 acquire();
506 dispose();
510 void ODatabaseSource::setName( const Reference< XDocumentDataSource >& _rxDocument, const OUString& _rNewName, DBContextAccess )
512 ODatabaseSource& rModelImpl = dynamic_cast< ODatabaseSource& >( *_rxDocument.get() );
514 ::osl::MutexGuard aGuard( rModelImpl.m_aMutex );
515 if ( rModelImpl.m_pImpl.is() )
516 rModelImpl.m_pImpl->m_sName = _rNewName;
519 // com::sun::star::lang::XTypeProvider
520 Sequence< Type > ODatabaseSource::getTypes() throw (RuntimeException, std::exception)
522 OTypeCollection aPropertyHelperTypes( cppu::UnoType<XFastPropertySet>::get(),
523 cppu::UnoType<XPropertySet>::get(),
524 cppu::UnoType<XMultiPropertySet>::get());
526 return ::comphelper::concatSequences(
527 ODatabaseSource_Base::getTypes(),
528 aPropertyHelperTypes.getTypes()
532 Sequence< sal_Int8 > ODatabaseSource::getImplementationId() throw (RuntimeException, std::exception)
534 return css::uno::Sequence<sal_Int8>();
537 // com::sun::star::uno::XInterface
538 Any ODatabaseSource::queryInterface( const Type & rType ) throw (RuntimeException, std::exception)
540 Any aIface = ODatabaseSource_Base::queryInterface( rType );
541 if ( !aIface.hasValue() )
542 aIface = ::cppu::OPropertySetHelper::queryInterface( rType );
543 return aIface;
546 void ODatabaseSource::acquire() throw ()
548 ODatabaseSource_Base::acquire();
551 void ODatabaseSource::release() throw ()
553 ODatabaseSource_Base::release();
556 void SAL_CALL ODatabaseSource::disposing( const ::com::sun::star::lang::EventObject& Source ) throw(RuntimeException, std::exception)
558 if ( m_pImpl.is() )
559 m_pImpl->disposing(Source);
562 // XServiceInfo
563 OUString ODatabaseSource::getImplementationName( ) throw(RuntimeException, std::exception)
565 return getImplementationName_static();
568 OUString ODatabaseSource::getImplementationName_static( ) throw(RuntimeException)
570 return OUString("com.sun.star.comp.dba.ODatabaseSource");
573 Sequence< OUString > ODatabaseSource::getSupportedServiceNames( ) throw (RuntimeException, std::exception)
575 return getSupportedServiceNames_static();
578 Reference< XInterface > ODatabaseSource::Create( const Reference< XComponentContext >& _rxContext )
580 Reference< XDatabaseContext > xDBContext( DatabaseContext::create(_rxContext) );
581 return xDBContext->createInstance();
584 Sequence< OUString > ODatabaseSource::getSupportedServiceNames_static( ) throw (RuntimeException)
586 Sequence< OUString > aSNS( 2 );
587 aSNS[0] = SERVICE_SDB_DATASOURCE;
588 aSNS[1] = "com.sun.star.sdb.DocumentDataSource";
589 return aSNS;
592 sal_Bool ODatabaseSource::supportsService( const OUString& _rServiceName ) throw (RuntimeException, std::exception)
594 return cppu::supportsService(this, _rServiceName);
597 // OComponentHelper
598 void ODatabaseSource::disposing()
600 SAL_INFO("dbaccess", "DS: disp: " << std::hex << this << ", " << std::hex << m_pImpl.get() );
601 ODatabaseSource_Base::WeakComponentImplHelperBase::disposing();
602 OPropertySetHelper::disposing();
604 EventObject aDisposeEvent(static_cast<XWeak*>(this));
605 m_aFlushListeners.disposeAndClear( aDisposeEvent );
607 ODatabaseDocument::clearObjectContainer(m_pImpl->m_xCommandDefinitions);
608 ODatabaseDocument::clearObjectContainer(m_pImpl->m_xTableDefinitions);
609 m_pImpl.clear();
612 Reference< XConnection > ODatabaseSource::buildLowLevelConnection(const OUString& _rUid, const OUString& _rPwd)
614 Reference< XConnection > xReturn;
616 Reference< XDriverManager > xManager;
617 try {
618 xManager.set( ConnectionPool::create( m_pImpl->m_aContext ), UNO_QUERY_THROW );
619 } catch( const Exception& ) { }
620 if ( !xManager.is() )
621 // no connection pool installed, fall back to driver manager
622 xManager.set( DriverManager::create(m_pImpl->m_aContext ), UNO_QUERY_THROW );
624 OUString sUser(_rUid);
625 OUString sPwd(_rPwd);
626 if ((sUser.isEmpty()) && (sPwd.isEmpty()) && (!m_pImpl->m_sUser.isEmpty()))
627 { // ease the usage of this method. data source which are intended to have a user automatically
628 // fill in the user/password combination if the caller of this method does not specify otherwise
629 sUser = m_pImpl->m_sUser;
630 if (!m_pImpl->m_aPassword.isEmpty())
631 sPwd = m_pImpl->m_aPassword;
634 sal_uInt16 nExceptionMessageId = RID_STR_COULDNOTCONNECT_UNSPECIFIED;
635 if (xManager.is())
637 sal_Int32 nAdditionalArgs(0);
638 if (!sUser.isEmpty()) ++nAdditionalArgs;
639 if (!sPwd.isEmpty()) ++nAdditionalArgs;
641 Sequence< PropertyValue > aUserPwd(nAdditionalArgs);
642 sal_Int32 nArgPos = 0;
643 if (!sUser.isEmpty())
645 aUserPwd[ nArgPos ].Name = "user";
646 aUserPwd[ nArgPos ].Value <<= sUser;
647 ++nArgPos;
649 if (!sPwd.isEmpty())
651 aUserPwd[ nArgPos ].Name = "password";
652 aUserPwd[ nArgPos ].Value <<= sPwd;
654 Reference< XDriver > xDriver;
657 Reference< XDriverAccess > xAccessDrivers( xManager, UNO_QUERY );
658 if ( xAccessDrivers.is() )
659 xDriver = xAccessDrivers->getDriverByURL( m_pImpl->m_sConnectURL );
661 catch( const Exception& )
663 SAL_WARN("dbaccess", "ODatabaseSource::buildLowLevelConnection: got a strange exception while analyzing the error!" );
665 if ( !xDriver.is() || !xDriver->acceptsURL( m_pImpl->m_sConnectURL ) )
667 // Nowadays, it's allowed for a driver to be registered for a given URL, but actually not to accept it.
668 // This is because registration nowadays happens at compile time (by adding respective configuration data),
669 // but acceptance is decided at runtime.
670 nExceptionMessageId = RID_STR_COULDNOTCONNECT_NODRIVER;
672 else
674 Sequence< PropertyValue > aDriverInfo = lcl_filterDriverProperties(
675 xDriver,
676 m_pImpl->m_sConnectURL,
677 m_pImpl->m_xSettings->getPropertyValues(),
678 dbaccess::ODatabaseModelImpl::getDefaultDataSourceSettings()
681 if ( m_pImpl->isEmbeddedDatabase() )
683 sal_Int32 nCount = aDriverInfo.getLength();
684 aDriverInfo.realloc(nCount + 3 );
686 aDriverInfo[nCount].Name = "URL";
687 aDriverInfo[nCount++].Value <<= m_pImpl->getURL();
689 aDriverInfo[nCount].Name = "Storage";
690 Reference< css::document::XDocumentSubStorageSupplier> xDocSup( m_pImpl->getDocumentSubStorageSupplier() );
691 aDriverInfo[nCount++].Value <<= xDocSup->getDocumentSubStorage("database",ElementModes::READWRITE);
693 aDriverInfo[nCount].Name = "Document";
694 aDriverInfo[nCount++].Value <<= getDatabaseDocument();
696 if (nAdditionalArgs)
697 xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL, ::comphelper::concatSequences(aUserPwd,aDriverInfo));
698 else
699 xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL,aDriverInfo);
701 if ( m_pImpl->isEmbeddedDatabase() )
703 // see ODatabaseSource::flushed for comment on why we register as FlushListener
704 // at the connection
705 Reference< XFlushable > xFlushable( xReturn, UNO_QUERY );
706 if ( xFlushable.is() )
707 FlushNotificationAdapter::installAdapter( xFlushable, this );
711 else
712 nExceptionMessageId = RID_STR_COULDNOTLOAD_MANAGER;
714 if ( !xReturn.is() )
716 OUString sMessage = DBACORE_RESSTRING( nExceptionMessageId )
717 .replaceAll("$name$", m_pImpl->m_sConnectURL);
719 SQLContext aContext;
720 aContext.Message = DBACORE_RESSTRING(RID_STR_CONNECTION_REQUEST).
721 replaceFirst("$name$", m_pImpl->m_sConnectURL);
723 throwGenericSQLException( sMessage, static_cast< XDataSource* >( this ), makeAny( aContext ) );
726 return xReturn;
729 // OPropertySetHelper
730 Reference< XPropertySetInfo > ODatabaseSource::getPropertySetInfo() throw (RuntimeException, std::exception)
732 return createPropertySetInfo( getInfoHelper() ) ;
735 // comphelper::OPropertyArrayUsageHelper
736 ::cppu::IPropertyArrayHelper* ODatabaseSource::createArrayHelper( ) const
738 BEGIN_PROPERTY_HELPER(13)
739 DECL_PROP1(INFO, Sequence< PropertyValue >, BOUND);
740 DECL_PROP1_BOOL(ISPASSWORDREQUIRED, BOUND);
741 DECL_PROP1_BOOL(ISREADONLY, READONLY);
742 DECL_PROP1(LAYOUTINFORMATION, Sequence< PropertyValue >, BOUND);
743 DECL_PROP1(NAME, OUString, READONLY);
744 DECL_PROP2_IFACE(NUMBERFORMATSSUPPLIER, XNumberFormatsSupplier, READONLY, TRANSIENT);
745 DECL_PROP1(PASSWORD, OUString, TRANSIENT);
746 DECL_PROP2_IFACE(SETTINGS, XPropertySet, BOUND, READONLY);
747 DECL_PROP1_BOOL(SUPPRESSVERSIONCL, BOUND);
748 DECL_PROP1(TABLEFILTER, Sequence< OUString >,BOUND);
749 DECL_PROP1(TABLETYPEFILTER, Sequence< OUString >,BOUND);
750 DECL_PROP1(URL, OUString, BOUND);
751 DECL_PROP1(USER, OUString, BOUND);
752 END_PROPERTY_HELPER();
755 // cppu::OPropertySetHelper
756 ::cppu::IPropertyArrayHelper& ODatabaseSource::getInfoHelper()
758 return *getArrayHelper();
761 sal_Bool ODatabaseSource::convertFastPropertyValue(Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue ) throw( IllegalArgumentException )
763 bool bModified(false);
764 if ( m_pImpl.is() )
766 switch (nHandle)
768 case PROPERTY_ID_TABLEFILTER:
769 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableFilter);
770 break;
771 case PROPERTY_ID_TABLETYPEFILTER:
772 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableTypeFilter);
773 break;
774 case PROPERTY_ID_USER:
775 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sUser);
776 break;
777 case PROPERTY_ID_PASSWORD:
778 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aPassword);
779 break;
780 case PROPERTY_ID_ISPASSWORDREQUIRED:
781 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bPasswordRequired);
782 break;
783 case PROPERTY_ID_SUPPRESSVERSIONCL:
784 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bSuppressVersionColumns);
785 break;
786 case PROPERTY_ID_LAYOUTINFORMATION:
787 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aLayoutInformation);
788 break;
789 case PROPERTY_ID_URL:
791 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sConnectURL);
792 } break;
793 case PROPERTY_ID_INFO:
795 Sequence<PropertyValue> aValues;
796 if (!(rValue >>= aValues))
797 throw IllegalArgumentException();
799 const PropertyValue* valueEnd = aValues.getConstArray() + aValues.getLength();
800 const PropertyValue* checkName = aValues.getConstArray();
801 for ( ;checkName != valueEnd; ++checkName )
803 if ( checkName->Name.isEmpty() )
804 throw IllegalArgumentException();
807 Sequence< PropertyValue > aSettings = m_pImpl->m_xSettings->getPropertyValues();
808 bModified = aSettings.getLength() != aValues.getLength();
809 if ( !bModified )
811 const PropertyValue* pInfoIter = aSettings.getConstArray();
812 const PropertyValue* checkValue = aValues.getConstArray();
813 for ( ;!bModified && checkValue != valueEnd ; ++checkValue,++pInfoIter)
815 bModified = checkValue->Name != pInfoIter->Name;
816 if ( !bModified )
818 bModified = !::comphelper::compare(checkValue->Value,pInfoIter->Value);
823 rConvertedValue = rValue;
824 rOldValue <<= aSettings;
826 break;
827 default:
828 SAL_WARN("dbaccess", "ODatabaseSource::convertFastPropertyValue: unknown or readonly Property!" );
831 return bModified;
834 namespace
836 struct SelectPropertyName : public ::std::unary_function< PropertyValue, OUString >
838 public:
839 const OUString& operator()( const PropertyValue& _lhs )
841 return _lhs.Name;
845 /** sets a new set of property values for a given property bag instance
847 The method takes a property bag, and a sequence of property values to set for this bag.
848 Upon return, every property which is not part of the given sequence is
849 <ul><li>removed from the bag, if it's a removable property</li>
850 <li><em>or</em>reset to its default value, if it's not a removable property</li>
851 </ul>.
853 @param _rxPropertyBag
854 the property bag to operate on
855 @param _rAllNewPropertyValues
856 the new property values to set for the bag
858 void lcl_setPropertyValues_resetOrRemoveOther( const Reference< XPropertyBag >& _rxPropertyBag, const Sequence< PropertyValue >& _rAllNewPropertyValues )
860 // sequences are ugly to operate on
861 typedef ::std::set< OUString > StringSet;
862 StringSet aToBeSetPropertyNames;
863 ::std::transform(
864 _rAllNewPropertyValues.getConstArray(),
865 _rAllNewPropertyValues.getConstArray() + _rAllNewPropertyValues.getLength(),
866 ::std::insert_iterator< StringSet >( aToBeSetPropertyNames, aToBeSetPropertyNames.end() ),
867 SelectPropertyName()
872 // obtain all properties currently known at the bag
873 Reference< XPropertySetInfo > xPSI( _rxPropertyBag->getPropertySetInfo(), UNO_QUERY_THROW );
874 Sequence< Property > aAllExistentProperties( xPSI->getProperties() );
876 Reference< XPropertyState > xPropertyState( _rxPropertyBag, UNO_QUERY_THROW );
878 // loop through them, and reset resp. default properties which are not to be set
879 const Property* pExistentProperty( aAllExistentProperties.getConstArray() );
880 const Property* pExistentPropertyEnd( aAllExistentProperties.getConstArray() + aAllExistentProperties.getLength() );
881 for ( ; pExistentProperty != pExistentPropertyEnd; ++pExistentProperty )
883 if ( aToBeSetPropertyNames.find( pExistentProperty->Name ) != aToBeSetPropertyNames.end() )
884 continue;
886 // this property is not to be set, but currently exists in the bag.
887 // -> Remove it, or reset it to the default.
888 if ( ( pExistentProperty->Attributes & PropertyAttribute::REMOVABLE ) != 0 )
889 _rxPropertyBag->removeProperty( pExistentProperty->Name );
890 else
891 xPropertyState->setPropertyToDefault( pExistentProperty->Name );
894 // finally, set the new property values
895 _rxPropertyBag->setPropertyValues( _rAllNewPropertyValues );
897 catch( const Exception& )
899 DBG_UNHANDLED_EXCEPTION();
904 void ODatabaseSource::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) throw (Exception, std::exception)
906 if ( m_pImpl.is() )
908 switch(nHandle)
910 case PROPERTY_ID_TABLEFILTER:
911 rValue >>= m_pImpl->m_aTableFilter;
912 break;
913 case PROPERTY_ID_TABLETYPEFILTER:
914 rValue >>= m_pImpl->m_aTableTypeFilter;
915 break;
916 case PROPERTY_ID_USER:
917 rValue >>= m_pImpl->m_sUser;
918 // if the user name has changed, reset the password
919 (m_pImpl->m_aPassword).clear();
920 break;
921 case PROPERTY_ID_PASSWORD:
922 rValue >>= m_pImpl->m_aPassword;
923 break;
924 case PROPERTY_ID_ISPASSWORDREQUIRED:
925 m_pImpl->m_bPasswordRequired = any2bool(rValue);
926 break;
927 case PROPERTY_ID_SUPPRESSVERSIONCL:
928 m_pImpl->m_bSuppressVersionColumns = any2bool(rValue);
929 break;
930 case PROPERTY_ID_URL:
931 rValue >>= m_pImpl->m_sConnectURL;
932 break;
933 case PROPERTY_ID_INFO:
935 Sequence< PropertyValue > aInfo;
936 OSL_VERIFY( rValue >>= aInfo );
937 lcl_setPropertyValues_resetOrRemoveOther( m_pImpl->m_xSettings, aInfo );
939 break;
940 case PROPERTY_ID_LAYOUTINFORMATION:
941 rValue >>= m_pImpl->m_aLayoutInformation;
942 break;
944 m_pImpl->setModified(true);
948 void ODatabaseSource::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
950 if ( m_pImpl.is() )
952 switch (nHandle)
954 case PROPERTY_ID_TABLEFILTER:
955 rValue <<= m_pImpl->m_aTableFilter;
956 break;
957 case PROPERTY_ID_TABLETYPEFILTER:
958 rValue <<= m_pImpl->m_aTableTypeFilter;
959 break;
960 case PROPERTY_ID_USER:
961 rValue <<= m_pImpl->m_sUser;
962 break;
963 case PROPERTY_ID_PASSWORD:
964 rValue <<= m_pImpl->m_aPassword;
965 break;
966 case PROPERTY_ID_ISPASSWORDREQUIRED:
967 rValue <<= m_pImpl->m_bPasswordRequired;
968 break;
969 case PROPERTY_ID_SUPPRESSVERSIONCL:
970 rValue <<= m_pImpl->m_bSuppressVersionColumns;
971 break;
972 case PROPERTY_ID_ISREADONLY:
973 rValue <<= m_pImpl->m_bReadOnly;
974 break;
975 case PROPERTY_ID_INFO:
979 // collect the property attributes of all current settings
980 Reference< XPropertySet > xSettingsAsProps( m_pImpl->m_xSettings, UNO_QUERY_THROW );
981 Reference< XPropertySetInfo > xPST( xSettingsAsProps->getPropertySetInfo(), UNO_QUERY_THROW );
982 Sequence< Property > aSettings( xPST->getProperties() );
983 ::std::map< OUString, sal_Int32 > aPropertyAttributes;
984 for ( const Property* pSettings = aSettings.getConstArray();
985 pSettings != aSettings.getConstArray() + aSettings.getLength();
986 ++pSettings
989 aPropertyAttributes[ pSettings->Name ] = pSettings->Attributes;
992 // get all current settings with their values
993 Sequence< PropertyValue > aValues( m_pImpl->m_xSettings->getPropertyValues() );
995 // transform them so that only property values which fulfill certain
996 // criteria survive
997 Sequence< PropertyValue > aNonDefaultOrUserDefined( aValues.getLength() );
998 const PropertyValue* pCopyEnd = ::std::remove_copy_if(
999 aValues.getConstArray(),
1000 aValues.getConstArray() + aValues.getLength(),
1001 aNonDefaultOrUserDefined.getArray(),
1002 IsDefaultAndNotRemoveable( aPropertyAttributes )
1004 aNonDefaultOrUserDefined.realloc( pCopyEnd - aNonDefaultOrUserDefined.getArray() );
1005 rValue <<= aNonDefaultOrUserDefined;
1007 catch( const Exception& )
1009 DBG_UNHANDLED_EXCEPTION();
1012 break;
1013 case PROPERTY_ID_SETTINGS:
1014 rValue <<= m_pImpl->m_xSettings;
1015 break;
1016 case PROPERTY_ID_URL:
1017 rValue <<= m_pImpl->m_sConnectURL;
1018 break;
1019 case PROPERTY_ID_NUMBERFORMATSSUPPLIER:
1020 rValue <<= m_pImpl->getNumberFormatsSupplier();
1021 break;
1022 case PROPERTY_ID_NAME:
1023 rValue <<= m_pImpl->m_sName;
1024 break;
1025 case PROPERTY_ID_LAYOUTINFORMATION:
1026 rValue <<= m_pImpl->m_aLayoutInformation;
1027 break;
1028 default:
1029 SAL_WARN("dbaccess","unknown Property");
1034 // XDataSource
1035 void ODatabaseSource::setLoginTimeout(sal_Int32 seconds) throw( SQLException, RuntimeException, std::exception )
1037 ModelMethodGuard aGuard( *this );
1038 m_pImpl->m_nLoginTimeout = seconds;
1041 sal_Int32 ODatabaseSource::getLoginTimeout() throw( SQLException, RuntimeException, std::exception )
1043 ModelMethodGuard aGuard( *this );
1044 return m_pImpl->m_nLoginTimeout;
1047 // XCompletedConnection
1048 Reference< XConnection > SAL_CALL ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler ) throw(SQLException, RuntimeException, std::exception)
1050 return connectWithCompletion(_rxHandler,false);
1053 Reference< XConnection > ODatabaseSource::getConnection(const OUString& user, const OUString& password) throw( SQLException, RuntimeException, std::exception )
1055 return getConnection(user,password,false);
1058 Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnection( const OUString& user, const OUString& password ) throw(SQLException, RuntimeException, std::exception)
1060 return getConnection(user,password,true);
1063 Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnectionWithCompletion( const Reference< XInteractionHandler >& _rxHandler ) throw(SQLException, RuntimeException, std::exception)
1065 return connectWithCompletion(_rxHandler,true);
1068 Reference< XConnection > SAL_CALL ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler,bool _bIsolated ) throw(SQLException, RuntimeException)
1070 ModelMethodGuard aGuard( *this );
1072 if (!_rxHandler.is())
1074 SAL_WARN("dbaccess","ODatabaseSource::connectWithCompletion: invalid interaction handler!");
1075 return getConnection(m_pImpl->m_sUser, m_pImpl->m_aPassword,_bIsolated);
1078 OUString sUser(m_pImpl->m_sUser), sPassword(m_pImpl->m_aPassword);
1079 bool bNewPasswordGiven = false;
1081 if (m_pImpl->m_bPasswordRequired && sPassword.isEmpty())
1082 { // we need a password, but don't have one yet.
1083 // -> ask the user
1085 // build an interaction request
1086 // two continuations (Ok and Cancel)
1087 OInteractionAbort* pAbort = new OInteractionAbort;
1088 OAuthenticationContinuation* pAuthenticate = new OAuthenticationContinuation;
1090 // the name which should be referred in the login dialog
1091 OUString sServerName( m_pImpl->m_sName );
1092 INetURLObject aURLCheck( sServerName );
1093 if ( aURLCheck.GetProtocol() != INetProtocol::NotValid )
1094 sServerName = aURLCheck.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_UNAMBIGUOUS );
1096 // the request
1097 AuthenticationRequest aRequest;
1098 aRequest.ServerName = sServerName;
1099 aRequest.HasRealm = aRequest.HasAccount = sal_False;
1100 aRequest.HasUserName = aRequest.HasPassword = sal_True;
1101 aRequest.UserName = m_pImpl->m_sUser;
1102 aRequest.Password = m_pImpl->m_sFailedPassword.isEmpty() ? m_pImpl->m_aPassword : m_pImpl->m_sFailedPassword;
1103 OInteractionRequest* pRequest = new OInteractionRequest(makeAny(aRequest));
1104 Reference< XInteractionRequest > xRequest(pRequest);
1105 // some knittings
1106 pRequest->addContinuation(pAbort);
1107 pRequest->addContinuation(pAuthenticate);
1109 // handle the request
1112 MutexRelease aRelease( getMutex() );
1113 // release the mutex when calling the handler, it may need to lock the SolarMutex
1114 _rxHandler->handle(xRequest);
1116 catch(Exception&)
1118 DBG_UNHANDLED_EXCEPTION();
1121 if (!pAuthenticate->wasSelected())
1122 return Reference< XConnection >();
1124 // get the result
1125 sUser = m_pImpl->m_sUser = pAuthenticate->getUser();
1126 sPassword = pAuthenticate->getPassword();
1128 if (pAuthenticate->getRememberPassword())
1130 m_pImpl->m_aPassword = pAuthenticate->getPassword();
1131 bNewPasswordGiven = true;
1133 (m_pImpl->m_sFailedPassword).clear();
1138 return getConnection(sUser, sPassword,_bIsolated);
1140 catch(Exception&)
1142 if (bNewPasswordGiven)
1144 m_pImpl->m_sFailedPassword = m_pImpl->m_aPassword;
1145 // assume that we had an authentication problem. Without this we may, after an unsuccessful connect, while
1146 // the user gave us a password an the order to remember it, never allow an password input again (at least
1147 // not without restarting the session)
1148 (m_pImpl->m_aPassword).clear();
1150 throw;
1154 Reference< XConnection > ODatabaseSource::buildIsolatedConnection(const OUString& user, const OUString& password)
1156 Reference< XConnection > xConn;
1157 Reference< XConnection > xSdbcConn = buildLowLevelConnection(user, password);
1158 OSL_ENSURE( xSdbcConn.is(), "ODatabaseSource::buildIsolatedConnection: invalid return value of buildLowLevelConnection!" );
1159 // buildLowLevelConnection is expected to always succeed
1160 if ( xSdbcConn.is() )
1162 // build a connection server and return it (no stubs)
1163 xConn = new OConnection(*this, xSdbcConn, m_pImpl->m_aContext);
1165 return xConn;
1168 Reference< XConnection > ODatabaseSource::getConnection(const OUString& user, const OUString& password,bool _bIsolated) throw( SQLException, RuntimeException )
1170 ModelMethodGuard aGuard( *this );
1172 Reference< XConnection > xConn;
1173 if ( _bIsolated )
1175 xConn = buildIsolatedConnection(user,password);
1177 else
1178 { // create a new proxy for the connection
1179 if ( !m_pImpl->m_xSharedConnectionManager.is() )
1181 m_pImpl->m_pSharedConnectionManager = new OSharedConnectionManager( m_pImpl->m_aContext );
1182 m_pImpl->m_xSharedConnectionManager = m_pImpl->m_pSharedConnectionManager;
1184 xConn = m_pImpl->m_pSharedConnectionManager->getConnection(
1185 m_pImpl->m_sConnectURL, user, password, m_pImpl->m_xSettings->getPropertyValues(), this );
1188 if ( xConn.is() )
1190 Reference< XComponent> xComp(xConn,UNO_QUERY);
1191 if ( xComp.is() )
1192 xComp->addEventListener( static_cast< XContainerListener* >( this ) );
1193 m_pImpl->m_aConnections.push_back(OWeakConnection(xConn));
1196 return xConn;
1199 Reference< XNameAccess > SAL_CALL ODatabaseSource::getBookmarks( ) throw (RuntimeException, std::exception)
1201 ModelMethodGuard aGuard( *this );
1202 return static_cast< XNameContainer* >(&m_aBookmarks);
1205 Reference< XNameAccess > SAL_CALL ODatabaseSource::getQueryDefinitions( ) throw(RuntimeException, std::exception)
1207 ModelMethodGuard aGuard( *this );
1209 Reference< XNameAccess > xContainer = m_pImpl->m_xCommandDefinitions;
1210 if ( !xContainer.is() )
1212 Any aValue;
1213 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xMy(*this);
1214 if ( dbtools::getDataSourceSetting(xMy,"CommandDefinitions",aValue) )
1216 OUString sSupportService;
1217 aValue >>= sSupportService;
1218 if ( !sSupportService.isEmpty() )
1220 Sequence<Any> aArgs(1);
1221 aArgs[0] <<= NamedValue("DataSource",makeAny(xMy));
1222 xContainer.set( m_pImpl->m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext(sSupportService, aArgs, m_pImpl->m_aContext), UNO_QUERY);
1225 if ( !xContainer.is() )
1227 TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_QUERY ) );
1228 xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, false );
1230 m_pImpl->m_xCommandDefinitions = xContainer;
1232 return xContainer;
1235 // XTablesSupplier
1236 Reference< XNameAccess > ODatabaseSource::getTables() throw( RuntimeException, std::exception )
1238 ModelMethodGuard aGuard( *this );
1240 Reference< XNameAccess > xContainer = m_pImpl->m_xTableDefinitions;
1241 if ( !xContainer.is() )
1243 TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_TABLE ) );
1244 xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, true );
1245 m_pImpl->m_xTableDefinitions = xContainer;
1247 return xContainer;
1250 void SAL_CALL ODatabaseSource::flush( ) throw (RuntimeException, std::exception)
1254 // SYNCHRONIZED ->
1256 ModelMethodGuard aGuard( *this );
1258 typedef ::utl::SharedUNOComponent< XModel, ::utl::CloseableComponent > SharedModel;
1259 SharedModel xModel( m_pImpl->getModel_noCreate(), SharedModel::NoTakeOwnership );
1261 if ( !xModel.is() )
1262 xModel.reset( m_pImpl->createNewModel_deliverOwnership( false ), SharedModel::TakeOwnership );
1264 Reference< css::frame::XStorable> xStorable( xModel, UNO_QUERY_THROW );
1265 xStorable->store();
1267 // <- SYNCHRONIZED
1269 css::lang::EventObject aFlushedEvent(*this);
1270 m_aFlushListeners.notifyEach( &XFlushListener::flushed, aFlushedEvent );
1272 catch( const Exception& )
1274 DBG_UNHANDLED_EXCEPTION();
1278 void SAL_CALL ODatabaseSource::flushed( const EventObject& /*rEvent*/ ) throw (RuntimeException, std::exception)
1280 ModelMethodGuard aGuard( *this );
1282 // Okay, this is some hack.
1284 // In general, we have the problem that embedded databases write into their underlying storage, which
1285 // logically is one of our sub storage, and practically is a temporary file maintained by the
1286 // package implementation. As long as we did not commit this storage and our main storage,
1287 // the changes made by the embedded database engine are not really reflected in the database document
1288 // file. This is Bad (TM) for a "real" database application - imagine somebody entering some
1289 // data, and then crashing: For a database application, you would expect that the data still is present
1290 // when you connect to the database next time.
1292 // Since this is a conceptual problem as long as we do use those ZIP packages (in fact, we *cannot*
1293 // provide the desired functionality as long as we do not have a package format which allows O(1) writes),
1294 // we cannot completely fix this. However, we can relax the problem by committing more often - often
1295 // enough so that data loss is more seldom, and seldom enough so that there's no noticeable performance
1296 // decrease.
1298 // For this, we introduced a few places which XFlushable::flush their connections, and register as
1299 // XFlushListener at the embedded connection (which needs to provide the XFlushable functionality).
1300 // Then, when the connection is flushed, we commit both the database storage and our main storage.
1302 // #i55274#
1304 OSL_ENSURE( m_pImpl->isEmbeddedDatabase(), "ODatabaseSource::flushed: no embedded database?!" );
1305 bool bWasModified = m_pImpl->m_bModified;
1306 m_pImpl->commitEmbeddedStorage();
1307 m_pImpl->setModified( bWasModified );
1310 void SAL_CALL ODatabaseSource::addFlushListener( const Reference< ::com::sun::star::util::XFlushListener >& _xListener ) throw (RuntimeException, std::exception)
1312 m_aFlushListeners.addInterface(_xListener);
1315 void SAL_CALL ODatabaseSource::removeFlushListener( const Reference< ::com::sun::star::util::XFlushListener >& _xListener ) throw (RuntimeException, std::exception)
1317 m_aFlushListeners.removeInterface(_xListener);
1320 void SAL_CALL ODatabaseSource::elementInserted( const ContainerEvent& /*Event*/ ) throw (RuntimeException, std::exception)
1322 ModelMethodGuard aGuard( *this );
1323 if ( m_pImpl.is() )
1324 m_pImpl->setModified(true);
1327 void SAL_CALL ODatabaseSource::elementRemoved( const ContainerEvent& /*Event*/ ) throw (RuntimeException, std::exception)
1329 ModelMethodGuard aGuard( *this );
1330 if ( m_pImpl.is() )
1331 m_pImpl->setModified(true);
1334 void SAL_CALL ODatabaseSource::elementReplaced( const ContainerEvent& /*Event*/ ) throw (RuntimeException, std::exception)
1336 ModelMethodGuard aGuard( *this );
1337 if ( m_pImpl.is() )
1338 m_pImpl->setModified(true);
1341 // XDocumentDataSource
1342 Reference< XOfficeDatabaseDocument > SAL_CALL ODatabaseSource::getDatabaseDocument() throw (RuntimeException, std::exception)
1344 ModelMethodGuard aGuard( *this );
1346 Reference< XModel > xModel( m_pImpl->getModel_noCreate() );
1347 if ( !xModel.is() )
1348 xModel = m_pImpl->createNewModel_deliverOwnership( false );
1350 return Reference< XOfficeDatabaseDocument >( xModel, UNO_QUERY_THROW );
1353 Reference< XInterface > ODatabaseSource::getThis() const
1355 return *const_cast< ODatabaseSource* >( this );
1358 } // namespace dbaccess
1360 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */