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 "DbAdminImpl.hxx"
23 #include <svl/poolitem.hxx>
24 #include <svl/itempool.hxx>
25 #include <svl/stritem.hxx>
26 #include <svl/intitem.hxx>
27 #include <svl/eitem.hxx>
28 #include <IItemSetHelper.hxx>
29 #include <UITools.hxx>
30 #include <core_resource.hxx>
31 #include <strings.hrc>
32 #include <strings.hxx>
33 #include <dsitems.hxx>
34 #include "dsnItem.hxx"
35 #include "optionalboolitem.hxx"
36 #include <stringlistitem.hxx>
37 #include <OAuthenticationContinuation.hxx>
39 #include <com/sun/star/beans/PropertyAttribute.hpp>
40 #include <com/sun/star/frame/XStorable.hpp>
41 #include <com/sun/star/sdb/DatabaseContext.hpp>
42 #include <com/sun/star/sdb/SQLContext.hpp>
43 #include <com/sun/star/sdbc/ConnectionPool.hpp>
44 #include <com/sun/star/sdbc/XDriver.hpp>
45 #include <com/sun/star/task/InteractionHandler.hpp>
46 #include <com/sun/star/ucb/AuthenticationRequest.hpp>
48 #include <comphelper/interaction.hxx>
49 #include <comphelper/sequence.hxx>
50 #include <connectivity/DriversConfig.hxx>
51 #include <connectivity/dbexception.hxx>
52 #include <osl/file.hxx>
53 #include <comphelper/diagnose_ex.hxx>
54 #include <osl/diagnose.h>
55 #include <sal/log.hxx>
56 #include <typelib/typedescription.hxx>
57 #include <vcl/svapp.hxx>
58 #include <vcl/stdtext.hxx>
59 #include <vcl/weld.hxx>
64 #include <o3tl/functional.hxx>
65 #include <comphelper/string.hxx>
69 using namespace ::dbtools
;
70 using namespace com::sun::star::uno
;
71 using namespace com::sun::star
;
72 using namespace com::sun::star::ucb
;
73 using namespace com::sun::star::task
;
74 using namespace com::sun::star::sdbc
;
75 using namespace com::sun::star::sdb
;
76 using namespace com::sun::star::beans
;
77 using namespace com::sun::star::util
;
78 using namespace com::sun::star::container
;
79 using namespace com::sun::star::frame
;
83 bool implCheckItemType( SfxItemSet
const & _rSet
, const sal_uInt16 _nId
, const std::function
<bool ( const SfxPoolItem
* )>& isItemType
)
85 bool bCorrectType
= false;
87 SfxItemPool
* pPool
= _rSet
.GetPool();
88 OSL_ENSURE( pPool
, "implCheckItemType: invalid item pool!" );
91 const SfxPoolItem
& rDefItem
= pPool
->GetUserOrPoolDefaultItem( _nId
);
92 bCorrectType
= isItemType(&rDefItem
);
97 void lcl_putProperty(const Reference
< XPropertySet
>& _rxSet
, const OUString
& _rName
, const Any
& _rValue
)
102 _rxSet
->setPropertyValue(_rName
, _rValue
);
106 SAL_WARN("dbaccess", "ODbAdminDialog::implTranslateProperty: could not set the property "
112 OUString
lcl_createHostWithPort(const SfxStringItem
* _pHostName
,const SfxInt32Item
* _pPortNumber
)
116 if ( _pHostName
&& _pHostName
->GetValue().getLength() )
117 sNewUrl
= _pHostName
->GetValue();
121 sNewUrl
+= ":" + OUString::number(_pPortNumber
->GetValue());
128 // ODbDataSourceAdministrationHelper
129 ODbDataSourceAdministrationHelper::ODbDataSourceAdministrationHelper(const Reference
< XComponentContext
>& _xORB
, weld::Window
* pParent
, weld::Window
* pTopParent
, IItemSetHelper
* _pItemSetHelper
)
132 , m_pItemSetHelper(_pItemSetHelper
)
134 /// initialize the property translation map
135 // direct properties of a data source
136 m_aDirectPropTranslator
.emplace( DSID_CONNECTURL
, PROPERTY_URL
);
137 m_aDirectPropTranslator
.emplace( DSID_NAME
, PROPERTY_NAME
);
138 m_aDirectPropTranslator
.emplace( DSID_USER
, PROPERTY_USER
);
139 m_aDirectPropTranslator
.emplace( DSID_PASSWORD
, PROPERTY_PASSWORD
);
140 m_aDirectPropTranslator
.emplace( DSID_PASSWORDREQUIRED
, PROPERTY_ISPASSWORDREQUIRED
);
141 m_aDirectPropTranslator
.emplace( DSID_TABLEFILTER
, PROPERTY_TABLEFILTER
);
142 m_aDirectPropTranslator
.emplace( DSID_READONLY
, PROPERTY_ISREADONLY
);
143 m_aDirectPropTranslator
.emplace( DSID_SUPPRESSVERSIONCL
, PROPERTY_SUPPRESSVERSIONCL
);
145 // implicit properties, to be found in the direct property "Info"
146 m_aIndirectPropTranslator
.emplace( DSID_JDBCDRIVERCLASS
, INFO_JDBCDRIVERCLASS
);
147 m_aIndirectPropTranslator
.emplace( DSID_TEXTFILEEXTENSION
, INFO_TEXTFILEEXTENSION
);
148 m_aIndirectPropTranslator
.emplace( DSID_CHARSET
, INFO_CHARSET
);
149 m_aIndirectPropTranslator
.emplace( DSID_TEXTFILEHEADER
, INFO_TEXTFILEHEADER
);
150 m_aIndirectPropTranslator
.emplace( DSID_FIELDDELIMITER
, INFO_FIELDDELIMITER
);
151 m_aIndirectPropTranslator
.emplace( DSID_TEXTDELIMITER
, INFO_TEXTDELIMITER
);
152 m_aIndirectPropTranslator
.emplace( DSID_DECIMALDELIMITER
, INFO_DECIMALDELIMITER
);
153 m_aIndirectPropTranslator
.emplace( DSID_THOUSANDSDELIMITER
, INFO_THOUSANDSDELIMITER
);
154 m_aIndirectPropTranslator
.emplace( DSID_SHOWDELETEDROWS
, INFO_SHOWDELETEDROWS
);
155 m_aIndirectPropTranslator
.emplace( DSID_ALLOWLONGTABLENAMES
, INFO_ALLOWLONGTABLENAMES
);
156 m_aIndirectPropTranslator
.emplace( DSID_ADDITIONALOPTIONS
, INFO_ADDITIONALOPTIONS
);
157 m_aIndirectPropTranslator
.emplace( DSID_SQL92CHECK
, PROPERTY_ENABLESQL92CHECK
);
158 m_aIndirectPropTranslator
.emplace( DSID_AUTOINCREMENTVALUE
, PROPERTY_AUTOINCREMENTCREATION
);
159 m_aIndirectPropTranslator
.emplace( DSID_AUTORETRIEVEVALUE
, INFO_AUTORETRIEVEVALUE
);
160 m_aIndirectPropTranslator
.emplace( DSID_AUTORETRIEVEENABLED
, INFO_AUTORETRIEVEENABLED
);
161 m_aIndirectPropTranslator
.emplace( DSID_APPEND_TABLE_ALIAS
, INFO_APPEND_TABLE_ALIAS
);
162 m_aIndirectPropTranslator
.emplace( DSID_AS_BEFORE_CORRNAME
, INFO_AS_BEFORE_CORRELATION_NAME
);
163 m_aIndirectPropTranslator
.emplace( DSID_CHECK_REQUIRED_FIELDS
, INFO_FORMS_CHECK_REQUIRED_FIELDS
);
164 m_aIndirectPropTranslator
.emplace( DSID_ESCAPE_DATETIME
, INFO_ESCAPE_DATETIME
);
165 m_aIndirectPropTranslator
.emplace( DSID_PRIMARY_KEY_SUPPORT
, u
"PrimaryKeySupport"_ustr
);
166 m_aIndirectPropTranslator
.emplace( DSID_PARAMETERNAMESUBST
, INFO_PARAMETERNAMESUBST
);
167 m_aIndirectPropTranslator
.emplace( DSID_IGNOREDRIVER_PRIV
, INFO_IGNOREDRIVER_PRIV
);
168 m_aIndirectPropTranslator
.emplace( DSID_BOOLEANCOMPARISON
, PROPERTY_BOOLEANCOMPARISONMODE
);
169 m_aIndirectPropTranslator
.emplace( DSID_ENABLEOUTERJOIN
, PROPERTY_ENABLEOUTERJOIN
);
170 m_aIndirectPropTranslator
.emplace( DSID_CATALOG
, PROPERTY_USECATALOGINSELECT
);
171 m_aIndirectPropTranslator
.emplace( DSID_SCHEMA
, PROPERTY_USESCHEMAINSELECT
);
172 m_aIndirectPropTranslator
.emplace( DSID_INDEXAPPENDIX
, u
"AddIndexAppendix"_ustr
);
173 m_aIndirectPropTranslator
.emplace( DSID_DOSLINEENDS
, u
"PreferDosLikeLineEnds"_ustr
);
174 m_aIndirectPropTranslator
.emplace( DSID_CONN_SOCKET
, u
"LocalSocket"_ustr
);
175 m_aIndirectPropTranslator
.emplace( DSID_NAMED_PIPE
, u
"NamedPipe"_ustr
);
176 m_aIndirectPropTranslator
.emplace( DSID_RESPECTRESULTSETTYPE
, u
"RespectDriverResultSetType"_ustr
);
177 m_aIndirectPropTranslator
.emplace( DSID_MAX_ROW_SCAN
, u
"MaxRowScan"_ustr
);
179 // extra settings for ODBC
180 m_aIndirectPropTranslator
.emplace( DSID_USECATALOG
, INFO_USECATALOG
);
181 // extra settings for an LDAP address book
182 m_aIndirectPropTranslator
.emplace( DSID_CONN_LDAP_BASEDN
, INFO_CONN_LDAP_BASEDN
);
183 m_aIndirectPropTranslator
.emplace( DSID_CONN_LDAP_ROWCOUNT
, INFO_CONN_LDAP_ROWCOUNT
);
184 m_aIndirectPropTranslator
.emplace( DSID_CONN_LDAP_USESSL
, u
"UseSSL"_ustr
);
185 m_aIndirectPropTranslator
.emplace( DSID_DOCUMENT_URL
, PROPERTY_URL
);
188 m_aIndirectPropTranslator
.emplace( DSID_IGNORECURRENCY
, u
"IgnoreCurrency"_ustr
);
192 m_xDatabaseContext
= DatabaseContext::create(m_xContext
);
194 catch(const Exception
&)
196 ShowServiceNotAvailableError(pTopParent
, u
"com.sun.star.sdb.DatabaseContext", true);
200 bool ODbDataSourceAdministrationHelper::getCurrentSettings(Sequence
< PropertyValue
>& _rDriverParam
)
202 OSL_ENSURE(m_pItemSetHelper
->getOutputSet(), "ODbDataSourceAdministrationHelper::getCurrentSettings : not to be called without an example set!");
203 if (!m_pItemSetHelper
->getOutputSet())
206 std::vector
< PropertyValue
> aReturn
;
207 // collecting this in a vector because it has a push_back, in opposite to sequences
209 // user: DSID_USER -> "user"
210 const SfxStringItem
* pUser
= m_pItemSetHelper
->getOutputSet()->GetItem
<SfxStringItem
>(DSID_USER
);
211 if (pUser
&& pUser
->GetValue().getLength())
212 aReturn
.emplace_back( "user", 0,
213 Any(pUser
->GetValue()), PropertyState_DIRECT_VALUE
);
215 // check if the connection type requires a password
216 if (hasAuthentication(*m_pItemSetHelper
->getOutputSet()))
218 // password: DSID_PASSWORD -> password
219 const SfxStringItem
* pPassword
= m_pItemSetHelper
->getOutputSet()->GetItem
<SfxStringItem
>(DSID_PASSWORD
);
220 OUString sPassword
= pPassword
? pPassword
->GetValue() : OUString();
221 const SfxBoolItem
* pPasswordRequired
= m_pItemSetHelper
->getOutputSet()->GetItem
<SfxBoolItem
>(DSID_PASSWORDREQUIRED
);
222 // if the set does not contain a password, but the item set says it requires one, ask the user
223 if ((!pPassword
|| !pPassword
->GetValue().getLength()) && (pPasswordRequired
&& pPasswordRequired
->GetValue()))
225 const SfxStringItem
* pName
= m_pItemSetHelper
->getOutputSet()->GetItem
<SfxStringItem
>(DSID_NAME
);
227 Reference
< XModel
> xModel( getDataSourceOrModel( m_xDatasource
), UNO_QUERY_THROW
);
228 ::comphelper::NamedValueCollection
aArgs( xModel
->getArgs() );
229 Reference
< XInteractionHandler
> xHandler( aArgs
.getOrDefault( u
"InteractionHandler"_ustr
, Reference
< XInteractionHandler
>() ) );
231 if ( !xHandler
.is() )
233 // instantiate the default SDB interaction handler
234 xHandler
= task::InteractionHandler::createWithParent(m_xContext
, m_pParent
->GetXWindow());
237 OUString sName
= pName
? pName
->GetValue() : OUString();
238 OUString
sLoginRequest(DBA_RES(STR_ENTER_CONNECTION_PASSWORD
));
239 OUString sTemp
= sName
;
240 sName
= ::dbaui::getStrippedDatabaseName(nullptr,sTemp
);
241 if ( !sName
.isEmpty() )
242 sLoginRequest
= sLoginRequest
.replaceAll("$name$", sName
);
245 sLoginRequest
= sLoginRequest
.replaceAll("\"$name$\"", "");
246 // ensure that in other languages the string will be deleted
247 sLoginRequest
= sLoginRequest
.replaceAll("$name$", "");
251 AuthenticationRequest aRequest
;
252 aRequest
.ServerName
= sName
;
253 aRequest
.Diagnostic
= sLoginRequest
;
254 aRequest
.HasRealm
= false;
256 aRequest
.HasUserName
= pUser
!= nullptr;
257 aRequest
.UserName
= pUser
? pUser
->GetValue() : OUString();
258 aRequest
.HasPassword
= true;
260 aRequest
.HasAccount
= false;
263 rtl::Reference
<comphelper::OInteractionRequest
> pRequest
= new comphelper::OInteractionRequest(Any(aRequest
));
265 // build an interaction request
266 // two continuations (Ok and Cancel)
267 ::rtl::Reference
< comphelper::OInteractionAbort
> pAbort
= new comphelper::OInteractionAbort
;
268 ::rtl::Reference
< dbaccess::OAuthenticationContinuation
> pAuthenticate
= new dbaccess::OAuthenticationContinuation
;
269 pAuthenticate
->setCanChangeUserName( false );
270 pAuthenticate
->setRememberPassword( RememberAuthentication_SESSION
);
273 pRequest
->addContinuation(pAbort
);
274 pRequest
->addContinuation(pAuthenticate
);
276 // handle the request
279 SolarMutexGuard aSolarGuard
;
280 // release the mutex when calling the handler, it may need to lock the SolarMutex
281 xHandler
->handle(pRequest
);
285 DBG_UNHANDLED_EXCEPTION("dbaccess");
287 if (!pAuthenticate
->wasSelected())
290 sPassword
= pAuthenticate
->getPassword();
291 if (pAuthenticate
->getRememberPassword())
292 m_pItemSetHelper
->getWriteOutputSet()->Put(SfxStringItem(DSID_PASSWORD
, sPassword
));
295 if (!sPassword
.isEmpty())
296 aReturn
.emplace_back( "password", 0,
297 Any(sPassword
), PropertyState_DIRECT_VALUE
);
300 if ( !aReturn
.empty() )
301 _rDriverParam
= comphelper::containerToSequence(aReturn
);
303 // append all the other stuff (charset etc.)
304 fillDatasourceInfo(*m_pItemSetHelper
->getOutputSet(), _rDriverParam
);
309 void ODbDataSourceAdministrationHelper::successfullyConnected()
311 OSL_ENSURE(m_pItemSetHelper
->getOutputSet(), "ODbDataSourceAdministrationHelper::successfullyConnected: not to be called without an example set!");
312 if (!m_pItemSetHelper
->getOutputSet())
315 if (hasAuthentication(*m_pItemSetHelper
->getOutputSet()))
317 const SfxStringItem
* pPassword
= m_pItemSetHelper
->getOutputSet()->GetItem
<SfxStringItem
>(DSID_PASSWORD
);
318 if (pPassword
&& (0 != pPassword
->GetValue().getLength()))
320 OUString sPassword
= pPassword
->GetValue();
322 Reference
< XPropertySet
> xCurrentDatasource
= getCurrentDataSource();
323 lcl_putProperty(xCurrentDatasource
,m_aDirectPropTranslator
[DSID_PASSWORD
], Any(sPassword
));
328 void ODbDataSourceAdministrationHelper::clearPassword()
330 if (m_pItemSetHelper
->getWriteOutputSet())
331 m_pItemSetHelper
->getWriteOutputSet()->ClearItem(DSID_PASSWORD
);
334 std::pair
< Reference
<XConnection
>,bool> ODbDataSourceAdministrationHelper::createConnection()
336 std::pair
< Reference
<XConnection
>,bool> aRet
;
338 Sequence
< PropertyValue
> aConnectionParams
;
339 if ( getCurrentSettings(aConnectionParams
) )
342 // fill the table list with this connection information
343 SQLExceptionInfo aErrorInfo
;
346 weld::WaitObject
aWaitCursor(m_pParent
);
347 aRet
.first
= getDriver()->connect(getConnectionURL(), aConnectionParams
);
350 catch (const SQLContext
& e
) { aErrorInfo
= SQLExceptionInfo(e
); }
351 catch (const SQLWarning
& e
) { aErrorInfo
= SQLExceptionInfo(e
); }
352 catch (const SQLException
& e
) { aErrorInfo
= SQLExceptionInfo(e
); }
354 showError(aErrorInfo
,m_pParent
->GetXWindow(),getORB());
356 if ( aRet
.first
.is() )
357 successfullyConnected();// notify the admindlg to save the password
362 Reference
< XDriver
> ODbDataSourceAdministrationHelper::getDriver()
364 return getDriver(getConnectionURL());
367 Reference
< XDriver
> ODbDataSourceAdministrationHelper::getDriver(const OUString
& _sURL
)
369 // get the global DriverManager
370 Reference
< XConnectionPool
> xDriverManager
;
372 OUString sCurrentActionError
= DBA_RES(STR_COULDNOTCREATE_DRIVERMANAGER
);
373 sCurrentActionError
= sCurrentActionError
.replaceFirst("#servicename#", "com.sun.star.sdbc.ConnectionPool");
377 xDriverManager
.set( ConnectionPool::create( getORB() ) );
379 catch (const Exception
&)
381 css::uno::Any anyEx
= cppu::getCaughtException();
382 // wrap the exception into an SQLException
383 throw SQLException(sCurrentActionError
, getORB(), u
"S1000"_ustr
, 0, anyEx
);
386 Reference
< XDriver
> xDriver
= xDriverManager
->getDriverByURL(_sURL
);
389 sCurrentActionError
= DBA_RES(STR_NOREGISTEREDDRIVER
);
390 sCurrentActionError
= sCurrentActionError
.replaceFirst("#connurl#", _sURL
);
391 // will be caught and translated into an SQLContext exception
392 throw SQLException(sCurrentActionError
, getORB(), u
"S1000"_ustr
, 0, Any());
397 Reference
< XPropertySet
> const & ODbDataSourceAdministrationHelper::getCurrentDataSource()
399 if ( !m_xDatasource
.is() )
401 Reference
<XInterface
> xIn(m_aDataSourceOrName
,UNO_QUERY
);
404 OUString sCurrentDatasource
;
405 m_aDataSourceOrName
>>= sCurrentDatasource
;
406 OSL_ENSURE(!sCurrentDatasource
.isEmpty(),"No datasource name given!");
409 if ( m_xDatabaseContext
.is() )
410 m_xDatasource
.set(m_xDatabaseContext
->getByName(sCurrentDatasource
),UNO_QUERY
);
413 catch(const Exception
&)
417 m_xModel
.set(getDataSourceOrModel(xIn
),UNO_QUERY
);
419 m_xDatasource
.set(xIn
,UNO_QUERY
);
422 m_xDatasource
.set(getDataSourceOrModel(xIn
),UNO_QUERY
);
423 m_xModel
.set(xIn
,UNO_QUERY
);
427 OSL_ENSURE(m_xDatasource
.is(), "ODbDataSourceAdministrationHelper::getCurrentDataSource: no data source!");
428 return m_xDatasource
;
431 OUString
ODbDataSourceAdministrationHelper::getDatasourceType( const SfxItemSet
& _rSet
)
433 const SfxStringItem
* pConnectURL
= _rSet
.GetItem
<SfxStringItem
>(DSID_CONNECTURL
);
434 assert(pConnectURL
&& "ODbDataSourceAdministrationHelper::getDatasourceType: invalid items in the source set!");
435 const DbuTypeCollectionItem
* pTypeCollection
= _rSet
.GetItem
<DbuTypeCollectionItem
>(DSID_TYPECOLLECTION
);
436 assert(pTypeCollection
&& "ODbDataSourceAdministrationHelper::getDatasourceType: invalid items in the source set!");
437 ::dbaccess::ODsnTypeCollection
* pCollection
= pTypeCollection
->getCollection();
438 return pCollection
->getType(pConnectURL
->GetValue());
441 bool ODbDataSourceAdministrationHelper::hasAuthentication(const SfxItemSet
& _rSet
)
443 return DataSourceMetaData::getAuthentication( getDatasourceType( _rSet
) ) != AuthNone
;
446 OUString
ODbDataSourceAdministrationHelper::getConnectionURL() const
450 OUString eType
= getDatasourceType(*m_pItemSetHelper
->getOutputSet());
452 const SfxStringItem
* pUrlItem
= m_pItemSetHelper
->getOutputSet()->GetItem
<SfxStringItem
>(DSID_CONNECTURL
);
453 const DbuTypeCollectionItem
* pTypeCollection
= m_pItemSetHelper
->getOutputSet()->GetItem
<DbuTypeCollectionItem
>(DSID_TYPECOLLECTION
);
455 assert(pUrlItem
&& "Connection URL is NULL. -> GPF!");
456 assert(pTypeCollection
&& "ODbDataSourceAdministrationHelper::getDatasourceType: invalid items in the source set!");
457 ::dbaccess::ODsnTypeCollection
* pCollection
= pTypeCollection
->getCollection();
458 assert(pCollection
&& "ODbDataSourceAdministrationHelper::getDatasourceType: invalid type collection!");
460 switch( pCollection
->determineType(eType
) )
462 case ::dbaccess::DST_DBASE
:
463 case ::dbaccess::DST_FLAT
:
464 case ::dbaccess::DST_CALC
:
465 case ::dbaccess::DST_WRITER
:
467 case ::dbaccess::DST_MSACCESS
:
469 OUString sFileName
= pCollection
->cutPrefix(pUrlItem
->GetValue());
470 OUString sNewFileName
;
471 if ( ::osl::FileBase::getSystemPathFromFileURL( sFileName
, sNewFileName
) == ::osl::FileBase::E_None
)
473 sNewUrl
+= sNewFileName
;
477 case ::dbaccess::DST_MYSQL_NATIVE
:
478 case ::dbaccess::DST_MYSQL_JDBC
:
480 const SfxStringItem
* pHostName
= m_pItemSetHelper
->getOutputSet()->GetItem
<SfxStringItem
>(DSID_CONN_HOSTNAME
);
481 const SfxInt32Item
* pPortNumber
= m_pItemSetHelper
->getOutputSet()->GetItem
<SfxInt32Item
>(DSID_MYSQL_PORTNUMBER
);
482 const SfxStringItem
* pDatabaseName
= m_pItemSetHelper
->getOutputSet()->GetItem
<SfxStringItem
>(DSID_DATABASENAME
);
483 sNewUrl
= lcl_createHostWithPort(pHostName
,pPortNumber
);
484 OUString sDatabaseName
= pDatabaseName
? pDatabaseName
->GetValue() : OUString();
485 if ( !sDatabaseName
.getLength() && pUrlItem
)
486 sDatabaseName
= pCollection
->cutPrefix( pUrlItem
->GetValue() );
487 // TODO: what's that? Why is the database name transported via the URL Item?
488 // Huh? Anybody there?
489 // OJ: It is needed when the connection properties are changed. There the URL is used for every type.
491 if ( !sDatabaseName
.isEmpty() )
493 sNewUrl
+= "/" + sDatabaseName
;
497 case ::dbaccess::DST_ORACLE_JDBC
:
499 const SfxStringItem
* pHostName
= m_pItemSetHelper
->getOutputSet()->GetItem
<SfxStringItem
>(DSID_CONN_HOSTNAME
);
500 const SfxInt32Item
* pPortNumber
= m_pItemSetHelper
->getOutputSet()->GetItem
<SfxInt32Item
>(DSID_ORACLE_PORTNUMBER
);
501 const SfxStringItem
* pDatabaseName
= m_pItemSetHelper
->getOutputSet()->GetItem
<SfxStringItem
>(DSID_DATABASENAME
);
502 if ( pHostName
&& pHostName
->GetValue().getLength() )
504 sNewUrl
= "@" + lcl_createHostWithPort(pHostName
,pPortNumber
);
505 OUString sDatabaseName
= pDatabaseName
? pDatabaseName
->GetValue() : OUString();
506 if ( sDatabaseName
.isEmpty() && pUrlItem
)
507 sDatabaseName
= pCollection
->cutPrefix( pUrlItem
->GetValue() );
508 if ( !sDatabaseName
.isEmpty() )
510 sNewUrl
+= ":" + sDatabaseName
;
514 { // here someone entered a JDBC url which looks like oracle, so we have to use the url property
519 case ::dbaccess::DST_LDAP
:
521 const SfxInt32Item
* pPortNumber
= m_pItemSetHelper
->getOutputSet()->GetItem
<SfxInt32Item
>(DSID_CONN_LDAP_PORTNUMBER
);
522 sNewUrl
= pCollection
->cutPrefix(pUrlItem
->GetValue()) + lcl_createHostWithPort(nullptr,pPortNumber
);
525 case ::dbaccess::DST_POSTGRES
:
527 OUString
rURL(comphelper::string::stripEnd(pUrlItem
->GetValue(), '*'));
528 const SfxStringItem
* pHostName
= m_pItemSetHelper
->getOutputSet()->GetItem
<SfxStringItem
>(DSID_CONN_HOSTNAME
);
529 const SfxInt32Item
* pPortNumber
= m_pItemSetHelper
->getOutputSet()->GetItem
<SfxInt32Item
>(DSID_POSTGRES_PORTNUMBER
);
530 const SfxStringItem
* pDatabaseName
= m_pItemSetHelper
->getOutputSet()->GetItem
<SfxStringItem
>(DSID_DATABASENAME
);
531 if (pHostName
&& pHostName
->GetValue().getLength())
533 OUString
hostname( pHostName
->GetValue() );
534 hostname
= hostname
.replaceAll( "\\", "\\\\");
535 hostname
= hostname
.replaceAll( "\'", "\\'");
536 hostname
= "'" + hostname
+ "'";
537 rURL
+= " host=" + hostname
;
539 // tdf#157260: if port is already in the URL, don't add another one
540 if (pPortNumber
&& pPortNumber
->GetValue() && (rURL
.indexOf("port=") == -1))
542 OUString port
= "'" + OUString::number(pPortNumber
->GetValue()) + "'";
543 rURL
+= " port=" + port
;
545 if (pDatabaseName
&& pDatabaseName
->GetValue().getLength())
547 OUString
dbname( pDatabaseName
->GetValue() );
548 dbname
= dbname
.replaceAll( "\\", "\\\\");
549 dbname
= dbname
.replaceAll( "\'", "\\'");
550 dbname
= "'" + dbname
+ "'";
551 rURL
+= " dbname=" + dbname
;
556 case ::dbaccess::DST_JDBC
:
561 if ( !sNewUrl
.isEmpty() )
562 sNewUrl
= pCollection
->getPrefix(eType
) + sNewUrl
;
564 sNewUrl
= pUrlItem
->GetValue();
571 struct PropertyValueLess
573 bool operator() (const PropertyValue
& x
, const PropertyValue
& y
) const
574 { return x
.Name
< y
.Name
; } // construct prevents a MSVC6 warning
579 typedef std::set
<PropertyValue
, PropertyValueLess
> PropertyValueSet
;
581 void ODbDataSourceAdministrationHelper::translateProperties(const Reference
< XPropertySet
>& _rxSource
, SfxItemSet
& _rDest
)
585 for (auto const& elem
: m_aDirectPropTranslator
)
587 // get the property value
591 aValue
= _rxSource
->getPropertyValue(elem
.second
);
595 SAL_WARN("dbaccess", "ODbDataSourceAdministrationHelper::translateProperties: could not extract the property "
598 // transfer it into an item
599 implTranslateProperty(_rDest
, elem
.first
, aValue
);
602 // get the additional information
603 Sequence
< PropertyValue
> aAdditionalInfo
;
606 _rxSource
->getPropertyValue(PROPERTY_INFO
) >>= aAdditionalInfo
;
608 catch(Exception
&) { }
610 // collect the names of the additional settings
611 PropertyValueSet aInfos
;
612 for (const PropertyValue
& rAdditionalInfo
: aAdditionalInfo
)
614 if( rAdditionalInfo
.Name
== "JDBCDRV" )
616 PropertyValue
aCompatibility(rAdditionalInfo
);
617 aCompatibility
.Name
= "JavaDriverClass";
618 aInfos
.insert(aCompatibility
);
621 aInfos
.insert(rAdditionalInfo
);
624 // go through all known translations and check if we have such a setting
625 if ( !aInfos
.empty() )
627 PropertyValue aSearchFor
;
628 for (auto const& elem
: m_aIndirectPropTranslator
)
630 aSearchFor
.Name
= elem
.second
;
631 PropertyValueSet::const_iterator aInfoPos
= aInfos
.find(aSearchFor
);
632 if (aInfos
.end() != aInfoPos
)
633 // the property is contained in the info sequence
634 // -> transfer it into an item
635 implTranslateProperty(_rDest
, elem
.first
, aInfoPos
->Value
);
644 Reference
<XStorable
> xStore(getDataSourceOrModel(_rxSource
),UNO_QUERY
);
645 _rDest
.Put(SfxBoolItem(DSID_READONLY
, !xStore
.is() || xStore
->isReadonly() ));
649 TOOLS_WARN_EXCEPTION("dbaccess", "IsReadOnly throws");
653 void ODbDataSourceAdministrationHelper::translateProperties(const SfxItemSet
& _rSource
, const Reference
< XPropertySet
>& _rxDest
)
655 OSL_ENSURE(_rxDest
.is(), "ODbDataSourceAdministrationHelper::translateProperties: invalid property set!");
659 // the property set info
660 Reference
< XPropertySetInfo
> xInfo
;
661 try { xInfo
= _rxDest
->getPropertySetInfo(); }
662 catch(Exception
&) { }
664 static constexpr OUStringLiteral
sUrlProp(u
"URL");
665 // transfer the direct properties
666 for (auto const& elem
: m_aDirectPropTranslator
)
668 const SfxPoolItem
* pCurrentItem
= _rSource
.GetItem(static_cast<sal_uInt16
>(elem
.first
));
671 sal_Int16 nAttributes
= PropertyAttribute::READONLY
;
674 try { nAttributes
= xInfo
->getPropertyByName(elem
.second
).Attributes
; }
675 catch(Exception
&) { }
677 if ((nAttributes
& PropertyAttribute::READONLY
) == 0)
679 if ( sUrlProp
== elem
.second
)
681 Any
aValue(getConnectionURL());
682 // aValue <<= OUString();
683 lcl_putProperty(_rxDest
, elem
.second
,aValue
);
686 implTranslateProperty(_rxDest
, elem
.second
, pCurrentItem
);
691 // now for the indirect properties
693 Sequence
< PropertyValue
> aInfo
;
694 // the original properties
697 _rxDest
->getPropertyValue(PROPERTY_INFO
) >>= aInfo
;
699 catch(Exception
&) { }
701 // overwrite and extend them
702 fillDatasourceInfo(_rSource
, aInfo
);
703 // and propagate the (newly composed) sequence to the set
704 lcl_putProperty(_rxDest
,PROPERTY_INFO
, Any(aInfo
));
707 void ODbDataSourceAdministrationHelper::fillDatasourceInfo(const SfxItemSet
& _rSource
, Sequence
< css::beans::PropertyValue
>& _rInfo
)
709 // within the current "Info" sequence, replace the ones we can examine from the item set
710 // (we don't just fill a completely new sequence with our own items, but we preserve any properties unknown to
713 // first determine which of all the items are relevant for the data source (depends on the connection url)
714 const OUString eType
= getDatasourceType(_rSource
);
715 const ::connectivity::DriversConfig
aDriverConfig(getORB());
716 const ::comphelper::NamedValueCollection
& aProperties
= aDriverConfig
.getProperties(eType
);
718 // collect the translated property values for the relevant items
719 PropertyValueSet aRelevantSettings
;
720 MapInt2String::const_iterator aTranslation
;
721 for (ItemID detailId
= DSID_FIRST_ITEM_ID
; detailId
<= DSID_LAST_ITEM_ID
; ++detailId
)
723 const SfxPoolItem
* pCurrent
= _rSource
.GetItem(static_cast<sal_uInt16
>(detailId
));
724 aTranslation
= m_aIndirectPropTranslator
.find(detailId
);
725 if ( pCurrent
&& (m_aIndirectPropTranslator
.end() != aTranslation
) &&
726 aProperties
.has(aTranslation
->second
) )
728 if ( aTranslation
->second
== INFO_CHARSET
)
731 implTranslateProperty(pCurrent
) >>= sCharSet
;
732 if ( !sCharSet
.isEmpty() )
733 aRelevantSettings
.insert(PropertyValue(aTranslation
->second
, 0, Any(sCharSet
), PropertyState_DIRECT_VALUE
));
736 aRelevantSettings
.insert(PropertyValue(aTranslation
->second
, 0, implTranslateProperty(pCurrent
), PropertyState_DIRECT_VALUE
));
740 // settings to preserve
741 MapInt2String aPreservedSettings
;
743 // now aRelevantSettings contains all the property values relevant for the current data source type,
744 // check the original sequence if it already contains any of these values (which have to be overwritten, then)
745 PropertyValue
* pInfo
= _rInfo
.getArray();
746 PropertyValue aSearchFor
;
747 sal_Int32 nObsoleteSetting
= -1;
748 sal_Int32 nCount
= _rInfo
.getLength();
749 for (sal_Int32 i
= 0; i
< nCount
; ++i
, ++pInfo
)
751 aSearchFor
.Name
= pInfo
->Name
;
752 PropertyValueSet::const_iterator aOverwrittenSetting
= aRelevantSettings
.find(aSearchFor
);
753 if (aRelevantSettings
.end() != aOverwrittenSetting
)
754 { // the setting was present in the original sequence, and it is to be overwritten -> replace it
755 if ( pInfo
->Value
!= aOverwrittenSetting
->Value
)
756 *pInfo
= *aOverwrittenSetting
;
757 aRelevantSettings
.erase(aOverwrittenSetting
);
759 else if( pInfo
->Name
== "JDBCDRV" )
760 { // this is a compatibility setting, remove it from the sequence (it's replaced by JavaDriverClass)
761 nObsoleteSetting
= i
;
764 aPreservedSettings
[i
] = pInfo
->Name
;
766 if (-1 != nObsoleteSetting
)
767 ::comphelper::removeElementAt(_rInfo
, nObsoleteSetting
);
769 if ( !aPreservedSettings
.empty() )
770 { // check if there are settings which
771 // * are known as indirect properties
772 // * but not relevant for the current data source type
773 // These settings have to be removed: If they're not relevant, we have no UI for changing them.
775 // for this, we need a string-controlled quick access to m_aIndirectPropTranslator
776 std::set
<OUString
> aIndirectProps
;
777 std::transform(m_aIndirectPropTranslator
.begin(),
778 m_aIndirectPropTranslator
.end(),
779 std::inserter(aIndirectProps
,aIndirectProps
.begin()),
780 ::o3tl::select2nd
< MapInt2String::value_type
>());
782 // now check the to-be-preserved props
783 std::vector
< sal_Int32
> aRemoveIndexes
;
784 sal_Int32 nPositionCorrector
= 0;
785 for (auto const& preservedSetting
: aPreservedSettings
)
787 if (aIndirectProps
.end() != aIndirectProps
.find(preservedSetting
.second
))
789 aRemoveIndexes
.push_back(preservedSetting
.first
- nPositionCorrector
);
790 ++nPositionCorrector
;
793 // now finally remove all such props
794 for (auto const& removeIndex
: aRemoveIndexes
)
795 ::comphelper::removeElementAt(_rInfo
, removeIndex
);
798 Sequence
< Any
> aTypeSettings
;
799 aTypeSettings
= aProperties
.getOrDefault(u
"TypeInfoSettings"_ustr
,aTypeSettings
);
800 // here we have a special entry for types from oracle
801 if ( aTypeSettings
.hasElements() )
803 aRelevantSettings
.insert(PropertyValue(u
"TypeInfoSettings"_ustr
, 0, Any(aTypeSettings
), PropertyState_DIRECT_VALUE
));
806 // check which values are still left ('cause they were not present in the original sequence, but are to be set)
807 if ( aRelevantSettings
.empty() )
810 sal_Int32 nOldLength
= _rInfo
.getLength();
811 _rInfo
.realloc(nOldLength
+ aRelevantSettings
.size());
812 PropertyValue
* pAppendValues
= _rInfo
.getArray() + nOldLength
;
813 for (auto const& relevantSetting
: aRelevantSettings
)
815 if ( relevantSetting
.Name
== INFO_CHARSET
)
818 relevantSetting
.Value
>>= sCharSet
;
819 if ( !sCharSet
.isEmpty() )
820 *pAppendValues
= relevantSetting
;
823 *pAppendValues
= relevantSetting
;
828 Any
ODbDataSourceAdministrationHelper::implTranslateProperty(const SfxPoolItem
* _pItem
)
830 // translate the SfxPoolItem
833 const SfxStringItem
* pStringItem
= dynamic_cast<const SfxStringItem
*>( _pItem
);
834 const SfxBoolItem
* pBoolItem
= dynamic_cast<const SfxBoolItem
*>( _pItem
);
835 const OptionalBoolItem
* pOptBoolItem
= dynamic_cast<const OptionalBoolItem
*>( _pItem
);
836 const SfxInt32Item
* pInt32Item
= dynamic_cast< const SfxInt32Item
* >( _pItem
);
837 const OStringListItem
* pStringListItem
= dynamic_cast<const OStringListItem
*>( _pItem
);
841 aValue
<<= pStringItem
->GetValue();
843 else if ( pBoolItem
)
845 aValue
<<= pBoolItem
->GetValue();
847 else if ( pOptBoolItem
)
849 if ( !pOptBoolItem
->HasValue() )
852 aValue
<<= pOptBoolItem
->GetValue();
854 else if ( pInt32Item
)
856 aValue
<<= pInt32Item
->GetValue();
858 else if ( pStringListItem
)
860 aValue
<<= pStringListItem
->getList();
864 OSL_FAIL("ODbDataSourceAdministrationHelper::implTranslateProperty: unsupported item type!");
871 void ODbDataSourceAdministrationHelper::implTranslateProperty(const Reference
< XPropertySet
>& _rxSet
, const OUString
& _rName
, const SfxPoolItem
* _pItem
)
873 Any aValue
= implTranslateProperty(_pItem
);
874 lcl_putProperty(_rxSet
, _rName
,aValue
);
877 OString
ODbDataSourceAdministrationHelper::translatePropertyId( sal_Int32 _nId
)
881 MapInt2String::const_iterator aPos
= m_aDirectPropTranslator
.find( _nId
);
882 if ( m_aDirectPropTranslator
.end() != aPos
)
884 aString
= aPos
->second
;
888 MapInt2String::const_iterator indirectPos
= m_aIndirectPropTranslator
.find( _nId
);
889 if ( m_aIndirectPropTranslator
.end() != indirectPos
)
890 aString
= indirectPos
->second
;
893 return OUStringToOString( aString
, RTL_TEXTENCODING_ASCII_US
);
895 template<class T
> static bool checkItemType(const SfxPoolItem
* pItem
){ return dynamic_cast<const T
*>(pItem
) != nullptr;}
897 void ODbDataSourceAdministrationHelper::implTranslateProperty( SfxItemSet
& _rSet
, sal_Int32 _nId
, const Any
& _rValue
)
899 switch ( _rValue
.getValueTypeClass() )
901 case TypeClass_STRING
:
902 if ( implCheckItemType( _rSet
, _nId
, checkItemType
<SfxStringItem
> ) )
906 _rSet
.Put(SfxStringItem(_nId
, sValue
));
909 SAL_WARN( "dbaccess", "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid property value ("
910 << translatePropertyId(_nId
) << " should be no string)!");
914 case TypeClass_BOOLEAN
:
915 if ( implCheckItemType( _rSet
, _nId
, checkItemType
<SfxBoolItem
> ) )
919 _rSet
.Put(SfxBoolItem(_nId
, bVal
));
921 else if ( implCheckItemType( _rSet
, _nId
, checkItemType
<OptionalBoolItem
> ) )
923 OptionalBoolItem
aItem( _nId
);
924 if ( _rValue
.hasValue() )
928 aItem
.SetValue( bValue
);
935 SAL_WARN( "dbaccess", "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid property value ("
936 << translatePropertyId(_nId
)
937 << " should be no boolean)!");
942 if ( implCheckItemType( _rSet
, _nId
, checkItemType
<SfxInt32Item
> ) )
944 sal_Int32 nValue
= 0;
946 _rSet
.Put( SfxInt32Item( TypedWhichId
<SfxInt32Item
>(_nId
), nValue
) );
949 SAL_WARN( "dbaccess", "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid property value ("
950 << translatePropertyId(_nId
)
951 << " should be no int)!");
955 case TypeClass_SEQUENCE
:
956 if ( implCheckItemType( _rSet
, _nId
, checkItemType
<OStringListItem
> ) )
958 // determine the element type
959 TypeDescription
aTD(_rValue
.getValueType());
960 typelib_IndirectTypeDescription
* pSequenceTD
=
961 reinterpret_cast< typelib_IndirectTypeDescription
* >(aTD
.get());
962 assert(pSequenceTD
&& pSequenceTD
->pType
&& "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid sequence type!");
964 Type
aElementType(pSequenceTD
->pType
);
965 switch (aElementType
.getTypeClass())
967 case TypeClass_STRING
:
969 Sequence
< OUString
> aStringList
;
970 _rValue
>>= aStringList
;
971 _rSet
.Put(OStringListItem(_nId
, aStringList
));
975 OSL_FAIL("ODbDataSourceAdministrationHelper::implTranslateProperty: unsupported property value type!");
979 SAL_WARN( "dbaccess", "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid property value ("
980 << translatePropertyId(_nId
)
981 << " should be no string sequence)!");
986 _rSet
.ClearItem(_nId
);
990 OSL_FAIL("ODbDataSourceAdministrationHelper::implTranslateProperty: unsupported property value type!");
994 OUString
ODbDataSourceAdministrationHelper::getDocumentUrl(SfxItemSet
const & _rDest
)
996 const SfxStringItem
* pUrlItem
= _rDest
.GetItem
<SfxStringItem
>(DSID_DOCUMENT_URL
);
997 assert(pUrlItem
&& "Document URL is NULL. -> GPF!");
998 return pUrlItem
->GetValue();
1001 void ODbDataSourceAdministrationHelper::convertUrl(SfxItemSet
& _rDest
)
1003 OUString eType
= getDatasourceType(_rDest
);
1005 const SfxStringItem
* pUrlItem
= _rDest
.GetItem
<SfxStringItem
>(DSID_CONNECTURL
);
1006 const DbuTypeCollectionItem
* pTypeCollection
= _rDest
.GetItem
<DbuTypeCollectionItem
>(DSID_TYPECOLLECTION
);
1008 assert(pUrlItem
&& "Connection URL is NULL. -> GPF!");
1009 assert(pTypeCollection
&& "ODbAdminDialog::getDatasourceType: invalid items in the source set!");
1010 ::dbaccess::ODsnTypeCollection
* pCollection
= pTypeCollection
->getCollection();
1011 assert(pCollection
&& "ODbAdminDialog::getDatasourceType: invalid type collection!");
1013 TypedWhichId
<SfxInt32Item
> nPortNumberId(0);
1014 sal_Int32 nPortNumber
= -1;
1015 OUString sNewHostName
;
1018 pCollection
->extractHostNamePort(pUrlItem
->GetValue(),sUrlPart
,sNewHostName
,nPortNumber
);
1019 const ::dbaccess::DATASOURCE_TYPE eTy
= pCollection
->determineType(eType
);
1023 case ::dbaccess::DST_MYSQL_NATIVE
:
1024 case ::dbaccess::DST_MYSQL_JDBC
:
1025 nPortNumberId
= DSID_MYSQL_PORTNUMBER
;
1027 case ::dbaccess::DST_ORACLE_JDBC
:
1028 nPortNumberId
= DSID_ORACLE_PORTNUMBER
;
1030 case ::dbaccess::DST_LDAP
:
1031 nPortNumberId
= DSID_CONN_LDAP_PORTNUMBER
;
1033 case ::dbaccess::DST_POSTGRES
:
1034 nPortNumberId
= DSID_POSTGRES_PORTNUMBER
;
1040 if ( !sUrlPart
.isEmpty() )
1042 if ( eTy
== ::dbaccess::DST_MYSQL_NATIVE
)
1044 _rDest
.Put( SfxStringItem( DSID_DATABASENAME
, sUrlPart
) );
1048 OUString sNewUrl
= pCollection
->getPrefix(eType
) + sUrlPart
;
1049 _rDest
.Put( SfxStringItem( DSID_CONNECTURL
, sNewUrl
) );
1053 if ( !sNewHostName
.isEmpty() )
1054 _rDest
.Put(SfxStringItem(DSID_CONN_HOSTNAME
, sNewHostName
));
1056 if ( nPortNumber
!= -1 && nPortNumberId
!= TypedWhichId
<SfxInt32Item
>(0) )
1057 _rDest
.Put(SfxInt32Item(nPortNumberId
, nPortNumber
));
1061 bool ODbDataSourceAdministrationHelper::saveChanges(const SfxItemSet
& _rSource
)
1063 // put the remembered settings into the property set
1064 Reference
<XPropertySet
> xDatasource
= getCurrentDataSource();
1065 if ( !xDatasource
.is() )
1068 translateProperties(_rSource
,xDatasource
);
1073 void ODbDataSourceAdministrationHelper::setDataSourceOrName( const Any
& _rDataSourceOrName
)
1075 OSL_ENSURE( !m_aDataSourceOrName
.hasValue(), "ODbDataSourceAdministrationHelper::setDataSourceOrName: already have one!" );
1076 // hmm. We could reset m_xDatasource/m_xModel, probably, and continue working
1077 m_aDataSourceOrName
= _rDataSourceOrName
;
1080 // DbuTypeCollectionItem
1081 DbuTypeCollectionItem::DbuTypeCollectionItem(sal_Int16 _nWhich
, ::dbaccess::ODsnTypeCollection
* _pCollection
)
1082 :SfxPoolItem(_nWhich
, SfxItemType::DbuTypeCollectionItemType
)
1083 ,m_pCollection(_pCollection
)
1087 DbuTypeCollectionItem::DbuTypeCollectionItem(const DbuTypeCollectionItem
& _rSource
)
1088 :SfxPoolItem(_rSource
)
1089 ,m_pCollection(_rSource
.getCollection())
1093 bool DbuTypeCollectionItem::operator==(const SfxPoolItem
& _rItem
) const
1095 return SfxPoolItem::operator==(_rItem
) &&
1096 static_cast<const DbuTypeCollectionItem
&>( _rItem
).getCollection() == getCollection();
1099 DbuTypeCollectionItem
* DbuTypeCollectionItem::Clone(SfxItemPool
* /*_pPool*/) const
1101 return new DbuTypeCollectionItem(*this);
1104 } // namespace dbaui
1106 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */