LibreOffice Module connectivity (master) 1
YDriver.cxx
Go to the documentation of this file.
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 <sal/config.h>
21
22#include <string_view>
23
24#include <mysql/YDriver.hxx>
25#include <mysql/YCatalog.hxx>
26#include <o3tl/string_view.hxx>
29#include <comphelper/types.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>
38
39namespace connectivity
40{
41using namespace mysql;
42using namespace ::com::sun::star::uno;
43using namespace ::com::sun::star::sdbc;
44using namespace ::com::sun::star::sdbcx;
45using namespace ::com::sun::star::beans;
46using namespace ::com::sun::star::lang;
47
48namespace
49{
50OUString getJavaDriverClass(css::uno::Sequence<css::beans::PropertyValue> const& info)
51{
52 return comphelper::NamedValueCollection::getOrDefault(info, u"JavaDriverClass",
53 OUString("com.mysql.jdbc.Driver"));
54}
55}
56
57ODriverDelegator::ODriverDelegator(const Reference<XComponentContext>& _rxContext)
59 , m_xContext(_rxContext)
60{
61}
62
63ODriverDelegator::~ODriverDelegator()
64{
65 try
66 {
67 ::comphelper::disposeComponent(m_xODBCDriver);
68 ::comphelper::disposeComponent(m_xNativeDriver);
69 for (auto& rEntry : m_aJdbcDrivers)
70 ::comphelper::disposeComponent(rEntry.second);
71 }
72 catch (const Exception&)
73 {
74 }
75}
76
77void ODriverDelegator::disposing()
78{
79 ::osl::MutexGuard aGuard(m_aMutex);
80
81 for (auto const& connection : m_aConnections)
82 {
83 Reference<XInterface> xTemp = connection.first.get();
84 ::comphelper::disposeComponent(xTemp);
85 }
86 m_aConnections.clear();
87 TWeakPairVector().swap(m_aConnections);
88
89 ODriverDelegator_BASE::disposing();
90}
91
92namespace
93{
94enum class T_DRIVERTYPE
95{
96 Odbc,
97 Jdbc,
98 Native
99};
100
101bool isOdbcUrl(std::u16string_view _sUrl) { return o3tl::starts_with(_sUrl, u"sdbc:mysql:odbc:"); }
102
103bool isNativeUrl(std::u16string_view _sUrl)
104{
105 return o3tl::starts_with(_sUrl, u"sdbc:mysql:mysqlc:");
106}
107
108T_DRIVERTYPE lcl_getDriverType(std::u16string_view _sUrl)
109{
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;
115 return eRet;
116}
117
118OUString transformUrl(std::u16string_view _sUrl)
119{
120 OUString sNewUrl(_sUrl.substr(11));
121 if (isOdbcUrl(_sUrl))
122 sNewUrl = "sdbc:" + sNewUrl;
123 else if (isNativeUrl(_sUrl))
124 sNewUrl = "sdbc:" + sNewUrl;
125 else
126 {
127 sNewUrl = OUString::Concat("jdbc:mysql://") + sNewUrl.subView(5);
128 }
129 return sNewUrl;
130}
131
132Reference<XDriver> lcl_loadDriver(const Reference<XComponentContext>& _rxContext,
133 const OUString& _sUrl)
134{
135 Reference<XDriverManager2> xDriverAccess = DriverManager::create(_rxContext);
136 Reference<XDriver> xDriver = xDriverAccess->getDriverByURL(_sUrl);
137 return xDriver;
138}
139
140Sequence<PropertyValue> lcl_convertProperties(T_DRIVERTYPE _eType,
141 const Sequence<PropertyValue>& info,
142 const OUString& _sUrl)
143{
144 std::vector<PropertyValue> aProps;
145 const PropertyValue* pSupported = info.getConstArray();
146 const PropertyValue* pEnd = pSupported + info.getLength();
147
148 aProps.reserve(info.getLength() + 5);
149 bool jdc = false;
150 for (; pSupported != pEnd; ++pSupported)
151 {
152 aProps.push_back(*pSupported);
153 if (pSupported->Name == "JavaDriverClass")
154 {
155 jdc = true;
156 }
157 }
158
159 if (_eType == T_DRIVERTYPE::Odbc)
160 {
161 aProps.push_back(PropertyValue("Silent", 0, Any(true), PropertyState_DIRECT_VALUE));
162 aProps.push_back(
163 PropertyValue("PreventGetVersionColumns", 0, Any(true), PropertyState_DIRECT_VALUE));
164 }
165 else if (_eType == T_DRIVERTYPE::Jdbc)
166 {
167 if (!jdc)
168 {
169 aProps.push_back(PropertyValue("JavaDriverClass", 0,
170 Any(OUString("com.mysql.jdbc.Driver")),
171 PropertyState_DIRECT_VALUE));
172 }
173 }
174 else
175 {
176 aProps.push_back(
177 PropertyValue("PublicConnectionURL", 0, Any(_sUrl), PropertyState_DIRECT_VALUE));
178 }
179 aProps.push_back(
180 PropertyValue("IsAutoRetrievingEnabled", 0, Any(true), PropertyState_DIRECT_VALUE));
181 aProps.push_back(PropertyValue("AutoRetrievingStatement", 0,
182 Any(OUString("SELECT LAST_INSERT_ID()")),
183 PropertyState_DIRECT_VALUE));
184 aProps.push_back(
185 PropertyValue("ParameterNameSubstitution", 0, Any(true), PropertyState_DIRECT_VALUE));
186 return Sequence<PropertyValue>(aProps.data(), aProps.size());
187}
188}
189
190Reference<XDriver> ODriverDelegator::loadDriver(std::u16string_view url,
191 const Sequence<PropertyValue>& info)
192{
193 Reference<XDriver> xDriver;
194 const OUString sCuttedUrl = transformUrl(url);
195 const T_DRIVERTYPE eType = lcl_getDriverType(url);
196 if (eType == T_DRIVERTYPE::Odbc)
197 {
198 if (!m_xODBCDriver.is())
199 m_xODBCDriver = lcl_loadDriver(m_xContext, sCuttedUrl);
200 xDriver = m_xODBCDriver;
201 } // if ( bIsODBC )
202 else if (eType == T_DRIVERTYPE::Native)
203 {
204 if (!m_xNativeDriver.is())
205 m_xNativeDriver = lcl_loadDriver(m_xContext, sCuttedUrl);
206 xDriver = m_xNativeDriver;
207 }
208 else
209 {
210 OUString sDriverClass(getJavaDriverClass(info));
211 TJDBCDrivers::iterator aFind = m_aJdbcDrivers.find(sDriverClass);
212 if (aFind == m_aJdbcDrivers.end())
213 aFind = m_aJdbcDrivers.emplace(sDriverClass, lcl_loadDriver(m_xContext, sCuttedUrl))
214 .first;
215 xDriver = aFind->second;
216 }
217
218 return xDriver;
219}
220
221Reference<XConnection> SAL_CALL ODriverDelegator::connect(const OUString& url,
222 const Sequence<PropertyValue>& info)
223{
224 Reference<XConnection> xConnection;
225 if (acceptsURL(url))
226 {
227 Reference<XDriver> xDriver = loadDriver(url, info);
228 if (xDriver.is())
229 {
230 OUString sCuttedUrl = transformUrl(url);
231 const T_DRIVERTYPE eType = lcl_getDriverType(url);
232 Sequence<PropertyValue> aConvertedProperties = lcl_convertProperties(eType, info, url);
233 if (eType == T_DRIVERTYPE::Jdbc)
234 {
236 info, u"CharSet", OUString());
237 if (!sIanaName.isEmpty())
238 {
239 ::dbtools::OCharsetMap aLookupIanaName;
241 = aLookupIanaName.findIanaName(sIanaName);
242 if (aLookup != aLookupIanaName.end())
243 {
244 OUString sAdd;
245 if (RTL_TEXTENCODING_UTF8 == (*aLookup).getEncoding())
246 {
247 static constexpr OUStringLiteral s_sCharSetOp = u"useUnicode=true&";
248 if (!sCuttedUrl.matchIgnoreAsciiCase(s_sCharSetOp))
249 {
250 sAdd = s_sCharSetOp;
251 } // if ( !sCuttedUrl.matchIgnoreAsciiCase(s_sCharSetOp) )
252 } // if ( RTL_TEXTENCODING_UTF8 == (*aLookup).getEncoding() )
253 if (sCuttedUrl.indexOf('?') == -1)
254 sCuttedUrl += "?";
255 else
256 sCuttedUrl += "&";
257 sCuttedUrl += sAdd + "characterEncoding=" + sIanaName;
258 }
259 }
260 } // if ( !bIsODBC )
261
262 xConnection = xDriver->connect(sCuttedUrl, aConvertedProperties);
263 if (xConnection.is())
264 {
265 // now we have to set the URL to get the correct answer for metadata()->getURL()
266 auto pMetaConnection = comphelper::getFromUnoTunnel<OMetaConnection>(xConnection);
267 if (pMetaConnection)
268 pMetaConnection->setURL(url);
269 m_aConnections.push_back(
270 TWeakPair(WeakReferenceHelper(xConnection),
271 TWeakConnectionPair(WeakReferenceHelper(), pMetaConnection)));
272 }
273 }
274 }
275 return xConnection;
276}
277
278sal_Bool SAL_CALL ODriverDelegator::acceptsURL(const OUString& url)
279{
280 Sequence<PropertyValue> info;
281
282 bool bOK = url.startsWith("sdbc:mysql:odbc:") || url.startsWith("sdbc:mysql:jdbc:")
283 || (url.startsWith("sdbc:mysql:mysqlc:") && loadDriver(url, info).is());
284 return bOK;
285}
286
287Sequence<DriverPropertyInfo> SAL_CALL
288ODriverDelegator::getPropertyInfo(const OUString& url, const Sequence<PropertyValue>& info)
289{
290 if (!acceptsURL(url))
291 return Sequence<DriverPropertyInfo>();
292
293 Sequence<OUString> aBoolean{ "0", "1" };
294
295 std::vector<DriverPropertyInfo> aDriverInfo{
296 { "CharSet", "CharSet of the database.", false, {}, {} },
297 { "SuppressVersionColumns", "Display version columns (when available).", false, "0",
298 aBoolean }
299 };
300 const T_DRIVERTYPE eType = lcl_getDriverType(url);
301 if (eType == T_DRIVERTYPE::Jdbc)
302 {
303 aDriverInfo.push_back(DriverPropertyInfo("JavaDriverClass", "The JDBC driver class name.",
304 true, getJavaDriverClass(info),
305 Sequence<OUString>()));
306 }
307 else if (eType == T_DRIVERTYPE::Native)
308 {
309 aDriverInfo.push_back(DriverPropertyInfo(
310 "LocalSocket", "The file path of a socket to connect to a local MySQL server.", false,
311 OUString(), Sequence<OUString>()));
312 aDriverInfo.push_back(DriverPropertyInfo(
313 "NamedPipe", "The name of a pipe to connect to a local MySQL server.", false,
314 OUString(), Sequence<OUString>()));
315 }
316
317 return Sequence<DriverPropertyInfo>(aDriverInfo.data(), aDriverInfo.size());
318}
319
320sal_Int32 SAL_CALL ODriverDelegator::getMajorVersion() { return 1; }
321
322sal_Int32 SAL_CALL ODriverDelegator::getMinorVersion() { return 0; }
323
324Reference<XTablesSupplier> SAL_CALL
325ODriverDelegator::getDataDefinitionByConnection(const Reference<XConnection>& connection)
326{
327 ::osl::MutexGuard aGuard(m_aMutex);
328 checkDisposed(ODriverDelegator_BASE::rBHelper.bDisposed);
329
330 Reference<XTablesSupplier> xTab;
331 auto pConnection = comphelper::getFromUnoTunnel<OMetaConnection>(connection);
332 if (pConnection)
333 {
334 TWeakPairVector::iterator i
335 = std::find_if(m_aConnections.begin(), m_aConnections.end(),
336 [&pConnection](const TWeakPairVector::value_type& rConnection) {
337 return rConnection.second.second == pConnection;
338 });
339 if (i != m_aConnections.end())
340 {
341 xTab.set(i->second.first.get(), UNO_QUERY);
342 if (!xTab.is())
343 {
344 xTab = new OMySQLCatalog(connection);
345 i->second.first = WeakReferenceHelper(xTab);
346 }
347 }
348 } // if (pConnection)
349 if (!xTab.is())
350 {
351 TWeakPairVector::iterator i
352 = std::find_if(m_aConnections.begin(), m_aConnections.end(),
353 [&connection](const TWeakPairVector::value_type& rConnection) {
354 Reference<XConnection> xTemp(rConnection.first.get(), UNO_QUERY);
355 return xTemp == connection;
356 });
357 if (i != m_aConnections.end())
358 {
359 xTab.set(i->second.first.get(), UNO_QUERY);
360 if (!xTab.is())
361 {
362 xTab = new OMySQLCatalog(connection);
363 i->second.first = WeakReferenceHelper(xTab);
364 }
365 }
366 }
367 return xTab;
368}
369
370Reference<XTablesSupplier> SAL_CALL
371ODriverDelegator::getDataDefinitionByURL(const OUString& url, const Sequence<PropertyValue>& info)
372{
373 if (!acceptsURL(url))
374 {
376 const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
378 } // if ( ! acceptsURL(url) )
379
380 return getDataDefinitionByConnection(connect(url, info));
381}
382
383// XServiceInfo
384
385OUString SAL_CALL ODriverDelegator::getImplementationName()
386{
387 return "org.openoffice.comp.drivers.MySQL.Driver";
388}
389
390sal_Bool SAL_CALL ODriverDelegator::supportsService(const OUString& _rServiceName)
391{
392 return cppu::supportsService(this, _rServiceName);
393}
394
395Sequence<OUString> SAL_CALL ODriverDelegator::getSupportedServiceNames()
396{
397 return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" };
398}
399
400} // namespace connectivity
401
402extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
404 css::uno::Sequence<css::uno::Any> const&)
405{
406 try
407 {
408 return cppu::acquire(new connectivity::ODriverDelegator(context));
409 }
410 catch (...)
411 {
412 return nullptr;
413 }
414}
415
416/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XComponentContext > m_xContext
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * connectivity_mysql_ODriverDelegator_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
Definition: YDriver.cxx:403
VALUE_TYPE getOrDefault(const OUString &_rValueName, const VALUE_TYPE &_rDefault) const
helper class for accessing resources shared by different libraries in the connectivity module
OUString getResourceString(TranslateId pResId) const
loads a string from the shared resource file
delegates all calls to the original driver and extend the existing one with the SDBCX layer.
Definition: HDriver.hxx:53
ODriverDelegator(const css::uno::Reference< css::uno::XComponentContext > &_rxContext)
creates a new delegator for a HSQLDB driver
is a class which translates between different charset representations.
Definition: dbcharset.hxx:54
CharsetIterator const_iterator
Definition: dbcharset.hxx:64
CharsetIterator findIanaName(std::u16string_view _rIanaName) const
find the given IANA name in the map.
Definition: dbcharset.cxx:96
CharsetIterator end() const
get access to the (last + 1st) element of the charset collection
Definition: dbcharset.cxx:118
float u
DocumentType eType
std::mutex m_aMutex
std::pair< css::uno::WeakReferenceHelper, TWeakConnectionPair > TWeakPair
Definition: HDriver.hxx:44
std::pair< OUString,TWeakRefPair > TWeakConnectionPair
Definition: HDriver.hxx:42
::cppu::WeakComponentImplHelper< css::sdbc::XDriver, css::sdbcx::XDataDefinitionSupplier, css::lang::XServiceInfo, css::sdbcx::XCreateCatalog, css::embed::XTransactionListener > ODriverDelegator_BASE
Definition: HDriver.hxx:39
std::vector< TWeakPair > TWeakPairVector
Definition: HDriver.hxx:45
void checkDisposed(bool _bThrow)
Definition: dbtools.cxx:1951
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
void throwGenericSQLException(const OUString &_rMsg, const css::uno::Reference< css::uno::XInterface > &_rxSource)
throw a generic SQLException, i.e.
int i
constexpr bool starts_with(std::basic_string_view< charT, traits > sv, std::basic_string_view< charT, traits > x) noexcept
OUString sMessage
unsigned char sal_Bool