1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
;
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
>
109 WeakReference
< XFlushable
> m_aBroadcaster
;
110 WeakReference
< XFlushListener
> m_aListener
;
113 static void installAdapter( const Reference
< XFlushable
>& _rxBroadcaster
, const Reference
< XFlushListener
>& _rxListener
)
115 new FlushNotificationAdapter( _rxBroadcaster
, _rxListener
);
119 FlushNotificationAdapter( const Reference
< XFlushable
>& _rxBroadcaster
, const Reference
< XFlushListener
>& _rxListener
);
120 virtual ~FlushNotificationAdapter() override
;
126 virtual void SAL_CALL
flushed( const css::lang::EventObject
& rEvent
) override
;
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 );
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
);
173 void SAL_CALL
FlushNotificationAdapter::disposing( const EventObject
& Source
)
175 Reference
< XFlushListener
> xListener( m_aListener
);
176 if ( xListener
.is() )
177 xListener
->disposing( Source
);
182 OAuthenticationContinuation::OAuthenticationContinuation()
183 :m_bRememberPassword(true), // TODO: a meaningful default
184 m_bCanSetUserName(true)
188 sal_Bool SAL_CALL
OAuthenticationContinuation::canSetRealm( )
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
)
210 sal_Bool SAL_CALL
OAuthenticationContinuation::canSetPassword( )
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( )
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
);
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
);
338 Sequence
< PropertyValue
> lcl_filterDriverProperties( const Reference
< XDriver
>& _xDriver
, const OUString
& _sUrl
,
339 const Sequence
< PropertyValue
>& _rDataSourceSettings
)
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
; });
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
);
365 return comphelper::containerToSequence(aRet
);
367 return Sequence
< PropertyValue
>();
370 typedef std::map
< OUString
, sal_Int32
> PropertyAttributeCache
;
372 struct IsDefaultAndNotRemoveable
375 const PropertyAttributeCache
& m_rAttribs
;
378 explicit IsDefaultAndNotRemoveable( const PropertyAttributeCache
& _rAttribs
) : m_rAttribs( _rAttribs
) { }
380 bool operator()( const PropertyValue
& _rProp
)
382 if ( _rProp
.State
!= PropertyState_DEFAULT_VALUE
)
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 );
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
)
419 void ODatabaseSource::setName( const Reference
< XDocumentDataSource
>& _rxDocument
, const OUString
& _rNewName
, DBContextAccess
)
421 ODatabaseSource
& rModelImpl
= dynamic_cast< ODatabaseSource
& >( *_rxDocument
);
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
);
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
)
468 m_pImpl
->disposing(Source
);
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
);
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
);
502 weld::Window
* ODatabaseModelImpl::GetFrameWeld()
504 if (m_xDialogParent
.is())
505 return Application::GetFrameWeld(m_xDialogParent
);
507 Reference
<XModel
> xModel
= getModel_noCreate();
510 Reference
<XController
> xController(xModel
->getCurrentController());
511 if (!xController
.is())
513 Reference
<XFrame
> xFrame(xController
->getFrame());
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();
532 //See ODbTypeWizDialogSetup::SaveDatabaseDocument
533 ::comphelper::NamedValueCollection::get(xModel
->getArgs(), u
"IgnoreFirebirdMigration") >>= bIgnoreMigration
;
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
,
550 if(!sMigrEnvVal
.isEmpty())
551 bNeedMigration
= true;
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
;
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
,
580 m_pImpl
->m_sConnectURL
= "sdbc:embedded:firebird";
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
;
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
;
620 aUserPwdRange
[ nArgPos
].Name
= "password";
621 aUserPwdRange
[ nArgPos
].Value
<<= sPwd
;
623 Reference
< XDriver
> xDriver
;
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
;
645 Sequence
< PropertyValue
> aDriverInfo
= lcl_filterDriverProperties(
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();
668 xReturn
= xManager
->getConnectionWithInfo(m_pImpl
->m_sConnectURL
, ::comphelper::concatSequences(aUserPwd
,aDriverInfo
));
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
676 Reference
< XFlushable
> xFlushable( xReturn
, UNO_QUERY
);
677 if ( xFlushable
.is() )
678 FlushNotificationAdapter::installAdapter( xFlushable
, this );
683 pExceptionMessageId
= RID_STR_COULDNOTLOAD_MANAGER
;
687 OUString sMessage
= DBA_RES(pExceptionMessageId
)
688 .replaceAll("$name$", m_pImpl
->m_sConnectURL
);
691 DBA_RES(RID_STR_CONNECTION_REQUEST
).replaceFirst("$name$", m_pImpl
->m_sConnectURL
),
694 throwGenericSQLException( sMessage
, static_cast< XDataSource
* >( this ), Any( aContext
) );
697 #if ENABLE_FIREBIRD_SDBC
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());
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
)
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())
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
)
799 SAL_WARN("dbaccess", "ODatabaseSource::convertFastPropertyValue: unknown or readonly Property!" );
807 struct SelectPropertyName
810 const OUString
& operator()( const PropertyValue
& _lhs
)
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>
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
;
834 _rAllNewPropertyValues
.begin(),
835 _rAllNewPropertyValues
.end(),
836 std::inserter( aToBeSetPropertyNames
, aToBeSetPropertyNames
.end() ),
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() )
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
);
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
)
879 case PROPERTY_ID_TABLEFILTER
:
880 rValue
>>= m_pImpl
->m_aTableFilter
;
882 case PROPERTY_ID_TABLETYPEFILTER
:
883 rValue
>>= m_pImpl
->m_aTableTypeFilter
;
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();
890 case PROPERTY_ID_PASSWORD
:
891 rValue
>>= m_pImpl
->m_aPassword
;
893 case PROPERTY_ID_ISPASSWORDREQUIRED
:
894 m_pImpl
->m_bPasswordRequired
= any2bool(rValue
);
896 case PROPERTY_ID_SUPPRESSVERSIONCL
:
897 m_pImpl
->m_bSuppressVersionColumns
= any2bool(rValue
);
899 case PROPERTY_ID_URL
:
900 rValue
>>= m_pImpl
->m_sConnectURL
;
902 case PROPERTY_ID_INFO
:
904 Sequence
< PropertyValue
> aInfo
;
905 OSL_VERIFY( rValue
>>= aInfo
);
906 lcl_setPropertyValues_resetOrRemoveOther( m_pImpl
->m_xSettings
, aInfo
);
909 case PROPERTY_ID_LAYOUTINFORMATION
:
910 rValue
>>= m_pImpl
->m_aLayoutInformation
;
913 m_pImpl
->setModified(true);
916 void ODatabaseSource::getFastPropertyValue( Any
& rValue
, sal_Int32 nHandle
) const
923 case PROPERTY_ID_TABLEFILTER
:
924 rValue
<<= m_pImpl
->m_aTableFilter
;
926 case PROPERTY_ID_TABLETYPEFILTER
:
927 rValue
<<= m_pImpl
->m_aTableTypeFilter
;
929 case PROPERTY_ID_USER
:
930 rValue
<<= m_pImpl
->m_sUser
;
932 case PROPERTY_ID_PASSWORD
:
933 rValue
<<= m_pImpl
->m_aPassword
;
935 case PROPERTY_ID_ISPASSWORDREQUIRED
:
936 rValue
<<= m_pImpl
->m_bPasswordRequired
;
938 case PROPERTY_ID_SUPPRESSVERSIONCL
:
939 rValue
<<= m_pImpl
->m_bSuppressVersionColumns
;
941 case PROPERTY_ID_ISREADONLY
:
942 rValue
<<= m_pImpl
->m_bReadOnly
;
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
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(
970 IsDefaultAndNotRemoveable( aPropertyAttributes
)
972 aNonDefaultOrUserDefined
.realloc( pCopyEnd
- pCopyStart
);
973 rValue
<<= aNonDefaultOrUserDefined
;
975 catch( const Exception
& )
977 DBG_UNHANDLED_EXCEPTION("dbaccess");
981 case PROPERTY_ID_SETTINGS
:
982 rValue
<<= m_pImpl
->m_xSettings
;
984 case PROPERTY_ID_URL
:
985 rValue
<<= m_pImpl
->m_sConnectURL
;
987 case PROPERTY_ID_NUMBERFORMATSSUPPLIER
:
988 rValue
<<= m_pImpl
->getNumberFormatsSupplier();
990 case PROPERTY_ID_NAME
:
991 rValue
<<= m_pImpl
->m_sName
;
993 case PROPERTY_ID_LAYOUTINFORMATION
:
994 rValue
<<= m_pImpl
->m_aLayoutInformation
;
997 SAL_WARN("dbaccess","unknown Property");
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.
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
);
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
));
1072 pRequest
->addContinuation(pAbort
);
1073 pRequest
->addContinuation(pAuthenticate
);
1075 // handle the request
1078 _rxHandler
->handle(pRequest
);
1082 DBG_UNHANDLED_EXCEPTION("dbaccess");
1085 if (!pAuthenticate
->wasSelected())
1086 return Reference
< XConnection
>();
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
);
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();
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
);
1132 Reference
< XConnection
> ODatabaseSource::getConnection(const OUString
& user
, const OUString
& password
,bool _bIsolated
)
1134 ModelMethodGuard
aGuard( *this );
1136 Reference
< XConnection
> xConn
;
1139 xConn
= buildIsolatedConnection(user
,password
);
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 );
1153 Reference
< XComponent
> xComp(xConn
,UNO_QUERY
);
1155 xComp
->addEventListener( static_cast< XContainerListener
* >( this ) );
1156 m_pImpl
->m_aConnections
.emplace_back(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() )
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
;
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();
1213 void SAL_CALL
ODatabaseSource::flush( )
1219 ModelMethodGuard
aGuard( *this );
1221 typedef ::utl::SharedUNOComponent
< XModel
, ::utl::CloseableComponent
> SharedModel
;
1222 SharedModel
xModel( m_pImpl
->getModel_noCreate(), SharedModel::NoTakeOwnership
);
1225 xModel
.reset( m_pImpl
->createNewModel_deliverOwnership(), SharedModel::TakeOwnership
);
1227 Reference
< css::frame::XStorable
> xStorable( xModel
, UNO_QUERY_THROW
);
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
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.
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 );
1287 m_pImpl
->setModified(true);
1290 void SAL_CALL
ODatabaseSource::elementRemoved( const ContainerEvent
& /*Event*/ )
1292 ModelMethodGuard
aGuard( *this );
1294 m_pImpl
->setModified(true);
1297 void SAL_CALL
ODatabaseSource::elementReplaced( const ContainerEvent
& /*Event*/ )
1299 ModelMethodGuard
aGuard( *this );
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() );
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());
1340 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */