nss: upgrade to release 3.73
[LibreOffice.git] / dbaccess / source / core / dataaccess / datasource.cxx
blob891df4de9dc8b16d990900f24749192b1560d5b1
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 "commandcontainer.hxx"
22 #include <stringconstants.hxx>
23 #include <core_resource.hxx>
24 #include <strings.hrc>
25 #include "connection.hxx"
26 #include "SharedConnection.hxx"
27 #include "databasedocument.hxx"
28 #include <OAuthenticationContinuation.hxx>
30 #include <hsqlimport.hxx>
31 #include <migrwarndlg.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/document/XDocumentSubStorageSupplier.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/sdb/SQLContext.hpp>
41 #include <com/sun/star/sdbc/ConnectionPool.hpp>
42 #include <com/sun/star/sdbc/XDriverAccess.hpp>
43 #include <com/sun/star/sdbc/XDriverManager.hpp>
44 #include <com/sun/star/sdbc/DriverManager.hpp>
45 #include <com/sun/star/ucb/AuthenticationRequest.hpp>
46 #include <com/sun/star/ucb/XInteractionSupplyAuthentication.hpp>
48 #include <cppuhelper/implbase.hxx>
49 #include <comphelper/interaction.hxx>
50 #include <comphelper/property.hxx>
51 #include <comphelper/sequence.hxx>
52 #include <comphelper/types.hxx>
53 #include <cppuhelper/supportsservice.hxx>
54 #include <connectivity/dbexception.hxx>
55 #include <connectivity/dbtools.hxx>
56 #include <cppuhelper/typeprovider.hxx>
57 #include <officecfg/Office/Common.hxx>
58 #include <tools/diagnose_ex.h>
59 #include <osl/diagnose.h>
60 #include <osl/process.h>
61 #include <sal/log.hxx>
62 #include <tools/urlobj.hxx>
63 #include <unotools/sharedunocomponent.hxx>
64 #include <rtl/digest.h>
66 #include <algorithm>
67 #include <iterator>
68 #include <set>
70 #include <config_firebird.h>
72 using namespace ::com::sun::star::sdbc;
73 using namespace ::com::sun::star::sdbcx;
74 using namespace ::com::sun::star::sdb;
75 using namespace ::com::sun::star::beans;
76 using namespace ::com::sun::star::uno;
77 using namespace ::com::sun::star::lang;
78 using namespace ::com::sun::star::embed;
79 using namespace ::com::sun::star::container;
80 using namespace ::com::sun::star::util;
81 using namespace ::com::sun::star::io;
82 using namespace ::com::sun::star::task;
83 using namespace ::com::sun::star::ucb;
84 using namespace ::com::sun::star::frame;
85 using namespace ::com::sun::star::reflection;
86 using namespace ::cppu;
87 using namespace ::osl;
88 using namespace ::dbtools;
89 using namespace ::comphelper;
91 namespace dbaccess
94 namespace {
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 new FlushNotificationAdapter( _rxBroadcaster, _rxListener );
118 protected:
119 FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener );
120 virtual ~FlushNotificationAdapter() override;
122 void impl_dispose();
124 protected:
125 // XFlushListener
126 virtual void SAL_CALL flushed( const css::lang::EventObject& rEvent ) override;
127 // XEventListener
128 virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
133 FlushNotificationAdapter::FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener )
134 :m_aBroadcaster( _rxBroadcaster )
135 ,m_aListener( _rxListener )
137 OSL_ENSURE( _rxBroadcaster.is(), "FlushNotificationAdapter::FlushNotificationAdapter: invalid flushable!" );
139 osl_atomic_increment( &m_refCount );
141 if ( _rxBroadcaster.is() )
142 _rxBroadcaster->addFlushListener( this );
144 osl_atomic_decrement( &m_refCount );
145 OSL_ENSURE( m_refCount == 1, "FlushNotificationAdapter::FlushNotificationAdapter: broadcaster isn't holding by hard ref!?" );
148 FlushNotificationAdapter::~FlushNotificationAdapter()
152 void FlushNotificationAdapter::impl_dispose()
154 Reference< XFlushListener > xKeepAlive( this );
156 Reference< XFlushable > xFlushable( m_aBroadcaster );
157 if ( xFlushable.is() )
158 xFlushable->removeFlushListener( this );
160 m_aListener.clear();
161 m_aBroadcaster.clear();
164 void SAL_CALL FlushNotificationAdapter::flushed( const EventObject& rEvent )
166 Reference< XFlushListener > xListener( m_aListener );
167 if ( xListener.is() )
168 xListener->flushed( rEvent );
169 else
170 impl_dispose();
173 void SAL_CALL FlushNotificationAdapter::disposing( const EventObject& Source )
175 Reference< XFlushListener > xListener( m_aListener );
176 if ( xListener.is() )
177 xListener->disposing( Source );
179 impl_dispose();
182 OAuthenticationContinuation::OAuthenticationContinuation()
183 :m_bRememberPassword(true), // TODO: a meaningful default
184 m_bCanSetUserName(true)
188 sal_Bool SAL_CALL OAuthenticationContinuation::canSetRealm( )
190 return false;
193 void SAL_CALL OAuthenticationContinuation::setRealm( const OUString& /*Realm*/ )
195 SAL_WARN("dbaccess","OAuthenticationContinuation::setRealm: not supported!");
198 sal_Bool SAL_CALL OAuthenticationContinuation::canSetUserName( )
200 // we always allow this, even if the database document is read-only. In this case,
201 // it's simply that the user cannot store the new user name.
202 return m_bCanSetUserName;
205 void SAL_CALL OAuthenticationContinuation::setUserName( const OUString& _rUser )
207 m_sUser = _rUser;
210 sal_Bool SAL_CALL OAuthenticationContinuation::canSetPassword( )
212 return true;
215 void SAL_CALL OAuthenticationContinuation::setPassword( const OUString& _rPassword )
217 m_sPassword = _rPassword;
220 Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberPasswordModes( RememberAuthentication& _reDefault )
222 Sequence< RememberAuthentication > aReturn(1);
223 _reDefault = aReturn[0] = RememberAuthentication_SESSION;
224 return aReturn;
227 void SAL_CALL OAuthenticationContinuation::setRememberPassword( RememberAuthentication _eRemember )
229 m_bRememberPassword = (RememberAuthentication_NO != _eRemember);
232 sal_Bool SAL_CALL OAuthenticationContinuation::canSetAccount( )
234 return false;
237 void SAL_CALL OAuthenticationContinuation::setAccount( const OUString& )
239 SAL_WARN("dbaccess","OAuthenticationContinuation::setAccount: not supported!");
242 Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberAccountModes( RememberAuthentication& _reDefault )
244 Sequence < RememberAuthentication > aReturn(1);
245 aReturn[0] = RememberAuthentication_NO;
246 _reDefault = RememberAuthentication_NO;
247 return aReturn;
250 void SAL_CALL OAuthenticationContinuation::setRememberAccount( RememberAuthentication /*Remember*/ )
252 SAL_WARN("dbaccess","OAuthenticationContinuation::setRememberAccount: not supported!");
255 namespace {
257 /** The class OSharedConnectionManager implements a structure to share connections.
258 It owns the master connections which will be disposed when the last connection proxy is gone.
260 // need to hold the digest
261 struct TDigestHolder
263 sal_uInt8 m_pBuffer[RTL_DIGEST_LENGTH_SHA1];
264 TDigestHolder()
266 m_pBuffer[0] = 0;
273 class OSharedConnectionManager : public ::cppu::WeakImplHelper< XEventListener >
276 // contains the currently used master connections
277 struct TConnectionHolder
279 Reference< XConnection > xMasterConnection;
280 oslInterlockedCount nALiveCount;
283 // the less-compare functor, used for the stl::map
284 struct TDigestLess
286 bool operator() (const TDigestHolder& x, const TDigestHolder& y) const
288 sal_uInt32 i;
289 for(i=0;i < RTL_DIGEST_LENGTH_SHA1 && (x.m_pBuffer[i] >= y.m_pBuffer[i]); ++i)
291 return i < RTL_DIGEST_LENGTH_SHA1;
295 typedef std::map< TDigestHolder,TConnectionHolder,TDigestLess> TConnectionMap; // holds the master connections
296 typedef std::map< Reference< XConnection >,TConnectionMap::iterator> TSharedConnectionMap;// holds the shared connections
298 ::osl::Mutex m_aMutex;
299 TConnectionMap m_aConnections; // remember the master connection in conjunction with the digest
300 TSharedConnectionMap m_aSharedConnection; // the shared connections with conjunction with an iterator into the connections map
301 Reference< XProxyFactory > m_xProxyFactory;
303 protected:
304 virtual ~OSharedConnectionManager() override;
306 public:
307 explicit OSharedConnectionManager(const Reference< XComponentContext >& _rxContext);
309 void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
310 Reference<XConnection> getConnection( const OUString& url,
311 const OUString& user,
312 const OUString& password,
313 const Sequence< PropertyValue >& _aInfo,
314 ODatabaseSource* _pDataSource);
315 void addEventListener(const Reference<XConnection>& _rxConnection, TConnectionMap::iterator const & _rIter);
318 OSharedConnectionManager::OSharedConnectionManager(const Reference< XComponentContext >& _rxContext)
320 m_xProxyFactory.set( ProxyFactory::create( _rxContext ) );
323 OSharedConnectionManager::~OSharedConnectionManager()
327 void SAL_CALL OSharedConnectionManager::disposing( const css::lang::EventObject& Source )
329 MutexGuard aGuard(m_aMutex);
330 Reference<XConnection> xConnection(Source.Source,UNO_QUERY);
331 TSharedConnectionMap::const_iterator aFind = m_aSharedConnection.find(xConnection);
332 if ( m_aSharedConnection.end() != aFind )
334 osl_atomic_decrement(&aFind->second->second.nALiveCount);
335 if ( !aFind->second->second.nALiveCount )
337 ::comphelper::disposeComponent(aFind->second->second.xMasterConnection);
338 m_aConnections.erase(aFind->second);
340 m_aSharedConnection.erase(aFind);
344 Reference<XConnection> OSharedConnectionManager::getConnection( const OUString& url,
345 const OUString& user,
346 const OUString& password,
347 const Sequence< PropertyValue >& _aInfo,
348 ODatabaseSource* _pDataSource)
350 MutexGuard aGuard(m_aMutex);
351 TConnectionMap::key_type nId;
352 Sequence< PropertyValue > aInfoCopy(_aInfo);
353 sal_Int32 nPos = aInfoCopy.getLength();
354 aInfoCopy.realloc( nPos + 2 );
355 aInfoCopy[nPos].Name = "TableFilter";
356 aInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableFilter;
357 aInfoCopy[nPos].Name = "TableTypeFilter";
358 aInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableTypeFilter;
360 OUString sUser = user;
361 OUString sPassword = password;
362 if ((sUser.isEmpty()) && (sPassword.isEmpty()) && (!_pDataSource->m_pImpl->m_sUser.isEmpty()))
363 { // ease the usage of this method. data source which are intended to have a user automatically
364 // fill in the user/password combination if the caller of this method does not specify otherwise
365 sUser = _pDataSource->m_pImpl->m_sUser;
366 if (!_pDataSource->m_pImpl->m_aPassword.isEmpty())
367 sPassword = _pDataSource->m_pImpl->m_aPassword;
370 ::connectivity::OConnectionWrapper::createUniqueId(url,aInfoCopy,nId.m_pBuffer,sUser,sPassword);
371 TConnectionMap::iterator aIter = m_aConnections.find(nId);
373 if ( m_aConnections.end() == aIter )
375 TConnectionHolder aHolder;
376 aHolder.nALiveCount = 0; // will be incremented by addListener
377 aHolder.xMasterConnection = _pDataSource->buildIsolatedConnection(user,password);
378 aIter = m_aConnections.emplace(nId,aHolder).first;
381 Reference<XConnection> xRet;
382 if ( aIter->second.xMasterConnection.is() )
384 Reference< XAggregation > xConProxy = m_xProxyFactory->createProxy(aIter->second.xMasterConnection.get());
385 xRet = new OSharedConnection(xConProxy);
386 m_aSharedConnection.emplace(xRet,aIter);
387 addEventListener(xRet,aIter);
390 return xRet;
393 void OSharedConnectionManager::addEventListener(const Reference<XConnection>& _rxConnection, TConnectionMap::iterator const & _rIter)
395 Reference<XComponent> xComp(_rxConnection,UNO_QUERY);
396 xComp->addEventListener(this);
397 OSL_ENSURE( m_aConnections.end() != _rIter , "Iterator is end!");
398 osl_atomic_increment(&_rIter->second.nALiveCount);
401 namespace
403 Sequence< PropertyValue > lcl_filterDriverProperties( const Reference< XDriver >& _xDriver, const OUString& _sUrl,
404 const Sequence< PropertyValue >& _rDataSourceSettings, const AsciiPropertyValue* _pKnownSettings )
406 if ( _xDriver.is() )
408 Sequence< DriverPropertyInfo > aDriverInfo(_xDriver->getPropertyInfo(_sUrl,_rDataSourceSettings));
410 const PropertyValue* pDataSourceSetting = _rDataSourceSettings.getConstArray();
411 const PropertyValue* pEnd = pDataSourceSetting + _rDataSourceSettings.getLength();
413 std::vector< PropertyValue > aRet;
415 for ( ; pDataSourceSetting != pEnd ; ++pDataSourceSetting )
417 bool bAllowSetting = false;
418 const AsciiPropertyValue* pSetting = _pKnownSettings;
419 for ( ; pSetting->AsciiName; ++pSetting )
421 if ( pDataSourceSetting->Name.equalsAscii( pSetting->AsciiName ) )
422 { // the particular data source setting is known
424 const DriverPropertyInfo* pAllowedDriverSetting = aDriverInfo.getConstArray();
425 const DriverPropertyInfo* pDriverSettingsEnd = pAllowedDriverSetting + aDriverInfo.getLength();
426 for ( ; pAllowedDriverSetting != pDriverSettingsEnd; ++pAllowedDriverSetting )
428 if ( pAllowedDriverSetting->Name.equalsAscii( pSetting->AsciiName ) )
429 { // the driver also allows this setting
430 bAllowSetting = true;
431 break;
434 break;
437 if ( bAllowSetting || !pSetting->AsciiName )
438 { // if the driver allows this particular setting, or if the setting is completely unknown,
439 // we pass it to the driver
440 aRet.push_back( *pDataSourceSetting );
443 if ( !aRet.empty() )
444 return comphelper::containerToSequence(aRet);
446 return Sequence< PropertyValue >();
449 typedef std::map< OUString, sal_Int32 > PropertyAttributeCache;
451 struct IsDefaultAndNotRemoveable
453 private:
454 const PropertyAttributeCache& m_rAttribs;
456 public:
457 explicit IsDefaultAndNotRemoveable( const PropertyAttributeCache& _rAttribs ) : m_rAttribs( _rAttribs ) { }
459 bool operator()( const PropertyValue& _rProp )
461 if ( _rProp.State != PropertyState_DEFAULT_VALUE )
462 return false;
464 bool bRemoveable = true;
466 PropertyAttributeCache::const_iterator pos = m_rAttribs.find( _rProp.Name );
467 OSL_ENSURE( pos != m_rAttribs.end(), "IsDefaultAndNotRemoveable: illegal property name!" );
468 if ( pos != m_rAttribs.end() )
469 bRemoveable = ( ( pos->second & PropertyAttribute::REMOVABLE ) != 0 );
471 return !bRemoveable;
477 ODatabaseSource::ODatabaseSource(const ::rtl::Reference<ODatabaseModelImpl>& _pImpl)
478 :ModelDependentComponent( _pImpl )
479 ,ODatabaseSource_Base( getMutex() )
480 ,OPropertySetHelper( ODatabaseSource_Base::rBHelper )
481 , m_Bookmarks(*this, getMutex())
482 ,m_aFlushListeners( getMutex() )
484 // some kind of default
485 SAL_INFO("dbaccess", "DS: ctor: " << std::hex << this << ": " << std::hex << m_pImpl.get() );
488 ODatabaseSource::~ODatabaseSource()
490 SAL_INFO("dbaccess", "DS: dtor: " << std::hex << this << ": " << std::hex << m_pImpl.get() );
491 if ( !ODatabaseSource_Base::rBHelper.bInDispose && !ODatabaseSource_Base::rBHelper.bDisposed )
493 acquire();
494 dispose();
498 void ODatabaseSource::setName( const Reference< XDocumentDataSource >& _rxDocument, const OUString& _rNewName, DBContextAccess )
500 ODatabaseSource& rModelImpl = dynamic_cast< ODatabaseSource& >( *_rxDocument );
502 SolarMutexGuard g;
503 if ( rModelImpl.m_pImpl.is() )
504 rModelImpl.m_pImpl->m_sName = _rNewName;
507 // css::lang::XTypeProvider
508 Sequence< Type > ODatabaseSource::getTypes()
510 OTypeCollection aPropertyHelperTypes( cppu::UnoType<XFastPropertySet>::get(),
511 cppu::UnoType<XPropertySet>::get(),
512 cppu::UnoType<XMultiPropertySet>::get());
514 return ::comphelper::concatSequences(
515 ODatabaseSource_Base::getTypes(),
516 aPropertyHelperTypes.getTypes()
520 Sequence< sal_Int8 > ODatabaseSource::getImplementationId()
522 return css::uno::Sequence<sal_Int8>();
525 // css::uno::XInterface
526 Any ODatabaseSource::queryInterface( const Type & rType )
528 Any aIface = ODatabaseSource_Base::queryInterface( rType );
529 if ( !aIface.hasValue() )
530 aIface = ::cppu::OPropertySetHelper::queryInterface( rType );
531 return aIface;
534 void ODatabaseSource::acquire() throw ()
536 ODatabaseSource_Base::acquire();
539 void ODatabaseSource::release() throw ()
541 ODatabaseSource_Base::release();
544 void SAL_CALL ODatabaseSource::disposing( const css::lang::EventObject& Source )
546 if ( m_pImpl.is() )
547 m_pImpl->disposing(Source);
550 // XServiceInfo
551 OUString ODatabaseSource::getImplementationName( )
553 return "com.sun.star.comp.dba.ODatabaseSource";
556 Sequence< OUString > ODatabaseSource::getSupportedServiceNames( )
558 return { SERVICE_SDB_DATASOURCE, "com.sun.star.sdb.DocumentDataSource" };
561 sal_Bool ODatabaseSource::supportsService( const OUString& _rServiceName )
563 return cppu::supportsService(this, _rServiceName);
566 // OComponentHelper
567 void ODatabaseSource::disposing()
569 SAL_INFO("dbaccess", "DS: disp: " << std::hex << this << ", " << std::hex << m_pImpl.get() );
570 ODatabaseSource_Base::WeakComponentImplHelperBase::disposing();
571 OPropertySetHelper::disposing();
573 EventObject aDisposeEvent(static_cast<XWeak*>(this));
574 m_aFlushListeners.disposeAndClear( aDisposeEvent );
576 ODatabaseDocument::clearObjectContainer(m_pImpl->m_xCommandDefinitions);
577 ODatabaseDocument::clearObjectContainer(m_pImpl->m_xTableDefinitions);
578 m_pImpl.clear();
581 weld::Window* ODatabaseModelImpl::GetFrameWeld()
583 if (m_xDialogParent.is())
584 return Application::GetFrameWeld(m_xDialogParent);
586 Reference<XModel> xModel = getModel_noCreate();
587 if (!xModel.is())
588 return nullptr;
589 Reference<XController> xController(xModel->getCurrentController());
590 if (!xController.is())
591 return nullptr;
592 Reference<XFrame> xFrame(xController->getFrame());
593 if (!xFrame.is())
594 return nullptr;
595 Reference<css::awt::XWindow> xWindow(xFrame->getContainerWindow());
596 return Application::GetFrameWeld(xWindow);
599 Reference< XConnection > ODatabaseSource::buildLowLevelConnection(const OUString& _rUid, const OUString& _rPwd)
601 Reference< XConnection > xReturn;
603 Reference< XDriverManager > xManager;
605 #if ENABLE_FIREBIRD_SDBC
606 bool bIgnoreMigration = false;
607 bool bNeedMigration = false;
608 Reference< XModel > xModel = m_pImpl->getModel_noCreate();
609 if ( xModel)
611 //See ODbTypeWizDialogSetup::SaveDatabaseDocument
612 ::comphelper::NamedValueCollection aArgs( xModel->getArgs() );
613 aArgs.get("IgnoreFirebirdMigration") >>= bIgnoreMigration;
615 else
617 //ignore when we don't have a model. E.g. Mailmerge, data sources, fields...
618 bIgnoreMigration = true;
621 if (!officecfg::Office::Common::Misc::ExperimentalMode::get())
622 bIgnoreMigration = true;
624 if(!bIgnoreMigration && m_pImpl->m_sConnectURL == "sdbc:embedded:hsqldb")
626 Reference<XStorage> const xRootStorage = m_pImpl->getOrCreateRootStorage();
627 OUString sMigrEnvVal;
628 osl_getEnvironment(OUString("DBACCESS_HSQL_MIGRATION").pData,
629 &sMigrEnvVal.pData);
630 if(!sMigrEnvVal.isEmpty())
631 bNeedMigration = true;
632 else
634 Reference<XPropertySet> const xPropSet(xRootStorage, UNO_QUERY_THROW);
635 sal_Int32 nOpenMode(0);
636 if ((xPropSet->getPropertyValue("OpenMode") >>= nOpenMode)
637 && (nOpenMode & css::embed::ElementModes::WRITE)
638 && (!Application::IsHeadlessModeEnabled()))
640 MigrationWarnDialog aWarnDlg(m_pImpl->GetFrameWeld());
641 bNeedMigration = aWarnDlg.run() == RET_OK;
644 if (bNeedMigration)
646 // back up content xml file if migration was successful
647 constexpr char BACKUP_XML_NAME[] = "content_before_migration.xml";
650 if(xRootStorage->isStreamElement(BACKUP_XML_NAME))
651 xRootStorage->removeElement(BACKUP_XML_NAME);
653 catch (NoSuchElementException&)
655 SAL_INFO("dbaccess", "No file content_before_migration.xml found" );
657 xRootStorage->copyElementTo("content.xml", xRootStorage,
658 BACKUP_XML_NAME);
660 m_pImpl->m_sConnectURL = "sdbc:embedded:firebird";
663 #endif
665 try {
666 xManager.set( ConnectionPool::create( m_pImpl->m_aContext ), UNO_QUERY_THROW );
667 } catch( const Exception& ) { }
668 if ( !xManager.is() )
669 // no connection pool installed, fall back to driver manager
670 xManager.set( DriverManager::create(m_pImpl->m_aContext ), UNO_QUERY_THROW );
672 OUString sUser(_rUid);
673 OUString sPwd(_rPwd);
674 if ((sUser.isEmpty()) && (sPwd.isEmpty()) && (!m_pImpl->m_sUser.isEmpty()))
675 { // ease the usage of this method. data source which are intended to have a user automatically
676 // fill in the user/password combination if the caller of this method does not specify otherwise
677 sUser = m_pImpl->m_sUser;
678 if (!m_pImpl->m_aPassword.isEmpty())
679 sPwd = m_pImpl->m_aPassword;
682 const char* pExceptionMessageId = RID_STR_COULDNOTCONNECT_UNSPECIFIED;
683 if (xManager.is())
685 sal_Int32 nAdditionalArgs(0);
686 if (!sUser.isEmpty()) ++nAdditionalArgs;
687 if (!sPwd.isEmpty()) ++nAdditionalArgs;
689 Sequence< PropertyValue > aUserPwd(nAdditionalArgs);
690 sal_Int32 nArgPos = 0;
691 if (!sUser.isEmpty())
693 aUserPwd[ nArgPos ].Name = "user";
694 aUserPwd[ nArgPos ].Value <<= sUser;
695 ++nArgPos;
697 if (!sPwd.isEmpty())
699 aUserPwd[ nArgPos ].Name = "password";
700 aUserPwd[ nArgPos ].Value <<= sPwd;
702 Reference< XDriver > xDriver;
706 // choose driver
707 Reference< XDriverAccess > xAccessDrivers( xManager, UNO_QUERY );
708 if ( xAccessDrivers.is() )
709 xDriver = xAccessDrivers->getDriverByURL( m_pImpl->m_sConnectURL );
711 catch( const Exception& )
713 TOOLS_WARN_EXCEPTION("dbaccess", "ODatabaseSource::buildLowLevelConnection: got a strange exception while analyzing the error" );
715 if ( !xDriver.is() || !xDriver->acceptsURL( m_pImpl->m_sConnectURL ) )
717 // Nowadays, it's allowed for a driver to be registered for a given URL, but actually not to accept it.
718 // This is because registration nowadays happens at compile time (by adding respective configuration data),
719 // but acceptance is decided at runtime.
720 pExceptionMessageId = RID_STR_COULDNOTCONNECT_NODRIVER;
722 else
724 Sequence< PropertyValue > aDriverInfo = lcl_filterDriverProperties(
725 xDriver,
726 m_pImpl->m_sConnectURL,
727 m_pImpl->m_xSettings->getPropertyValues(),
728 dbaccess::ODatabaseModelImpl::getDefaultDataSourceSettings()
731 if ( m_pImpl->isEmbeddedDatabase() )
733 sal_Int32 nCount = aDriverInfo.getLength();
734 aDriverInfo.realloc(nCount + 3 );
736 aDriverInfo[nCount].Name = "URL";
737 aDriverInfo[nCount++].Value <<= m_pImpl->getURL();
739 aDriverInfo[nCount].Name = "Storage";
740 Reference< css::document::XDocumentSubStorageSupplier> xDocSup( m_pImpl->getDocumentSubStorageSupplier() );
741 aDriverInfo[nCount++].Value <<= xDocSup->getDocumentSubStorage("database",ElementModes::READWRITE);
743 aDriverInfo[nCount].Name = "Document";
744 aDriverInfo[nCount++].Value <<= getDatabaseDocument();
746 if (nAdditionalArgs)
747 xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL, ::comphelper::concatSequences(aUserPwd,aDriverInfo));
748 else
749 xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL,aDriverInfo);
751 if ( m_pImpl->isEmbeddedDatabase() )
753 // see ODatabaseSource::flushed for comment on why we register as FlushListener
754 // at the connection
755 Reference< XFlushable > xFlushable( xReturn, UNO_QUERY );
756 if ( xFlushable.is() )
757 FlushNotificationAdapter::installAdapter( xFlushable, this );
761 else
762 pExceptionMessageId = RID_STR_COULDNOTLOAD_MANAGER;
764 if ( !xReturn.is() )
766 OUString sMessage = DBA_RES(pExceptionMessageId)
767 .replaceAll("$name$", m_pImpl->m_sConnectURL);
769 SQLContext aContext;
770 aContext.Message = DBA_RES(RID_STR_CONNECTION_REQUEST).
771 replaceFirst("$name$", m_pImpl->m_sConnectURL);
773 throwGenericSQLException( sMessage, static_cast< XDataSource* >( this ), makeAny( aContext ) );
776 #if ENABLE_FIREBIRD_SDBC
777 if( bNeedMigration )
779 Reference< css::document::XDocumentSubStorageSupplier> xDocSup(
780 m_pImpl->getDocumentSubStorageSupplier() );
781 dbahsql::HsqlImporter importer(xReturn,
782 xDocSup->getDocumentSubStorage("database",ElementModes::READWRITE) );
783 importer.importHsqlDatabase(m_pImpl->GetFrameWeld());
785 #endif
787 return xReturn;
790 // OPropertySetHelper
791 Reference< XPropertySetInfo > ODatabaseSource::getPropertySetInfo()
793 return createPropertySetInfo( getInfoHelper() ) ;
796 // comphelper::OPropertyArrayUsageHelper
797 ::cppu::IPropertyArrayHelper* ODatabaseSource::createArrayHelper( ) const
799 BEGIN_PROPERTY_HELPER(13)
800 DECL_PROP1(INFO, Sequence< PropertyValue >, BOUND);
801 DECL_PROP1_BOOL(ISPASSWORDREQUIRED, BOUND);
802 DECL_PROP1_BOOL(ISREADONLY, READONLY);
803 DECL_PROP1(LAYOUTINFORMATION, Sequence< PropertyValue >, BOUND);
804 DECL_PROP1(NAME, OUString, READONLY);
805 DECL_PROP2_IFACE(NUMBERFORMATSSUPPLIER, XNumberFormatsSupplier, READONLY, TRANSIENT);
806 DECL_PROP1(PASSWORD, OUString, TRANSIENT);
807 DECL_PROP2_IFACE(SETTINGS, XPropertySet, BOUND, READONLY);
808 DECL_PROP1_BOOL(SUPPRESSVERSIONCL, BOUND);
809 DECL_PROP1(TABLEFILTER, Sequence< OUString >,BOUND);
810 DECL_PROP1(TABLETYPEFILTER, Sequence< OUString >,BOUND);
811 DECL_PROP1(URL, OUString, BOUND);
812 DECL_PROP1(USER, OUString, BOUND);
813 END_PROPERTY_HELPER();
816 // cppu::OPropertySetHelper
817 ::cppu::IPropertyArrayHelper& ODatabaseSource::getInfoHelper()
819 return *getArrayHelper();
822 sal_Bool ODatabaseSource::convertFastPropertyValue(Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue )
824 bool bModified(false);
825 if ( m_pImpl.is() )
827 switch (nHandle)
829 case PROPERTY_ID_TABLEFILTER:
830 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableFilter);
831 break;
832 case PROPERTY_ID_TABLETYPEFILTER:
833 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableTypeFilter);
834 break;
835 case PROPERTY_ID_USER:
836 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sUser);
837 break;
838 case PROPERTY_ID_PASSWORD:
839 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aPassword);
840 break;
841 case PROPERTY_ID_ISPASSWORDREQUIRED:
842 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bPasswordRequired);
843 break;
844 case PROPERTY_ID_SUPPRESSVERSIONCL:
845 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bSuppressVersionColumns);
846 break;
847 case PROPERTY_ID_LAYOUTINFORMATION:
848 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aLayoutInformation);
849 break;
850 case PROPERTY_ID_URL:
852 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sConnectURL);
853 } break;
854 case PROPERTY_ID_INFO:
856 Sequence<PropertyValue> aValues;
857 if (!(rValue >>= aValues))
858 throw IllegalArgumentException();
860 for ( auto const & checkName : std::as_const(aValues) )
862 if ( checkName.Name.isEmpty() )
863 throw IllegalArgumentException();
866 Sequence< PropertyValue > aSettings = m_pImpl->m_xSettings->getPropertyValues();
867 bModified = aSettings.getLength() != aValues.getLength();
868 if ( !bModified )
870 const PropertyValue* pInfoIter = aSettings.getConstArray();
871 const PropertyValue* checkValue = aValues.getConstArray();
872 for ( ;!bModified && checkValue != aValues.end() ; ++checkValue,++pInfoIter)
874 bModified = checkValue->Name != pInfoIter->Name;
875 if ( !bModified )
877 bModified = checkValue->Value != pInfoIter->Value;
882 rConvertedValue = rValue;
883 rOldValue <<= aSettings;
885 break;
886 default:
887 SAL_WARN("dbaccess", "ODatabaseSource::convertFastPropertyValue: unknown or readonly Property!" );
890 return bModified;
893 namespace
895 struct SelectPropertyName
897 public:
898 const OUString& operator()( const PropertyValue& _lhs )
900 return _lhs.Name;
904 /** sets a new set of property values for a given property bag instance
906 The method takes a property bag, and a sequence of property values to set for this bag.
907 Upon return, every property which is not part of the given sequence is
908 <ul><li>removed from the bag, if it's a removable property</li>
909 <li><em>or</em>reset to its default value, if it's not a removable property</li>
910 </ul>.
912 @param _rxPropertyBag
913 the property bag to operate on
914 @param _rAllNewPropertyValues
915 the new property values to set for the bag
917 void lcl_setPropertyValues_resetOrRemoveOther( const Reference< XPropertyBag >& _rxPropertyBag, const Sequence< PropertyValue >& _rAllNewPropertyValues )
919 // sequences are ugly to operate on
920 std::set<OUString> aToBeSetPropertyNames;
921 std::transform(
922 _rAllNewPropertyValues.begin(),
923 _rAllNewPropertyValues.end(),
924 std::inserter( aToBeSetPropertyNames, aToBeSetPropertyNames.end() ),
925 SelectPropertyName()
930 // obtain all properties currently known at the bag
931 Reference< XPropertySetInfo > xPSI( _rxPropertyBag->getPropertySetInfo(), UNO_SET_THROW );
932 const Sequence< Property > aAllExistentProperties( xPSI->getProperties() );
934 Reference< XPropertyState > xPropertyState( _rxPropertyBag, UNO_QUERY_THROW );
936 // loop through them, and reset resp. default properties which are not to be set
937 for ( auto const & existentProperty : aAllExistentProperties )
939 if ( aToBeSetPropertyNames.find( existentProperty.Name ) != aToBeSetPropertyNames.end() )
940 continue;
942 // this property is not to be set, but currently exists in the bag.
943 // -> Remove it, or reset it to the default.
944 if ( ( existentProperty.Attributes & PropertyAttribute::REMOVABLE ) != 0 )
945 _rxPropertyBag->removeProperty( existentProperty.Name );
946 else
947 xPropertyState->setPropertyToDefault( existentProperty.Name );
950 // finally, set the new property values
951 _rxPropertyBag->setPropertyValues( _rAllNewPropertyValues );
953 catch( const Exception& )
955 DBG_UNHANDLED_EXCEPTION("dbaccess");
960 void ODatabaseSource::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
962 if ( !m_pImpl.is() )
963 return;
965 switch(nHandle)
967 case PROPERTY_ID_TABLEFILTER:
968 rValue >>= m_pImpl->m_aTableFilter;
969 break;
970 case PROPERTY_ID_TABLETYPEFILTER:
971 rValue >>= m_pImpl->m_aTableTypeFilter;
972 break;
973 case PROPERTY_ID_USER:
974 rValue >>= m_pImpl->m_sUser;
975 // if the user name has changed, reset the password
976 m_pImpl->m_aPassword.clear();
977 break;
978 case PROPERTY_ID_PASSWORD:
979 rValue >>= m_pImpl->m_aPassword;
980 break;
981 case PROPERTY_ID_ISPASSWORDREQUIRED:
982 m_pImpl->m_bPasswordRequired = any2bool(rValue);
983 break;
984 case PROPERTY_ID_SUPPRESSVERSIONCL:
985 m_pImpl->m_bSuppressVersionColumns = any2bool(rValue);
986 break;
987 case PROPERTY_ID_URL:
988 rValue >>= m_pImpl->m_sConnectURL;
989 break;
990 case PROPERTY_ID_INFO:
992 Sequence< PropertyValue > aInfo;
993 OSL_VERIFY( rValue >>= aInfo );
994 lcl_setPropertyValues_resetOrRemoveOther( m_pImpl->m_xSettings, aInfo );
996 break;
997 case PROPERTY_ID_LAYOUTINFORMATION:
998 rValue >>= m_pImpl->m_aLayoutInformation;
999 break;
1001 m_pImpl->setModified(true);
1004 void ODatabaseSource::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
1006 if ( !m_pImpl.is() )
1007 return;
1009 switch (nHandle)
1011 case PROPERTY_ID_TABLEFILTER:
1012 rValue <<= m_pImpl->m_aTableFilter;
1013 break;
1014 case PROPERTY_ID_TABLETYPEFILTER:
1015 rValue <<= m_pImpl->m_aTableTypeFilter;
1016 break;
1017 case PROPERTY_ID_USER:
1018 rValue <<= m_pImpl->m_sUser;
1019 break;
1020 case PROPERTY_ID_PASSWORD:
1021 rValue <<= m_pImpl->m_aPassword;
1022 break;
1023 case PROPERTY_ID_ISPASSWORDREQUIRED:
1024 rValue <<= m_pImpl->m_bPasswordRequired;
1025 break;
1026 case PROPERTY_ID_SUPPRESSVERSIONCL:
1027 rValue <<= m_pImpl->m_bSuppressVersionColumns;
1028 break;
1029 case PROPERTY_ID_ISREADONLY:
1030 rValue <<= m_pImpl->m_bReadOnly;
1031 break;
1032 case PROPERTY_ID_INFO:
1036 // collect the property attributes of all current settings
1037 Reference< XPropertySet > xSettingsAsProps( m_pImpl->m_xSettings, UNO_QUERY_THROW );
1038 Reference< XPropertySetInfo > xPST( xSettingsAsProps->getPropertySetInfo(), UNO_SET_THROW );
1039 const Sequence< Property > aSettings( xPST->getProperties() );
1040 std::map< OUString, sal_Int32 > aPropertyAttributes;
1041 for ( auto const & setting : aSettings )
1043 aPropertyAttributes[ setting.Name ] = setting.Attributes;
1046 // get all current settings with their values
1047 Sequence< PropertyValue > aValues( m_pImpl->m_xSettings->getPropertyValues() );
1049 // transform them so that only property values which fulfill certain
1050 // criteria survive
1051 Sequence< PropertyValue > aNonDefaultOrUserDefined( aValues.getLength() );
1052 const PropertyValue* pCopyEnd = std::remove_copy_if(
1053 aValues.begin(),
1054 aValues.end(),
1055 aNonDefaultOrUserDefined.getArray(),
1056 IsDefaultAndNotRemoveable( aPropertyAttributes )
1058 aNonDefaultOrUserDefined.realloc( pCopyEnd - aNonDefaultOrUserDefined.getArray() );
1059 rValue <<= aNonDefaultOrUserDefined;
1061 catch( const Exception& )
1063 DBG_UNHANDLED_EXCEPTION("dbaccess");
1066 break;
1067 case PROPERTY_ID_SETTINGS:
1068 rValue <<= m_pImpl->m_xSettings;
1069 break;
1070 case PROPERTY_ID_URL:
1071 rValue <<= m_pImpl->m_sConnectURL;
1072 break;
1073 case PROPERTY_ID_NUMBERFORMATSSUPPLIER:
1074 rValue <<= m_pImpl->getNumberFormatsSupplier();
1075 break;
1076 case PROPERTY_ID_NAME:
1077 rValue <<= m_pImpl->m_sName;
1078 break;
1079 case PROPERTY_ID_LAYOUTINFORMATION:
1080 rValue <<= m_pImpl->m_aLayoutInformation;
1081 break;
1082 default:
1083 SAL_WARN("dbaccess","unknown Property");
1087 // XDataSource
1088 void ODatabaseSource::setLoginTimeout(sal_Int32 seconds)
1090 ModelMethodGuard aGuard( *this );
1091 m_pImpl->m_nLoginTimeout = seconds;
1094 sal_Int32 ODatabaseSource::getLoginTimeout()
1096 ModelMethodGuard aGuard( *this );
1097 return m_pImpl->m_nLoginTimeout;
1100 // XCompletedConnection
1101 Reference< XConnection > SAL_CALL ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler )
1103 return connectWithCompletion(_rxHandler,false);
1106 Reference< XConnection > ODatabaseSource::getConnection(const OUString& user, const OUString& password)
1108 return getConnection(user,password,false);
1111 Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnection( const OUString& user, const OUString& password )
1113 return getConnection(user,password,true);
1116 Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnectionWithCompletion( const Reference< XInteractionHandler >& _rxHandler )
1118 return connectWithCompletion(_rxHandler,true);
1121 Reference< XConnection > ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler,bool _bIsolated )
1123 ModelMethodGuard aGuard( *this );
1125 if (!_rxHandler.is())
1127 SAL_WARN("dbaccess","ODatabaseSource::connectWithCompletion: invalid interaction handler!");
1128 return getConnection(m_pImpl->m_sUser, m_pImpl->m_aPassword,_bIsolated);
1131 OUString sUser(m_pImpl->m_sUser), sPassword(m_pImpl->m_aPassword);
1132 bool bNewPasswordGiven = false;
1134 if (m_pImpl->m_bPasswordRequired && sPassword.isEmpty())
1135 { // we need a password, but don't have one yet.
1136 // -> ask the user
1138 // build an interaction request
1139 // two continuations (Ok and Cancel)
1140 OInteractionAbort* pAbort = new OInteractionAbort;
1141 OAuthenticationContinuation* pAuthenticate = new OAuthenticationContinuation;
1143 // the name which should be referred in the login dialog
1144 OUString sServerName( m_pImpl->m_sName );
1145 INetURLObject aURLCheck( sServerName );
1146 if ( aURLCheck.GetProtocol() != INetProtocol::NotValid )
1147 sServerName = aURLCheck.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::Unambiguous );
1149 // the request
1150 AuthenticationRequest aRequest;
1151 aRequest.ServerName = sServerName;
1152 aRequest.HasRealm = aRequest.HasAccount = false;
1153 aRequest.HasUserName = aRequest.HasPassword = true;
1154 aRequest.UserName = m_pImpl->m_sUser;
1155 aRequest.Password = m_pImpl->m_sFailedPassword.isEmpty() ? m_pImpl->m_aPassword : m_pImpl->m_sFailedPassword;
1156 OInteractionRequest* pRequest = new OInteractionRequest(makeAny(aRequest));
1157 Reference< XInteractionRequest > xRequest(pRequest);
1158 // some knittings
1159 pRequest->addContinuation(pAbort);
1160 pRequest->addContinuation(pAuthenticate);
1162 // handle the request
1165 _rxHandler->handle(xRequest);
1167 catch(Exception&)
1169 DBG_UNHANDLED_EXCEPTION("dbaccess");
1172 if (!pAuthenticate->wasSelected())
1173 return Reference< XConnection >();
1175 // get the result
1176 sUser = m_pImpl->m_sUser = pAuthenticate->getUser();
1177 sPassword = pAuthenticate->getPassword();
1179 if (pAuthenticate->getRememberPassword())
1181 m_pImpl->m_aPassword = pAuthenticate->getPassword();
1182 bNewPasswordGiven = true;
1184 m_pImpl->m_sFailedPassword.clear();
1189 return getConnection(sUser, sPassword,_bIsolated);
1191 catch(Exception&)
1193 if (bNewPasswordGiven)
1195 m_pImpl->m_sFailedPassword = m_pImpl->m_aPassword;
1196 // assume that we had an authentication problem. Without this we may, after an unsuccessful connect, while
1197 // the user gave us a password and the order to remember it, never allow a password input again (at least
1198 // not without restarting the session)
1199 m_pImpl->m_aPassword.clear();
1201 throw;
1205 Reference< XConnection > ODatabaseSource::buildIsolatedConnection(const OUString& user, const OUString& password)
1207 Reference< XConnection > xConn;
1208 Reference< XConnection > xSdbcConn = buildLowLevelConnection(user, password);
1209 OSL_ENSURE( xSdbcConn.is(), "ODatabaseSource::buildIsolatedConnection: invalid return value of buildLowLevelConnection!" );
1210 // buildLowLevelConnection is expected to always succeed
1211 if ( xSdbcConn.is() )
1213 // build a connection server and return it (no stubs)
1214 xConn = new OConnection(*this, xSdbcConn, m_pImpl->m_aContext);
1216 return xConn;
1219 Reference< XConnection > ODatabaseSource::getConnection(const OUString& user, const OUString& password,bool _bIsolated)
1221 ModelMethodGuard aGuard( *this );
1223 Reference< XConnection > xConn;
1224 if ( _bIsolated )
1226 xConn = buildIsolatedConnection(user,password);
1228 else
1229 { // create a new proxy for the connection
1230 if ( !m_pImpl->m_xSharedConnectionManager.is() )
1232 m_pImpl->m_pSharedConnectionManager = new OSharedConnectionManager( m_pImpl->m_aContext );
1233 m_pImpl->m_xSharedConnectionManager = m_pImpl->m_pSharedConnectionManager;
1235 xConn = m_pImpl->m_pSharedConnectionManager->getConnection(
1236 m_pImpl->m_sConnectURL, user, password, m_pImpl->m_xSettings->getPropertyValues(), this );
1239 if ( xConn.is() )
1241 Reference< XComponent> xComp(xConn,UNO_QUERY);
1242 if ( xComp.is() )
1243 xComp->addEventListener( static_cast< XContainerListener* >( this ) );
1244 m_pImpl->m_aConnections.emplace_back(xConn);
1247 return xConn;
1250 Reference< XNameAccess > SAL_CALL ODatabaseSource::getBookmarks( )
1252 ModelMethodGuard aGuard( *this );
1253 // tdf#114596 this may look nutty but see OBookmarkContainer::acquire()
1254 return static_cast<XNameContainer*>(&m_Bookmarks);
1257 Reference< XNameAccess > SAL_CALL ODatabaseSource::getQueryDefinitions( )
1259 ModelMethodGuard aGuard( *this );
1261 Reference< XNameAccess > xContainer = m_pImpl->m_xCommandDefinitions;
1262 if ( !xContainer.is() )
1264 Any aValue;
1265 css::uno::Reference< css::uno::XInterface > xMy(*this);
1266 if ( dbtools::getDataSourceSetting(xMy,"CommandDefinitions",aValue) )
1268 OUString sSupportService;
1269 aValue >>= sSupportService;
1270 if ( !sSupportService.isEmpty() )
1272 Sequence<Any> aArgs(1);
1273 aArgs[0] <<= NamedValue("DataSource",makeAny(xMy));
1274 xContainer.set( m_pImpl->m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext(sSupportService, aArgs, m_pImpl->m_aContext), UNO_QUERY);
1277 if ( !xContainer.is() )
1279 TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_QUERY ) );
1280 xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, false );
1282 m_pImpl->m_xCommandDefinitions = xContainer;
1284 return xContainer;
1287 // XTablesSupplier
1288 Reference< XNameAccess > ODatabaseSource::getTables()
1290 ModelMethodGuard aGuard( *this );
1292 Reference< XNameAccess > xContainer = m_pImpl->m_xTableDefinitions;
1293 if ( !xContainer.is() )
1295 TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_TABLE ) );
1296 xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, true );
1297 m_pImpl->m_xTableDefinitions = xContainer;
1299 return xContainer;
1302 void SAL_CALL ODatabaseSource::flush( )
1306 // SYNCHRONIZED ->
1308 ModelMethodGuard aGuard( *this );
1310 typedef ::utl::SharedUNOComponent< XModel, ::utl::CloseableComponent > SharedModel;
1311 SharedModel xModel( m_pImpl->getModel_noCreate(), SharedModel::NoTakeOwnership );
1313 if ( !xModel.is() )
1314 xModel.reset( m_pImpl->createNewModel_deliverOwnership(), SharedModel::TakeOwnership );
1316 Reference< css::frame::XStorable> xStorable( xModel, UNO_QUERY_THROW );
1317 xStorable->store();
1319 // <- SYNCHRONIZED
1321 css::lang::EventObject aFlushedEvent(*this);
1322 m_aFlushListeners.notifyEach( &XFlushListener::flushed, aFlushedEvent );
1324 catch( const Exception& )
1326 DBG_UNHANDLED_EXCEPTION("dbaccess");
1330 void SAL_CALL ODatabaseSource::flushed( const EventObject& /*rEvent*/ )
1332 ModelMethodGuard aGuard( *this );
1334 // Okay, this is some hack.
1336 // In general, we have the problem that embedded databases write into their underlying storage, which
1337 // logically is one of our sub storage, and practically is a temporary file maintained by the
1338 // package implementation. As long as we did not commit this storage and our main storage,
1339 // the changes made by the embedded database engine are not really reflected in the database document
1340 // file. This is Bad (TM) for a "real" database application - imagine somebody entering some
1341 // data, and then crashing: For a database application, you would expect that the data still is present
1342 // when you connect to the database next time.
1344 // Since this is a conceptual problem as long as we do use those ZIP packages (in fact, we *cannot*
1345 // provide the desired functionality as long as we do not have a package format which allows O(1) writes),
1346 // we cannot completely fix this. However, we can relax the problem by committing more often - often
1347 // enough so that data loss is more seldom, and seldom enough so that there's no noticeable performance
1348 // decrease.
1350 // For this, we introduced a few places which XFlushable::flush their connections, and register as
1351 // XFlushListener at the embedded connection (which needs to provide the XFlushable functionality).
1352 // Then, when the connection is flushed, we commit both the database storage and our main storage.
1354 // #i55274#
1356 OSL_ENSURE( m_pImpl->isEmbeddedDatabase(), "ODatabaseSource::flushed: no embedded database?!" );
1357 bool bWasModified = m_pImpl->m_bModified;
1358 m_pImpl->commitEmbeddedStorage();
1359 m_pImpl->setModified( bWasModified );
1362 void SAL_CALL ODatabaseSource::addFlushListener( const Reference< css::util::XFlushListener >& _xListener )
1364 m_aFlushListeners.addInterface(_xListener);
1367 void SAL_CALL ODatabaseSource::removeFlushListener( const Reference< css::util::XFlushListener >& _xListener )
1369 m_aFlushListeners.removeInterface(_xListener);
1372 void SAL_CALL ODatabaseSource::elementInserted( const ContainerEvent& /*Event*/ )
1374 ModelMethodGuard aGuard( *this );
1375 if ( m_pImpl.is() )
1376 m_pImpl->setModified(true);
1379 void SAL_CALL ODatabaseSource::elementRemoved( const ContainerEvent& /*Event*/ )
1381 ModelMethodGuard aGuard( *this );
1382 if ( m_pImpl.is() )
1383 m_pImpl->setModified(true);
1386 void SAL_CALL ODatabaseSource::elementReplaced( const ContainerEvent& /*Event*/ )
1388 ModelMethodGuard aGuard( *this );
1389 if ( m_pImpl.is() )
1390 m_pImpl->setModified(true);
1393 // XDocumentDataSource
1394 Reference< XOfficeDatabaseDocument > SAL_CALL ODatabaseSource::getDatabaseDocument()
1396 ModelMethodGuard aGuard( *this );
1398 Reference< XModel > xModel( m_pImpl->getModel_noCreate() );
1399 if ( !xModel.is() )
1400 xModel = m_pImpl->createNewModel_deliverOwnership();
1402 return Reference< XOfficeDatabaseDocument >( xModel, UNO_QUERY_THROW );
1405 void SAL_CALL ODatabaseSource::initialize( css::uno::Sequence< css::uno::Any > const & rArguments)
1407 ::comphelper::NamedValueCollection aProperties( rArguments );
1408 if (aProperties.has("ParentWindow"))
1409 aProperties.get("ParentWindow") >>= m_pImpl->m_xDialogParent;
1412 Reference< XInterface > ODatabaseSource::getThis() const
1414 return *const_cast< ODatabaseSource* >( this );
1417 } // namespace dbaccess
1419 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
1420 com_sun_star_comp_dba_ODatabaseSource(css::uno::XComponentContext* context,
1421 css::uno::Sequence<css::uno::Any> const &)
1423 css::uno::Reference<XInterface> inst(
1424 DatabaseContext::create(context)->createInstance());
1425 inst->acquire();
1426 return inst.get();
1429 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */