1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
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>
29 
30 #include <hsqlimport.hxx>
31 #include <migrwarndlg.hxx>
32 
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>
47 
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>
65 
66 #include <algorithm>
67 #include <iterator>
68 #include <set>
69 
70 #include <config_firebird.h>
71 
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;
90 
91 namespace dbaccess
92 {
93 
94 namespace {
95 
96 /** helper class which implements a XFlushListener, and forwards all
97     notification events to another XFlushListener
98 
99     The speciality is that the foreign XFlushListener instance, to which
100     the notifications are forwarded, is held weak.
101 
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.
105 */
106 class FlushNotificationAdapter : public ::cppu::WeakImplHelper< XFlushListener >
107 {
108 private:
109     WeakReference< XFlushable >     m_aBroadcaster;
110     WeakReference< XFlushListener > m_aListener;
111 
112 public:
installAdapter(const Reference<XFlushable> & _rxBroadcaster,const Reference<XFlushListener> & _rxListener)113     static void installAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener )
114     {
115         new FlushNotificationAdapter( _rxBroadcaster, _rxListener );
116     }
117 
118 protected:
119     FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener );
120     virtual ~FlushNotificationAdapter() override;
121 
122     void impl_dispose();
123 
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;
129 };
130 
131 }
132 
FlushNotificationAdapter(const Reference<XFlushable> & _rxBroadcaster,const Reference<XFlushListener> & _rxListener)133 FlushNotificationAdapter::FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener )
134     :m_aBroadcaster( _rxBroadcaster )
135     ,m_aListener( _rxListener )
136 {
137     OSL_ENSURE( _rxBroadcaster.is(), "FlushNotificationAdapter::FlushNotificationAdapter: invalid flushable!" );
138 
139     osl_atomic_increment( &m_refCount );
140     {
141         if ( _rxBroadcaster.is() )
142             _rxBroadcaster->addFlushListener( this );
143     }
144     osl_atomic_decrement( &m_refCount );
145     OSL_ENSURE( m_refCount == 1, "FlushNotificationAdapter::FlushNotificationAdapter: broadcaster isn't holding by hard ref!?" );
146 }
147 
~FlushNotificationAdapter()148 FlushNotificationAdapter::~FlushNotificationAdapter()
149 {
150 }
151 
impl_dispose()152 void FlushNotificationAdapter::impl_dispose()
153 {
154     Reference< XFlushListener > xKeepAlive( this );
155 
156     Reference< XFlushable > xFlushable( m_aBroadcaster );
157     if ( xFlushable.is() )
158         xFlushable->removeFlushListener( this );
159 
160     m_aListener.clear();
161     m_aBroadcaster.clear();
162 }
163 
flushed(const EventObject & rEvent)164 void SAL_CALL FlushNotificationAdapter::flushed( const EventObject& rEvent )
165 {
166     Reference< XFlushListener > xListener( m_aListener );
167     if ( xListener.is() )
168         xListener->flushed( rEvent );
169     else
170         impl_dispose();
171 }
172 
disposing(const EventObject & Source)173 void SAL_CALL FlushNotificationAdapter::disposing( const EventObject& Source )
174 {
175     Reference< XFlushListener > xListener( m_aListener );
176     if ( xListener.is() )
177         xListener->disposing( Source );
178 
179     impl_dispose();
180 }
181 
OAuthenticationContinuation()182 OAuthenticationContinuation::OAuthenticationContinuation()
183     :m_bRememberPassword(true),   // TODO: a meaningful default
184     m_bCanSetUserName(true)
185 {
186 }
187 
canSetRealm()188 sal_Bool SAL_CALL OAuthenticationContinuation::canSetRealm(  )
189 {
190     return false;
191 }
192 
setRealm(const OUString &)193 void SAL_CALL OAuthenticationContinuation::setRealm( const OUString& /*Realm*/ )
194 {
195     SAL_WARN("dbaccess","OAuthenticationContinuation::setRealm: not supported!");
196 }
197 
canSetUserName()198 sal_Bool SAL_CALL OAuthenticationContinuation::canSetUserName(  )
199 {
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;
203 }
204 
setUserName(const OUString & _rUser)205 void SAL_CALL OAuthenticationContinuation::setUserName( const OUString& _rUser )
206 {
207     m_sUser = _rUser;
208 }
209 
canSetPassword()210 sal_Bool SAL_CALL OAuthenticationContinuation::canSetPassword(  )
211 {
212     return true;
213 }
214 
setPassword(const OUString & _rPassword)215 void SAL_CALL OAuthenticationContinuation::setPassword( const OUString& _rPassword )
216 {
217     m_sPassword = _rPassword;
218 }
219 
getRememberPasswordModes(RememberAuthentication & _reDefault)220 Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberPasswordModes( RememberAuthentication& _reDefault )
221 {
222     _reDefault = RememberAuthentication_SESSION;
223     return { _reDefault };
224 }
225 
setRememberPassword(RememberAuthentication _eRemember)226 void SAL_CALL OAuthenticationContinuation::setRememberPassword( RememberAuthentication _eRemember )
227 {
228     m_bRememberPassword = (RememberAuthentication_NO != _eRemember);
229 }
230 
canSetAccount()231 sal_Bool SAL_CALL OAuthenticationContinuation::canSetAccount(  )
232 {
233     return false;
234 }
235 
setAccount(const OUString &)236 void SAL_CALL OAuthenticationContinuation::setAccount( const OUString& )
237 {
238     SAL_WARN("dbaccess","OAuthenticationContinuation::setAccount: not supported!");
239 }
240 
getRememberAccountModes(RememberAuthentication & _reDefault)241 Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberAccountModes( RememberAuthentication& _reDefault )
242 {
243     _reDefault = RememberAuthentication_NO;
244     return { RememberAuthentication_NO };
245 }
246 
setRememberAccount(RememberAuthentication)247 void SAL_CALL OAuthenticationContinuation::setRememberAccount( RememberAuthentication /*Remember*/ )
248 {
249     SAL_WARN("dbaccess","OAuthenticationContinuation::setRememberAccount: not supported!");
250 }
251 
252 namespace {
253 
254 /** The class OSharedConnectionManager implements a structure to share connections.
255     It owns the master connections which will be disposed when the last connection proxy is gone.
256 */
257 // need to hold the digest
258 struct TDigestHolder
259 {
260     sal_uInt8 m_pBuffer[RTL_DIGEST_LENGTH_SHA1];
TDigestHolderdbaccess::__anon5ce340130211::TDigestHolder261     TDigestHolder()
262     {
263         m_pBuffer[0] = 0;
264     }
265 
266 };
267 
268 }
269 
270 class OSharedConnectionManager : public ::cppu::WeakImplHelper< XEventListener >
271 {
272 
273      // contains the currently used master connections
274     struct TConnectionHolder
275     {
276         Reference< XConnection >    xMasterConnection;
277         oslInterlockedCount         nALiveCount;
278     };
279 
280     // the less-compare functor, used for the stl::map
281     struct TDigestLess
282     {
operator ()dbaccess::OSharedConnectionManager::TDigestLess283         bool operator() (const TDigestHolder& x, const TDigestHolder& y) const
284         {
285             sal_uInt32 i;
286             for(i=0;i < RTL_DIGEST_LENGTH_SHA1 && (x.m_pBuffer[i] >= y.m_pBuffer[i]); ++i)
287                 ;
288             return i < RTL_DIGEST_LENGTH_SHA1;
289         }
290     };
291 
292     typedef std::map< TDigestHolder,TConnectionHolder,TDigestLess>        TConnectionMap;      // holds the master connections
293     typedef std::map< Reference< XConnection >,TConnectionMap::iterator>  TSharedConnectionMap;// holds the shared connections
294 
295     ::osl::Mutex                m_aMutex;
296     TConnectionMap              m_aConnections;         // remember the master connection in conjunction with the digest
297     TSharedConnectionMap        m_aSharedConnection;    // the shared connections with conjunction with an iterator into the connections map
298     Reference< XProxyFactory >  m_xProxyFactory;
299 
300 protected:
301     virtual ~OSharedConnectionManager() override;
302 
303 public:
304     explicit OSharedConnectionManager(const Reference< XComponentContext >& _rxContext);
305 
306     void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
307     Reference<XConnection> getConnection(   const OUString& url,
308                                             const OUString& user,
309                                             const OUString& password,
310                                             const Sequence< PropertyValue >& _aInfo,
311                                             ODatabaseSource* _pDataSource);
312     void addEventListener(const Reference<XConnection>& _rxConnection, TConnectionMap::iterator const & _rIter);
313 };
314 
OSharedConnectionManager(const Reference<XComponentContext> & _rxContext)315 OSharedConnectionManager::OSharedConnectionManager(const Reference< XComponentContext >& _rxContext)
316 {
317     m_xProxyFactory.set( ProxyFactory::create( _rxContext ) );
318 }
319 
~OSharedConnectionManager()320 OSharedConnectionManager::~OSharedConnectionManager()
321 {
322 }
323 
disposing(const css::lang::EventObject & Source)324 void SAL_CALL OSharedConnectionManager::disposing( const css::lang::EventObject& Source )
325 {
326     MutexGuard aGuard(m_aMutex);
327     Reference<XConnection> xConnection(Source.Source,UNO_QUERY);
328     TSharedConnectionMap::const_iterator aFind = m_aSharedConnection.find(xConnection);
329     if ( m_aSharedConnection.end() != aFind )
330     {
331         osl_atomic_decrement(&aFind->second->second.nALiveCount);
332         if ( !aFind->second->second.nALiveCount )
333         {
334             ::comphelper::disposeComponent(aFind->second->second.xMasterConnection);
335             m_aConnections.erase(aFind->second);
336         }
337         m_aSharedConnection.erase(aFind);
338     }
339 }
340 
getConnection(const OUString & url,const OUString & user,const OUString & password,const Sequence<PropertyValue> & _aInfo,ODatabaseSource * _pDataSource)341 Reference<XConnection> OSharedConnectionManager::getConnection( const OUString& url,
342                                         const OUString& user,
343                                         const OUString& password,
344                                         const Sequence< PropertyValue >& _aInfo,
345                                         ODatabaseSource* _pDataSource)
346 {
347     MutexGuard aGuard(m_aMutex);
348     TConnectionMap::key_type nId;
349     Sequence< PropertyValue > aInfoCopy(_aInfo);
350     sal_Int32 nPos = aInfoCopy.getLength();
351     aInfoCopy.realloc( nPos + 2 );
352     aInfoCopy[nPos].Name      = "TableFilter";
353     aInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableFilter;
354     aInfoCopy[nPos].Name      = "TableTypeFilter";
355     aInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableTypeFilter;
356 
357     OUString sUser = user;
358     OUString sPassword = password;
359     if ((sUser.isEmpty()) && (sPassword.isEmpty()) && (!_pDataSource->m_pImpl->m_sUser.isEmpty()))
360     {   // ease the usage of this method. data source which are intended to have a user automatically
361         // fill in the user/password combination if the caller of this method does not specify otherwise
362         sUser = _pDataSource->m_pImpl->m_sUser;
363         if (!_pDataSource->m_pImpl->m_aPassword.isEmpty())
364             sPassword = _pDataSource->m_pImpl->m_aPassword;
365     }
366 
367     ::connectivity::OConnectionWrapper::createUniqueId(url,aInfoCopy,nId.m_pBuffer,sUser,sPassword);
368     TConnectionMap::iterator aIter = m_aConnections.find(nId);
369 
370     if ( m_aConnections.end() == aIter )
371     {
372         TConnectionHolder aHolder;
373         aHolder.nALiveCount = 0; // will be incremented by addListener
374         aHolder.xMasterConnection = _pDataSource->buildIsolatedConnection(user,password);
375         aIter = m_aConnections.emplace(nId,aHolder).first;
376     }
377 
378     Reference<XConnection> xRet;
379     if ( aIter->second.xMasterConnection.is() )
380     {
381         Reference< XAggregation > xConProxy = m_xProxyFactory->createProxy(aIter->second.xMasterConnection);
382         xRet = new OSharedConnection(xConProxy);
383         m_aSharedConnection.emplace(xRet,aIter);
384         addEventListener(xRet,aIter);
385     }
386 
387     return xRet;
388 }
389 
addEventListener(const Reference<XConnection> & _rxConnection,TConnectionMap::iterator const & _rIter)390 void OSharedConnectionManager::addEventListener(const Reference<XConnection>& _rxConnection, TConnectionMap::iterator const & _rIter)
391 {
392     Reference<XComponent> xComp(_rxConnection,UNO_QUERY);
393     xComp->addEventListener(this);
394     OSL_ENSURE( m_aConnections.end() != _rIter , "Iterator is end!");
395     osl_atomic_increment(&_rIter->second.nALiveCount);
396 }
397 
398 namespace
399 {
lcl_filterDriverProperties(const Reference<XDriver> & _xDriver,const OUString & _sUrl,const Sequence<PropertyValue> & _rDataSourceSettings,const AsciiPropertyValue * _pKnownSettings)400     Sequence< PropertyValue > lcl_filterDriverProperties( const Reference< XDriver >& _xDriver, const OUString& _sUrl,
401         const Sequence< PropertyValue >& _rDataSourceSettings, const AsciiPropertyValue* _pKnownSettings )
402     {
403         if ( _xDriver.is() )
404         {
405             Sequence< DriverPropertyInfo > aDriverInfo(_xDriver->getPropertyInfo(_sUrl,_rDataSourceSettings));
406 
407             const PropertyValue* pDataSourceSetting = _rDataSourceSettings.getConstArray();
408             const PropertyValue* pEnd = pDataSourceSetting + _rDataSourceSettings.getLength();
409 
410             std::vector< PropertyValue > aRet;
411 
412             for ( ; pDataSourceSetting != pEnd ; ++pDataSourceSetting )
413             {
414                 bool bAllowSetting = false;
415                 const AsciiPropertyValue* pSetting = _pKnownSettings;
416                 for ( ; pSetting->AsciiName; ++pSetting )
417                 {
418                     if ( pDataSourceSetting->Name.equalsAscii( pSetting->AsciiName ) )
419                     {   // the particular data source setting is known
420 
421                         const DriverPropertyInfo* pAllowedDriverSetting = aDriverInfo.getConstArray();
422                         const DriverPropertyInfo* pDriverSettingsEnd = pAllowedDriverSetting + aDriverInfo.getLength();
423                         for ( ; pAllowedDriverSetting != pDriverSettingsEnd; ++pAllowedDriverSetting )
424                         {
425                             if ( pAllowedDriverSetting->Name.equalsAscii( pSetting->AsciiName ) )
426                             {   // the driver also allows this setting
427                                 bAllowSetting = true;
428                                 break;
429                             }
430                         }
431                         break;
432                     }
433                 }
434                 if ( bAllowSetting || !pSetting->AsciiName )
435                 {   // if the driver allows this particular setting, or if the setting is completely unknown,
436                     // we pass it to the driver
437                     aRet.push_back( *pDataSourceSetting );
438                 }
439             }
440             if ( !aRet.empty() )
441                 return comphelper::containerToSequence(aRet);
442         }
443         return Sequence< PropertyValue >();
444     }
445 
446     typedef std::map< OUString, sal_Int32 > PropertyAttributeCache;
447 
448     struct IsDefaultAndNotRemoveable
449     {
450     private:
451         const PropertyAttributeCache& m_rAttribs;
452 
453     public:
IsDefaultAndNotRemoveabledbaccess::__anon5ce340130311::IsDefaultAndNotRemoveable454         explicit IsDefaultAndNotRemoveable( const PropertyAttributeCache& _rAttribs ) : m_rAttribs( _rAttribs ) { }
455 
operator ()dbaccess::__anon5ce340130311::IsDefaultAndNotRemoveable456         bool operator()( const PropertyValue& _rProp )
457         {
458             if ( _rProp.State != PropertyState_DEFAULT_VALUE )
459                 return false;
460 
461             bool bRemoveable = true;
462 
463             PropertyAttributeCache::const_iterator pos = m_rAttribs.find( _rProp.Name );
464             OSL_ENSURE( pos != m_rAttribs.end(), "IsDefaultAndNotRemoveable: illegal property name!" );
465             if ( pos != m_rAttribs.end() )
466                 bRemoveable = ( ( pos->second & PropertyAttribute::REMOVABLE ) != 0 );
467 
468             return !bRemoveable;
469         }
470     };
471 }
472 
473 
ODatabaseSource(const::rtl::Reference<ODatabaseModelImpl> & _pImpl)474 ODatabaseSource::ODatabaseSource(const ::rtl::Reference<ODatabaseModelImpl>& _pImpl)
475             :ModelDependentComponent( _pImpl )
476             ,ODatabaseSource_Base( getMutex() )
477             ,OPropertySetHelper( ODatabaseSource_Base::rBHelper )
478             , m_Bookmarks(*this, getMutex())
479             ,m_aFlushListeners( getMutex() )
480 {
481     // some kind of default
482     SAL_INFO("dbaccess", "DS: ctor: " << std::hex << this << ": " << std::hex << m_pImpl.get() );
483 }
484 
~ODatabaseSource()485 ODatabaseSource::~ODatabaseSource()
486 {
487     SAL_INFO("dbaccess", "DS: dtor: " << std::hex << this << ": " << std::hex << m_pImpl.get() );
488     if ( !ODatabaseSource_Base::rBHelper.bInDispose && !ODatabaseSource_Base::rBHelper.bDisposed )
489     {
490         acquire();
491         dispose();
492     }
493 }
494 
setName(const Reference<XDocumentDataSource> & _rxDocument,const OUString & _rNewName,DBContextAccess)495 void ODatabaseSource::setName( const Reference< XDocumentDataSource >& _rxDocument, const OUString& _rNewName, DBContextAccess )
496 {
497     ODatabaseSource& rModelImpl = dynamic_cast< ODatabaseSource& >( *_rxDocument );
498 
499     SolarMutexGuard g;
500     if ( rModelImpl.m_pImpl.is() )
501         rModelImpl.m_pImpl->m_sName = _rNewName;
502 }
503 
504 // css::lang::XTypeProvider
getTypes()505 Sequence< Type > ODatabaseSource::getTypes()
506 {
507     OTypeCollection aPropertyHelperTypes(   cppu::UnoType<XFastPropertySet>::get(),
508                                             cppu::UnoType<XPropertySet>::get(),
509                                             cppu::UnoType<XMultiPropertySet>::get());
510 
511     return ::comphelper::concatSequences(
512         ODatabaseSource_Base::getTypes(),
513         aPropertyHelperTypes.getTypes()
514     );
515 }
516 
getImplementationId()517 Sequence< sal_Int8 > ODatabaseSource::getImplementationId()
518 {
519     return css::uno::Sequence<sal_Int8>();
520 }
521 
522 // css::uno::XInterface
queryInterface(const Type & rType)523 Any ODatabaseSource::queryInterface( const Type & rType )
524 {
525     Any aIface = ODatabaseSource_Base::queryInterface( rType );
526     if ( !aIface.hasValue() )
527         aIface = ::cppu::OPropertySetHelper::queryInterface( rType );
528     return aIface;
529 }
530 
acquire()531 void ODatabaseSource::acquire() noexcept
532 {
533     ODatabaseSource_Base::acquire();
534 }
535 
release()536 void ODatabaseSource::release() noexcept
537 {
538     ODatabaseSource_Base::release();
539 }
540 
disposing(const css::lang::EventObject & Source)541 void SAL_CALL ODatabaseSource::disposing( const css::lang::EventObject& Source )
542 {
543     if ( m_pImpl.is() )
544         m_pImpl->disposing(Source);
545 }
546 
547 // XServiceInfo
getImplementationName()548 OUString ODatabaseSource::getImplementationName(  )
549 {
550     return "com.sun.star.comp.dba.ODatabaseSource";
551 }
552 
getSupportedServiceNames()553 Sequence< OUString > ODatabaseSource::getSupportedServiceNames(  )
554 {
555     return { SERVICE_SDB_DATASOURCE, "com.sun.star.sdb.DocumentDataSource" };
556 }
557 
supportsService(const OUString & _rServiceName)558 sal_Bool ODatabaseSource::supportsService( const OUString& _rServiceName )
559 {
560     return cppu::supportsService(this, _rServiceName);
561 }
562 
563 // OComponentHelper
disposing()564 void ODatabaseSource::disposing()
565 {
566     SAL_INFO("dbaccess", "DS: disp: " << std::hex << this << ", " << std::hex << m_pImpl.get() );
567     ODatabaseSource_Base::WeakComponentImplHelperBase::disposing();
568     OPropertySetHelper::disposing();
569 
570     EventObject aDisposeEvent(static_cast<XWeak*>(this));
571     m_aFlushListeners.disposeAndClear( aDisposeEvent );
572 
573     ODatabaseDocument::clearObjectContainer(m_pImpl->m_xCommandDefinitions);
574     ODatabaseDocument::clearObjectContainer(m_pImpl->m_xTableDefinitions);
575     m_pImpl.clear();
576 }
577 
GetFrameWeld()578 weld::Window* ODatabaseModelImpl::GetFrameWeld()
579 {
580     if (m_xDialogParent.is())
581         return Application::GetFrameWeld(m_xDialogParent);
582 
583     Reference<XModel> xModel = getModel_noCreate();
584     if (!xModel.is())
585         return nullptr;
586     Reference<XController> xController(xModel->getCurrentController());
587     if (!xController.is())
588         return nullptr;
589     Reference<XFrame> xFrame(xController->getFrame());
590     if (!xFrame.is())
591         return nullptr;
592     Reference<css::awt::XWindow> xWindow(xFrame->getContainerWindow());
593     return Application::GetFrameWeld(xWindow);
594 }
595 
buildLowLevelConnection(const OUString & _rUid,const OUString & _rPwd)596 Reference< XConnection > ODatabaseSource::buildLowLevelConnection(const OUString& _rUid, const OUString& _rPwd)
597 {
598     Reference< XConnection > xReturn;
599 
600     Reference< XDriverManager > xManager;
601 
602 #if ENABLE_FIREBIRD_SDBC
603     bool bIgnoreMigration = false;
604     bool bNeedMigration = false;
605     Reference< XModel > xModel = m_pImpl->getModel_noCreate();
606     if ( xModel)
607     {
608         //See ODbTypeWizDialogSetup::SaveDatabaseDocument
609         ::comphelper::NamedValueCollection aArgs( xModel->getArgs() );
610         aArgs.get("IgnoreFirebirdMigration") >>= bIgnoreMigration;
611     }
612     else
613     {
614         //ignore when we don't have a model. E.g. Mailmerge, data sources, fields...
615         bIgnoreMigration = true;
616     }
617 
618     if (!officecfg::Office::Common::Misc::ExperimentalMode::get())
619         bIgnoreMigration = true;
620 
621     if(!bIgnoreMigration && m_pImpl->m_sConnectURL == "sdbc:embedded:hsqldb")
622     {
623         Reference<XStorage> const xRootStorage = m_pImpl->getOrCreateRootStorage();
624         OUString sMigrEnvVal;
625         osl_getEnvironment(OUString("DBACCESS_HSQL_MIGRATION").pData,
626             &sMigrEnvVal.pData);
627         if(!sMigrEnvVal.isEmpty())
628             bNeedMigration = true;
629         else
630         {
631             Reference<XPropertySet> const xPropSet(xRootStorage, UNO_QUERY_THROW);
632             sal_Int32 nOpenMode(0);
633             if ((xPropSet->getPropertyValue("OpenMode") >>= nOpenMode)
634                 && (nOpenMode & css::embed::ElementModes::WRITE)
635                 && (!Application::IsHeadlessModeEnabled()))
636             {
637                 MigrationWarnDialog aWarnDlg(m_pImpl->GetFrameWeld());
638                 bNeedMigration = aWarnDlg.run() == RET_OK;
639             }
640         }
641         if (bNeedMigration)
642         {
643             // back up content xml file if migration was successful
644             static constexpr OUStringLiteral BACKUP_XML_NAME = u"content_before_migration.xml";
645             try
646             {
647                 if(xRootStorage->isStreamElement(BACKUP_XML_NAME))
648                     xRootStorage->removeElement(BACKUP_XML_NAME);
649             }
650             catch (NoSuchElementException&)
651             {
652                 SAL_INFO("dbaccess", "No file content_before_migration.xml found" );
653             }
654             xRootStorage->copyElementTo("content.xml", xRootStorage,
655                 BACKUP_XML_NAME);
656 
657             m_pImpl->m_sConnectURL = "sdbc:embedded:firebird";
658         }
659     }
660 #endif
661 
662     try {
663         xManager.set( ConnectionPool::create( m_pImpl->m_aContext ), UNO_QUERY_THROW );
664     } catch( const Exception& ) {  }
665     if ( !xManager.is() )
666         // no connection pool installed, fall back to driver manager
667         xManager.set( DriverManager::create(m_pImpl->m_aContext ), UNO_QUERY_THROW );
668 
669     OUString sUser(_rUid);
670     OUString sPwd(_rPwd);
671     if ((sUser.isEmpty()) && (sPwd.isEmpty()) && (!m_pImpl->m_sUser.isEmpty()))
672     {   // ease the usage of this method. data source which are intended to have a user automatically
673         // fill in the user/password combination if the caller of this method does not specify otherwise
674         sUser = m_pImpl->m_sUser;
675         if (!m_pImpl->m_aPassword.isEmpty())
676             sPwd = m_pImpl->m_aPassword;
677     }
678 
679     const char* pExceptionMessageId = RID_STR_COULDNOTCONNECT_UNSPECIFIED;
680     if (xManager.is())
681     {
682         sal_Int32 nAdditionalArgs(0);
683         if (!sUser.isEmpty()) ++nAdditionalArgs;
684         if (!sPwd.isEmpty()) ++nAdditionalArgs;
685 
686         Sequence< PropertyValue > aUserPwd(nAdditionalArgs);
687         sal_Int32 nArgPos = 0;
688         if (!sUser.isEmpty())
689         {
690             aUserPwd[ nArgPos ].Name = "user";
691             aUserPwd[ nArgPos ].Value <<= sUser;
692             ++nArgPos;
693         }
694         if (!sPwd.isEmpty())
695         {
696             aUserPwd[ nArgPos ].Name = "password";
697             aUserPwd[ nArgPos ].Value <<= sPwd;
698         }
699         Reference< XDriver > xDriver;
700         try
701         {
702 
703             // choose driver
704             Reference< XDriverAccess > xAccessDrivers( xManager, UNO_QUERY );
705             if ( xAccessDrivers.is() )
706                 xDriver = xAccessDrivers->getDriverByURL( m_pImpl->m_sConnectURL );
707         }
708         catch( const Exception& )
709         {
710             TOOLS_WARN_EXCEPTION("dbaccess",  "ODatabaseSource::buildLowLevelConnection: got a strange exception while analyzing the error" );
711         }
712         if ( !xDriver.is() || !xDriver->acceptsURL( m_pImpl->m_sConnectURL ) )
713         {
714             // Nowadays, it's allowed for a driver to be registered for a given URL, but actually not to accept it.
715             // This is because registration nowadays happens at compile time (by adding respective configuration data),
716             // but acceptance is decided at runtime.
717             pExceptionMessageId = RID_STR_COULDNOTCONNECT_NODRIVER;
718         }
719         else
720         {
721             Sequence< PropertyValue > aDriverInfo = lcl_filterDriverProperties(
722                 xDriver,
723                 m_pImpl->m_sConnectURL,
724                 m_pImpl->m_xSettings->getPropertyValues(),
725                 dbaccess::ODatabaseModelImpl::getDefaultDataSourceSettings()
726             );
727 
728             if ( m_pImpl->isEmbeddedDatabase() )
729             {
730                 sal_Int32 nCount = aDriverInfo.getLength();
731                 aDriverInfo.realloc(nCount + 3 );
732 
733                 aDriverInfo[nCount].Name = "URL";
734                 aDriverInfo[nCount++].Value <<= m_pImpl->getURL();
735 
736                 aDriverInfo[nCount].Name = "Storage";
737                 Reference< css::document::XDocumentSubStorageSupplier> xDocSup( m_pImpl->getDocumentSubStorageSupplier() );
738                 aDriverInfo[nCount++].Value <<= xDocSup->getDocumentSubStorage("database",ElementModes::READWRITE);
739 
740                 aDriverInfo[nCount].Name = "Document";
741                 aDriverInfo[nCount++].Value <<= getDatabaseDocument();
742             }
743             if (nAdditionalArgs)
744                 xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL, ::comphelper::concatSequences(aUserPwd,aDriverInfo));
745             else
746                 xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL,aDriverInfo);
747 
748             if ( m_pImpl->isEmbeddedDatabase() )
749             {
750                 // see ODatabaseSource::flushed for comment on why we register as FlushListener
751                 // at the connection
752                 Reference< XFlushable > xFlushable( xReturn, UNO_QUERY );
753                 if ( xFlushable.is() )
754                     FlushNotificationAdapter::installAdapter( xFlushable, this );
755             }
756         }
757     }
758     else
759         pExceptionMessageId = RID_STR_COULDNOTLOAD_MANAGER;
760 
761     if ( !xReturn.is() )
762     {
763         OUString sMessage = DBA_RES(pExceptionMessageId)
764             .replaceAll("$name$", m_pImpl->m_sConnectURL);
765 
766         SQLContext aContext;
767         aContext.Message = DBA_RES(RID_STR_CONNECTION_REQUEST).
768             replaceFirst("$name$", m_pImpl->m_sConnectURL);
769 
770         throwGenericSQLException( sMessage, static_cast< XDataSource* >( this ), makeAny( aContext ) );
771     }
772 
773 #if ENABLE_FIREBIRD_SDBC
774     if( bNeedMigration )
775     {
776         Reference< css::document::XDocumentSubStorageSupplier> xDocSup(
777                 m_pImpl->getDocumentSubStorageSupplier() );
778         dbahsql::HsqlImporter importer(xReturn,
779                 xDocSup->getDocumentSubStorage("database",ElementModes::READWRITE) );
780         importer.importHsqlDatabase(m_pImpl->GetFrameWeld());
781     }
782 #endif
783 
784     return xReturn;
785 }
786 
787 // OPropertySetHelper
getPropertySetInfo()788 Reference< XPropertySetInfo >  ODatabaseSource::getPropertySetInfo()
789 {
790     return createPropertySetInfo( getInfoHelper() ) ;
791 }
792 
793 // comphelper::OPropertyArrayUsageHelper
createArrayHelper() const794 ::cppu::IPropertyArrayHelper* ODatabaseSource::createArrayHelper( ) const
795 {
796     BEGIN_PROPERTY_HELPER(13)
797         DECL_PROP1(INFO,                        Sequence< PropertyValue >,  BOUND);
798         DECL_PROP1_BOOL(ISPASSWORDREQUIRED,                                 BOUND);
799         DECL_PROP1_BOOL(ISREADONLY,                                         READONLY);
800         DECL_PROP1(LAYOUTINFORMATION,           Sequence< PropertyValue >,  BOUND);
801         DECL_PROP1(NAME,                        OUString,            READONLY);
802         DECL_PROP2_IFACE(NUMBERFORMATSSUPPLIER, XNumberFormatsSupplier,     READONLY, TRANSIENT);
803         DECL_PROP1(PASSWORD,                    OUString,            TRANSIENT);
804         DECL_PROP2_IFACE(SETTINGS,              XPropertySet,               BOUND, READONLY);
805         DECL_PROP1_BOOL(SUPPRESSVERSIONCL,                                  BOUND);
806         DECL_PROP1(TABLEFILTER,                 Sequence< OUString >,BOUND);
807         DECL_PROP1(TABLETYPEFILTER,             Sequence< OUString >,BOUND);
808         DECL_PROP1(URL,                         OUString,            BOUND);
809         DECL_PROP1(USER,                        OUString,            BOUND);
810     END_PROPERTY_HELPER();
811 }
812 
813 // cppu::OPropertySetHelper
getInfoHelper()814 ::cppu::IPropertyArrayHelper& ODatabaseSource::getInfoHelper()
815 {
816     return *getArrayHelper();
817 }
818 
convertFastPropertyValue(Any & rConvertedValue,Any & rOldValue,sal_Int32 nHandle,const Any & rValue)819 sal_Bool ODatabaseSource::convertFastPropertyValue(Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue )
820 {
821     bool bModified(false);
822     if ( m_pImpl.is() )
823     {
824         switch (nHandle)
825         {
826             case PROPERTY_ID_TABLEFILTER:
827                 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableFilter);
828                 break;
829             case PROPERTY_ID_TABLETYPEFILTER:
830                 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableTypeFilter);
831                 break;
832             case PROPERTY_ID_USER:
833                 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sUser);
834                 break;
835             case PROPERTY_ID_PASSWORD:
836                 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aPassword);
837                 break;
838             case PROPERTY_ID_ISPASSWORDREQUIRED:
839                 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bPasswordRequired);
840                 break;
841             case PROPERTY_ID_SUPPRESSVERSIONCL:
842                 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bSuppressVersionColumns);
843                 break;
844             case PROPERTY_ID_LAYOUTINFORMATION:
845                 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aLayoutInformation);
846                 break;
847             case PROPERTY_ID_URL:
848             {
849                 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sConnectURL);
850             }   break;
851             case PROPERTY_ID_INFO:
852             {
853                 Sequence<PropertyValue> aValues;
854                 if (!(rValue >>= aValues))
855                     throw IllegalArgumentException();
856 
857                 for ( auto const & checkName : std::as_const(aValues) )
858                 {
859                     if ( checkName.Name.isEmpty() )
860                         throw IllegalArgumentException();
861                 }
862 
863                 Sequence< PropertyValue > aSettings = m_pImpl->m_xSettings->getPropertyValues();
864                 bModified = aSettings.getLength() != aValues.getLength();
865                 if ( !bModified )
866                 {
867                     const PropertyValue* pInfoIter = aSettings.getConstArray();
868                     const PropertyValue* checkValue = aValues.getConstArray();
869                     for ( ;!bModified && checkValue != aValues.end() ; ++checkValue,++pInfoIter)
870                     {
871                         bModified = checkValue->Name != pInfoIter->Name;
872                         if ( !bModified )
873                         {
874                             bModified = checkValue->Value != pInfoIter->Value;
875                         }
876                     }
877                 }
878 
879                 rConvertedValue = rValue;
880                 rOldValue <<= aSettings;
881             }
882             break;
883             default:
884                 SAL_WARN("dbaccess", "ODatabaseSource::convertFastPropertyValue: unknown or readonly Property!" );
885         }
886     }
887     return bModified;
888 }
889 
890 namespace
891 {
892     struct SelectPropertyName
893     {
894     public:
operator ()dbaccess::__anon5ce340130411::SelectPropertyName895         const OUString& operator()( const PropertyValue& _lhs )
896         {
897             return _lhs.Name;
898         }
899     };
900 
901     /** sets a new set of property values for a given property bag instance
902 
903         The method takes a property bag, and a sequence of property values to set for this bag.
904         Upon return, every property which is not part of the given sequence is
905         <ul><li>removed from the bag, if it's a removable property</li>
906             <li><em>or</em>reset to its default value, if it's not a removable property</li>
907         </ul>.
908 
909         @param  _rxPropertyBag
910             the property bag to operate on
911         @param  _rAllNewPropertyValues
912             the new property values to set for the bag
913     */
lcl_setPropertyValues_resetOrRemoveOther(const Reference<XPropertyBag> & _rxPropertyBag,const Sequence<PropertyValue> & _rAllNewPropertyValues)914     void lcl_setPropertyValues_resetOrRemoveOther( const Reference< XPropertyBag >& _rxPropertyBag, const Sequence< PropertyValue >& _rAllNewPropertyValues )
915     {
916         // sequences are ugly to operate on
917         std::set<OUString> aToBeSetPropertyNames;
918         std::transform(
919             _rAllNewPropertyValues.begin(),
920             _rAllNewPropertyValues.end(),
921             std::inserter( aToBeSetPropertyNames, aToBeSetPropertyNames.end() ),
922             SelectPropertyName()
923         );
924 
925         try
926         {
927             // obtain all properties currently known at the bag
928             Reference< XPropertySetInfo > xPSI( _rxPropertyBag->getPropertySetInfo(), UNO_SET_THROW );
929             const Sequence< Property > aAllExistentProperties( xPSI->getProperties() );
930 
931             Reference< XPropertyState > xPropertyState( _rxPropertyBag, UNO_QUERY_THROW );
932 
933             // loop through them, and reset resp. default properties which are not to be set
934             for ( auto const & existentProperty : aAllExistentProperties )
935             {
936                 if ( aToBeSetPropertyNames.find( existentProperty.Name ) != aToBeSetPropertyNames.end() )
937                     continue;
938 
939                 // this property is not to be set, but currently exists in the bag.
940                 // -> Remove it, or reset it to the default.
941                 if ( ( existentProperty.Attributes & PropertyAttribute::REMOVABLE ) != 0 )
942                     _rxPropertyBag->removeProperty( existentProperty.Name );
943                 else
944                     xPropertyState->setPropertyToDefault( existentProperty.Name );
945             }
946 
947             // finally, set the new property values
948             _rxPropertyBag->setPropertyValues( _rAllNewPropertyValues );
949         }
950         catch( const Exception& )
951         {
952             DBG_UNHANDLED_EXCEPTION("dbaccess");
953         }
954     }
955 }
956 
setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any & rValue)957 void ODatabaseSource::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
958 {
959     if ( !m_pImpl.is() )
960         return;
961 
962     switch(nHandle)
963     {
964         case PROPERTY_ID_TABLEFILTER:
965             rValue >>= m_pImpl->m_aTableFilter;
966             break;
967         case PROPERTY_ID_TABLETYPEFILTER:
968             rValue >>= m_pImpl->m_aTableTypeFilter;
969             break;
970         case PROPERTY_ID_USER:
971             rValue >>= m_pImpl->m_sUser;
972             // if the user name has changed, reset the password
973             m_pImpl->m_aPassword.clear();
974             break;
975         case PROPERTY_ID_PASSWORD:
976             rValue >>= m_pImpl->m_aPassword;
977             break;
978         case PROPERTY_ID_ISPASSWORDREQUIRED:
979             m_pImpl->m_bPasswordRequired = any2bool(rValue);
980             break;
981         case PROPERTY_ID_SUPPRESSVERSIONCL:
982             m_pImpl->m_bSuppressVersionColumns = any2bool(rValue);
983             break;
984         case PROPERTY_ID_URL:
985             rValue >>= m_pImpl->m_sConnectURL;
986             break;
987         case PROPERTY_ID_INFO:
988         {
989             Sequence< PropertyValue > aInfo;
990             OSL_VERIFY( rValue >>= aInfo );
991             lcl_setPropertyValues_resetOrRemoveOther( m_pImpl->m_xSettings, aInfo );
992         }
993         break;
994         case PROPERTY_ID_LAYOUTINFORMATION:
995             rValue >>= m_pImpl->m_aLayoutInformation;
996             break;
997     }
998     m_pImpl->setModified(true);
999 }
1000 
getFastPropertyValue(Any & rValue,sal_Int32 nHandle) const1001 void ODatabaseSource::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
1002 {
1003     if ( !m_pImpl.is() )
1004         return;
1005 
1006     switch (nHandle)
1007     {
1008         case PROPERTY_ID_TABLEFILTER:
1009             rValue <<= m_pImpl->m_aTableFilter;
1010             break;
1011         case PROPERTY_ID_TABLETYPEFILTER:
1012             rValue <<= m_pImpl->m_aTableTypeFilter;
1013             break;
1014         case PROPERTY_ID_USER:
1015             rValue <<= m_pImpl->m_sUser;
1016             break;
1017         case PROPERTY_ID_PASSWORD:
1018             rValue <<= m_pImpl->m_aPassword;
1019             break;
1020         case PROPERTY_ID_ISPASSWORDREQUIRED:
1021             rValue <<= m_pImpl->m_bPasswordRequired;
1022             break;
1023         case PROPERTY_ID_SUPPRESSVERSIONCL:
1024             rValue <<= m_pImpl->m_bSuppressVersionColumns;
1025             break;
1026         case PROPERTY_ID_ISREADONLY:
1027             rValue <<= m_pImpl->m_bReadOnly;
1028             break;
1029         case PROPERTY_ID_INFO:
1030         {
1031             try
1032             {
1033                 // collect the property attributes of all current settings
1034                 Reference< XPropertySet > xSettingsAsProps( m_pImpl->m_xSettings, UNO_QUERY_THROW );
1035                 Reference< XPropertySetInfo > xPST( xSettingsAsProps->getPropertySetInfo(), UNO_SET_THROW );
1036                 const Sequence< Property > aSettings( xPST->getProperties() );
1037                 std::map< OUString, sal_Int32 > aPropertyAttributes;
1038                 for ( auto const & setting : aSettings )
1039                 {
1040                     aPropertyAttributes[ setting.Name ] = setting.Attributes;
1041                 }
1042 
1043                 // get all current settings with their values
1044                 Sequence< PropertyValue > aValues( m_pImpl->m_xSettings->getPropertyValues() );
1045 
1046                 // transform them so that only property values which fulfill certain
1047                 // criteria survive
1048                 Sequence< PropertyValue > aNonDefaultOrUserDefined( aValues.getLength() );
1049                 const PropertyValue* pCopyEnd = std::remove_copy_if(
1050                     aValues.begin(),
1051                     aValues.end(),
1052                     aNonDefaultOrUserDefined.getArray(),
1053                     IsDefaultAndNotRemoveable( aPropertyAttributes )
1054                 );
1055                 aNonDefaultOrUserDefined.realloc( pCopyEnd - aNonDefaultOrUserDefined.getArray() );
1056                 rValue <<= aNonDefaultOrUserDefined;
1057             }
1058             catch( const Exception& )
1059             {
1060                 DBG_UNHANDLED_EXCEPTION("dbaccess");
1061             }
1062         }
1063         break;
1064         case PROPERTY_ID_SETTINGS:
1065             rValue <<= m_pImpl->m_xSettings;
1066             break;
1067         case PROPERTY_ID_URL:
1068             rValue <<= m_pImpl->m_sConnectURL;
1069             break;
1070         case PROPERTY_ID_NUMBERFORMATSSUPPLIER:
1071             rValue <<= m_pImpl->getNumberFormatsSupplier();
1072             break;
1073         case PROPERTY_ID_NAME:
1074             rValue <<= m_pImpl->m_sName;
1075             break;
1076         case PROPERTY_ID_LAYOUTINFORMATION:
1077             rValue <<= m_pImpl->m_aLayoutInformation;
1078             break;
1079         default:
1080             SAL_WARN("dbaccess","unknown Property");
1081     }
1082 }
1083 
1084 // XDataSource
setLoginTimeout(sal_Int32 seconds)1085 void ODatabaseSource::setLoginTimeout(sal_Int32 seconds)
1086 {
1087     ModelMethodGuard aGuard( *this );
1088     m_pImpl->m_nLoginTimeout = seconds;
1089 }
1090 
getLoginTimeout()1091 sal_Int32 ODatabaseSource::getLoginTimeout()
1092 {
1093     ModelMethodGuard aGuard( *this );
1094     return m_pImpl->m_nLoginTimeout;
1095 }
1096 
1097 // XCompletedConnection
connectWithCompletion(const Reference<XInteractionHandler> & _rxHandler)1098 Reference< XConnection > SAL_CALL ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler )
1099 {
1100     return connectWithCompletion(_rxHandler,false);
1101 }
1102 
getConnection(const OUString & user,const OUString & password)1103 Reference< XConnection > ODatabaseSource::getConnection(const OUString& user, const OUString& password)
1104 {
1105     return getConnection(user,password,false);
1106 }
1107 
getIsolatedConnection(const OUString & user,const OUString & password)1108 Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnection( const OUString& user, const OUString& password )
1109 {
1110     return getConnection(user,password,true);
1111 }
1112 
getIsolatedConnectionWithCompletion(const Reference<XInteractionHandler> & _rxHandler)1113 Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnectionWithCompletion( const Reference< XInteractionHandler >& _rxHandler )
1114 {
1115     return connectWithCompletion(_rxHandler,true);
1116 }
1117 
connectWithCompletion(const Reference<XInteractionHandler> & _rxHandler,bool _bIsolated)1118 Reference< XConnection > ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler,bool _bIsolated )
1119 {
1120     ModelMethodGuard aGuard( *this );
1121 
1122     if (!_rxHandler.is())
1123     {
1124         SAL_WARN("dbaccess","ODatabaseSource::connectWithCompletion: invalid interaction handler!");
1125         return getConnection(m_pImpl->m_sUser, m_pImpl->m_aPassword,_bIsolated);
1126     }
1127 
1128     OUString sUser(m_pImpl->m_sUser), sPassword(m_pImpl->m_aPassword);
1129     bool bNewPasswordGiven = false;
1130 
1131     if (m_pImpl->m_bPasswordRequired && sPassword.isEmpty())
1132     {   // we need a password, but don't have one yet.
1133         // -> ask the user
1134 
1135         // build an interaction request
1136         // two continuations (Ok and Cancel)
1137         rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort;
1138         rtl::Reference<OAuthenticationContinuation> pAuthenticate = new OAuthenticationContinuation;
1139 
1140         // the name which should be referred in the login dialog
1141         OUString sServerName( m_pImpl->m_sName );
1142         INetURLObject aURLCheck( sServerName );
1143         if ( aURLCheck.GetProtocol() != INetProtocol::NotValid )
1144             sServerName = aURLCheck.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::Unambiguous );
1145 
1146         // the request
1147         AuthenticationRequest aRequest;
1148         aRequest.ServerName = sServerName;
1149         aRequest.HasRealm = aRequest.HasAccount = false;
1150         aRequest.HasUserName = aRequest.HasPassword = true;
1151         aRequest.UserName = m_pImpl->m_sUser;
1152         aRequest.Password = m_pImpl->m_sFailedPassword.isEmpty() ?  m_pImpl->m_aPassword : m_pImpl->m_sFailedPassword;
1153         rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest(makeAny(aRequest));
1154         // some knittings
1155         pRequest->addContinuation(pAbort);
1156         pRequest->addContinuation(pAuthenticate);
1157 
1158         // handle the request
1159         try
1160         {
1161             _rxHandler->handle(pRequest);
1162         }
1163         catch(Exception&)
1164         {
1165             DBG_UNHANDLED_EXCEPTION("dbaccess");
1166         }
1167 
1168         if (!pAuthenticate->wasSelected())
1169             return Reference< XConnection >();
1170 
1171         // get the result
1172         sUser = m_pImpl->m_sUser = pAuthenticate->getUser();
1173         sPassword = pAuthenticate->getPassword();
1174 
1175         if (pAuthenticate->getRememberPassword())
1176         {
1177             m_pImpl->m_aPassword = pAuthenticate->getPassword();
1178             bNewPasswordGiven = true;
1179         }
1180         m_pImpl->m_sFailedPassword.clear();
1181     }
1182 
1183     try
1184     {
1185         return getConnection(sUser, sPassword,_bIsolated);
1186     }
1187     catch(Exception&)
1188     {
1189         if (bNewPasswordGiven)
1190         {
1191             m_pImpl->m_sFailedPassword = m_pImpl->m_aPassword;
1192             // assume that we had an authentication problem. Without this we may, after an unsuccessful connect, while
1193             // the user gave us a password and the order to remember it, never allow a password input again (at least
1194             // not without restarting the session)
1195             m_pImpl->m_aPassword.clear();
1196         }
1197         throw;
1198     }
1199 }
1200 
buildIsolatedConnection(const OUString & user,const OUString & password)1201 Reference< XConnection > ODatabaseSource::buildIsolatedConnection(const OUString& user, const OUString& password)
1202 {
1203     Reference< XConnection > xConn;
1204     Reference< XConnection > xSdbcConn = buildLowLevelConnection(user, password);
1205     OSL_ENSURE( xSdbcConn.is(), "ODatabaseSource::buildIsolatedConnection: invalid return value of buildLowLevelConnection!" );
1206     // buildLowLevelConnection is expected to always succeed
1207     if ( xSdbcConn.is() )
1208     {
1209         // build a connection server and return it (no stubs)
1210         xConn = new OConnection(*this, xSdbcConn, m_pImpl->m_aContext);
1211     }
1212     return xConn;
1213 }
1214 
getConnection(const OUString & user,const OUString & password,bool _bIsolated)1215 Reference< XConnection > ODatabaseSource::getConnection(const OUString& user, const OUString& password,bool _bIsolated)
1216 {
1217     ModelMethodGuard aGuard( *this );
1218 
1219     Reference< XConnection > xConn;
1220     if ( _bIsolated )
1221     {
1222         xConn = buildIsolatedConnection(user,password);
1223     }
1224     else
1225     { // create a new proxy for the connection
1226         if ( !m_pImpl->m_xSharedConnectionManager.is() )
1227         {
1228             // TODO ideally we could just have one field, but to make that work
1229             // we'd need to move OSharedConnectionManager into its own file and header
1230             rtl::Reference<OSharedConnectionManager> manager =
1231                 new OSharedConnectionManager( m_pImpl->m_aContext );
1232             m_pImpl->m_pSharedConnectionManager = manager.get();
1233             m_pImpl->m_xSharedConnectionManager = m_pImpl->m_pSharedConnectionManager;
1234         }
1235         xConn = m_pImpl->m_pSharedConnectionManager->getConnection(
1236             m_pImpl->m_sConnectURL, user, password, m_pImpl->m_xSettings->getPropertyValues(), this );
1237     }
1238 
1239     if ( xConn.is() )
1240     {
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);
1245     }
1246 
1247     return xConn;
1248 }
1249 
getBookmarks()1250 Reference< XNameAccess > SAL_CALL ODatabaseSource::getBookmarks(  )
1251 {
1252     ModelMethodGuard aGuard( *this );
1253     // tdf#114596 this may look nutty but see OBookmarkContainer::acquire()
1254     return static_cast<XNameContainer*>(&m_Bookmarks);
1255 }
1256 
getQueryDefinitions()1257 Reference< XNameAccess > SAL_CALL ODatabaseSource::getQueryDefinitions( )
1258 {
1259     ModelMethodGuard aGuard( *this );
1260 
1261     Reference< XNameAccess > xContainer = m_pImpl->m_xCommandDefinitions;
1262     if ( !xContainer.is() )
1263     {
1264         Any aValue;
1265         css::uno::Reference< css::uno::XInterface > xMy(*this);
1266         if ( dbtools::getDataSourceSetting(xMy,"CommandDefinitions",aValue) )
1267         {
1268             OUString sSupportService;
1269             aValue >>= sSupportService;
1270             if ( !sSupportService.isEmpty() )
1271             {
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);
1275             }
1276         }
1277         if ( !xContainer.is() )
1278         {
1279             TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_QUERY ) );
1280             xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, false );
1281         }
1282         m_pImpl->m_xCommandDefinitions = xContainer;
1283     }
1284     return xContainer;
1285 }
1286 
1287 // XTablesSupplier
getTables()1288 Reference< XNameAccess >  ODatabaseSource::getTables()
1289 {
1290     ModelMethodGuard aGuard( *this );
1291 
1292     Reference< XNameAccess > xContainer = m_pImpl->m_xTableDefinitions;
1293     if ( !xContainer.is() )
1294     {
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;
1298     }
1299     return xContainer;
1300 }
1301 
flush()1302 void SAL_CALL ODatabaseSource::flush(  )
1303 {
1304     try
1305     {
1306         // SYNCHRONIZED ->
1307         {
1308             ModelMethodGuard aGuard( *this );
1309 
1310             typedef ::utl::SharedUNOComponent< XModel, ::utl::CloseableComponent > SharedModel;
1311             SharedModel xModel( m_pImpl->getModel_noCreate(), SharedModel::NoTakeOwnership );
1312 
1313             if ( !xModel.is() )
1314                 xModel.reset( m_pImpl->createNewModel_deliverOwnership(), SharedModel::TakeOwnership );
1315 
1316             Reference< css::frame::XStorable> xStorable( xModel, UNO_QUERY_THROW );
1317             xStorable->store();
1318         }
1319         // <- SYNCHRONIZED
1320 
1321         css::lang::EventObject aFlushedEvent(*this);
1322         m_aFlushListeners.notifyEach( &XFlushListener::flushed, aFlushedEvent );
1323     }
1324     catch( const Exception& )
1325     {
1326         DBG_UNHANDLED_EXCEPTION("dbaccess");
1327     }
1328 }
1329 
flushed(const EventObject &)1330 void SAL_CALL ODatabaseSource::flushed( const EventObject& /*rEvent*/ )
1331 {
1332     ModelMethodGuard aGuard( *this );
1333 
1334     // Okay, this is some hack.
1335     //
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.
1343     //
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.
1349     //
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.
1353     //
1354     // #i55274#
1355 
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 );
1360 }
1361 
addFlushListener(const Reference<css::util::XFlushListener> & _xListener)1362 void SAL_CALL ODatabaseSource::addFlushListener( const Reference< css::util::XFlushListener >& _xListener )
1363 {
1364     m_aFlushListeners.addInterface(_xListener);
1365 }
1366 
removeFlushListener(const Reference<css::util::XFlushListener> & _xListener)1367 void SAL_CALL ODatabaseSource::removeFlushListener( const Reference< css::util::XFlushListener >& _xListener )
1368 {
1369     m_aFlushListeners.removeInterface(_xListener);
1370 }
1371 
elementInserted(const ContainerEvent &)1372 void SAL_CALL ODatabaseSource::elementInserted( const ContainerEvent& /*Event*/ )
1373 {
1374     ModelMethodGuard aGuard( *this );
1375     if ( m_pImpl.is() )
1376         m_pImpl->setModified(true);
1377 }
1378 
elementRemoved(const ContainerEvent &)1379 void SAL_CALL ODatabaseSource::elementRemoved( const ContainerEvent& /*Event*/ )
1380 {
1381     ModelMethodGuard aGuard( *this );
1382     if ( m_pImpl.is() )
1383         m_pImpl->setModified(true);
1384 }
1385 
elementReplaced(const ContainerEvent &)1386 void SAL_CALL ODatabaseSource::elementReplaced( const ContainerEvent& /*Event*/ )
1387 {
1388     ModelMethodGuard aGuard( *this );
1389     if ( m_pImpl.is() )
1390         m_pImpl->setModified(true);
1391 }
1392 
1393 // XDocumentDataSource
getDatabaseDocument()1394 Reference< XOfficeDatabaseDocument > SAL_CALL ODatabaseSource::getDatabaseDocument()
1395 {
1396     ModelMethodGuard aGuard( *this );
1397 
1398     Reference< XModel > xModel( m_pImpl->getModel_noCreate() );
1399     if ( !xModel.is() )
1400         xModel = m_pImpl->createNewModel_deliverOwnership();
1401 
1402     return Reference< XOfficeDatabaseDocument >( xModel, UNO_QUERY_THROW );
1403 }
1404 
initialize(css::uno::Sequence<css::uno::Any> const & rArguments)1405 void SAL_CALL ODatabaseSource::initialize( css::uno::Sequence< css::uno::Any > const & rArguments)
1406 {
1407     ::comphelper::NamedValueCollection aProperties( rArguments );
1408     if (aProperties.has("ParentWindow"))
1409         aProperties.get("ParentWindow") >>= m_pImpl->m_xDialogParent;
1410 }
1411 
getThis() const1412 Reference< XInterface > ODatabaseSource::getThis() const
1413 {
1414     return *const_cast< ODatabaseSource* >( this );
1415 }
1416 
1417 }   // namespace dbaccess
1418 
1419 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
com_sun_star_comp_dba_ODatabaseSource(css::uno::XComponentContext * context,css::uno::Sequence<css::uno::Any> const &)1420 com_sun_star_comp_dba_ODatabaseSource(css::uno::XComponentContext* context,
1421         css::uno::Sequence<css::uno::Any> const &)
1422 {
1423     css::uno::Reference<XInterface> inst(
1424         DatabaseContext::create(context)->createInstance());
1425     inst->acquire();
1426     return inst.get();
1427 }
1428 
1429 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1430