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 <comphelper/namedvaluecollection.hxx>
23 #include <comphelper/servicehelper.hxx>
24 #include <comphelper/types.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 <strings.hrc>
32 #include <resource/sharedresources.hxx>
34 namespace connectivity
36 using namespace mysql
;
37 using namespace ::com::sun::star::uno
;
38 using namespace ::com::sun::star::sdbc
;
39 using namespace ::com::sun::star::sdbcx
;
40 using namespace ::com::sun::star::beans
;
41 using namespace ::com::sun::star::lang
;
45 OUString
getJavaDriverClass(css::uno::Sequence
<css::beans::PropertyValue
> const& info
)
47 return comphelper::NamedValueCollection(info
).getOrDefault("JavaDriverClass",
48 OUString("com.mysql.jdbc.Driver"));
52 ODriverDelegator::ODriverDelegator(const Reference
<XComponentContext
>& _rxContext
)
53 : ODriverDelegator_BASE(m_aMutex
)
54 , m_xContext(_rxContext
)
58 ODriverDelegator::~ODriverDelegator()
62 ::comphelper::disposeComponent(m_xODBCDriver
);
63 ::comphelper::disposeComponent(m_xNativeDriver
);
64 for (auto& rEntry
: m_aJdbcDrivers
)
65 ::comphelper::disposeComponent(rEntry
.second
);
67 catch (const Exception
&)
72 void ODriverDelegator::disposing()
74 ::osl::MutexGuard
aGuard(m_aMutex
);
76 for (auto const& connection
: m_aConnections
)
78 Reference
<XInterface
> xTemp
= connection
.first
.get();
79 ::comphelper::disposeComponent(xTemp
);
81 m_aConnections
.clear();
82 TWeakPairVector().swap(m_aConnections
);
84 ODriverDelegator_BASE::disposing();
89 enum class T_DRIVERTYPE
96 bool isOdbcUrl(const OUString
& _sUrl
) { return _sUrl
.startsWith("sdbc:mysql:odbc:"); }
98 bool isNativeUrl(const OUString
& _sUrl
) { return _sUrl
.startsWith("sdbc:mysql:mysqlc:"); }
100 T_DRIVERTYPE
lcl_getDriverType(const OUString
& _sUrl
)
102 T_DRIVERTYPE eRet
= T_DRIVERTYPE::Jdbc
;
103 if (isOdbcUrl(_sUrl
))
104 eRet
= T_DRIVERTYPE::Odbc
;
105 else if (isNativeUrl(_sUrl
))
106 eRet
= T_DRIVERTYPE::Native
;
110 OUString
transformUrl(const OUString
& _sUrl
)
112 OUString sNewUrl
= _sUrl
.copy(11);
113 if (isOdbcUrl(_sUrl
))
114 sNewUrl
= "sdbc:" + sNewUrl
;
115 else if (isNativeUrl(_sUrl
))
116 sNewUrl
= "sdbc:" + sNewUrl
;
119 sNewUrl
= OUString::Concat("jdbc:mysql://") + sNewUrl
.subView(5);
124 Reference
<XDriver
> lcl_loadDriver(const Reference
<XComponentContext
>& _rxContext
,
125 const OUString
& _sUrl
)
127 Reference
<XDriverManager2
> xDriverAccess
= DriverManager::create(_rxContext
);
128 Reference
<XDriver
> xDriver
= xDriverAccess
->getDriverByURL(_sUrl
);
132 Sequence
<PropertyValue
> lcl_convertProperties(T_DRIVERTYPE _eType
,
133 const Sequence
<PropertyValue
>& info
,
134 const OUString
& _sUrl
)
136 std::vector
<PropertyValue
> aProps
;
137 const PropertyValue
* pSupported
= info
.getConstArray();
138 const PropertyValue
* pEnd
= pSupported
+ info
.getLength();
140 aProps
.reserve(info
.getLength() + 5);
142 for (; pSupported
!= pEnd
; ++pSupported
)
144 aProps
.push_back(*pSupported
);
145 if (pSupported
->Name
== "JavaDriverClass")
151 if (_eType
== T_DRIVERTYPE::Odbc
)
153 aProps
.push_back(PropertyValue("Silent", 0, makeAny(true), PropertyState_DIRECT_VALUE
));
154 aProps
.push_back(PropertyValue("PreventGetVersionColumns", 0, makeAny(true),
155 PropertyState_DIRECT_VALUE
));
157 else if (_eType
== T_DRIVERTYPE::Jdbc
)
161 aProps
.push_back(PropertyValue("JavaDriverClass", 0,
162 makeAny(OUString("com.mysql.jdbc.Driver")),
163 PropertyState_DIRECT_VALUE
));
169 PropertyValue("PublicConnectionURL", 0, makeAny(_sUrl
), PropertyState_DIRECT_VALUE
));
172 PropertyValue("IsAutoRetrievingEnabled", 0, makeAny(true), PropertyState_DIRECT_VALUE
));
173 aProps
.push_back(PropertyValue("AutoRetrievingStatement", 0,
174 makeAny(OUString("SELECT LAST_INSERT_ID()")),
175 PropertyState_DIRECT_VALUE
));
177 PropertyValue("ParameterNameSubstitution", 0, makeAny(true), PropertyState_DIRECT_VALUE
));
178 return Sequence
<PropertyValue
>(aProps
.data(), aProps
.size());
182 Reference
<XDriver
> ODriverDelegator::loadDriver(const OUString
& url
,
183 const Sequence
<PropertyValue
>& info
)
185 Reference
<XDriver
> xDriver
;
186 const OUString sCuttedUrl
= transformUrl(url
);
187 const T_DRIVERTYPE eType
= lcl_getDriverType(url
);
188 if (eType
== T_DRIVERTYPE::Odbc
)
190 if (!m_xODBCDriver
.is())
191 m_xODBCDriver
= lcl_loadDriver(m_xContext
, sCuttedUrl
);
192 xDriver
= m_xODBCDriver
;
194 else if (eType
== T_DRIVERTYPE::Native
)
196 if (!m_xNativeDriver
.is())
197 m_xNativeDriver
= lcl_loadDriver(m_xContext
, sCuttedUrl
);
198 xDriver
= m_xNativeDriver
;
202 OUString
sDriverClass(getJavaDriverClass(info
));
203 TJDBCDrivers::iterator aFind
= m_aJdbcDrivers
.find(sDriverClass
);
204 if (aFind
== m_aJdbcDrivers
.end())
205 aFind
= m_aJdbcDrivers
.emplace(sDriverClass
, lcl_loadDriver(m_xContext
, sCuttedUrl
))
207 xDriver
= aFind
->second
;
213 Reference
<XConnection
> SAL_CALL
ODriverDelegator::connect(const OUString
& url
,
214 const Sequence
<PropertyValue
>& info
)
216 Reference
<XConnection
> xConnection
;
219 Reference
<XDriver
> xDriver
= loadDriver(url
, info
);
222 OUString sCuttedUrl
= transformUrl(url
);
223 const T_DRIVERTYPE eType
= lcl_getDriverType(url
);
224 Sequence
<PropertyValue
> aConvertedProperties
= lcl_convertProperties(eType
, info
, url
);
225 if (eType
== T_DRIVERTYPE::Jdbc
)
227 ::comphelper::NamedValueCollection
aSettings(info
);
228 OUString sIanaName
= aSettings
.getOrDefault("CharSet", OUString());
229 if (!sIanaName
.isEmpty())
231 ::dbtools::OCharsetMap aLookupIanaName
;
232 ::dbtools::OCharsetMap::const_iterator aLookup
233 = aLookupIanaName
.findIanaName(sIanaName
);
234 if (aLookup
!= aLookupIanaName
.end())
237 if (RTL_TEXTENCODING_UTF8
== (*aLookup
).getEncoding())
239 static constexpr OUStringLiteral s_sCharSetOp
= u
"useUnicode=true&";
240 if (!sCuttedUrl
.matchIgnoreAsciiCase(s_sCharSetOp
))
243 } // if ( !sCuttedUrl.matchIgnoreAsciiCase(s_sCharSetOp) )
244 } // if ( RTL_TEXTENCODING_UTF8 == (*aLookup).getEncoding() )
245 if (sCuttedUrl
.indexOf('?') == -1)
249 sCuttedUrl
+= sAdd
+ "characterEncoding=" + sIanaName
;
254 xConnection
= xDriver
->connect(sCuttedUrl
, aConvertedProperties
);
255 if (xConnection
.is())
257 // now we have to set the URL to get the correct answer for metadata()->getURL()
259 = comphelper::getUnoTunnelImplementation
<OMetaConnection
>(xConnection
);
261 pMetaConnection
->setURL(url
);
262 m_aConnections
.push_back(
263 TWeakPair(WeakReferenceHelper(xConnection
),
264 TWeakConnectionPair(WeakReferenceHelper(), pMetaConnection
)));
271 sal_Bool SAL_CALL
ODriverDelegator::acceptsURL(const OUString
& url
)
273 Sequence
<PropertyValue
> info
;
275 bool bOK
= url
.startsWith("sdbc:mysql:odbc:") || url
.startsWith("sdbc:mysql:jdbc:")
276 || (url
.startsWith("sdbc:mysql:mysqlc:") && loadDriver(url
, info
).is());
280 Sequence
<DriverPropertyInfo
> SAL_CALL
281 ODriverDelegator::getPropertyInfo(const OUString
& url
, const Sequence
<PropertyValue
>& info
)
283 if (!acceptsURL(url
))
284 return Sequence
<DriverPropertyInfo
>();
286 Sequence
<OUString
> aBoolean
{ "0", "1" };
288 std::vector
<DriverPropertyInfo
> aDriverInfo
{
289 { "CharSet", "CharSet of the database.", false, {}, {} },
290 { "SuppressVersionColumns", "Display version columns (when available).", false, "0",
293 const T_DRIVERTYPE eType
= lcl_getDriverType(url
);
294 if (eType
== T_DRIVERTYPE::Jdbc
)
296 aDriverInfo
.push_back(DriverPropertyInfo("JavaDriverClass", "The JDBC driver class name.",
297 true, getJavaDriverClass(info
),
298 Sequence
<OUString
>()));
300 else if (eType
== T_DRIVERTYPE::Native
)
302 aDriverInfo
.push_back(DriverPropertyInfo(
303 "LocalSocket", "The file path of a socket to connect to a local MySQL server.", false,
304 OUString(), Sequence
<OUString
>()));
305 aDriverInfo
.push_back(DriverPropertyInfo(
306 "NamedPipe", "The name of a pipe to connect to a local MySQL server.", false,
307 OUString(), Sequence
<OUString
>()));
310 return Sequence
<DriverPropertyInfo
>(aDriverInfo
.data(), aDriverInfo
.size());
313 sal_Int32 SAL_CALL
ODriverDelegator::getMajorVersion() { return 1; }
315 sal_Int32 SAL_CALL
ODriverDelegator::getMinorVersion() { return 0; }
317 Reference
<XTablesSupplier
> SAL_CALL
318 ODriverDelegator::getDataDefinitionByConnection(const Reference
<XConnection
>& connection
)
320 ::osl::MutexGuard
aGuard(m_aMutex
);
321 checkDisposed(ODriverDelegator_BASE::rBHelper
.bDisposed
);
323 Reference
<XTablesSupplier
> xTab
;
324 auto pConnection
= comphelper::getUnoTunnelImplementation
<OMetaConnection
>(connection
);
327 TWeakPairVector::iterator i
328 = std::find_if(m_aConnections
.begin(), m_aConnections
.end(),
329 [&pConnection
](const TWeakPairVector::value_type
& rConnection
) {
330 return rConnection
.second
.second
== pConnection
;
332 if (i
!= m_aConnections
.end())
334 xTab
.set(i
->second
.first
.get(), UNO_QUERY
);
337 xTab
= new OMySQLCatalog(connection
);
338 i
->second
.first
= WeakReferenceHelper(xTab
);
341 } // if (pConnection)
344 TWeakPairVector::iterator i
345 = std::find_if(m_aConnections
.begin(), m_aConnections
.end(),
346 [&connection
](const TWeakPairVector::value_type
& rConnection
) {
347 Reference
<XConnection
> xTemp(rConnection
.first
.get(), UNO_QUERY
);
348 return xTemp
== connection
;
350 if (i
!= m_aConnections
.end())
352 xTab
.set(i
->second
.first
.get(), UNO_QUERY
);
355 xTab
= new OMySQLCatalog(connection
);
356 i
->second
.first
= WeakReferenceHelper(xTab
);
363 Reference
<XTablesSupplier
> SAL_CALL
364 ODriverDelegator::getDataDefinitionByURL(const OUString
& url
, const Sequence
<PropertyValue
>& info
)
366 if (!acceptsURL(url
))
368 ::connectivity::SharedResources aResources
;
369 const OUString sMessage
= aResources
.getResourceString(STR_URI_SYNTAX_ERROR
);
370 ::dbtools::throwGenericSQLException(sMessage
, *this);
371 } // if ( ! acceptsURL(url) )
373 return getDataDefinitionByConnection(connect(url
, info
));
378 OUString SAL_CALL
ODriverDelegator::getImplementationName()
380 return "org.openoffice.comp.drivers.MySQL.Driver";
383 sal_Bool SAL_CALL
ODriverDelegator::supportsService(const OUString
& _rServiceName
)
385 return cppu::supportsService(this, _rServiceName
);
388 Sequence
<OUString
> SAL_CALL
ODriverDelegator::getSupportedServiceNames()
390 return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" };
393 } // namespace connectivity
395 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
396 connectivity_mysql_ODriverDelegator_get_implementation(css::uno::XComponentContext
* context
,
397 css::uno::Sequence
<css::uno::Any
> const&)
401 return cppu::acquire(new connectivity::ODriverDelegator(context
));
409 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */