tdf#154285 Check upper bound of arguments in SbRtl_Minute function
[LibreOffice.git] / dbaccess / source / core / dataaccess / datasource.cxx
blob40b248411597d279a227dfe351b96369161c02c3
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 <strings.hxx>
26 #include <connection.hxx>
27 #include "SharedConnection.hxx"
28 #include "databasedocument.hxx"
29 #include <OAuthenticationContinuation.hxx>
31 #include <hsqlimport.hxx>
32 #include <migrwarndlg.hxx>
34 #include <com/sun/star/beans/NamedValue.hpp>
35 #include <com/sun/star/beans/PropertyAttribute.hpp>
36 #include <com/sun/star/beans/PropertyState.hpp>
37 #include <com/sun/star/document/XDocumentSubStorageSupplier.hpp>
38 #include <com/sun/star/lang/DisposedException.hpp>
39 #include <com/sun/star/reflection/ProxyFactory.hpp>
40 #include <com/sun/star/sdb/DatabaseContext.hpp>
41 #include <com/sun/star/sdb/SQLContext.hpp>
42 #include <com/sun/star/sdbc/ConnectionPool.hpp>
43 #include <com/sun/star/sdbc/XDriverAccess.hpp>
44 #include <com/sun/star/sdbc/XDriverManager.hpp>
45 #include <com/sun/star/sdbc/DriverManager.hpp>
46 #include <com/sun/star/ucb/AuthenticationRequest.hpp>
47 #include <com/sun/star/ucb/XInteractionSupplyAuthentication.hpp>
49 #include <cppuhelper/implbase.hxx>
50 #include <comphelper/interaction.hxx>
51 #include <comphelper/property.hxx>
52 #include <comphelper/sequence.hxx>
53 #include <comphelper/types.hxx>
54 #include <cppuhelper/supportsservice.hxx>
55 #include <connectivity/dbexception.hxx>
56 #include <connectivity/dbtools.hxx>
57 #include <cppuhelper/typeprovider.hxx>
58 #include <officecfg/Office/Common.hxx>
59 #include <comphelper/diagnose_ex.hxx>
60 #include <osl/diagnose.h>
61 #include <osl/process.h>
62 #include <sal/log.hxx>
63 #include <tools/urlobj.hxx>
64 #include <unotools/sharedunocomponent.hxx>
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 _reDefault = RememberAuthentication_SESSION;
223 return { _reDefault };
226 void SAL_CALL OAuthenticationContinuation::setRememberPassword( RememberAuthentication _eRemember )
228 m_bRememberPassword = (RememberAuthentication_NO != _eRemember);
231 sal_Bool SAL_CALL OAuthenticationContinuation::canSetAccount( )
233 return false;
236 void SAL_CALL OAuthenticationContinuation::setAccount( const OUString& )
238 SAL_WARN("dbaccess","OAuthenticationContinuation::setAccount: not supported!");
241 Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberAccountModes( RememberAuthentication& _reDefault )
243 _reDefault = RememberAuthentication_NO;
244 return { RememberAuthentication_NO };
247 void SAL_CALL OAuthenticationContinuation::setRememberAccount( RememberAuthentication /*Remember*/ )
249 SAL_WARN("dbaccess","OAuthenticationContinuation::setRememberAccount: not supported!");
252 OSharedConnectionManager::OSharedConnectionManager(const Reference< XComponentContext >& _rxContext)
254 m_xProxyFactory.set( ProxyFactory::create( _rxContext ) );
257 OSharedConnectionManager::~OSharedConnectionManager()
261 void SAL_CALL OSharedConnectionManager::disposing( const css::lang::EventObject& Source )
263 MutexGuard aGuard(m_aMutex);
264 Reference<XConnection> xConnection(Source.Source,UNO_QUERY);
265 TSharedConnectionMap::const_iterator aFind = m_aSharedConnection.find(xConnection);
266 if ( m_aSharedConnection.end() != aFind )
268 osl_atomic_decrement(&aFind->second->second.nALiveCount);
269 if ( !aFind->second->second.nALiveCount )
271 ::comphelper::disposeComponent(aFind->second->second.xMasterConnection);
272 m_aConnections.erase(aFind->second);
274 m_aSharedConnection.erase(aFind);
278 Reference<XConnection> OSharedConnectionManager::getConnection( const OUString& url,
279 const OUString& user,
280 const OUString& password,
281 const Sequence< PropertyValue >& _aInfo,
282 ODatabaseSource* _pDataSource)
284 MutexGuard aGuard(m_aMutex);
285 TConnectionMap::key_type nId;
286 Sequence< PropertyValue > aInfoCopy(_aInfo);
287 sal_Int32 nPos = aInfoCopy.getLength();
288 aInfoCopy.realloc( nPos + 2 );
289 auto pInfoCopy = aInfoCopy.getArray();
290 pInfoCopy[nPos].Name = "TableFilter";
291 pInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableFilter;
292 pInfoCopy[nPos].Name = "TableTypeFilter";
293 pInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableTypeFilter;
295 OUString sUser = user;
296 OUString sPassword = password;
297 if ((sUser.isEmpty()) && (sPassword.isEmpty()) && (!_pDataSource->m_pImpl->m_sUser.isEmpty()))
298 { // ease the usage of this method. data source which are intended to have a user automatically
299 // fill in the user/password combination if the caller of this method does not specify otherwise
300 sUser = _pDataSource->m_pImpl->m_sUser;
301 if (!_pDataSource->m_pImpl->m_aPassword.isEmpty())
302 sPassword = _pDataSource->m_pImpl->m_aPassword;
305 ::connectivity::OConnectionWrapper::createUniqueId(url,aInfoCopy,nId.m_pBuffer,sUser,sPassword);
306 TConnectionMap::iterator aIter = m_aConnections.find(nId);
308 if ( m_aConnections.end() == aIter )
310 TConnectionHolder aHolder;
311 aHolder.nALiveCount = 0; // will be incremented by addListener
312 aHolder.xMasterConnection = _pDataSource->buildIsolatedConnection(user,password);
313 aIter = m_aConnections.emplace(nId,aHolder).first;
316 Reference<XConnection> xRet;
317 if ( aIter->second.xMasterConnection.is() )
319 Reference< XAggregation > xConProxy = m_xProxyFactory->createProxy(aIter->second.xMasterConnection);
320 xRet = new OSharedConnection(xConProxy);
321 m_aSharedConnection.emplace(xRet,aIter);
322 addEventListener(xRet,aIter);
325 return xRet;
328 void OSharedConnectionManager::addEventListener(const Reference<XConnection>& _rxConnection, TConnectionMap::iterator const & _rIter)
330 Reference<XComponent> xComp(_rxConnection,UNO_QUERY);
331 xComp->addEventListener(this);
332 OSL_ENSURE( m_aConnections.end() != _rIter , "Iterator is end!");
333 osl_atomic_increment(&_rIter->second.nALiveCount);
336 namespace
338 Sequence< PropertyValue > lcl_filterDriverProperties( const Reference< XDriver >& _xDriver, const OUString& _sUrl,
339 const Sequence< PropertyValue >& _rDataSourceSettings )
341 if ( _xDriver.is() )
343 Sequence< DriverPropertyInfo > aDriverInfo(_xDriver->getPropertyInfo(_sUrl,_rDataSourceSettings));
345 std::vector< PropertyValue > aRet;
347 for (auto& dataSourceSetting : _rDataSourceSettings)
349 auto knownSettings = dbaccess::ODatabaseModelImpl::getDefaultDataSourceSettings();
350 bool isSettingKnown = std::any_of(knownSettings.begin(), knownSettings.end(),
351 [name = dataSourceSetting.Name](auto& setting)
352 { return name == setting.Name; });
353 // Allow if the particular data source setting is unknown or allowed by the driver
354 bool bAllowSetting = !isSettingKnown
355 || std::any_of(aDriverInfo.begin(), aDriverInfo.end(),
356 [name = dataSourceSetting.Name](auto& setting)
357 { return name == setting.Name; });
358 if (bAllowSetting)
359 { // if the driver allows this particular setting, or if the setting is completely unknown,
360 // we pass it to the driver
361 aRet.push_back(dataSourceSetting);
364 if ( !aRet.empty() )
365 return comphelper::containerToSequence(aRet);
367 return Sequence< PropertyValue >();
370 typedef std::map< OUString, sal_Int32 > PropertyAttributeCache;
372 struct IsDefaultAndNotRemoveable
374 private:
375 const PropertyAttributeCache& m_rAttribs;
377 public:
378 explicit IsDefaultAndNotRemoveable( const PropertyAttributeCache& _rAttribs ) : m_rAttribs( _rAttribs ) { }
380 bool operator()( const PropertyValue& _rProp )
382 if ( _rProp.State != PropertyState_DEFAULT_VALUE )
383 return false;
385 bool bRemoveable = true;
387 PropertyAttributeCache::const_iterator pos = m_rAttribs.find( _rProp.Name );
388 OSL_ENSURE( pos != m_rAttribs.end(), "IsDefaultAndNotRemoveable: illegal property name!" );
389 if ( pos != m_rAttribs.end() )
390 bRemoveable = ( ( pos->second & PropertyAttribute::REMOVABLE ) != 0 );
392 return !bRemoveable;
398 ODatabaseSource::ODatabaseSource(const ::rtl::Reference<ODatabaseModelImpl>& _pImpl)
399 :ModelDependentComponent( _pImpl )
400 ,ODatabaseSource_Base( getMutex() )
401 ,OPropertySetHelper( ODatabaseSource_Base::rBHelper )
402 , m_Bookmarks(*this, getMutex())
403 ,m_aFlushListeners( getMutex() )
405 // some kind of default
406 SAL_INFO("dbaccess", "DS: ctor: " << std::hex << this << ": " << std::hex << m_pImpl.get() );
409 ODatabaseSource::~ODatabaseSource()
411 SAL_INFO("dbaccess", "DS: dtor: " << std::hex << this << ": " << std::hex << m_pImpl.get() );
412 if ( !ODatabaseSource_Base::rBHelper.bInDispose && !ODatabaseSource_Base::rBHelper.bDisposed )
414 acquire();
415 dispose();
419 void ODatabaseSource::setName( const Reference< XDocumentDataSource >& _rxDocument, const OUString& _rNewName, DBContextAccess )
421 ODatabaseSource& rModelImpl = dynamic_cast< ODatabaseSource& >( *_rxDocument );
423 SolarMutexGuard g;
424 if ( rModelImpl.m_pImpl.is() )
425 rModelImpl.m_pImpl->m_sName = _rNewName;
428 // css::lang::XTypeProvider
429 Sequence< Type > ODatabaseSource::getTypes()
431 OTypeCollection aPropertyHelperTypes( cppu::UnoType<XFastPropertySet>::get(),
432 cppu::UnoType<XPropertySet>::get(),
433 cppu::UnoType<XMultiPropertySet>::get());
435 return ::comphelper::concatSequences(
436 ODatabaseSource_Base::getTypes(),
437 aPropertyHelperTypes.getTypes()
441 Sequence< sal_Int8 > ODatabaseSource::getImplementationId()
443 return css::uno::Sequence<sal_Int8>();
446 // css::uno::XInterface
447 Any ODatabaseSource::queryInterface( const Type & rType )
449 Any aIface = ODatabaseSource_Base::queryInterface( rType );
450 if ( !aIface.hasValue() )
451 aIface = ::cppu::OPropertySetHelper::queryInterface( rType );
452 return aIface;
455 void ODatabaseSource::acquire() noexcept
457 ODatabaseSource_Base::acquire();
460 void ODatabaseSource::release() noexcept
462 ODatabaseSource_Base::release();
465 void SAL_CALL ODatabaseSource::disposing( const css::lang::EventObject& Source )
467 if ( m_pImpl.is() )
468 m_pImpl->disposing(Source);
471 // XServiceInfo
472 OUString ODatabaseSource::getImplementationName( )
474 return u"com.sun.star.comp.dba.ODatabaseSource"_ustr;
477 Sequence< OUString > ODatabaseSource::getSupportedServiceNames( )
479 return { SERVICE_SDB_DATASOURCE, u"com.sun.star.sdb.DocumentDataSource"_ustr };
482 sal_Bool ODatabaseSource::supportsService( const OUString& _rServiceName )
484 return cppu::supportsService(this, _rServiceName);
487 // OComponentHelper
488 void ODatabaseSource::disposing()
490 SAL_INFO("dbaccess", "DS: disp: " << std::hex << this << ", " << std::hex << m_pImpl.get() );
491 ODatabaseSource_Base::WeakComponentImplHelperBase::disposing();
492 OPropertySetHelper::disposing();
494 EventObject aDisposeEvent(static_cast<XWeak*>(this));
495 m_aFlushListeners.disposeAndClear( aDisposeEvent );
497 ODatabaseDocument::clearObjectContainer(m_pImpl->m_xCommandDefinitions);
498 ODatabaseDocument::clearObjectContainer(m_pImpl->m_xTableDefinitions);
499 m_pImpl.clear();
502 weld::Window* ODatabaseModelImpl::GetFrameWeld()
504 if (m_xDialogParent.is())
505 return Application::GetFrameWeld(m_xDialogParent);
507 Reference<XModel> xModel = getModel_noCreate();
508 if (!xModel.is())
509 return nullptr;
510 Reference<XController> xController(xModel->getCurrentController());
511 if (!xController.is())
512 return nullptr;
513 Reference<XFrame> xFrame(xController->getFrame());
514 if (!xFrame.is())
515 return nullptr;
516 Reference<css::awt::XWindow> xWindow(xFrame->getContainerWindow());
517 return Application::GetFrameWeld(xWindow);
520 Reference< XConnection > ODatabaseSource::buildLowLevelConnection(const OUString& _rUid, const OUString& _rPwd)
522 Reference< XConnection > xReturn;
524 Reference< XDriverManager > xManager;
526 #if ENABLE_FIREBIRD_SDBC
527 bool bIgnoreMigration = false;
528 bool bNeedMigration = false;
529 Reference< XModel > xModel = m_pImpl->getModel_noCreate();
530 if ( xModel)
532 //See ODbTypeWizDialogSetup::SaveDatabaseDocument
533 ::comphelper::NamedValueCollection::get(xModel->getArgs(), u"IgnoreFirebirdMigration") >>= bIgnoreMigration;
535 else
537 //ignore when we don't have a model. E.g. Mailmerge, data sources, fields...
538 bIgnoreMigration = true;
541 if (!officecfg::Office::Common::Misc::ExperimentalMode::get())
542 bIgnoreMigration = true;
544 if(!bIgnoreMigration && m_pImpl->m_sConnectURL == "sdbc:embedded:hsqldb")
546 Reference<XStorage> const xRootStorage = m_pImpl->getOrCreateRootStorage();
547 OUString sMigrEnvVal;
548 osl_getEnvironment(u"DBACCESS_HSQL_MIGRATION"_ustr.pData,
549 &sMigrEnvVal.pData);
550 if(!sMigrEnvVal.isEmpty())
551 bNeedMigration = true;
552 else
554 Reference<XPropertySet> const xPropSet(xRootStorage, UNO_QUERY_THROW);
555 sal_Int32 nOpenMode(0);
556 if ((xPropSet->getPropertyValue(u"OpenMode"_ustr) >>= nOpenMode)
557 && (nOpenMode & css::embed::ElementModes::WRITE)
558 && (!Application::IsHeadlessModeEnabled()))
560 MigrationWarnDialog aWarnDlg(m_pImpl->GetFrameWeld());
561 bNeedMigration = aWarnDlg.run() == RET_OK;
564 if (bNeedMigration)
566 // back up content xml file if migration was successful
567 static constexpr OUString BACKUP_XML_NAME = u"content_before_migration.xml"_ustr;
570 if(xRootStorage->isStreamElement(BACKUP_XML_NAME))
571 xRootStorage->removeElement(BACKUP_XML_NAME);
573 catch (NoSuchElementException&)
575 SAL_INFO("dbaccess", "No file content_before_migration.xml found" );
577 xRootStorage->copyElementTo(u"content.xml"_ustr, xRootStorage,
578 BACKUP_XML_NAME);
580 m_pImpl->m_sConnectURL = "sdbc:embedded:firebird";
583 #endif
585 try {
586 xManager.set( ConnectionPool::create( m_pImpl->m_aContext ), UNO_QUERY_THROW );
587 } catch( const Exception& ) { }
588 if ( !xManager.is() )
589 // no connection pool installed, fall back to driver manager
590 xManager.set( DriverManager::create(m_pImpl->m_aContext ), UNO_QUERY_THROW );
592 OUString sUser(_rUid);
593 OUString sPwd(_rPwd);
594 if ((sUser.isEmpty()) && (sPwd.isEmpty()) && (!m_pImpl->m_sUser.isEmpty()))
595 { // ease the usage of this method. data source which are intended to have a user automatically
596 // fill in the user/password combination if the caller of this method does not specify otherwise
597 sUser = m_pImpl->m_sUser;
598 if (!m_pImpl->m_aPassword.isEmpty())
599 sPwd = m_pImpl->m_aPassword;
602 TranslateId pExceptionMessageId = RID_STR_COULDNOTCONNECT_UNSPECIFIED;
603 if (xManager.is())
605 sal_Int32 nAdditionalArgs(0);
606 if (!sUser.isEmpty()) ++nAdditionalArgs;
607 if (!sPwd.isEmpty()) ++nAdditionalArgs;
609 Sequence< PropertyValue > aUserPwd(nAdditionalArgs);
610 auto aUserPwdRange = asNonConstRange(aUserPwd);
611 sal_Int32 nArgPos = 0;
612 if (!sUser.isEmpty())
614 aUserPwdRange[ nArgPos ].Name = "user";
615 aUserPwdRange[ nArgPos ].Value <<= sUser;
616 ++nArgPos;
618 if (!sPwd.isEmpty())
620 aUserPwdRange[ nArgPos ].Name = "password";
621 aUserPwdRange[ nArgPos ].Value <<= sPwd;
623 Reference< XDriver > xDriver;
627 // choose driver
628 Reference< XDriverAccess > xAccessDrivers( xManager, UNO_QUERY );
629 if ( xAccessDrivers.is() )
630 xDriver = xAccessDrivers->getDriverByURL( m_pImpl->m_sConnectURL );
632 catch( const Exception& )
634 TOOLS_WARN_EXCEPTION("dbaccess", "ODatabaseSource::buildLowLevelConnection: got a strange exception while analyzing the error" );
636 if ( !xDriver.is() || !xDriver->acceptsURL( m_pImpl->m_sConnectURL ) )
638 // Nowadays, it's allowed for a driver to be registered for a given URL, but actually not to accept it.
639 // This is because registration nowadays happens at compile time (by adding respective configuration data),
640 // but acceptance is decided at runtime.
641 pExceptionMessageId = RID_STR_COULDNOTCONNECT_NODRIVER;
643 else
645 Sequence< PropertyValue > aDriverInfo = lcl_filterDriverProperties(
646 xDriver,
647 m_pImpl->m_sConnectURL,
648 m_pImpl->m_xSettings->getPropertyValues()
651 if ( m_pImpl->isEmbeddedDatabase() )
653 sal_Int32 nCount = aDriverInfo.getLength();
654 aDriverInfo.realloc(nCount + 3 );
655 auto pDriverInfo = aDriverInfo.getArray();
657 pDriverInfo[nCount].Name = "URL";
658 pDriverInfo[nCount++].Value <<= m_pImpl->getURL();
660 pDriverInfo[nCount].Name = "Storage";
661 Reference< css::document::XDocumentSubStorageSupplier> xDocSup( m_pImpl->getDocumentSubStorageSupplier() );
662 pDriverInfo[nCount++].Value <<= xDocSup->getDocumentSubStorage(u"database"_ustr,ElementModes::READWRITE);
664 pDriverInfo[nCount].Name = "Document";
665 pDriverInfo[nCount++].Value <<= getDatabaseDocument();
667 if (nAdditionalArgs)
668 xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL, ::comphelper::concatSequences(aUserPwd,aDriverInfo));
669 else
670 xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL,aDriverInfo);
672 if ( m_pImpl->isEmbeddedDatabase() )
674 // see ODatabaseSource::flushed for comment on why we register as FlushListener
675 // at the connection
676 Reference< XFlushable > xFlushable( xReturn, UNO_QUERY );
677 if ( xFlushable.is() )
678 FlushNotificationAdapter::installAdapter( xFlushable, this );
682 else
683 pExceptionMessageId = RID_STR_COULDNOTLOAD_MANAGER;
685 if ( !xReturn.is() )
687 OUString sMessage = DBA_RES(pExceptionMessageId)
688 .replaceAll("$name$", m_pImpl->m_sConnectURL);
690 SQLContext aContext(
691 DBA_RES(RID_STR_CONNECTION_REQUEST).replaceFirst("$name$", m_pImpl->m_sConnectURL),
692 {}, {}, 0, {}, {});
694 throwGenericSQLException( sMessage, static_cast< XDataSource* >( this ), Any( aContext ) );
697 #if ENABLE_FIREBIRD_SDBC
698 if( bNeedMigration )
700 Reference< css::document::XDocumentSubStorageSupplier> xDocSup(
701 m_pImpl->getDocumentSubStorageSupplier() );
702 dbahsql::HsqlImporter importer(xReturn,
703 xDocSup->getDocumentSubStorage(u"database"_ustr,ElementModes::READWRITE) );
704 importer.importHsqlDatabase(m_pImpl->GetFrameWeld());
706 #endif
708 return xReturn;
711 // OPropertySetHelper
712 Reference< XPropertySetInfo > ODatabaseSource::getPropertySetInfo()
714 return createPropertySetInfo( getInfoHelper() ) ;
717 // comphelper::OPropertyArrayUsageHelper
718 ::cppu::IPropertyArrayHelper* ODatabaseSource::createArrayHelper( ) const
720 return new ::cppu::OPropertyArrayHelper
723 // a change here means a change should also been done in OApplicationController::disposing()
724 { PROPERTY_INFO, PROPERTY_ID_INFO, cppu::UnoType<Sequence< PropertyValue >>::get(), css::beans::PropertyAttribute::BOUND },
725 { PROPERTY_ISPASSWORDREQUIRED, PROPERTY_ID_ISPASSWORDREQUIRED, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::BOUND },
726 { PROPERTY_ISREADONLY, PROPERTY_ID_ISREADONLY, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
727 { PROPERTY_LAYOUTINFORMATION, PROPERTY_ID_LAYOUTINFORMATION, cppu::UnoType<Sequence< PropertyValue >>::get(), css::beans::PropertyAttribute::BOUND },
728 { PROPERTY_NAME, PROPERTY_ID_NAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
729 { PROPERTY_NUMBERFORMATSSUPPLIER, PROPERTY_ID_NUMBERFORMATSSUPPLIER, cppu::UnoType<XNumberFormatsSupplier>::get(),
730 css::beans::PropertyAttribute::READONLY | css::beans::PropertyAttribute::TRANSIENT },
731 { PROPERTY_PASSWORD, PROPERTY_ID_PASSWORD, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::TRANSIENT },
732 { PROPERTY_SETTINGS, PROPERTY_ID_SETTINGS, cppu::UnoType<XPropertySet>::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY },
733 { PROPERTY_SUPPRESSVERSIONCL, PROPERTY_ID_SUPPRESSVERSIONCL, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::BOUND },
734 { PROPERTY_TABLEFILTER, PROPERTY_ID_TABLEFILTER, cppu::UnoType<Sequence< OUString >>::get(), css::beans::PropertyAttribute::BOUND },
735 { PROPERTY_TABLETYPEFILTER, PROPERTY_ID_TABLETYPEFILTER, cppu::UnoType<Sequence< OUString >>::get(), css::beans::PropertyAttribute::BOUND },
736 { PROPERTY_URL, PROPERTY_ID_URL, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND },
737 { PROPERTY_USER, PROPERTY_ID_USER, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND }
742 // cppu::OPropertySetHelper
743 ::cppu::IPropertyArrayHelper& ODatabaseSource::getInfoHelper()
745 return *getArrayHelper();
748 sal_Bool ODatabaseSource::convertFastPropertyValue(Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue )
750 if ( m_pImpl.is() )
752 switch (nHandle)
754 case PROPERTY_ID_TABLEFILTER:
755 return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableFilter);
756 case PROPERTY_ID_TABLETYPEFILTER:
757 return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableTypeFilter);
758 case PROPERTY_ID_USER:
759 return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sUser);
760 case PROPERTY_ID_PASSWORD:
761 return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aPassword);
762 case PROPERTY_ID_ISPASSWORDREQUIRED:
763 return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bPasswordRequired);
764 case PROPERTY_ID_SUPPRESSVERSIONCL:
765 return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bSuppressVersionColumns);
766 case PROPERTY_ID_LAYOUTINFORMATION:
767 return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aLayoutInformation);
768 case PROPERTY_ID_URL:
769 return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sConnectURL);
770 case PROPERTY_ID_INFO:
772 Sequence<PropertyValue> aValues;
773 if (!(rValue >>= aValues))
774 throw IllegalArgumentException();
776 for (auto const& checkName : aValues)
778 if ( checkName.Name.isEmpty() )
779 throw IllegalArgumentException();
782 Sequence< PropertyValue > aSettings = m_pImpl->m_xSettings->getPropertyValues();
784 rConvertedValue = rValue;
785 rOldValue <<= aSettings;
787 if (aSettings.getLength() != aValues.getLength())
788 return true;
790 for (sal_Int32 i = 0; i < aSettings.getLength(); ++i)
792 if (aValues[i].Name != aSettings[i].Name
793 || aValues[i].Value != aSettings[i].Value)
794 return true;
797 break;
798 default:
799 SAL_WARN("dbaccess", "ODatabaseSource::convertFastPropertyValue: unknown or readonly Property!" );
802 return false;
805 namespace
807 struct SelectPropertyName
809 public:
810 const OUString& operator()( const PropertyValue& _lhs )
812 return _lhs.Name;
816 /** sets a new set of property values for a given property bag instance
818 The method takes a property bag, and a sequence of property values to set for this bag.
819 Upon return, every property which is not part of the given sequence is
820 <ul><li>removed from the bag, if it's a removable property</li>
821 <li><em>or</em>reset to its default value, if it's not a removable property</li>
822 </ul>.
824 @param _rxPropertyBag
825 the property bag to operate on
826 @param _rAllNewPropertyValues
827 the new property values to set for the bag
829 void lcl_setPropertyValues_resetOrRemoveOther( const Reference< XPropertyBag >& _rxPropertyBag, const Sequence< PropertyValue >& _rAllNewPropertyValues )
831 // sequences are ugly to operate on
832 std::set<OUString> aToBeSetPropertyNames;
833 std::transform(
834 _rAllNewPropertyValues.begin(),
835 _rAllNewPropertyValues.end(),
836 std::inserter( aToBeSetPropertyNames, aToBeSetPropertyNames.end() ),
837 SelectPropertyName()
842 // obtain all properties currently known at the bag
843 Reference< XPropertySetInfo > xPSI( _rxPropertyBag->getPropertySetInfo(), UNO_SET_THROW );
844 const Sequence< Property > aAllExistentProperties( xPSI->getProperties() );
846 Reference< XPropertyState > xPropertyState( _rxPropertyBag, UNO_QUERY_THROW );
848 // loop through them, and reset resp. default properties which are not to be set
849 for ( auto const & existentProperty : aAllExistentProperties )
851 if ( aToBeSetPropertyNames.find( existentProperty.Name ) != aToBeSetPropertyNames.end() )
852 continue;
854 // this property is not to be set, but currently exists in the bag.
855 // -> Remove it, or reset it to the default.
856 if ( ( existentProperty.Attributes & PropertyAttribute::REMOVABLE ) != 0 )
857 _rxPropertyBag->removeProperty( existentProperty.Name );
858 else
859 xPropertyState->setPropertyToDefault( existentProperty.Name );
862 // finally, set the new property values
863 _rxPropertyBag->setPropertyValues( _rAllNewPropertyValues );
865 catch( const Exception& )
867 DBG_UNHANDLED_EXCEPTION("dbaccess");
872 void ODatabaseSource::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
874 if ( !m_pImpl.is() )
875 return;
877 switch(nHandle)
879 case PROPERTY_ID_TABLEFILTER:
880 rValue >>= m_pImpl->m_aTableFilter;
881 break;
882 case PROPERTY_ID_TABLETYPEFILTER:
883 rValue >>= m_pImpl->m_aTableTypeFilter;
884 break;
885 case PROPERTY_ID_USER:
886 rValue >>= m_pImpl->m_sUser;
887 // if the user name has changed, reset the password
888 m_pImpl->m_aPassword.clear();
889 break;
890 case PROPERTY_ID_PASSWORD:
891 rValue >>= m_pImpl->m_aPassword;
892 break;
893 case PROPERTY_ID_ISPASSWORDREQUIRED:
894 m_pImpl->m_bPasswordRequired = any2bool(rValue);
895 break;
896 case PROPERTY_ID_SUPPRESSVERSIONCL:
897 m_pImpl->m_bSuppressVersionColumns = any2bool(rValue);
898 break;
899 case PROPERTY_ID_URL:
900 rValue >>= m_pImpl->m_sConnectURL;
901 break;
902 case PROPERTY_ID_INFO:
904 Sequence< PropertyValue > aInfo;
905 OSL_VERIFY( rValue >>= aInfo );
906 lcl_setPropertyValues_resetOrRemoveOther( m_pImpl->m_xSettings, aInfo );
908 break;
909 case PROPERTY_ID_LAYOUTINFORMATION:
910 rValue >>= m_pImpl->m_aLayoutInformation;
911 break;
913 m_pImpl->setModified(true);
916 void ODatabaseSource::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
918 if ( !m_pImpl.is() )
919 return;
921 switch (nHandle)
923 case PROPERTY_ID_TABLEFILTER:
924 rValue <<= m_pImpl->m_aTableFilter;
925 break;
926 case PROPERTY_ID_TABLETYPEFILTER:
927 rValue <<= m_pImpl->m_aTableTypeFilter;
928 break;
929 case PROPERTY_ID_USER:
930 rValue <<= m_pImpl->m_sUser;
931 break;
932 case PROPERTY_ID_PASSWORD:
933 rValue <<= m_pImpl->m_aPassword;
934 break;
935 case PROPERTY_ID_ISPASSWORDREQUIRED:
936 rValue <<= m_pImpl->m_bPasswordRequired;
937 break;
938 case PROPERTY_ID_SUPPRESSVERSIONCL:
939 rValue <<= m_pImpl->m_bSuppressVersionColumns;
940 break;
941 case PROPERTY_ID_ISREADONLY:
942 rValue <<= m_pImpl->m_bReadOnly;
943 break;
944 case PROPERTY_ID_INFO:
948 // collect the property attributes of all current settings
949 Reference< XPropertySet > xSettingsAsProps( m_pImpl->m_xSettings, UNO_QUERY_THROW );
950 Reference< XPropertySetInfo > xPST( xSettingsAsProps->getPropertySetInfo(), UNO_SET_THROW );
951 const Sequence< Property > aSettings( xPST->getProperties() );
952 std::map< OUString, sal_Int32 > aPropertyAttributes;
953 for ( auto const & setting : aSettings )
955 aPropertyAttributes[ setting.Name ] = setting.Attributes;
958 // get all current settings with their values
959 Sequence< PropertyValue > aValues( m_pImpl->m_xSettings->getPropertyValues() );
961 // transform them so that only property values which fulfill certain
962 // criteria survive
963 Sequence< PropertyValue > aNonDefaultOrUserDefined( aValues.getLength() );
964 auto [begin, end] = asNonConstRange(aValues);
965 auto pCopyStart = aNonDefaultOrUserDefined.getArray();
966 const PropertyValue* pCopyEnd = std::remove_copy_if(
967 begin,
968 end,
969 pCopyStart,
970 IsDefaultAndNotRemoveable( aPropertyAttributes )
972 aNonDefaultOrUserDefined.realloc( pCopyEnd - pCopyStart );
973 rValue <<= aNonDefaultOrUserDefined;
975 catch( const Exception& )
977 DBG_UNHANDLED_EXCEPTION("dbaccess");
980 break;
981 case PROPERTY_ID_SETTINGS:
982 rValue <<= m_pImpl->m_xSettings;
983 break;
984 case PROPERTY_ID_URL:
985 rValue <<= m_pImpl->m_sConnectURL;
986 break;
987 case PROPERTY_ID_NUMBERFORMATSSUPPLIER:
988 rValue <<= m_pImpl->getNumberFormatsSupplier();
989 break;
990 case PROPERTY_ID_NAME:
991 rValue <<= m_pImpl->m_sName;
992 break;
993 case PROPERTY_ID_LAYOUTINFORMATION:
994 rValue <<= m_pImpl->m_aLayoutInformation;
995 break;
996 default:
997 SAL_WARN("dbaccess","unknown Property");
1001 // XDataSource
1002 void ODatabaseSource::setLoginTimeout(sal_Int32 seconds)
1004 ModelMethodGuard aGuard( *this );
1005 m_pImpl->m_nLoginTimeout = seconds;
1008 sal_Int32 ODatabaseSource::getLoginTimeout()
1010 ModelMethodGuard aGuard( *this );
1011 return m_pImpl->m_nLoginTimeout;
1014 // XCompletedConnection
1015 Reference< XConnection > SAL_CALL ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler )
1017 return connectWithCompletion(_rxHandler,false);
1020 Reference< XConnection > ODatabaseSource::getConnection(const OUString& user, const OUString& password)
1022 return getConnection(user,password,false);
1025 Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnection( const OUString& user, const OUString& password )
1027 return getConnection(user,password,true);
1030 Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnectionWithCompletion( const Reference< XInteractionHandler >& _rxHandler )
1032 return connectWithCompletion(_rxHandler,true);
1035 Reference< XConnection > ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler,bool _bIsolated )
1037 ModelMethodGuard aGuard( *this );
1039 if (!_rxHandler.is())
1041 SAL_WARN("dbaccess","ODatabaseSource::connectWithCompletion: invalid interaction handler!");
1042 return getConnection(m_pImpl->m_sUser, m_pImpl->m_aPassword,_bIsolated);
1045 OUString sUser(m_pImpl->m_sUser), sPassword(m_pImpl->m_aPassword);
1046 bool bNewPasswordGiven = false;
1048 if (m_pImpl->m_bPasswordRequired && sPassword.isEmpty())
1049 { // we need a password, but don't have one yet.
1050 // -> ask the user
1052 // build an interaction request
1053 // two continuations (Ok and Cancel)
1054 rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort;
1055 rtl::Reference<OAuthenticationContinuation> pAuthenticate = new OAuthenticationContinuation;
1057 // the name which should be referred in the login dialog
1058 OUString sServerName( m_pImpl->m_sName );
1059 INetURLObject aURLCheck( sServerName );
1060 if ( aURLCheck.GetProtocol() != INetProtocol::NotValid )
1061 sServerName = aURLCheck.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::Unambiguous );
1063 // the request
1064 AuthenticationRequest aRequest;
1065 aRequest.ServerName = sServerName;
1066 aRequest.HasRealm = aRequest.HasAccount = false;
1067 aRequest.HasUserName = aRequest.HasPassword = true;
1068 aRequest.UserName = m_pImpl->m_sUser;
1069 aRequest.Password = m_pImpl->m_sFailedPassword.isEmpty() ? m_pImpl->m_aPassword : m_pImpl->m_sFailedPassword;
1070 rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest(Any(aRequest));
1071 // some knittings
1072 pRequest->addContinuation(pAbort);
1073 pRequest->addContinuation(pAuthenticate);
1075 // handle the request
1078 _rxHandler->handle(pRequest);
1080 catch(Exception&)
1082 DBG_UNHANDLED_EXCEPTION("dbaccess");
1085 if (!pAuthenticate->wasSelected())
1086 return Reference< XConnection >();
1088 // get the result
1089 sUser = m_pImpl->m_sUser = pAuthenticate->getUser();
1090 sPassword = pAuthenticate->getPassword();
1092 if (pAuthenticate->getRememberPassword())
1094 m_pImpl->m_aPassword = pAuthenticate->getPassword();
1095 bNewPasswordGiven = true;
1097 m_pImpl->m_sFailedPassword.clear();
1102 return getConnection(sUser, sPassword,_bIsolated);
1104 catch(Exception&)
1106 if (bNewPasswordGiven)
1108 m_pImpl->m_sFailedPassword = m_pImpl->m_aPassword;
1109 // assume that we had an authentication problem. Without this we may, after an unsuccessful connect, while
1110 // the user gave us a password and the order to remember it, never allow a password input again (at least
1111 // not without restarting the session)
1112 m_pImpl->m_aPassword.clear();
1114 throw;
1118 Reference< XConnection > ODatabaseSource::buildIsolatedConnection(const OUString& user, const OUString& password)
1120 Reference< XConnection > xConn;
1121 Reference< XConnection > xSdbcConn = buildLowLevelConnection(user, password);
1122 OSL_ENSURE( xSdbcConn.is(), "ODatabaseSource::buildIsolatedConnection: invalid return value of buildLowLevelConnection!" );
1123 // buildLowLevelConnection is expected to always succeed
1124 if ( xSdbcConn.is() )
1126 // build a connection server and return it (no stubs)
1127 xConn = new OConnection(*this, xSdbcConn, m_pImpl->m_aContext);
1129 return xConn;
1132 Reference< XConnection > ODatabaseSource::getConnection(const OUString& user, const OUString& password,bool _bIsolated)
1134 ModelMethodGuard aGuard( *this );
1136 Reference< XConnection > xConn;
1137 if ( _bIsolated )
1139 xConn = buildIsolatedConnection(user,password);
1141 else
1142 { // create a new proxy for the connection
1143 if ( !m_pImpl->m_xSharedConnectionManager.is() )
1145 m_pImpl->m_xSharedConnectionManager = new OSharedConnectionManager( m_pImpl->m_aContext );
1147 xConn = m_pImpl->m_xSharedConnectionManager->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.emplace_back(xConn);
1159 return xConn;
1162 Reference< XNameAccess > SAL_CALL ODatabaseSource::getBookmarks( )
1164 ModelMethodGuard aGuard( *this );
1165 // tdf#114596 this may look nutty but see OBookmarkContainer::acquire()
1166 return static_cast<XNameContainer*>(&m_Bookmarks);
1169 Reference< XNameAccess > SAL_CALL ODatabaseSource::getQueryDefinitions( )
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{ Any(NamedValue(u"DataSource"_ustr,Any(xMy))) };
1185 xContainer.set( m_pImpl->m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext(sSupportService, aArgs, m_pImpl->m_aContext), UNO_QUERY);
1188 if ( !xContainer.is() )
1190 TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::ObjectType::Query ) );
1191 xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, false );
1193 m_pImpl->m_xCommandDefinitions = xContainer;
1195 return xContainer;
1198 // XTablesSupplier
1199 Reference< XNameAccess > ODatabaseSource::getTables()
1201 ModelMethodGuard aGuard( *this );
1203 rtl::Reference< OCommandContainer > xContainer = m_pImpl->m_xTableDefinitions;
1204 if ( !xContainer.is() )
1206 TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::ObjectType::Table ) );
1207 xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, true );
1208 m_pImpl->m_xTableDefinitions = xContainer.get();
1210 return xContainer;
1213 void SAL_CALL ODatabaseSource::flush( )
1217 // SYNCHRONIZED ->
1219 ModelMethodGuard aGuard( *this );
1221 typedef ::utl::SharedUNOComponent< XModel, ::utl::CloseableComponent > SharedModel;
1222 SharedModel xModel( m_pImpl->getModel_noCreate(), SharedModel::NoTakeOwnership );
1224 if ( !xModel.is() )
1225 xModel.reset( m_pImpl->createNewModel_deliverOwnership(), SharedModel::TakeOwnership );
1227 Reference< css::frame::XStorable> xStorable( xModel, UNO_QUERY_THROW );
1228 xStorable->store();
1230 // <- SYNCHRONIZED
1232 css::lang::EventObject aFlushedEvent(*this);
1233 m_aFlushListeners.notifyEach( &XFlushListener::flushed, aFlushedEvent );
1235 catch( const Exception& )
1237 DBG_UNHANDLED_EXCEPTION("dbaccess");
1241 void SAL_CALL ODatabaseSource::flushed( const EventObject& /*rEvent*/ )
1243 ModelMethodGuard aGuard( *this );
1245 // Okay, this is some hack.
1247 // In general, we have the problem that embedded databases write into their underlying storage, which
1248 // logically is one of our sub storage, and practically is a temporary file maintained by the
1249 // package implementation. As long as we did not commit this storage and our main storage,
1250 // the changes made by the embedded database engine are not really reflected in the database document
1251 // file. This is Bad (TM) for a "real" database application - imagine somebody entering some
1252 // data, and then crashing: For a database application, you would expect that the data still is present
1253 // when you connect to the database next time.
1255 // Since this is a conceptual problem as long as we do use those ZIP packages (in fact, we *cannot*
1256 // provide the desired functionality as long as we do not have a package format which allows O(1) writes),
1257 // we cannot completely fix this. However, we can relax the problem by committing more often - often
1258 // enough so that data loss is more seldom, and seldom enough so that there's no noticeable performance
1259 // decrease.
1261 // For this, we introduced a few places which XFlushable::flush their connections, and register as
1262 // XFlushListener at the embedded connection (which needs to provide the XFlushable functionality).
1263 // Then, when the connection is flushed, we commit both the database storage and our main storage.
1265 // #i55274#
1267 OSL_ENSURE( m_pImpl->isEmbeddedDatabase(), "ODatabaseSource::flushed: no embedded database?!" );
1268 bool bWasModified = m_pImpl->m_bModified;
1269 m_pImpl->commitEmbeddedStorage();
1270 m_pImpl->setModified( bWasModified );
1273 void SAL_CALL ODatabaseSource::addFlushListener( const Reference< css::util::XFlushListener >& _xListener )
1275 m_aFlushListeners.addInterface(_xListener);
1278 void SAL_CALL ODatabaseSource::removeFlushListener( const Reference< css::util::XFlushListener >& _xListener )
1280 m_aFlushListeners.removeInterface(_xListener);
1283 void SAL_CALL ODatabaseSource::elementInserted( const ContainerEvent& /*Event*/ )
1285 ModelMethodGuard aGuard( *this );
1286 if ( m_pImpl.is() )
1287 m_pImpl->setModified(true);
1290 void SAL_CALL ODatabaseSource::elementRemoved( const ContainerEvent& /*Event*/ )
1292 ModelMethodGuard aGuard( *this );
1293 if ( m_pImpl.is() )
1294 m_pImpl->setModified(true);
1297 void SAL_CALL ODatabaseSource::elementReplaced( const ContainerEvent& /*Event*/ )
1299 ModelMethodGuard aGuard( *this );
1300 if ( m_pImpl.is() )
1301 m_pImpl->setModified(true);
1304 // XDocumentDataSource
1305 Reference< XOfficeDatabaseDocument > SAL_CALL ODatabaseSource::getDatabaseDocument()
1307 ModelMethodGuard aGuard( *this );
1309 Reference< XModel > xModel( m_pImpl->getModel_noCreate() );
1310 if ( !xModel.is() )
1311 xModel = m_pImpl->createNewModel_deliverOwnership();
1313 return Reference< XOfficeDatabaseDocument >( xModel, UNO_QUERY_THROW );
1316 void SAL_CALL ODatabaseSource::initialize( css::uno::Sequence< css::uno::Any > const & rArguments)
1318 ::comphelper::NamedValueCollection aProperties( rArguments );
1319 if (aProperties.has(u"ParentWindow"_ustr))
1320 aProperties.get(u"ParentWindow"_ustr) >>= m_pImpl->m_xDialogParent;
1323 Reference< XInterface > ODatabaseSource::getThis() const
1325 return *const_cast< ODatabaseSource* >( this );
1328 } // namespace dbaccess
1330 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
1331 com_sun_star_comp_dba_ODatabaseSource(css::uno::XComponentContext* context,
1332 css::uno::Sequence<css::uno::Any> const &)
1334 css::uno::Reference<XInterface> inst(
1335 DatabaseContext::create(context)->createInstance());
1336 inst->acquire();
1337 return inst.get();
1340 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */