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 <sal/config.h>
22 #include <string_view>
24 #include <mysql/YDriver.hxx>
25 #include <mysql/YCatalog.hxx>
26 #include <o3tl/string_view.hxx>
27 #include <comphelper/namedvaluecollection.hxx>
28 #include <comphelper/servicehelper.hxx>
29 #include <comphelper/types.hxx>
30 #include <cppuhelper/supportsservice.hxx>
31 #include <connectivity/dbexception.hxx>
32 #include <connectivity/dbcharset.hxx>
33 #include <com/sun/star/sdbc/DriverManager.hpp>
34 #include <com/sun/star/uno/XComponentContext.hpp>
35 #include <TConnection.hxx>
36 #include <strings.hrc>
37 #include <resource/sharedresources.hxx>
39 namespace connectivity
41 using namespace mysql
;
42 using namespace ::com::sun::star::uno
;
43 using namespace ::com::sun::star::sdbc
;
44 using namespace ::com::sun::star::sdbcx
;
45 using namespace ::com::sun::star::beans
;
46 using namespace ::com::sun::star::lang
;
50 OUString
getJavaDriverClass(css::uno::Sequence
<css::beans::PropertyValue
> const& info
)
52 return comphelper::NamedValueCollection::getOrDefault(info
, u
"JavaDriverClass",
53 u
"com.mysql.jdbc.Driver"_ustr
);
57 ODriverDelegator::ODriverDelegator(const Reference
<XComponentContext
>& _rxContext
)
58 : ODriverDelegator_BASE(m_aMutex
)
59 , m_xContext(_rxContext
)
63 ODriverDelegator::~ODriverDelegator()
67 ::comphelper::disposeComponent(m_xODBCDriver
);
68 ::comphelper::disposeComponent(m_xNativeDriver
);
69 for (auto& rEntry
: m_aJdbcDrivers
)
70 ::comphelper::disposeComponent(rEntry
.second
);
72 catch (const Exception
&)
77 void ODriverDelegator::disposing()
79 ::osl::MutexGuard
aGuard(m_aMutex
);
81 for (auto const& connection
: m_aConnections
)
83 Reference
<XInterface
> xTemp
= connection
.first
.get();
84 ::comphelper::disposeComponent(xTemp
);
86 m_aConnections
.clear();
87 TWeakPairVector().swap(m_aConnections
);
89 ODriverDelegator_BASE::disposing();
94 enum class T_DRIVERTYPE
101 bool isOdbcUrl(std::u16string_view _sUrl
) { return o3tl::starts_with(_sUrl
, u
"sdbc:mysql:odbc:"); }
103 bool isNativeUrl(std::u16string_view _sUrl
)
105 return o3tl::starts_with(_sUrl
, u
"sdbc:mysql:mysqlc:");
108 T_DRIVERTYPE
lcl_getDriverType(std::u16string_view _sUrl
)
110 T_DRIVERTYPE eRet
= T_DRIVERTYPE::Jdbc
;
111 if (isOdbcUrl(_sUrl
))
112 eRet
= T_DRIVERTYPE::Odbc
;
113 else if (isNativeUrl(_sUrl
))
114 eRet
= T_DRIVERTYPE::Native
;
118 OUString
transformUrl(std::u16string_view _sUrl
)
120 OUString
sNewUrl(_sUrl
.substr(11));
121 if (isOdbcUrl(_sUrl
))
122 sNewUrl
= "sdbc:" + sNewUrl
;
123 else if (isNativeUrl(_sUrl
))
124 sNewUrl
= "sdbc:" + sNewUrl
;
127 sNewUrl
= OUString::Concat("jdbc:mysql://") + sNewUrl
.subView(5);
132 Reference
<XDriver
> lcl_loadDriver(const Reference
<XComponentContext
>& _rxContext
,
133 const OUString
& _sUrl
)
135 Reference
<XDriverManager2
> xDriverAccess
= DriverManager::create(_rxContext
);
136 Reference
<XDriver
> xDriver
= xDriverAccess
->getDriverByURL(_sUrl
);
140 Sequence
<PropertyValue
> lcl_convertProperties(T_DRIVERTYPE _eType
,
141 const Sequence
<PropertyValue
>& info
,
142 const OUString
& _sUrl
)
144 std::vector
<PropertyValue
> aProps
;
145 const PropertyValue
* pSupported
= info
.getConstArray();
146 const PropertyValue
* pEnd
= pSupported
+ info
.getLength();
148 aProps
.reserve(info
.getLength() + 5);
150 for (; pSupported
!= pEnd
; ++pSupported
)
152 aProps
.push_back(*pSupported
);
153 if (pSupported
->Name
== "JavaDriverClass")
159 if (_eType
== T_DRIVERTYPE::Odbc
)
161 aProps
.emplace_back("Silent", 0, Any(true), PropertyState_DIRECT_VALUE
);
162 aProps
.emplace_back("PreventGetVersionColumns", 0, Any(true), PropertyState_DIRECT_VALUE
);
164 else if (_eType
== T_DRIVERTYPE::Jdbc
)
168 aProps
.emplace_back("JavaDriverClass", 0, Any(u
"com.mysql.jdbc.Driver"_ustr
),
169 PropertyState_DIRECT_VALUE
);
174 aProps
.emplace_back("PublicConnectionURL", 0, Any(_sUrl
), PropertyState_DIRECT_VALUE
);
176 aProps
.emplace_back("IsAutoRetrievingEnabled", 0, Any(true), PropertyState_DIRECT_VALUE
);
177 aProps
.emplace_back("AutoRetrievingStatement", 0, Any(u
"SELECT LAST_INSERT_ID()"_ustr
),
178 PropertyState_DIRECT_VALUE
);
179 aProps
.emplace_back("ParameterNameSubstitution", 0, Any(true), PropertyState_DIRECT_VALUE
);
180 return Sequence
<PropertyValue
>(aProps
.data(), aProps
.size());
184 Reference
<XDriver
> ODriverDelegator::loadDriver(std::u16string_view url
,
185 const Sequence
<PropertyValue
>& info
)
187 Reference
<XDriver
> xDriver
;
188 const OUString sCuttedUrl
= transformUrl(url
);
189 const T_DRIVERTYPE eType
= lcl_getDriverType(url
);
190 if (eType
== T_DRIVERTYPE::Odbc
)
192 if (!m_xODBCDriver
.is())
193 m_xODBCDriver
= lcl_loadDriver(m_xContext
, sCuttedUrl
);
194 xDriver
= m_xODBCDriver
;
196 else if (eType
== T_DRIVERTYPE::Native
)
198 if (!m_xNativeDriver
.is())
199 m_xNativeDriver
= lcl_loadDriver(m_xContext
, sCuttedUrl
);
200 xDriver
= m_xNativeDriver
;
204 OUString
sDriverClass(getJavaDriverClass(info
));
205 TJDBCDrivers::iterator aFind
= m_aJdbcDrivers
.find(sDriverClass
);
206 if (aFind
== m_aJdbcDrivers
.end())
207 aFind
= m_aJdbcDrivers
.emplace(sDriverClass
, lcl_loadDriver(m_xContext
, sCuttedUrl
))
209 xDriver
= aFind
->second
;
215 Reference
<XConnection
> SAL_CALL
ODriverDelegator::connect(const OUString
& url
,
216 const Sequence
<PropertyValue
>& info
)
218 Reference
<XConnection
> xConnection
;
221 Reference
<XDriver
> xDriver
= loadDriver(url
, info
);
224 OUString sCuttedUrl
= transformUrl(url
);
225 const T_DRIVERTYPE eType
= lcl_getDriverType(url
);
226 Sequence
<PropertyValue
> aConvertedProperties
= lcl_convertProperties(eType
, info
, url
);
227 if (eType
== T_DRIVERTYPE::Jdbc
)
229 OUString sIanaName
= ::comphelper::NamedValueCollection::getOrDefault(
230 info
, u
"CharSet", OUString());
231 if (!sIanaName
.isEmpty())
233 ::dbtools::OCharsetMap aLookupIanaName
;
234 ::dbtools::OCharsetMap::const_iterator aLookup
235 = aLookupIanaName
.findIanaName(sIanaName
);
236 if (aLookup
!= aLookupIanaName
.end())
239 if (RTL_TEXTENCODING_UTF8
== (*aLookup
).getEncoding())
241 static constexpr OUString s_sCharSetOp
= u
"useUnicode=true&"_ustr
;
242 if (!sCuttedUrl
.matchIgnoreAsciiCase(s_sCharSetOp
))
245 } // if ( !sCuttedUrl.matchIgnoreAsciiCase(s_sCharSetOp) )
246 } // if ( RTL_TEXTENCODING_UTF8 == (*aLookup).getEncoding() )
247 if (sCuttedUrl
.indexOf('?') == -1)
251 sCuttedUrl
+= sAdd
+ "characterEncoding=" + sIanaName
;
256 xConnection
= xDriver
->connect(sCuttedUrl
, aConvertedProperties
);
257 if (xConnection
.is())
259 // now we have to set the URL to get the correct answer for metadata()->getURL()
260 auto pMetaConnection
= comphelper::getFromUnoTunnel
<OMetaConnection
>(xConnection
);
262 pMetaConnection
->setURL(url
);
263 m_aConnections
.emplace_back(
264 WeakReferenceHelper(xConnection
),
265 TWeakConnectionPair(WeakReferenceHelper(), pMetaConnection
));
272 sal_Bool SAL_CALL
ODriverDelegator::acceptsURL(const OUString
& url
)
274 Sequence
<PropertyValue
> info
;
276 bool bOK
= url
.startsWith("sdbc:mysql:odbc:") || url
.startsWith("sdbc:mysql:jdbc:")
277 || (url
.startsWith("sdbc:mysql:mysqlc:") && loadDriver(url
, info
).is());
281 Sequence
<DriverPropertyInfo
> SAL_CALL
282 ODriverDelegator::getPropertyInfo(const OUString
& url
, const Sequence
<PropertyValue
>& info
)
284 if (!acceptsURL(url
))
285 return Sequence
<DriverPropertyInfo
>();
287 Sequence
<OUString
> aBoolean
{ u
"0"_ustr
, u
"1"_ustr
};
289 std::vector
<DriverPropertyInfo
> aDriverInfo
{
290 { u
"CharSet"_ustr
, u
"CharSet of the database."_ustr
, false, {}, {} },
291 { u
"SuppressVersionColumns"_ustr
, u
"Display version columns (when available)."_ustr
, false,
292 u
"0"_ustr
, aBoolean
}
294 const T_DRIVERTYPE eType
= lcl_getDriverType(url
);
295 if (eType
== T_DRIVERTYPE::Jdbc
)
297 aDriverInfo
.emplace_back("JavaDriverClass", "The JDBC driver class name.", true,
298 getJavaDriverClass(info
), Sequence
<OUString
>());
300 else if (eType
== T_DRIVERTYPE::Native
)
302 aDriverInfo
.emplace_back("LocalSocket",
303 "The file path of a socket to connect to a local MySQL server.",
304 false, OUString(), Sequence
<OUString
>());
305 aDriverInfo
.emplace_back("NamedPipe",
306 "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::getFromUnoTunnel
<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 u
"org.openoffice.comp.drivers.MySQL.Driver"_ustr
;
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 { u
"com.sun.star.sdbc.Driver"_ustr
, u
"com.sun.star.sdbcx.Driver"_ustr
};
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: */