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 "mysql/YDriver.hxx"
21 #include "mysql/YCatalog.hxx"
22 #include <osl/diagnose.h>
23 #include <comphelper/namedvaluecollection.hxx>
24 #include <comphelper/processfactory.hxx>
25 #include <cppuhelper/supportsservice.hxx>
26 #include <connectivity/dbexception.hxx>
27 #include <connectivity/dbcharset.hxx>
28 #include <com/sun/star/sdbc/DriverManager.hpp>
29 #include <com/sun/star/uno/XComponentContext.hpp>
30 #include "TConnection.hxx"
31 #include "resource/common_res.hrc"
32 #include "resource/sharedresources.hxx"
35 namespace connectivity
38 using namespace mysql
;
39 using namespace ::com::sun::star::uno
;
40 using namespace ::com::sun::star::sdbc
;
41 using namespace ::com::sun::star::sdbcx
;
42 using namespace ::com::sun::star::beans
;
43 using namespace ::com::sun::star::lang
;
47 Reference
< XInterface
> SAL_CALL
ODriverDelegator_CreateInstance(const Reference
< css::lang::XMultiServiceFactory
>& _rxFac
) throw( Exception
)
49 return *(new ODriverDelegator( comphelper::getComponentContext(_rxFac
) ));
55 OUString
getJavaDriverClass(
56 css::uno::Sequence
<css::beans::PropertyValue
> const & info
)
58 return comphelper::NamedValueCollection(info
).getOrDefault(
59 "JavaDriverClass", OUString("com.mysql.jdbc.Driver"));
63 ODriverDelegator::ODriverDelegator(const Reference
< XComponentContext
>& _rxContext
)
64 : ODriverDelegator_BASE(m_aMutex
)
65 ,m_xContext(_rxContext
)
70 ODriverDelegator::~ODriverDelegator()
74 ::comphelper::disposeComponent(m_xODBCDriver
);
75 ::comphelper::disposeComponent(m_xNativeDriver
);
76 TJDBCDrivers::iterator aIter
= m_aJdbcDrivers
.begin();
77 TJDBCDrivers::const_iterator aEnd
= m_aJdbcDrivers
.end();
78 for ( ;aIter
!= aEnd
;++aIter
)
79 ::comphelper::disposeComponent(aIter
->second
);
81 catch(const Exception
&)
87 void ODriverDelegator::disposing()
89 ::osl::MutexGuard
aGuard(m_aMutex
);
92 for (TWeakPairVector::iterator i
= m_aConnections
.begin(); m_aConnections
.end() != i
; ++i
)
94 Reference
<XInterface
> xTemp
= i
->first
.get();
95 ::comphelper::disposeComponent(xTemp
);
97 m_aConnections
.clear();
98 TWeakPairVector().swap(m_aConnections
);
100 ODriverDelegator_BASE::disposing();
105 enum class T_DRIVERTYPE
112 bool isOdbcUrl(const OUString
& _sUrl
)
114 return _sUrl
.startsWith("sdbc:mysql:odbc:");
117 bool isNativeUrl(const OUString
& _sUrl
)
119 return _sUrl
.startsWith("sdbc:mysql:mysqlc:");
122 T_DRIVERTYPE
lcl_getDriverType(const OUString
& _sUrl
)
124 T_DRIVERTYPE eRet
= T_DRIVERTYPE::Jdbc
;
125 if ( isOdbcUrl(_sUrl
) )
126 eRet
= T_DRIVERTYPE::Odbc
;
127 else if ( isNativeUrl(_sUrl
) )
128 eRet
= T_DRIVERTYPE::Native
;
132 OUString
transformUrl(const OUString
& _sUrl
)
134 OUString sNewUrl
= _sUrl
.copy(11);
135 if ( isOdbcUrl( _sUrl
) )
136 sNewUrl
= "sdbc:" + sNewUrl
;
137 else if ( isNativeUrl( _sUrl
) )
138 sNewUrl
= "sdbc:" + sNewUrl
;
141 sNewUrl
= "jdbc:mysql://" + sNewUrl
.copy(5);
146 Reference
< XDriver
> lcl_loadDriver(const Reference
< XComponentContext
>& _rxContext
,const OUString
& _sUrl
)
148 Reference
<XDriverManager2
> xDriverAccess
= DriverManager::create(_rxContext
);
149 Reference
< XDriver
> xDriver
= xDriverAccess
->getDriverByURL(_sUrl
);
153 Sequence
< PropertyValue
> lcl_convertProperties(T_DRIVERTYPE _eType
,const Sequence
< PropertyValue
>& info
,const OUString
& _sUrl
)
155 ::std::vector
<PropertyValue
> aProps
;
156 const PropertyValue
* pSupported
= info
.getConstArray();
157 const PropertyValue
* pEnd
= pSupported
+ info
.getLength();
159 aProps
.reserve(info
.getLength() + 5);
161 for (;pSupported
!= pEnd
; ++pSupported
)
163 aProps
.push_back( *pSupported
);
164 if (pSupported
->Name
== "JavaDriverClass")
170 if ( _eType
== T_DRIVERTYPE::Odbc
)
172 aProps
.push_back( PropertyValue(
176 ,PropertyState_DIRECT_VALUE
) );
177 aProps
.push_back( PropertyValue(
178 OUString("PreventGetVersionColumns")
181 ,PropertyState_DIRECT_VALUE
) );
183 else if ( _eType
== T_DRIVERTYPE::Jdbc
)
187 aProps
.push_back( PropertyValue(
188 OUString("JavaDriverClass")
190 ,makeAny(OUString("com.mysql.jdbc.Driver"))
191 ,PropertyState_DIRECT_VALUE
) );
196 aProps
.push_back( PropertyValue(
197 OUString("PublicConnectionURL")
200 ,PropertyState_DIRECT_VALUE
) );
202 aProps
.push_back( PropertyValue(
203 OUString("IsAutoRetrievingEnabled")
206 ,PropertyState_DIRECT_VALUE
) );
207 aProps
.push_back( PropertyValue(
208 OUString("AutoRetrievingStatement")
210 ,makeAny(OUString("SELECT LAST_INSERT_ID()"))
211 ,PropertyState_DIRECT_VALUE
) );
212 aProps
.push_back( PropertyValue(
213 OUString("ParameterNameSubstitution")
216 ,PropertyState_DIRECT_VALUE
) );
217 return Sequence
< PropertyValue
>(aProps
.data(), aProps
.size());
221 Reference
< XDriver
> ODriverDelegator::loadDriver( const OUString
& url
, const Sequence
< PropertyValue
>& info
)
223 Reference
< XDriver
> xDriver
;
224 const OUString sCuttedUrl
= transformUrl(url
);
225 const T_DRIVERTYPE eType
= lcl_getDriverType( url
);
226 if ( eType
== T_DRIVERTYPE::Odbc
)
228 if ( !m_xODBCDriver
.is() )
229 m_xODBCDriver
= lcl_loadDriver(m_xContext
,sCuttedUrl
);
230 xDriver
= m_xODBCDriver
;
232 else if ( eType
== T_DRIVERTYPE::Native
)
234 if ( !m_xNativeDriver
.is() )
235 m_xNativeDriver
= lcl_loadDriver(m_xContext
,sCuttedUrl
);
236 xDriver
= m_xNativeDriver
;
240 OUString
sDriverClass(getJavaDriverClass(info
));
241 TJDBCDrivers::iterator aFind
= m_aJdbcDrivers
.find(sDriverClass
);
242 if ( aFind
== m_aJdbcDrivers
.end() )
243 aFind
= m_aJdbcDrivers
.insert(TJDBCDrivers::value_type(sDriverClass
,lcl_loadDriver(m_xContext
,sCuttedUrl
))).first
;
244 xDriver
= aFind
->second
;
251 Reference
< XConnection
> SAL_CALL
ODriverDelegator::connect( const OUString
& url
, const Sequence
< PropertyValue
>& info
) throw (SQLException
, RuntimeException
, std::exception
)
253 Reference
< XConnection
> xConnection
;
254 if ( acceptsURL(url
) )
256 Reference
< XDriver
> xDriver
;
257 xDriver
= loadDriver(url
,info
);
260 OUString sCuttedUrl
= transformUrl(url
);
261 const T_DRIVERTYPE eType
= lcl_getDriverType( url
);
262 Sequence
< PropertyValue
> aConvertedProperties
= lcl_convertProperties(eType
,info
,url
);
263 if ( eType
== T_DRIVERTYPE::Jdbc
)
265 ::comphelper::NamedValueCollection
aSettings( info
);
266 OUString sIanaName
= aSettings
.getOrDefault( "CharSet", OUString() );
267 if ( !sIanaName
.isEmpty() )
269 ::dbtools::OCharsetMap aLookupIanaName
;
270 ::dbtools::OCharsetMap::const_iterator aLookup
= aLookupIanaName
.find(sIanaName
, ::dbtools::OCharsetMap::IANA());
271 if (aLookup
!= aLookupIanaName
.end() )
274 if ( RTL_TEXTENCODING_UTF8
== (*aLookup
).getEncoding() )
276 static const char s_sCharSetOp
[] = "useUnicode=true&";
277 if ( !sCuttedUrl
.matchIgnoreAsciiCase(s_sCharSetOp
) )
280 } // if ( !sCuttedUrl.matchIgnoreAsciiCase(s_sCharSetOp) )
281 } // if ( RTL_TEXTENCODING_UTF8 == (*aLookup).getEncoding() )
282 if ( sCuttedUrl
.indexOf('?') == -1 )
287 sCuttedUrl
+= "characterEncoding=";
288 sCuttedUrl
+= sIanaName
;
293 xConnection
= xDriver
->connect( sCuttedUrl
, aConvertedProperties
);
294 if ( xConnection
.is() )
296 OMetaConnection
* pMetaConnection
= nullptr;
297 // now we have to set the URL to get the correct answer for metadata()->getURL()
298 Reference
< XUnoTunnel
> xTunnel(xConnection
,UNO_QUERY
);
301 pMetaConnection
= reinterpret_cast<OMetaConnection
*>(xTunnel
->getSomething( OMetaConnection::getUnoTunnelImplementationId() ));
302 if ( pMetaConnection
)
303 pMetaConnection
->setURL(url
);
305 m_aConnections
.push_back(TWeakPair(WeakReferenceHelper(xConnection
),TWeakConnectionPair(WeakReferenceHelper(),pMetaConnection
)));
313 sal_Bool SAL_CALL
ODriverDelegator::acceptsURL( const OUString
& url
) throw (SQLException
, RuntimeException
, std::exception
)
315 Sequence
< PropertyValue
> info
;
317 bool bOK
= url
.startsWith( "sdbc:mysql:odbc:" )
318 || url
.startsWith( "sdbc:mysql:jdbc:" )
319 || ( url
.startsWith( "sdbc:mysql:mysqlc:" )
320 && loadDriver( url
, info
).is()
326 Sequence
< DriverPropertyInfo
> SAL_CALL
ODriverDelegator::getPropertyInfo( const OUString
& url
, const Sequence
< PropertyValue
>& info
) throw (SQLException
, RuntimeException
, std::exception
)
328 ::std::vector
< DriverPropertyInfo
> aDriverInfo
;
329 if ( !acceptsURL(url
) )
330 return Sequence
< DriverPropertyInfo
>();
332 Sequence
< OUString
> aBoolean(2);
337 aDriverInfo
.push_back(DriverPropertyInfo(
339 ,OUString("CharSet of the database.")
342 ,Sequence
< OUString
>())
344 aDriverInfo
.push_back(DriverPropertyInfo(
345 OUString("SuppressVersionColumns")
346 ,OUString("Display version columns (when available).")
351 const T_DRIVERTYPE eType
= lcl_getDriverType( url
);
352 if ( eType
== T_DRIVERTYPE::Jdbc
)
354 aDriverInfo
.push_back(DriverPropertyInfo(
355 OUString("JavaDriverClass")
356 ,OUString("The JDBC driver class name.")
358 ,getJavaDriverClass(info
)
359 ,Sequence
< OUString
>())
362 else if ( eType
== T_DRIVERTYPE::Native
)
364 aDriverInfo
.push_back(DriverPropertyInfo(
365 OUString("LocalSocket")
366 ,OUString("The file path of a socket to connect to a local MySQL server.")
369 ,Sequence
< OUString
>())
371 aDriverInfo
.push_back(DriverPropertyInfo(
372 OUString("NamedPipe")
373 ,OUString("The name of a pipe to connect to a local MySQL server.")
376 ,Sequence
< OUString
>())
380 return Sequence
< DriverPropertyInfo
>(&aDriverInfo
[0],aDriverInfo
.size());
384 sal_Int32 SAL_CALL
ODriverDelegator::getMajorVersion( ) throw (RuntimeException
, std::exception
)
390 sal_Int32 SAL_CALL
ODriverDelegator::getMinorVersion( ) throw (RuntimeException
, std::exception
)
396 Reference
< XTablesSupplier
> SAL_CALL
ODriverDelegator::getDataDefinitionByConnection( const Reference
< XConnection
>& connection
) throw (SQLException
, RuntimeException
, std::exception
)
398 ::osl::MutexGuard
aGuard( m_aMutex
);
399 checkDisposed(ODriverDelegator_BASE::rBHelper
.bDisposed
);
401 Reference
< XTablesSupplier
> xTab
;
402 Reference
< XUnoTunnel
> xTunnel(connection
,UNO_QUERY
);
405 OMetaConnection
* pConnection
= reinterpret_cast<OMetaConnection
*>(xTunnel
->getSomething( OMetaConnection::getUnoTunnelImplementationId() ));
408 TWeakPairVector::const_iterator aEnd
= m_aConnections
.end();
409 for (TWeakPairVector::iterator i
= m_aConnections
.begin(); aEnd
!= i
; ++i
)
411 if ( i
->second
.second
== pConnection
)
413 xTab
.set(i
->second
.first
.get().get(),UNO_QUERY
);
416 xTab
= new OMySQLCatalog(connection
);
417 i
->second
.first
= WeakReferenceHelper(xTab
);
423 } // if ( xTunnel.is() )
426 TWeakPairVector::const_iterator aEnd
= m_aConnections
.end();
427 for (TWeakPairVector::iterator i
= m_aConnections
.begin(); aEnd
!= i
; ++i
)
429 Reference
< XConnection
> xTemp(i
->first
.get(),UNO_QUERY
);
430 if ( xTemp
== connection
)
432 xTab
.set(i
->second
.first
.get().get(),UNO_QUERY
);
435 xTab
= new OMySQLCatalog(connection
);
436 i
->second
.first
= WeakReferenceHelper(xTab
);
446 Reference
< XTablesSupplier
> SAL_CALL
ODriverDelegator::getDataDefinitionByURL( const OUString
& url
, const Sequence
< PropertyValue
>& info
) throw (SQLException
, RuntimeException
, std::exception
)
448 if ( ! acceptsURL(url
) )
450 ::connectivity::SharedResources aResources
;
451 const OUString sMessage
= aResources
.getResourceString(STR_URI_SYNTAX_ERROR
);
452 ::dbtools::throwGenericSQLException(sMessage
,*this);
453 } // if ( ! acceptsURL(url) )
455 return getDataDefinitionByConnection(connect(url
,info
));
461 OUString
ODriverDelegator::getImplementationName_Static( ) throw(RuntimeException
)
463 return OUString("org.openoffice.comp.drivers.MySQL.Driver");
466 Sequence
< OUString
> ODriverDelegator::getSupportedServiceNames_Static( ) throw (RuntimeException
)
468 Sequence
< OUString
> aSNS( 2 );
469 aSNS
[0] = "com.sun.star.sdbc.Driver";
470 aSNS
[1] = "com.sun.star.sdbcx.Driver";
474 OUString SAL_CALL
ODriverDelegator::getImplementationName( ) throw(RuntimeException
, std::exception
)
476 return getImplementationName_Static();
479 sal_Bool SAL_CALL
ODriverDelegator::supportsService( const OUString
& _rServiceName
) throw(RuntimeException
, std::exception
)
481 return cppu::supportsService(this, _rServiceName
);
484 Sequence
< OUString
> SAL_CALL
ODriverDelegator::getSupportedServiceNames( ) throw(RuntimeException
, std::exception
)
486 return getSupportedServiceNames_Static();
490 } // namespace connectivity
493 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */