build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / dbaccess / source / core / dataaccess / datasource.cxx
blob8052903c0e49322ca520309656eedd4b6db2d85d
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 "userinformation.hxx"
22 #include "commandcontainer.hxx"
23 #include "dbastrings.hrc"
24 #include "core_resource.hxx"
25 #include "core_resource.hrc"
26 #include "connection.hxx"
27 #include "SharedConnection.hxx"
28 #include "databasedocument.hxx"
29 #include "OAuthenticationContinuation.hxx"
31 #include <com/sun/star/beans/NamedValue.hpp>
32 #include <com/sun/star/beans/PropertyAttribute.hpp>
33 #include <com/sun/star/beans/PropertyState.hpp>
34 #include <com/sun/star/beans/XPropertyContainer.hpp>
35 #include <com/sun/star/document/XDocumentSubStorageSupplier.hpp>
36 #include <com/sun/star/embed/XTransactedObject.hpp>
37 #include <com/sun/star/lang/DisposedException.hpp>
38 #include <com/sun/star/reflection/ProxyFactory.hpp>
39 #include <com/sun/star/sdb/DatabaseContext.hpp>
40 #include <com/sun/star/sdbc/ConnectionPool.hpp>
41 #include <com/sun/star/sdbc/XDriverAccess.hpp>
42 #include <com/sun/star/sdbc/XDriverManager.hpp>
43 #include <com/sun/star/sdbc/DriverManager.hpp>
44 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
45 #include <com/sun/star/ucb/AuthenticationRequest.hpp>
46 #include <com/sun/star/ucb/XInteractionSupplyAuthentication.hpp>
47 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
48 #include <com/sun/star/view/XPrintable.hpp>
50 #include <comphelper/guarding.hxx>
51 #include <cppuhelper/implbase.hxx>
52 #include <comphelper/interaction.hxx>
53 #include <comphelper/namedvaluecollection.hxx>
54 #include <comphelper/property.hxx>
55 #include <comphelper/seqstream.hxx>
56 #include <comphelper/sequence.hxx>
57 #include <cppuhelper/supportsservice.hxx>
58 #include <connectivity/dbexception.hxx>
59 #include <connectivity/dbtools.hxx>
60 #include <cppuhelper/typeprovider.hxx>
61 #include <tools/debug.hxx>
62 #include <tools/diagnose_ex.h>
63 #include <osl/diagnose.h>
64 #include <tools/urlobj.hxx>
65 #include <typelib/typedescription.hxx>
66 #include <unotools/confignode.hxx>
67 #include <unotools/sharedunocomponent.hxx>
68 #include <rtl/digest.h>
70 #include <algorithm>
71 #include <iterator>
72 #include <set>
74 using namespace ::com::sun::star::sdbc;
75 using namespace ::com::sun::star::sdbcx;
76 using namespace ::com::sun::star::sdb;
77 using namespace ::com::sun::star::beans;
78 using namespace ::com::sun::star::uno;
79 using namespace ::com::sun::star::lang;
80 using namespace ::com::sun::star::embed;
81 using namespace ::com::sun::star::container;
82 using namespace ::com::sun::star::util;
83 using namespace ::com::sun::star::io;
84 using namespace ::com::sun::star::task;
85 using namespace ::com::sun::star::ucb;
86 using namespace ::com::sun::star::frame;
87 using namespace ::com::sun::star::reflection;
88 using namespace ::cppu;
89 using namespace ::osl;
90 using namespace ::dbtools;
91 using namespace ::comphelper;
93 namespace dbaccess
96 /** helper class which implements a XFlushListener, and forwards all
97 notification events to another XFlushListener
99 The speciality is that the foreign XFlushListener instance, to which
100 the notifications are forwarded, is held weak.
102 Thus, the class can be used with XFlushable instance which hold
103 their listeners with a hard reference, if you simply do not *want*
104 to be held hard-ref-wise.
106 class FlushNotificationAdapter : public ::cppu::WeakImplHelper< XFlushListener >
108 private:
109 WeakReference< XFlushable > m_aBroadcaster;
110 WeakReference< XFlushListener > m_aListener;
112 public:
113 static void installAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener )
115 Reference< XFlushListener > xAdapter( new FlushNotificationAdapter( _rxBroadcaster, _rxListener ) );
118 protected:
119 FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener );
120 virtual ~FlushNotificationAdapter() override;
122 void SAL_CALL impl_dispose();
124 protected:
125 // XFlushListener
126 virtual void SAL_CALL flushed( const css::lang::EventObject& rEvent ) throw (css::uno::RuntimeException, std::exception) override;
127 // XEventListener
128 virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) throw (css::uno::RuntimeException, std::exception) override;
131 FlushNotificationAdapter::FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener )
132 :m_aBroadcaster( _rxBroadcaster )
133 ,m_aListener( _rxListener )
135 OSL_ENSURE( _rxBroadcaster.is(), "FlushNotificationAdapter::FlushNotificationAdapter: invalid flushable!" );
137 osl_atomic_increment( &m_refCount );
139 if ( _rxBroadcaster.is() )
140 _rxBroadcaster->addFlushListener( this );
142 osl_atomic_decrement( &m_refCount );
143 OSL_ENSURE( m_refCount == 1, "FlushNotificationAdapter::FlushNotificationAdapter: broadcaster isn't holding by hard ref!?" );
146 FlushNotificationAdapter::~FlushNotificationAdapter()
150 void SAL_CALL FlushNotificationAdapter::impl_dispose()
152 Reference< XFlushListener > xKeepAlive( this );
154 Reference< XFlushable > xFlushable( m_aBroadcaster );
155 if ( xFlushable.is() )
156 xFlushable->removeFlushListener( this );
158 m_aListener.clear();
159 m_aBroadcaster.clear();
162 void SAL_CALL FlushNotificationAdapter::flushed( const EventObject& rEvent ) throw (RuntimeException, std::exception)
164 Reference< XFlushListener > xListener( m_aListener );
165 if ( xListener.is() )
166 xListener->flushed( rEvent );
167 else
168 impl_dispose();
171 void SAL_CALL FlushNotificationAdapter::disposing( const EventObject& Source ) throw (RuntimeException, std::exception)
173 Reference< XFlushListener > xListener( m_aListener );
174 if ( xListener.is() )
175 xListener->disposing( Source );
177 impl_dispose();
180 OAuthenticationContinuation::OAuthenticationContinuation()
181 :m_bRemberPassword(true), // TODO: a meaningful default
182 m_bCanSetUserName(true)
186 sal_Bool SAL_CALL OAuthenticationContinuation::canSetRealm( ) throw(RuntimeException, std::exception)
188 return false;
191 void SAL_CALL OAuthenticationContinuation::setRealm( const OUString& /*Realm*/ ) throw(RuntimeException, std::exception)
193 SAL_WARN("dbaccess","OAuthenticationContinuation::setRealm: not supported!");
196 sal_Bool SAL_CALL OAuthenticationContinuation::canSetUserName( ) throw(RuntimeException, std::exception)
198 // we always allow this, even if the database document is read-only. In this case,
199 // it's simply that the user cannot store the new user name.
200 return m_bCanSetUserName;
203 void SAL_CALL OAuthenticationContinuation::setUserName( const OUString& _rUser ) throw(RuntimeException, std::exception)
205 m_sUser = _rUser;
208 sal_Bool SAL_CALL OAuthenticationContinuation::canSetPassword( ) throw(RuntimeException, std::exception)
210 return true;
213 void SAL_CALL OAuthenticationContinuation::setPassword( const OUString& _rPassword ) throw(RuntimeException, std::exception)
215 m_sPassword = _rPassword;
218 Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberPasswordModes( RememberAuthentication& _reDefault ) throw(RuntimeException, std::exception)
220 Sequence< RememberAuthentication > aReturn(1);
221 _reDefault = aReturn[0] = RememberAuthentication_SESSION;
222 return aReturn;
225 void SAL_CALL OAuthenticationContinuation::setRememberPassword( RememberAuthentication _eRemember ) throw(RuntimeException, std::exception)
227 m_bRemberPassword = (RememberAuthentication_NO != _eRemember);
230 sal_Bool SAL_CALL OAuthenticationContinuation::canSetAccount( ) throw(RuntimeException, std::exception)
232 return false;
235 void SAL_CALL OAuthenticationContinuation::setAccount( const OUString& ) throw(RuntimeException, std::exception)
237 SAL_WARN("dbaccess","OAuthenticationContinuation::setAccount: not supported!");
240 Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberAccountModes( RememberAuthentication& _reDefault ) throw(RuntimeException, std::exception)
242 Sequence < RememberAuthentication > aReturn(1);
243 aReturn[0] = RememberAuthentication_NO;
244 _reDefault = RememberAuthentication_NO;
245 return aReturn;
248 void SAL_CALL OAuthenticationContinuation::setRememberAccount( RememberAuthentication /*Remember*/ ) throw(RuntimeException, std::exception)
250 SAL_WARN("dbaccess","OAuthenticationContinuation::setRememberAccount: not supported!");
253 /** The class OSharedConnectionManager implements a structure to share connections.
254 It owns the master connections which will be disposed when the last connection proxy is gone.
256 // need to hold the digest
257 struct TDigestHolder
259 sal_uInt8 m_pBuffer[RTL_DIGEST_LENGTH_SHA1];
260 TDigestHolder()
262 m_pBuffer[0] = 0;
267 class OSharedConnectionManager : public ::cppu::WeakImplHelper< XEventListener >
270 // contains the currently used master connections
271 typedef struct
273 Reference< XConnection > xMasterConnection;
274 oslInterlockedCount nALiveCount;
275 } TConnectionHolder;
277 // the less-compare functor, used for the stl::map
278 struct TDigestLess : public ::std::binary_function< TDigestHolder, TDigestHolder, bool>
280 bool operator() (const TDigestHolder& x, const TDigestHolder& y) const
282 sal_uInt32 i;
283 for(i=0;i < RTL_DIGEST_LENGTH_SHA1 && (x.m_pBuffer[i] >= y.m_pBuffer[i]); ++i)
285 return i < RTL_DIGEST_LENGTH_SHA1;
289 typedef ::std::map< TDigestHolder,TConnectionHolder,TDigestLess> TConnectionMap; // holds the master connections
290 typedef ::std::map< Reference< XConnection >,TConnectionMap::iterator> TSharedConnectionMap;// holds the shared connections
292 ::osl::Mutex m_aMutex;
293 TConnectionMap m_aConnections; // remember the master connection in conjunction with the digest
294 TSharedConnectionMap m_aSharedConnection; // the shared connections with conjunction with an iterator into the connections map
295 Reference< XProxyFactory > m_xProxyFactory;
297 protected:
298 virtual ~OSharedConnectionManager() override;
300 public:
301 explicit OSharedConnectionManager(const Reference< XComponentContext >& _rxContext);
303 void SAL_CALL disposing( const css::lang::EventObject& Source ) throw(RuntimeException, std::exception) override;
304 Reference<XConnection> getConnection( const OUString& url,
305 const OUString& user,
306 const OUString& password,
307 const Sequence< PropertyValue >& _aInfo,
308 ODatabaseSource* _pDataSource);
309 void addEventListener(const Reference<XConnection>& _rxConnection,TConnectionMap::iterator& _rIter);
312 OSharedConnectionManager::OSharedConnectionManager(const Reference< XComponentContext >& _rxContext)
314 m_xProxyFactory.set( ProxyFactory::create( _rxContext ) );
317 OSharedConnectionManager::~OSharedConnectionManager()
321 void SAL_CALL OSharedConnectionManager::disposing( const css::lang::EventObject& Source ) throw(RuntimeException, std::exception)
323 MutexGuard aGuard(m_aMutex);
324 Reference<XConnection> xConnection(Source.Source,UNO_QUERY);
325 TSharedConnectionMap::const_iterator aFind = m_aSharedConnection.find(xConnection);
326 if ( m_aSharedConnection.end() != aFind )
328 osl_atomic_decrement(&aFind->second->second.nALiveCount);
329 if ( !aFind->second->second.nALiveCount )
331 ::comphelper::disposeComponent(aFind->second->second.xMasterConnection);
332 m_aConnections.erase(aFind->second);
334 m_aSharedConnection.erase(aFind);
338 Reference<XConnection> OSharedConnectionManager::getConnection( const OUString& url,
339 const OUString& user,
340 const OUString& password,
341 const Sequence< PropertyValue >& _aInfo,
342 ODatabaseSource* _pDataSource)
344 MutexGuard aGuard(m_aMutex);
345 TConnectionMap::key_type nId;
346 Sequence< PropertyValue > aInfoCopy(_aInfo);
347 sal_Int32 nPos = aInfoCopy.getLength();
348 aInfoCopy.realloc( nPos + 2 );
349 aInfoCopy[nPos].Name = "TableFilter";
350 aInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableFilter;
351 aInfoCopy[nPos].Name = "TableTypeFilter";
352 aInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableTypeFilter;
354 OUString sUser = user;
355 OUString sPassword = password;
356 if ((sUser.isEmpty()) && (sPassword.isEmpty()) && (!_pDataSource->m_pImpl->m_sUser.isEmpty()))
357 { // ease the usage of this method. data source which are intended to have a user automatically
358 // fill in the user/password combination if the caller of this method does not specify otherwise
359 sUser = _pDataSource->m_pImpl->m_sUser;
360 if (!_pDataSource->m_pImpl->m_aPassword.isEmpty())
361 sPassword = _pDataSource->m_pImpl->m_aPassword;
364 ::connectivity::OConnectionWrapper::createUniqueId(url,aInfoCopy,nId.m_pBuffer,sUser,sPassword);
365 TConnectionMap::iterator aIter = m_aConnections.find(nId);
367 if ( m_aConnections.end() == aIter )
369 TConnectionHolder aHolder;
370 aHolder.nALiveCount = 0; // will be incremented by addListener
371 aHolder.xMasterConnection = _pDataSource->buildIsolatedConnection(user,password);
372 aIter = m_aConnections.insert(TConnectionMap::value_type(nId,aHolder)).first;
375 Reference<XConnection> xRet;
376 if ( aIter->second.xMasterConnection.is() )
378 Reference< XAggregation > xConProxy = m_xProxyFactory->createProxy(aIter->second.xMasterConnection.get());
379 xRet = new OSharedConnection(xConProxy);
380 m_aSharedConnection.insert(TSharedConnectionMap::value_type(xRet,aIter));
381 addEventListener(xRet,aIter);
384 return xRet;
387 void OSharedConnectionManager::addEventListener(const Reference<XConnection>& _rxConnection,TConnectionMap::iterator& _rIter)
389 Reference<XComponent> xComp(_rxConnection,UNO_QUERY);
390 xComp->addEventListener(this);
391 OSL_ENSURE( m_aConnections.end() != _rIter , "Iterator is end!");
392 osl_atomic_increment(&_rIter->second.nALiveCount);
395 namespace
397 Sequence< PropertyValue > lcl_filterDriverProperties( const Reference< XDriver >& _xDriver, const OUString& _sUrl,
398 const Sequence< PropertyValue >& _rDataSourceSettings, const AsciiPropertyValue* _pKnownSettings )
400 if ( _xDriver.is() )
402 Sequence< DriverPropertyInfo > aDriverInfo(_xDriver->getPropertyInfo(_sUrl,_rDataSourceSettings));
404 const PropertyValue* pDataSourceSetting = _rDataSourceSettings.getConstArray();
405 const PropertyValue* pEnd = pDataSourceSetting + _rDataSourceSettings.getLength();
407 ::std::vector< PropertyValue > aRet;
409 for ( ; pDataSourceSetting != pEnd ; ++pDataSourceSetting )
411 bool bAllowSetting = false;
412 const AsciiPropertyValue* pSetting = _pKnownSettings;
413 for ( ; pSetting->AsciiName; ++pSetting )
415 if ( pDataSourceSetting->Name.equalsAscii( pSetting->AsciiName ) )
416 { // the particular data source setting is known
418 const DriverPropertyInfo* pAllowedDriverSetting = aDriverInfo.getConstArray();
419 const DriverPropertyInfo* pDriverSettingsEnd = pAllowedDriverSetting + aDriverInfo.getLength();
420 for ( ; pAllowedDriverSetting != pDriverSettingsEnd; ++pAllowedDriverSetting )
422 if ( pAllowedDriverSetting->Name.equalsAscii( pSetting->AsciiName ) )
423 { // the driver also allows this setting
424 bAllowSetting = true;
425 break;
428 break;
431 if ( bAllowSetting || !pSetting->AsciiName )
432 { // if the driver allows this particular setting, or if the setting is completely unknown,
433 // we pass it to the driver
434 aRet.push_back( *pDataSourceSetting );
437 if ( !aRet.empty() )
438 return Sequence< PropertyValue >(&(*aRet.begin()),aRet.size());
440 return Sequence< PropertyValue >();
443 typedef ::std::map< OUString, sal_Int32 > PropertyAttributeCache;
445 struct IsDefaultAndNotRemoveable : public ::std::unary_function< PropertyValue, bool >
447 private:
448 const PropertyAttributeCache& m_rAttribs;
450 public:
451 explicit IsDefaultAndNotRemoveable( const PropertyAttributeCache& _rAttribs ) : m_rAttribs( _rAttribs ) { }
453 bool operator()( const PropertyValue& _rProp )
455 if ( _rProp.State != PropertyState_DEFAULT_VALUE )
456 return false;
458 bool bRemoveable = true;
460 PropertyAttributeCache::const_iterator pos = m_rAttribs.find( _rProp.Name );
461 OSL_ENSURE( pos != m_rAttribs.end(), "IsDefaultAndNotRemoveable: illegal property name!" );
462 if ( pos != m_rAttribs.end() )
463 bRemoveable = ( ( pos->second & PropertyAttribute::REMOVABLE ) != 0 );
465 return !bRemoveable;
471 ODatabaseSource::ODatabaseSource(const ::rtl::Reference<ODatabaseModelImpl>& _pImpl)
472 :ModelDependentComponent( _pImpl )
473 ,ODatabaseSource_Base( getMutex() )
474 ,OPropertySetHelper( ODatabaseSource_Base::rBHelper )
475 , m_Bookmarks(*this, getMutex())
476 ,m_aFlushListeners( getMutex() )
478 // some kind of default
479 SAL_INFO("dbaccess", "DS: ctor: " << std::hex << this << ": " << std::hex << m_pImpl.get() );
482 ODatabaseSource::~ODatabaseSource()
484 SAL_INFO("dbaccess", "DS: dtor: " << std::hex << this << ": " << std::hex << m_pImpl.get() );
485 if ( !ODatabaseSource_Base::rBHelper.bInDispose && !ODatabaseSource_Base::rBHelper.bDisposed )
487 acquire();
488 dispose();
492 void ODatabaseSource::setName( const Reference< XDocumentDataSource >& _rxDocument, const OUString& _rNewName, DBContextAccess )
494 ODatabaseSource& rModelImpl = dynamic_cast< ODatabaseSource& >( *_rxDocument.get() );
496 ::osl::MutexGuard aGuard( rModelImpl.m_aMutex );
497 if ( rModelImpl.m_pImpl.is() )
498 rModelImpl.m_pImpl->m_sName = _rNewName;
501 // css::lang::XTypeProvider
502 Sequence< Type > ODatabaseSource::getTypes() throw (RuntimeException, std::exception)
504 OTypeCollection aPropertyHelperTypes( cppu::UnoType<XFastPropertySet>::get(),
505 cppu::UnoType<XPropertySet>::get(),
506 cppu::UnoType<XMultiPropertySet>::get());
508 return ::comphelper::concatSequences(
509 ODatabaseSource_Base::getTypes(),
510 aPropertyHelperTypes.getTypes()
514 Sequence< sal_Int8 > ODatabaseSource::getImplementationId() throw (RuntimeException, std::exception)
516 return css::uno::Sequence<sal_Int8>();
519 // css::uno::XInterface
520 Any ODatabaseSource::queryInterface( const Type & rType ) throw (RuntimeException, std::exception)
522 Any aIface = ODatabaseSource_Base::queryInterface( rType );
523 if ( !aIface.hasValue() )
524 aIface = ::cppu::OPropertySetHelper::queryInterface( rType );
525 return aIface;
528 void ODatabaseSource::acquire() throw ()
530 ODatabaseSource_Base::acquire();
533 void ODatabaseSource::release() throw ()
535 ODatabaseSource_Base::release();
538 void SAL_CALL ODatabaseSource::disposing( const css::lang::EventObject& Source ) throw(RuntimeException, std::exception)
540 if ( m_pImpl.is() )
541 m_pImpl->disposing(Source);
544 // XServiceInfo
545 OUString ODatabaseSource::getImplementationName( ) throw(RuntimeException, std::exception)
547 return OUString("com.sun.star.comp.dba.ODatabaseSource");
550 Sequence< OUString > ODatabaseSource::getSupportedServiceNames( ) throw (RuntimeException, std::exception)
552 return { SERVICE_SDB_DATASOURCE, "com.sun.star.sdb.DocumentDataSource" };
555 sal_Bool ODatabaseSource::supportsService( const OUString& _rServiceName ) throw (RuntimeException, std::exception)
557 return cppu::supportsService(this, _rServiceName);
560 // OComponentHelper
561 void ODatabaseSource::disposing()
563 SAL_INFO("dbaccess", "DS: disp: " << std::hex << this << ", " << std::hex << m_pImpl.get() );
564 ODatabaseSource_Base::WeakComponentImplHelperBase::disposing();
565 OPropertySetHelper::disposing();
567 EventObject aDisposeEvent(static_cast<XWeak*>(this));
568 m_aFlushListeners.disposeAndClear( aDisposeEvent );
570 ODatabaseDocument::clearObjectContainer(m_pImpl->m_xCommandDefinitions);
571 ODatabaseDocument::clearObjectContainer(m_pImpl->m_xTableDefinitions);
572 m_pImpl.clear();
575 Reference< XConnection > ODatabaseSource::buildLowLevelConnection(const OUString& _rUid, const OUString& _rPwd)
577 Reference< XConnection > xReturn;
579 Reference< XDriverManager > xManager;
580 try {
581 xManager.set( ConnectionPool::create( m_pImpl->m_aContext ), UNO_QUERY_THROW );
582 } catch( const Exception& ) { }
583 if ( !xManager.is() )
584 // no connection pool installed, fall back to driver manager
585 xManager.set( DriverManager::create(m_pImpl->m_aContext ), UNO_QUERY_THROW );
587 OUString sUser(_rUid);
588 OUString sPwd(_rPwd);
589 if ((sUser.isEmpty()) && (sPwd.isEmpty()) && (!m_pImpl->m_sUser.isEmpty()))
590 { // ease the usage of this method. data source which are intended to have a user automatically
591 // fill in the user/password combination if the caller of this method does not specify otherwise
592 sUser = m_pImpl->m_sUser;
593 if (!m_pImpl->m_aPassword.isEmpty())
594 sPwd = m_pImpl->m_aPassword;
597 sal_uInt16 nExceptionMessageId = RID_STR_COULDNOTCONNECT_UNSPECIFIED;
598 if (xManager.is())
600 sal_Int32 nAdditionalArgs(0);
601 if (!sUser.isEmpty()) ++nAdditionalArgs;
602 if (!sPwd.isEmpty()) ++nAdditionalArgs;
604 Sequence< PropertyValue > aUserPwd(nAdditionalArgs);
605 sal_Int32 nArgPos = 0;
606 if (!sUser.isEmpty())
608 aUserPwd[ nArgPos ].Name = "user";
609 aUserPwd[ nArgPos ].Value <<= sUser;
610 ++nArgPos;
612 if (!sPwd.isEmpty())
614 aUserPwd[ nArgPos ].Name = "password";
615 aUserPwd[ nArgPos ].Value <<= sPwd;
617 Reference< XDriver > xDriver;
620 Reference< XDriverAccess > xAccessDrivers( xManager, UNO_QUERY );
621 if ( xAccessDrivers.is() )
622 xDriver = xAccessDrivers->getDriverByURL( m_pImpl->m_sConnectURL );
624 catch( const Exception& )
626 SAL_WARN("dbaccess", "ODatabaseSource::buildLowLevelConnection: got a strange exception while analyzing the error!" );
628 if ( !xDriver.is() || !xDriver->acceptsURL( m_pImpl->m_sConnectURL ) )
630 // Nowadays, it's allowed for a driver to be registered for a given URL, but actually not to accept it.
631 // This is because registration nowadays happens at compile time (by adding respective configuration data),
632 // but acceptance is decided at runtime.
633 nExceptionMessageId = RID_STR_COULDNOTCONNECT_NODRIVER;
635 else
637 Sequence< PropertyValue > aDriverInfo = lcl_filterDriverProperties(
638 xDriver,
639 m_pImpl->m_sConnectURL,
640 m_pImpl->m_xSettings->getPropertyValues(),
641 dbaccess::ODatabaseModelImpl::getDefaultDataSourceSettings()
644 if ( m_pImpl->isEmbeddedDatabase() )
646 sal_Int32 nCount = aDriverInfo.getLength();
647 aDriverInfo.realloc(nCount + 3 );
649 aDriverInfo[nCount].Name = "URL";
650 aDriverInfo[nCount++].Value <<= m_pImpl->getURL();
652 aDriverInfo[nCount].Name = "Storage";
653 Reference< css::document::XDocumentSubStorageSupplier> xDocSup( m_pImpl->getDocumentSubStorageSupplier() );
654 aDriverInfo[nCount++].Value <<= xDocSup->getDocumentSubStorage("database",ElementModes::READWRITE);
656 aDriverInfo[nCount].Name = "Document";
657 aDriverInfo[nCount++].Value <<= getDatabaseDocument();
659 if (nAdditionalArgs)
660 xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL, ::comphelper::concatSequences(aUserPwd,aDriverInfo));
661 else
662 xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL,aDriverInfo);
664 if ( m_pImpl->isEmbeddedDatabase() )
666 // see ODatabaseSource::flushed for comment on why we register as FlushListener
667 // at the connection
668 Reference< XFlushable > xFlushable( xReturn, UNO_QUERY );
669 if ( xFlushable.is() )
670 FlushNotificationAdapter::installAdapter( xFlushable, this );
674 else
675 nExceptionMessageId = RID_STR_COULDNOTLOAD_MANAGER;
677 if ( !xReturn.is() )
679 OUString sMessage = DBACORE_RESSTRING( nExceptionMessageId )
680 .replaceAll("$name$", m_pImpl->m_sConnectURL);
682 SQLContext aContext;
683 aContext.Message = DBACORE_RESSTRING(RID_STR_CONNECTION_REQUEST).
684 replaceFirst("$name$", m_pImpl->m_sConnectURL);
686 throwGenericSQLException( sMessage, static_cast< XDataSource* >( this ), makeAny( aContext ) );
689 return xReturn;
692 // OPropertySetHelper
693 Reference< XPropertySetInfo > ODatabaseSource::getPropertySetInfo() throw (RuntimeException, std::exception)
695 return createPropertySetInfo( getInfoHelper() ) ;
698 // comphelper::OPropertyArrayUsageHelper
699 ::cppu::IPropertyArrayHelper* ODatabaseSource::createArrayHelper( ) const
701 BEGIN_PROPERTY_HELPER(13)
702 DECL_PROP1(INFO, Sequence< PropertyValue >, BOUND);
703 DECL_PROP1_BOOL(ISPASSWORDREQUIRED, BOUND);
704 DECL_PROP1_BOOL(ISREADONLY, READONLY);
705 DECL_PROP1(LAYOUTINFORMATION, Sequence< PropertyValue >, BOUND);
706 DECL_PROP1(NAME, OUString, READONLY);
707 DECL_PROP2_IFACE(NUMBERFORMATSSUPPLIER, XNumberFormatsSupplier, READONLY, TRANSIENT);
708 DECL_PROP1(PASSWORD, OUString, TRANSIENT);
709 DECL_PROP2_IFACE(SETTINGS, XPropertySet, BOUND, READONLY);
710 DECL_PROP1_BOOL(SUPPRESSVERSIONCL, BOUND);
711 DECL_PROP1(TABLEFILTER, Sequence< OUString >,BOUND);
712 DECL_PROP1(TABLETYPEFILTER, Sequence< OUString >,BOUND);
713 DECL_PROP1(URL, OUString, BOUND);
714 DECL_PROP1(USER, OUString, BOUND);
715 END_PROPERTY_HELPER();
718 // cppu::OPropertySetHelper
719 ::cppu::IPropertyArrayHelper& ODatabaseSource::getInfoHelper()
721 return *getArrayHelper();
724 sal_Bool ODatabaseSource::convertFastPropertyValue(Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue ) throw( IllegalArgumentException, RuntimeException, std::exception )
726 bool bModified(false);
727 if ( m_pImpl.is() )
729 switch (nHandle)
731 case PROPERTY_ID_TABLEFILTER:
732 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableFilter);
733 break;
734 case PROPERTY_ID_TABLETYPEFILTER:
735 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableTypeFilter);
736 break;
737 case PROPERTY_ID_USER:
738 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sUser);
739 break;
740 case PROPERTY_ID_PASSWORD:
741 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aPassword);
742 break;
743 case PROPERTY_ID_ISPASSWORDREQUIRED:
744 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bPasswordRequired);
745 break;
746 case PROPERTY_ID_SUPPRESSVERSIONCL:
747 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bSuppressVersionColumns);
748 break;
749 case PROPERTY_ID_LAYOUTINFORMATION:
750 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aLayoutInformation);
751 break;
752 case PROPERTY_ID_URL:
754 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sConnectURL);
755 } break;
756 case PROPERTY_ID_INFO:
758 Sequence<PropertyValue> aValues;
759 if (!(rValue >>= aValues))
760 throw IllegalArgumentException();
762 const PropertyValue* valueEnd = aValues.getConstArray() + aValues.getLength();
763 const PropertyValue* checkName = aValues.getConstArray();
764 for ( ;checkName != valueEnd; ++checkName )
766 if ( checkName->Name.isEmpty() )
767 throw IllegalArgumentException();
770 Sequence< PropertyValue > aSettings = m_pImpl->m_xSettings->getPropertyValues();
771 bModified = aSettings.getLength() != aValues.getLength();
772 if ( !bModified )
774 const PropertyValue* pInfoIter = aSettings.getConstArray();
775 const PropertyValue* checkValue = aValues.getConstArray();
776 for ( ;!bModified && checkValue != valueEnd ; ++checkValue,++pInfoIter)
778 bModified = checkValue->Name != pInfoIter->Name;
779 if ( !bModified )
781 bModified = checkValue->Value != pInfoIter->Value;
786 rConvertedValue = rValue;
787 rOldValue <<= aSettings;
789 break;
790 default:
791 SAL_WARN("dbaccess", "ODatabaseSource::convertFastPropertyValue: unknown or readonly Property!" );
794 return bModified;
797 namespace
799 struct SelectPropertyName : public ::std::unary_function< PropertyValue, OUString >
801 public:
802 const OUString& operator()( const PropertyValue& _lhs )
804 return _lhs.Name;
808 /** sets a new set of property values for a given property bag instance
810 The method takes a property bag, and a sequence of property values to set for this bag.
811 Upon return, every property which is not part of the given sequence is
812 <ul><li>removed from the bag, if it's a removable property</li>
813 <li><em>or</em>reset to its default value, if it's not a removable property</li>
814 </ul>.
816 @param _rxPropertyBag
817 the property bag to operate on
818 @param _rAllNewPropertyValues
819 the new property values to set for the bag
821 void lcl_setPropertyValues_resetOrRemoveOther( const Reference< XPropertyBag >& _rxPropertyBag, const Sequence< PropertyValue >& _rAllNewPropertyValues )
823 // sequences are ugly to operate on
824 typedef ::std::set< OUString > StringSet;
825 StringSet aToBeSetPropertyNames;
826 ::std::transform(
827 _rAllNewPropertyValues.getConstArray(),
828 _rAllNewPropertyValues.getConstArray() + _rAllNewPropertyValues.getLength(),
829 ::std::insert_iterator< StringSet >( aToBeSetPropertyNames, aToBeSetPropertyNames.end() ),
830 SelectPropertyName()
835 // obtain all properties currently known at the bag
836 Reference< XPropertySetInfo > xPSI( _rxPropertyBag->getPropertySetInfo(), UNO_QUERY_THROW );
837 Sequence< Property > aAllExistentProperties( xPSI->getProperties() );
839 Reference< XPropertyState > xPropertyState( _rxPropertyBag, UNO_QUERY_THROW );
841 // loop through them, and reset resp. default properties which are not to be set
842 const Property* pExistentProperty( aAllExistentProperties.getConstArray() );
843 const Property* pExistentPropertyEnd( aAllExistentProperties.getConstArray() + aAllExistentProperties.getLength() );
844 for ( ; pExistentProperty != pExistentPropertyEnd; ++pExistentProperty )
846 if ( aToBeSetPropertyNames.find( pExistentProperty->Name ) != aToBeSetPropertyNames.end() )
847 continue;
849 // this property is not to be set, but currently exists in the bag.
850 // -> Remove it, or reset it to the default.
851 if ( ( pExistentProperty->Attributes & PropertyAttribute::REMOVABLE ) != 0 )
852 _rxPropertyBag->removeProperty( pExistentProperty->Name );
853 else
854 xPropertyState->setPropertyToDefault( pExistentProperty->Name );
857 // finally, set the new property values
858 _rxPropertyBag->setPropertyValues( _rAllNewPropertyValues );
860 catch( const Exception& )
862 DBG_UNHANDLED_EXCEPTION();
867 void ODatabaseSource::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) throw (Exception, std::exception)
869 if ( m_pImpl.is() )
871 switch(nHandle)
873 case PROPERTY_ID_TABLEFILTER:
874 rValue >>= m_pImpl->m_aTableFilter;
875 break;
876 case PROPERTY_ID_TABLETYPEFILTER:
877 rValue >>= m_pImpl->m_aTableTypeFilter;
878 break;
879 case PROPERTY_ID_USER:
880 rValue >>= m_pImpl->m_sUser;
881 // if the user name has changed, reset the password
882 (m_pImpl->m_aPassword).clear();
883 break;
884 case PROPERTY_ID_PASSWORD:
885 rValue >>= m_pImpl->m_aPassword;
886 break;
887 case PROPERTY_ID_ISPASSWORDREQUIRED:
888 m_pImpl->m_bPasswordRequired = any2bool(rValue);
889 break;
890 case PROPERTY_ID_SUPPRESSVERSIONCL:
891 m_pImpl->m_bSuppressVersionColumns = any2bool(rValue);
892 break;
893 case PROPERTY_ID_URL:
894 rValue >>= m_pImpl->m_sConnectURL;
895 break;
896 case PROPERTY_ID_INFO:
898 Sequence< PropertyValue > aInfo;
899 OSL_VERIFY( rValue >>= aInfo );
900 lcl_setPropertyValues_resetOrRemoveOther( m_pImpl->m_xSettings, aInfo );
902 break;
903 case PROPERTY_ID_LAYOUTINFORMATION:
904 rValue >>= m_pImpl->m_aLayoutInformation;
905 break;
907 m_pImpl->setModified(true);
911 void ODatabaseSource::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
913 if ( m_pImpl.is() )
915 switch (nHandle)
917 case PROPERTY_ID_TABLEFILTER:
918 rValue <<= m_pImpl->m_aTableFilter;
919 break;
920 case PROPERTY_ID_TABLETYPEFILTER:
921 rValue <<= m_pImpl->m_aTableTypeFilter;
922 break;
923 case PROPERTY_ID_USER:
924 rValue <<= m_pImpl->m_sUser;
925 break;
926 case PROPERTY_ID_PASSWORD:
927 rValue <<= m_pImpl->m_aPassword;
928 break;
929 case PROPERTY_ID_ISPASSWORDREQUIRED:
930 rValue <<= m_pImpl->m_bPasswordRequired;
931 break;
932 case PROPERTY_ID_SUPPRESSVERSIONCL:
933 rValue <<= m_pImpl->m_bSuppressVersionColumns;
934 break;
935 case PROPERTY_ID_ISREADONLY:
936 rValue <<= m_pImpl->m_bReadOnly;
937 break;
938 case PROPERTY_ID_INFO:
942 // collect the property attributes of all current settings
943 Reference< XPropertySet > xSettingsAsProps( m_pImpl->m_xSettings, UNO_QUERY_THROW );
944 Reference< XPropertySetInfo > xPST( xSettingsAsProps->getPropertySetInfo(), UNO_QUERY_THROW );
945 Sequence< Property > aSettings( xPST->getProperties() );
946 ::std::map< OUString, sal_Int32 > aPropertyAttributes;
947 for ( const Property* pSettings = aSettings.getConstArray();
948 pSettings != aSettings.getConstArray() + aSettings.getLength();
949 ++pSettings
952 aPropertyAttributes[ pSettings->Name ] = pSettings->Attributes;
955 // get all current settings with their values
956 Sequence< PropertyValue > aValues( m_pImpl->m_xSettings->getPropertyValues() );
958 // transform them so that only property values which fulfill certain
959 // criteria survive
960 Sequence< PropertyValue > aNonDefaultOrUserDefined( aValues.getLength() );
961 const PropertyValue* pCopyEnd = ::std::remove_copy_if(
962 aValues.getConstArray(),
963 aValues.getConstArray() + aValues.getLength(),
964 aNonDefaultOrUserDefined.getArray(),
965 IsDefaultAndNotRemoveable( aPropertyAttributes )
967 aNonDefaultOrUserDefined.realloc( pCopyEnd - aNonDefaultOrUserDefined.getArray() );
968 rValue <<= aNonDefaultOrUserDefined;
970 catch( const Exception& )
972 DBG_UNHANDLED_EXCEPTION();
975 break;
976 case PROPERTY_ID_SETTINGS:
977 rValue <<= m_pImpl->m_xSettings;
978 break;
979 case PROPERTY_ID_URL:
980 rValue <<= m_pImpl->m_sConnectURL;
981 break;
982 case PROPERTY_ID_NUMBERFORMATSSUPPLIER:
983 rValue <<= m_pImpl->getNumberFormatsSupplier();
984 break;
985 case PROPERTY_ID_NAME:
986 rValue <<= m_pImpl->m_sName;
987 break;
988 case PROPERTY_ID_LAYOUTINFORMATION:
989 rValue <<= m_pImpl->m_aLayoutInformation;
990 break;
991 default:
992 SAL_WARN("dbaccess","unknown Property");
997 // XDataSource
998 void ODatabaseSource::setLoginTimeout(sal_Int32 seconds) throw( SQLException, RuntimeException, std::exception )
1000 ModelMethodGuard aGuard( *this );
1001 m_pImpl->m_nLoginTimeout = seconds;
1004 sal_Int32 ODatabaseSource::getLoginTimeout() throw( SQLException, RuntimeException, std::exception )
1006 ModelMethodGuard aGuard( *this );
1007 return m_pImpl->m_nLoginTimeout;
1010 // XCompletedConnection
1011 Reference< XConnection > SAL_CALL ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler ) throw(SQLException, RuntimeException, std::exception)
1013 return connectWithCompletion(_rxHandler,false);
1016 Reference< XConnection > ODatabaseSource::getConnection(const OUString& user, const OUString& password) throw( SQLException, RuntimeException, std::exception )
1018 return getConnection(user,password,false);
1021 Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnection( const OUString& user, const OUString& password ) throw(SQLException, RuntimeException, std::exception)
1023 return getConnection(user,password,true);
1026 Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnectionWithCompletion( const Reference< XInteractionHandler >& _rxHandler ) throw(SQLException, RuntimeException, std::exception)
1028 return connectWithCompletion(_rxHandler,true);
1031 Reference< XConnection > SAL_CALL ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler,bool _bIsolated ) throw(SQLException, RuntimeException)
1033 ModelMethodGuard aGuard( *this );
1035 if (!_rxHandler.is())
1037 SAL_WARN("dbaccess","ODatabaseSource::connectWithCompletion: invalid interaction handler!");
1038 return getConnection(m_pImpl->m_sUser, m_pImpl->m_aPassword,_bIsolated);
1041 OUString sUser(m_pImpl->m_sUser), sPassword(m_pImpl->m_aPassword);
1042 bool bNewPasswordGiven = false;
1044 if (m_pImpl->m_bPasswordRequired && sPassword.isEmpty())
1045 { // we need a password, but don't have one yet.
1046 // -> ask the user
1048 // build an interaction request
1049 // two continuations (Ok and Cancel)
1050 OInteractionAbort* pAbort = new OInteractionAbort;
1051 OAuthenticationContinuation* pAuthenticate = new OAuthenticationContinuation;
1053 // the name which should be referred in the login dialog
1054 OUString sServerName( m_pImpl->m_sName );
1055 INetURLObject aURLCheck( sServerName );
1056 if ( aURLCheck.GetProtocol() != INetProtocol::NotValid )
1057 sServerName = aURLCheck.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::Unambiguous );
1059 // the request
1060 AuthenticationRequest aRequest;
1061 aRequest.ServerName = sServerName;
1062 aRequest.HasRealm = aRequest.HasAccount = false;
1063 aRequest.HasUserName = aRequest.HasPassword = true;
1064 aRequest.UserName = m_pImpl->m_sUser;
1065 aRequest.Password = m_pImpl->m_sFailedPassword.isEmpty() ? m_pImpl->m_aPassword : m_pImpl->m_sFailedPassword;
1066 OInteractionRequest* pRequest = new OInteractionRequest(makeAny(aRequest));
1067 Reference< XInteractionRequest > xRequest(pRequest);
1068 // some knittings
1069 pRequest->addContinuation(pAbort);
1070 pRequest->addContinuation(pAuthenticate);
1072 // handle the request
1075 MutexRelease aRelease( getMutex() );
1076 // release the mutex when calling the handler, it may need to lock the SolarMutex
1077 _rxHandler->handle(xRequest);
1079 catch(Exception&)
1081 DBG_UNHANDLED_EXCEPTION();
1084 if (!pAuthenticate->wasSelected())
1085 return Reference< XConnection >();
1087 // get the result
1088 sUser = m_pImpl->m_sUser = pAuthenticate->getUser();
1089 sPassword = pAuthenticate->getPassword();
1091 if (pAuthenticate->getRememberPassword())
1093 m_pImpl->m_aPassword = pAuthenticate->getPassword();
1094 bNewPasswordGiven = true;
1096 (m_pImpl->m_sFailedPassword).clear();
1101 return getConnection(sUser, sPassword,_bIsolated);
1103 catch(Exception&)
1105 if (bNewPasswordGiven)
1107 m_pImpl->m_sFailedPassword = m_pImpl->m_aPassword;
1108 // assume that we had an authentication problem. Without this we may, after an unsuccessful connect, while
1109 // the user gave us a password an the order to remember it, never allow an password input again (at least
1110 // not without restarting the session)
1111 (m_pImpl->m_aPassword).clear();
1113 throw;
1117 Reference< XConnection > ODatabaseSource::buildIsolatedConnection(const OUString& user, const OUString& password)
1119 Reference< XConnection > xConn;
1120 Reference< XConnection > xSdbcConn = buildLowLevelConnection(user, password);
1121 OSL_ENSURE( xSdbcConn.is(), "ODatabaseSource::buildIsolatedConnection: invalid return value of buildLowLevelConnection!" );
1122 // buildLowLevelConnection is expected to always succeed
1123 if ( xSdbcConn.is() )
1125 // build a connection server and return it (no stubs)
1126 xConn = new OConnection(*this, xSdbcConn, m_pImpl->m_aContext);
1128 return xConn;
1131 Reference< XConnection > ODatabaseSource::getConnection(const OUString& user, const OUString& password,bool _bIsolated) throw( SQLException, RuntimeException, std::exception )
1133 ModelMethodGuard aGuard( *this );
1135 Reference< XConnection > xConn;
1136 if ( _bIsolated )
1138 xConn = buildIsolatedConnection(user,password);
1140 else
1141 { // create a new proxy for the connection
1142 if ( !m_pImpl->m_xSharedConnectionManager.is() )
1144 m_pImpl->m_pSharedConnectionManager = new OSharedConnectionManager( m_pImpl->m_aContext );
1145 m_pImpl->m_xSharedConnectionManager = m_pImpl->m_pSharedConnectionManager;
1147 xConn = m_pImpl->m_pSharedConnectionManager->getConnection(
1148 m_pImpl->m_sConnectURL, user, password, m_pImpl->m_xSettings->getPropertyValues(), this );
1151 if ( xConn.is() )
1153 Reference< XComponent> xComp(xConn,UNO_QUERY);
1154 if ( xComp.is() )
1155 xComp->addEventListener( static_cast< XContainerListener* >( this ) );
1156 m_pImpl->m_aConnections.push_back(css::uno::WeakReference< css::sdbc::XConnection >(xConn));
1159 return xConn;
1162 Reference< XNameAccess > SAL_CALL ODatabaseSource::getBookmarks( ) throw (RuntimeException, std::exception)
1164 ModelMethodGuard aGuard( *this );
1165 // tdf#114596 this may look nutty but see OBookmarkContainer::aquire()
1166 return static_cast<XNameContainer*>(&m_Bookmarks);
1169 Reference< XNameAccess > SAL_CALL ODatabaseSource::getQueryDefinitions( ) throw(RuntimeException, std::exception)
1171 ModelMethodGuard aGuard( *this );
1173 Reference< XNameAccess > xContainer = m_pImpl->m_xCommandDefinitions;
1174 if ( !xContainer.is() )
1176 Any aValue;
1177 css::uno::Reference< css::uno::XInterface > xMy(*this);
1178 if ( dbtools::getDataSourceSetting(xMy,"CommandDefinitions",aValue) )
1180 OUString sSupportService;
1181 aValue >>= sSupportService;
1182 if ( !sSupportService.isEmpty() )
1184 Sequence<Any> aArgs(1);
1185 aArgs[0] <<= NamedValue("DataSource",makeAny(xMy));
1186 xContainer.set( m_pImpl->m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext(sSupportService, aArgs, m_pImpl->m_aContext), UNO_QUERY);
1189 if ( !xContainer.is() )
1191 TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_QUERY ) );
1192 xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, false );
1194 m_pImpl->m_xCommandDefinitions = xContainer;
1196 return xContainer;
1199 // XTablesSupplier
1200 Reference< XNameAccess > ODatabaseSource::getTables() throw( RuntimeException, std::exception )
1202 ModelMethodGuard aGuard( *this );
1204 Reference< XNameAccess > xContainer = m_pImpl->m_xTableDefinitions;
1205 if ( !xContainer.is() )
1207 TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_TABLE ) );
1208 xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, true );
1209 m_pImpl->m_xTableDefinitions = xContainer;
1211 return xContainer;
1214 void SAL_CALL ODatabaseSource::flush( ) throw (RuntimeException, std::exception)
1218 // SYNCHRONIZED ->
1220 ModelMethodGuard aGuard( *this );
1222 typedef ::utl::SharedUNOComponent< XModel, ::utl::CloseableComponent > SharedModel;
1223 SharedModel xModel( m_pImpl->getModel_noCreate(), SharedModel::NoTakeOwnership );
1225 if ( !xModel.is() )
1226 xModel.reset( m_pImpl->createNewModel_deliverOwnership(), SharedModel::TakeOwnership );
1228 Reference< css::frame::XStorable> xStorable( xModel, UNO_QUERY_THROW );
1229 xStorable->store();
1231 // <- SYNCHRONIZED
1233 css::lang::EventObject aFlushedEvent(*this);
1234 m_aFlushListeners.notifyEach( &XFlushListener::flushed, aFlushedEvent );
1236 catch( const Exception& )
1238 DBG_UNHANDLED_EXCEPTION();
1242 void SAL_CALL ODatabaseSource::flushed( const EventObject& /*rEvent*/ ) throw (RuntimeException, std::exception)
1244 ModelMethodGuard aGuard( *this );
1246 // Okay, this is some hack.
1248 // In general, we have the problem that embedded databases write into their underlying storage, which
1249 // logically is one of our sub storage, and practically is a temporary file maintained by the
1250 // package implementation. As long as we did not commit this storage and our main storage,
1251 // the changes made by the embedded database engine are not really reflected in the database document
1252 // file. This is Bad (TM) for a "real" database application - imagine somebody entering some
1253 // data, and then crashing: For a database application, you would expect that the data still is present
1254 // when you connect to the database next time.
1256 // Since this is a conceptual problem as long as we do use those ZIP packages (in fact, we *cannot*
1257 // provide the desired functionality as long as we do not have a package format which allows O(1) writes),
1258 // we cannot completely fix this. However, we can relax the problem by committing more often - often
1259 // enough so that data loss is more seldom, and seldom enough so that there's no noticeable performance
1260 // decrease.
1262 // For this, we introduced a few places which XFlushable::flush their connections, and register as
1263 // XFlushListener at the embedded connection (which needs to provide the XFlushable functionality).
1264 // Then, when the connection is flushed, we commit both the database storage and our main storage.
1266 // #i55274#
1268 OSL_ENSURE( m_pImpl->isEmbeddedDatabase(), "ODatabaseSource::flushed: no embedded database?!" );
1269 bool bWasModified = m_pImpl->m_bModified;
1270 m_pImpl->commitEmbeddedStorage();
1271 m_pImpl->setModified( bWasModified );
1274 void SAL_CALL ODatabaseSource::addFlushListener( const Reference< css::util::XFlushListener >& _xListener ) throw (RuntimeException, std::exception)
1276 m_aFlushListeners.addInterface(_xListener);
1279 void SAL_CALL ODatabaseSource::removeFlushListener( const Reference< css::util::XFlushListener >& _xListener ) throw (RuntimeException, std::exception)
1281 m_aFlushListeners.removeInterface(_xListener);
1284 void SAL_CALL ODatabaseSource::elementInserted( const ContainerEvent& /*Event*/ ) throw (RuntimeException, std::exception)
1286 ModelMethodGuard aGuard( *this );
1287 if ( m_pImpl.is() )
1288 m_pImpl->setModified(true);
1291 void SAL_CALL ODatabaseSource::elementRemoved( const ContainerEvent& /*Event*/ ) throw (RuntimeException, std::exception)
1293 ModelMethodGuard aGuard( *this );
1294 if ( m_pImpl.is() )
1295 m_pImpl->setModified(true);
1298 void SAL_CALL ODatabaseSource::elementReplaced( const ContainerEvent& /*Event*/ ) throw (RuntimeException, std::exception)
1300 ModelMethodGuard aGuard( *this );
1301 if ( m_pImpl.is() )
1302 m_pImpl->setModified(true);
1305 // XDocumentDataSource
1306 Reference< XOfficeDatabaseDocument > SAL_CALL ODatabaseSource::getDatabaseDocument() throw (RuntimeException, std::exception)
1308 ModelMethodGuard aGuard( *this );
1310 Reference< XModel > xModel( m_pImpl->getModel_noCreate() );
1311 if ( !xModel.is() )
1312 xModel = m_pImpl->createNewModel_deliverOwnership();
1314 return Reference< XOfficeDatabaseDocument >( xModel, UNO_QUERY_THROW );
1317 Reference< XInterface > ODatabaseSource::getThis() const
1319 return *const_cast< ODatabaseSource* >( this );
1322 } // namespace dbaccess
1324 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* SAL_CALL
1325 com_sun_star_comp_dba_ODatabaseSource(css::uno::XComponentContext* context,
1326 css::uno::Sequence<css::uno::Any> const &)
1328 css::uno::Reference<XInterface> inst(
1329 DatabaseContext::create(context)->createInstance());
1330 inst->acquire();
1331 return inst.get();
1334 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */