/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace connectivity { using namespace mysql; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::sdbc; using namespace ::com::sun::star::sdbcx; using namespace ::com::sun::star::beans; using namespace ::com::sun::star::lang; namespace { OUString getJavaDriverClass(css::uno::Sequence const& info) { return comphelper::NamedValueCollection::getOrDefault(info, u"JavaDriverClass", OUString("com.mysql.jdbc.Driver")); } } ODriverDelegator::ODriverDelegator(const Reference& _rxContext) : ODriverDelegator_BASE(m_aMutex) , m_xContext(_rxContext) { } ODriverDelegator::~ODriverDelegator() { try { ::comphelper::disposeComponent(m_xODBCDriver); ::comphelper::disposeComponent(m_xNativeDriver); for (auto& rEntry : m_aJdbcDrivers) ::comphelper::disposeComponent(rEntry.second); } catch (const Exception&) { } } void ODriverDelegator::disposing() { ::osl::MutexGuard aGuard(m_aMutex); for (auto const& connection : m_aConnections) { Reference xTemp = connection.first.get(); ::comphelper::disposeComponent(xTemp); } m_aConnections.clear(); TWeakPairVector().swap(m_aConnections); ODriverDelegator_BASE::disposing(); } namespace { enum class T_DRIVERTYPE { Odbc, Jdbc, Native }; bool isOdbcUrl(std::u16string_view _sUrl) { return o3tl::starts_with(_sUrl, u"sdbc:mysql:odbc:"); } bool isNativeUrl(std::u16string_view _sUrl) { return o3tl::starts_with(_sUrl, u"sdbc:mysql:mysqlc:"); } T_DRIVERTYPE lcl_getDriverType(std::u16string_view _sUrl) { T_DRIVERTYPE eRet = T_DRIVERTYPE::Jdbc; if (isOdbcUrl(_sUrl)) eRet = T_DRIVERTYPE::Odbc; else if (isNativeUrl(_sUrl)) eRet = T_DRIVERTYPE::Native; return eRet; } OUString transformUrl(std::u16string_view _sUrl) { OUString sNewUrl(_sUrl.substr(11)); if (isOdbcUrl(_sUrl)) sNewUrl = "sdbc:" + sNewUrl; else if (isNativeUrl(_sUrl)) sNewUrl = "sdbc:" + sNewUrl; else { sNewUrl = OUString::Concat("jdbc:mysql://") + sNewUrl.subView(5); } return sNewUrl; } Reference lcl_loadDriver(const Reference& _rxContext, const OUString& _sUrl) { Reference xDriverAccess = DriverManager::create(_rxContext); Reference xDriver = xDriverAccess->getDriverByURL(_sUrl); return xDriver; } Sequence lcl_convertProperties(T_DRIVERTYPE _eType, const Sequence& info, const OUString& _sUrl) { std::vector aProps; const PropertyValue* pSupported = info.getConstArray(); const PropertyValue* pEnd = pSupported + info.getLength(); aProps.reserve(info.getLength() + 5); bool jdc = false; for (; pSupported != pEnd; ++pSupported) { aProps.push_back(*pSupported); if (pSupported->Name == "JavaDriverClass") { jdc = true; } } if (_eType == T_DRIVERTYPE::Odbc) { aProps.push_back(PropertyValue("Silent", 0, Any(true), PropertyState_DIRECT_VALUE)); aProps.push_back( PropertyValue("PreventGetVersionColumns", 0, Any(true), PropertyState_DIRECT_VALUE)); } else if (_eType == T_DRIVERTYPE::Jdbc) { if (!jdc) { aProps.push_back(PropertyValue("JavaDriverClass", 0, Any(OUString("com.mysql.jdbc.Driver")), PropertyState_DIRECT_VALUE)); } } else { aProps.push_back( PropertyValue("PublicConnectionURL", 0, Any(_sUrl), PropertyState_DIRECT_VALUE)); } aProps.push_back( PropertyValue("IsAutoRetrievingEnabled", 0, Any(true), PropertyState_DIRECT_VALUE)); aProps.push_back(PropertyValue("AutoRetrievingStatement", 0, Any(OUString("SELECT LAST_INSERT_ID()")), PropertyState_DIRECT_VALUE)); aProps.push_back( PropertyValue("ParameterNameSubstitution", 0, Any(true), PropertyState_DIRECT_VALUE)); return Sequence(aProps.data(), aProps.size()); } } Reference ODriverDelegator::loadDriver(std::u16string_view url, const Sequence& info) { Reference xDriver; const OUString sCuttedUrl = transformUrl(url); const T_DRIVERTYPE eType = lcl_getDriverType(url); if (eType == T_DRIVERTYPE::Odbc) { if (!m_xODBCDriver.is()) m_xODBCDriver = lcl_loadDriver(m_xContext, sCuttedUrl); xDriver = m_xODBCDriver; } // if ( bIsODBC ) else if (eType == T_DRIVERTYPE::Native) { if (!m_xNativeDriver.is()) m_xNativeDriver = lcl_loadDriver(m_xContext, sCuttedUrl); xDriver = m_xNativeDriver; } else { OUString sDriverClass(getJavaDriverClass(info)); TJDBCDrivers::iterator aFind = m_aJdbcDrivers.find(sDriverClass); if (aFind == m_aJdbcDrivers.end()) aFind = m_aJdbcDrivers.emplace(sDriverClass, lcl_loadDriver(m_xContext, sCuttedUrl)) .first; xDriver = aFind->second; } return xDriver; } Reference SAL_CALL ODriverDelegator::connect(const OUString& url, const Sequence& info) { Reference xConnection; if (acceptsURL(url)) { Reference xDriver = loadDriver(url, info); if (xDriver.is()) { OUString sCuttedUrl = transformUrl(url); const T_DRIVERTYPE eType = lcl_getDriverType(url); Sequence aConvertedProperties = lcl_convertProperties(eType, info, url); if (eType == T_DRIVERTYPE::Jdbc) { OUString sIanaName = ::comphelper::NamedValueCollection::getOrDefault( info, u"CharSet", OUString()); if (!sIanaName.isEmpty()) { ::dbtools::OCharsetMap aLookupIanaName; ::dbtools::OCharsetMap::const_iterator aLookup = aLookupIanaName.findIanaName(sIanaName); if (aLookup != aLookupIanaName.end()) { OUString sAdd; if (RTL_TEXTENCODING_UTF8 == (*aLookup).getEncoding()) { static constexpr OUString s_sCharSetOp = u"useUnicode=true&"_ustr; if (!sCuttedUrl.matchIgnoreAsciiCase(s_sCharSetOp)) { sAdd = s_sCharSetOp; } // if ( !sCuttedUrl.matchIgnoreAsciiCase(s_sCharSetOp) ) } // if ( RTL_TEXTENCODING_UTF8 == (*aLookup).getEncoding() ) if (sCuttedUrl.indexOf('?') == -1) sCuttedUrl += "?"; else sCuttedUrl += "&"; sCuttedUrl += sAdd + "characterEncoding=" + sIanaName; } } } // if ( !bIsODBC ) xConnection = xDriver->connect(sCuttedUrl, aConvertedProperties); if (xConnection.is()) { // now we have to set the URL to get the correct answer for metadata()->getURL() auto pMetaConnection = comphelper::getFromUnoTunnel(xConnection); if (pMetaConnection) pMetaConnection->setURL(url); m_aConnections.push_back( TWeakPair(WeakReferenceHelper(xConnection), TWeakConnectionPair(WeakReferenceHelper(), pMetaConnection))); } } } return xConnection; } sal_Bool SAL_CALL ODriverDelegator::acceptsURL(const OUString& url) { Sequence info; bool bOK = url.startsWith("sdbc:mysql:odbc:") || url.startsWith("sdbc:mysql:jdbc:") || (url.startsWith("sdbc:mysql:mysqlc:") && loadDriver(url, info).is()); return bOK; } Sequence SAL_CALL ODriverDelegator::getPropertyInfo(const OUString& url, const Sequence& info) { if (!acceptsURL(url)) return Sequence(); Sequence aBoolean{ "0", "1" }; std::vector aDriverInfo{ { "CharSet", "CharSet of the database.", false, {}, {} }, { "SuppressVersionColumns", "Display version columns (when available).", false, "0", aBoolean } }; const T_DRIVERTYPE eType = lcl_getDriverType(url); if (eType == T_DRIVERTYPE::Jdbc) { aDriverInfo.push_back(DriverPropertyInfo("JavaDriverClass", "The JDBC driver class name.", true, getJavaDriverClass(info), Sequence())); } else if (eType == T_DRIVERTYPE::Native) { aDriverInfo.push_back(DriverPropertyInfo( "LocalSocket", "The file path of a socket to connect to a local MySQL server.", false, OUString(), Sequence())); aDriverInfo.push_back(DriverPropertyInfo( "NamedPipe", "The name of a pipe to connect to a local MySQL server.", false, OUString(), Sequence())); } return Sequence(aDriverInfo.data(), aDriverInfo.size()); } sal_Int32 SAL_CALL ODriverDelegator::getMajorVersion() { return 1; } sal_Int32 SAL_CALL ODriverDelegator::getMinorVersion() { return 0; } Reference SAL_CALL ODriverDelegator::getDataDefinitionByConnection(const Reference& connection) { ::osl::MutexGuard aGuard(m_aMutex); checkDisposed(ODriverDelegator_BASE::rBHelper.bDisposed); Reference xTab; auto pConnection = comphelper::getFromUnoTunnel(connection); if (pConnection) { TWeakPairVector::iterator i = std::find_if(m_aConnections.begin(), m_aConnections.end(), [&pConnection](const TWeakPairVector::value_type& rConnection) { return rConnection.second.second == pConnection; }); if (i != m_aConnections.end()) { xTab.set(i->second.first.get(), UNO_QUERY); if (!xTab.is()) { xTab = new OMySQLCatalog(connection); i->second.first = WeakReferenceHelper(xTab); } } } // if (pConnection) if (!xTab.is()) { TWeakPairVector::iterator i = std::find_if(m_aConnections.begin(), m_aConnections.end(), [&connection](const TWeakPairVector::value_type& rConnection) { Reference xTemp(rConnection.first.get(), UNO_QUERY); return xTemp == connection; }); if (i != m_aConnections.end()) { xTab.set(i->second.first.get(), UNO_QUERY); if (!xTab.is()) { xTab = new OMySQLCatalog(connection); i->second.first = WeakReferenceHelper(xTab); } } } return xTab; } Reference SAL_CALL ODriverDelegator::getDataDefinitionByURL(const OUString& url, const Sequence& info) { if (!acceptsURL(url)) { ::connectivity::SharedResources aResources; const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR); ::dbtools::throwGenericSQLException(sMessage, *this); } // if ( ! acceptsURL(url) ) return getDataDefinitionByConnection(connect(url, info)); } // XServiceInfo OUString SAL_CALL ODriverDelegator::getImplementationName() { return "org.openoffice.comp.drivers.MySQL.Driver"; } sal_Bool SAL_CALL ODriverDelegator::supportsService(const OUString& _rServiceName) { return cppu::supportsService(this, _rServiceName); } Sequence SAL_CALL ODriverDelegator::getSupportedServiceNames() { return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" }; } } // namespace connectivity extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* connectivity_mysql_ODriverDelegator_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence const&) { try { return cppu::acquire(new connectivity::ODriverDelegator(context)); } catch (...) { return nullptr; } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */