diff options
Diffstat (limited to 'connectivity/source/drivers/mysql_jdbc')
-rw-r--r-- | connectivity/source/drivers/mysql_jdbc/YCatalog.cxx | 132 | ||||
-rw-r--r-- | connectivity/source/drivers/mysql_jdbc/YColumns.cxx | 72 | ||||
-rw-r--r-- | connectivity/source/drivers/mysql_jdbc/YDriver.cxx | 416 | ||||
-rw-r--r-- | connectivity/source/drivers/mysql_jdbc/YTable.cxx | 327 | ||||
-rw-r--r-- | connectivity/source/drivers/mysql_jdbc/YTables.cxx | 208 | ||||
-rw-r--r-- | connectivity/source/drivers/mysql_jdbc/YUser.cxx | 325 | ||||
-rw-r--r-- | connectivity/source/drivers/mysql_jdbc/YUsers.cxx | 91 | ||||
-rw-r--r-- | connectivity/source/drivers/mysql_jdbc/YViews.cxx | 138 | ||||
-rw-r--r-- | connectivity/source/drivers/mysql_jdbc/mysql_jdbc.component | 27 |
9 files changed, 1736 insertions, 0 deletions
diff --git a/connectivity/source/drivers/mysql_jdbc/YCatalog.cxx b/connectivity/source/drivers/mysql_jdbc/YCatalog.cxx new file mode 100644 index 000000000..9c0afb55a --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/YCatalog.cxx @@ -0,0 +1,132 @@ +/* -*- 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 <mysql/YCatalog.hxx> +#include <mysql/YUsers.hxx> +#include <mysql/YTables.hxx> +#include <mysql/YViews.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <comphelper/types.hxx> + +using namespace connectivity; +using namespace connectivity::mysql; +using namespace connectivity::sdbcx; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +OMySQLCatalog::OMySQLCatalog(const Reference<XConnection>& _xConnection) + : OCatalog(_xConnection) + , m_xConnection(_xConnection) +{ +} + +void OMySQLCatalog::refreshObjects(const Sequence<OUString>& _sKindOfObject, + ::std::vector<OUString>& _rNames) +{ + Reference<XResultSet> xResult = m_xMetaData->getTables(Any(), "%", "%", _sKindOfObject); + fillNames(xResult, _rNames); +} + +void OMySQLCatalog::refreshTables() +{ + ::std::vector<OUString> aVector; + + Sequence<OUString> sTableTypes{ + "VIEW", "TABLE", "%" + }; // this last one just to be sure to include anything else... + + refreshObjects(sTableTypes, aVector); + + if (m_pTables) + m_pTables->reFill(aVector); + else + m_pTables.reset(new OTables(m_xMetaData, *this, m_aMutex, aVector)); +} + +void OMySQLCatalog::refreshViews() +{ + Sequence<OUString> aTypes{ "VIEW" }; + + // let's simply assume the server is new enough to support views. Current drivers + // as of this writing might not return the proper information in getTableTypes, so + // don't rely on it. + + ::std::vector<OUString> aVector; + refreshObjects(aTypes, aVector); + + if (m_pViews) + m_pViews->reFill(aVector); + else + m_pViews.reset(new OViews(m_xMetaData, *this, m_aMutex, aVector)); +} + +void OMySQLCatalog::refreshGroups() {} + +void OMySQLCatalog::refreshUsers() +{ + ::std::vector<OUString> aVector; + Reference<XStatement> xStmt = m_xConnection->createStatement(); + Reference<XResultSet> xResult = xStmt->executeQuery( + "SELECT grantee FROM information_schema.user_privileges GROUP BY grantee"); + if (xResult.is()) + { + Reference<XRow> xRow(xResult, UNO_QUERY); + while (xResult->next()) + aVector.push_back(xRow->getString(1)); + ::comphelper::disposeComponent(xResult); + } + ::comphelper::disposeComponent(xStmt); + + if (m_pUsers) + m_pUsers->reFill(aVector); + else + m_pUsers.reset(new OUsers(*this, m_aMutex, aVector, m_xConnection, this)); +} + +Any SAL_CALL OMySQLCatalog::queryInterface(const Type& rType) +{ + if (rType == cppu::UnoType<XGroupsSupplier>::get()) + return Any(); + + return OCatalog::queryInterface(rType); +} + +Sequence<Type> SAL_CALL OMySQLCatalog::getTypes() +{ + Sequence<Type> aTypes = OCatalog::getTypes(); + std::vector<Type> aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + const Type* pBegin = aTypes.getConstArray(); + const Type* pEnd = pBegin + aTypes.getLength(); + for (; pBegin != pEnd; ++pBegin) + { + if (*pBegin != cppu::UnoType<XGroupsSupplier>::get()) + { + aOwnTypes.push_back(*pBegin); + } + } + return Sequence<Type>(aOwnTypes.data(), aOwnTypes.size()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysql_jdbc/YColumns.cxx b/connectivity/source/drivers/mysql_jdbc/YColumns.cxx new file mode 100644 index 000000000..54beb77ca --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/YColumns.cxx @@ -0,0 +1,72 @@ +/* -*- 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 <mysql/YColumns.hxx> +#include <TConnection.hxx> + +using namespace ::comphelper; +using namespace connectivity::mysql; +using namespace connectivity::sdbcx; +using namespace connectivity; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +OMySQLColumns::OMySQLColumns(::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector<OUString>& _rVector) + : OColumnsHelper(_rParent, true /*_bCase*/, _rMutex, _rVector, true /*_bUseHardRef*/) +{ +} + +Reference<XPropertySet> OMySQLColumns::createDescriptor() { return new OMySQLColumn; } + +OMySQLColumn::OMySQLColumn() + : connectivity::sdbcx::OColumn(true) +{ + construct(); +} + +void OMySQLColumn::construct() +{ + m_sAutoIncrement = "auto_increment"; + registerProperty( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION), + PROPERTY_ID_AUTOINCREMENTCREATION, 0, &m_sAutoIncrement, + cppu::UnoType<decltype(m_sAutoIncrement)>::get()); +} + +::cppu::IPropertyArrayHelper* OMySQLColumn::createArrayHelper(sal_Int32 /*_nId*/) const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper& SAL_CALL OMySQLColumn::getInfoHelper() +{ + return *OMySQLColumn_PROP::getArrayHelper(isNew() ? 1 : 0); +} + +Sequence<OUString> SAL_CALL OMySQLColumn::getSupportedServiceNames() +{ + return { "com.sun.star.sdbcx.Column" }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysql_jdbc/YDriver.cxx b/connectivity/source/drivers/mysql_jdbc/YDriver.cxx new file mode 100644 index 000000000..0f8357abd --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/YDriver.cxx @@ -0,0 +1,416 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include <mysql/YDriver.hxx> +#include <mysql/YCatalog.hxx> +#include <o3tl/string_view.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbcharset.hxx> +#include <com/sun/star/sdbc/DriverManager.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <TConnection.hxx> +#include <strings.hrc> +#include <resource/sharedresources.hxx> + +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<css::beans::PropertyValue> const& info) +{ + return comphelper::NamedValueCollection::getOrDefault(info, u"JavaDriverClass", + OUString("com.mysql.jdbc.Driver")); +} +} + +ODriverDelegator::ODriverDelegator(const Reference<XComponentContext>& _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<XInterface> 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<XDriver> lcl_loadDriver(const Reference<XComponentContext>& _rxContext, + const OUString& _sUrl) +{ + Reference<XDriverManager2> xDriverAccess = DriverManager::create(_rxContext); + Reference<XDriver> xDriver = xDriverAccess->getDriverByURL(_sUrl); + return xDriver; +} + +Sequence<PropertyValue> lcl_convertProperties(T_DRIVERTYPE _eType, + const Sequence<PropertyValue>& info, + const OUString& _sUrl) +{ + std::vector<PropertyValue> 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<PropertyValue>(aProps.data(), aProps.size()); +} +} + +Reference<XDriver> ODriverDelegator::loadDriver(std::u16string_view url, + const Sequence<PropertyValue>& info) +{ + Reference<XDriver> 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<XConnection> SAL_CALL ODriverDelegator::connect(const OUString& url, + const Sequence<PropertyValue>& info) +{ + Reference<XConnection> xConnection; + if (acceptsURL(url)) + { + Reference<XDriver> xDriver = loadDriver(url, info); + if (xDriver.is()) + { + OUString sCuttedUrl = transformUrl(url); + const T_DRIVERTYPE eType = lcl_getDriverType(url); + Sequence<PropertyValue> 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 OUStringLiteral s_sCharSetOp = u"useUnicode=true&"; + 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<OMetaConnection>(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<PropertyValue> 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<DriverPropertyInfo> SAL_CALL +ODriverDelegator::getPropertyInfo(const OUString& url, const Sequence<PropertyValue>& info) +{ + if (!acceptsURL(url)) + return Sequence<DriverPropertyInfo>(); + + Sequence<OUString> aBoolean{ "0", "1" }; + + std::vector<DriverPropertyInfo> 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<OUString>())); + } + 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<OUString>())); + aDriverInfo.push_back(DriverPropertyInfo( + "NamedPipe", "The name of a pipe to connect to a local MySQL server.", false, + OUString(), Sequence<OUString>())); + } + + return Sequence<DriverPropertyInfo>(aDriverInfo.data(), aDriverInfo.size()); +} + +sal_Int32 SAL_CALL ODriverDelegator::getMajorVersion() { return 1; } + +sal_Int32 SAL_CALL ODriverDelegator::getMinorVersion() { return 0; } + +Reference<XTablesSupplier> SAL_CALL +ODriverDelegator::getDataDefinitionByConnection(const Reference<XConnection>& connection) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(ODriverDelegator_BASE::rBHelper.bDisposed); + + Reference<XTablesSupplier> xTab; + auto pConnection = comphelper::getFromUnoTunnel<OMetaConnection>(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<XConnection> 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<XTablesSupplier> SAL_CALL +ODriverDelegator::getDataDefinitionByURL(const OUString& url, const Sequence<PropertyValue>& 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<OUString> 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<css::uno::Any> const&) +{ + try + { + return cppu::acquire(new connectivity::ODriverDelegator(context)); + } + catch (...) + { + return nullptr; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysql_jdbc/YTable.cxx b/connectivity/source/drivers/mysql_jdbc/YTable.cxx new file mode 100644 index 000000000..3dfdfbdae --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/YTable.cxx @@ -0,0 +1,327 @@ +/* -*- 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 <mysql/YTable.hxx> +#include <mysql/YTables.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <comphelper/property.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/sdbcx/VColumn.hxx> +#include <connectivity/TKeys.hxx> +#include <connectivity/TIndexes.hxx> +#include <mysql/YColumns.hxx> +#include <TConnection.hxx> + +using namespace ::comphelper; +using namespace connectivity::mysql; +using namespace connectivity::sdbcx; +using namespace connectivity; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +namespace connectivity::mysql +{ +namespace +{ +class OMySQLKeysHelper : public OKeysHelper +{ +protected: + virtual OUString getDropForeignKey() const override { return " DROP FOREIGN KEY "; } + +public: + OMySQLKeysHelper(OTableHelper* _pTable, ::osl::Mutex& _rMutex, + const ::std::vector<OUString>& _rVector) + : OKeysHelper(_pTable, _rMutex, _rVector) + { + } +}; +} +} + +OMySQLTable::OMySQLTable(sdbcx::OCollection* _pTables, const Reference<XConnection>& _xConnection) + : OTableHelper(_pTables, _xConnection, true) +{ + // we create a new table here, so we should have all the rights or ;-) + m_nPrivileges = Privilege::DROP | Privilege::REFERENCE | Privilege::ALTER | Privilege::CREATE + | Privilege::READ | Privilege::DELETE | Privilege::UPDATE | Privilege::INSERT + | Privilege::SELECT; + construct(); +} + +OMySQLTable::OMySQLTable(sdbcx::OCollection* _pTables, const Reference<XConnection>& _xConnection, + const OUString& Name, const OUString& Type, const OUString& Description, + const OUString& SchemaName, const OUString& CatalogName, + sal_Int32 _nPrivileges) + : OTableHelper(_pTables, _xConnection, true, Name, Type, Description, SchemaName, CatalogName) + , m_nPrivileges(_nPrivileges) +{ + construct(); +} + +void OMySQLTable::construct() +{ + OTableHelper::construct(); + if (!isNew()) + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRIVILEGES), + PROPERTY_ID_PRIVILEGES, PropertyAttribute::READONLY, &m_nPrivileges, + cppu::UnoType<decltype(m_nPrivileges)>::get()); +} + +::cppu::IPropertyArrayHelper* OMySQLTable::createArrayHelper(sal_Int32 /*_nId*/) const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper& OMySQLTable::getInfoHelper() +{ + return *static_cast<OMySQLTable_PROP*>(this)->getArrayHelper(isNew() ? 1 : 0); +} + +sdbcx::OCollection* OMySQLTable::createColumns(const ::std::vector<OUString>& _rNames) +{ + OMySQLColumns* pColumns = new OMySQLColumns(*this, m_aMutex, _rNames); + pColumns->setParent(this); + return pColumns; +} + +sdbcx::OCollection* OMySQLTable::createKeys(const ::std::vector<OUString>& _rNames) +{ + return new OMySQLKeysHelper(this, m_aMutex, _rNames); +} + +sdbcx::OCollection* OMySQLTable::createIndexes(const ::std::vector<OUString>& _rNames) +{ + return new OIndexesHelper(this, m_aMutex, _rNames); +} + +const Sequence<sal_Int8>& OMySQLTable::getUnoTunnelId() +{ + static const comphelper::UnoIdInit implId; + return implId.getSeq(); +} + +// css::lang::XUnoTunnel + +sal_Int64 OMySQLTable::getSomething(const Sequence<sal_Int8>& rId) +{ + return comphelper::getSomethingImpl(rId, this, + comphelper::FallbackToGetSomethingOf<OTable_TYPEDEF>{}); +} + +// XAlterTable +void SAL_CALL OMySQLTable::alterColumnByName(const OUString& colName, + const Reference<XPropertySet>& descriptor) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed( +#ifdef __GNUC__ + ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed +#else + rBHelper.bDisposed +#endif + ); + + if (!m_xColumns || !m_xColumns->hasByName(colName)) + throw NoSuchElementException(colName, *this); + + if (!isNew()) + { + // first we have to check what should be altered + Reference<XPropertySet> xProp; + m_xColumns->getByName(colName) >>= xProp; + // first check the types + sal_Int32 nOldType = 0, nNewType = 0, nOldPrec = 0, nNewPrec = 0, nOldScale = 0, + nNewScale = 0; + + ::dbtools::OPropertyMap& rProp = OMetaConnection::getPropMap(); + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nOldType; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nNewType; + // and precisions and scale + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_PRECISION)) >>= nOldPrec; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_PRECISION)) >>= nNewPrec; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_SCALE)) >>= nOldScale; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_SCALE)) >>= nNewScale; + // second: check the "is nullable" value + sal_Int32 nOldNullable = 0, nNewNullable = 0; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nOldNullable; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nNewNullable; + + // check also the auto_increment + bool bOldAutoIncrement = false, bAutoIncrement = false; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) + >>= bOldAutoIncrement; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) + >>= bAutoIncrement; + bool bColumnNameChanged = false; + OUString sOldDesc, sNewDesc; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DESCRIPTION)) >>= sOldDesc; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DESCRIPTION)) >>= sNewDesc; + + if (nOldType != nNewType || nOldPrec != nNewPrec || nOldScale != nNewScale + || nNewNullable != nOldNullable || bOldAutoIncrement != bAutoIncrement + || sOldDesc != sNewDesc) + { + // special handling because they changed the type names to distinguish + // if a column should be an auto_increment one + if (bOldAutoIncrement != bAutoIncrement) + { + OUString sTypeName; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME)) + >>= sTypeName; + + static const char s_sAutoIncrement[] = "auto_increment"; + if (bAutoIncrement) + { + if (sTypeName.indexOf(s_sAutoIncrement) == -1) + { + sTypeName += OUString::Concat(" ") + s_sAutoIncrement; + descriptor->setPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME), + Any(sTypeName)); + } + } + else + { + if (!sTypeName.isEmpty()) + { + sal_Int32 nIndex = sTypeName.indexOf(s_sAutoIncrement); + if (nIndex != -1) + { + sTypeName = sTypeName.copy(0, nIndex); + descriptor->setPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME), + Any(sTypeName)); + } + } + } + } + alterColumnType(nNewType, colName, descriptor); + bColumnNameChanged = true; + } + + // third: check the default values + OUString sNewDefault, sOldDefault; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) >>= sOldDefault; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) + >>= sNewDefault; + + if (!sOldDefault.isEmpty()) + { + dropDefaultValue(colName); + if (!sNewDefault.isEmpty() && sOldDefault != sNewDefault) + alterDefaultValue(sNewDefault, colName); + } + else if (!sNewDefault.isEmpty()) + alterDefaultValue(sNewDefault, colName); + + // now we should look if the name of the column changed + OUString sNewColumnName; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_NAME)) >>= sNewColumnName; + if (!sNewColumnName.equalsIgnoreAsciiCase(colName) && !bColumnNameChanged) + { + const OUString sQuote = getMetaData()->getIdentifierQuoteString(); + OUString sSql = getAlterTableColumnPart() + " CHANGE " + + ::dbtools::quoteName(sQuote, colName) + " " + + OTables::adjustSQL(::dbtools::createStandardColumnPart( + descriptor, getConnection(), static_cast<OTables*>(m_pTables), + getTypeCreatePattern())); + executeStatement(sSql); + } + m_xColumns->refresh(); + } + else + { + if (m_xColumns) + { + m_xColumns->dropByName(colName); + m_xColumns->appendByDescriptor(descriptor); + } + } +} + +void OMySQLTable::alterColumnType(sal_Int32 nNewType, const OUString& _rColName, + const Reference<XPropertySet>& _xDescriptor) +{ + const OUString sQuote = getMetaData()->getIdentifierQuoteString(); + OUString sSql + = getAlterTableColumnPart() + " CHANGE " + ::dbtools::quoteName(sQuote, _rColName) + " "; + + rtl::Reference<OColumn> pColumn = new OColumn(true); + ::comphelper::copyProperties(_xDescriptor, pColumn); + pColumn->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE), + Any(nNewType)); + + sSql += OTables::adjustSQL(::dbtools::createStandardColumnPart( + pColumn, getConnection(), static_cast<OTables*>(m_pTables), getTypeCreatePattern())); + executeStatement(sSql); +} + +OUString OMySQLTable::getTypeCreatePattern() const { return "(M,D)"; } + +void OMySQLTable::alterDefaultValue(std::u16string_view _sNewDefault, const OUString& _rColName) +{ + const OUString sQuote = getMetaData()->getIdentifierQuoteString(); + OUString sSql = getAlterTableColumnPart() + " ALTER " + ::dbtools::quoteName(sQuote, _rColName) + + " SET DEFAULT '" + _sNewDefault + "'"; + + executeStatement(sSql); +} + +void OMySQLTable::dropDefaultValue(const OUString& _rColName) +{ + const OUString sQuote = getMetaData()->getIdentifierQuoteString(); + OUString sSql = getAlterTableColumnPart() + " ALTER " + ::dbtools::quoteName(sQuote, _rColName) + + " DROP DEFAULT"; + + executeStatement(sSql); +} + +OUString OMySQLTable::getAlterTableColumnPart() const +{ + OUString sSql("ALTER TABLE "); + + OUString sComposedName( + ::dbtools::composeTableName(getMetaData(), m_CatalogName, m_SchemaName, m_Name, true, + ::dbtools::EComposeRule::InTableDefinitions)); + sSql += sComposedName; + + return sSql; +} + +void OMySQLTable::executeStatement(const OUString& _rStatement) +{ + OUString sSQL = _rStatement; + if (sSQL.endsWith(",")) + sSQL = sSQL.replaceAt(sSQL.getLength() - 1, 1, u")"); + + Reference<XStatement> xStmt = getConnection()->createStatement(); + if (xStmt.is()) + { + xStmt->execute(sSQL); + ::comphelper::disposeComponent(xStmt); + } +} + +OUString OMySQLTable::getRenameStart() const { return "RENAME TABLE "; } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysql_jdbc/YTables.cxx b/connectivity/source/drivers/mysql_jdbc/YTables.cxx new file mode 100644 index 000000000..c28f8e44e --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/YTables.cxx @@ -0,0 +1,208 @@ +/* -*- 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 <mysql/YTables.hxx> +#include <mysql/YViews.hxx> +#include <mysql/YTable.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <mysql/YCatalog.hxx> +#include <connectivity/dbtools.hxx> +#include <comphelper/types.hxx> +#include <TConnection.hxx> + +using namespace ::comphelper; +using namespace connectivity; +using namespace ::cppu; +using namespace connectivity::mysql; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace dbtools; + +sdbcx::ObjectType OTables::createObject(const OUString& _rName) +{ + OUString sCatalog, sSchema, sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData, _rName, sCatalog, sSchema, sTable, + ::dbtools::EComposeRule::InDataManipulation); + + Sequence<OUString> sTableTypes{ + "VIEW", "TABLE", "%" + }; // this last one just to be sure to include anything else... + + Any aCatalog; + if (!sCatalog.isEmpty()) + aCatalog <<= sCatalog; + Reference<XResultSet> xResult = m_xMetaData->getTables(aCatalog, sSchema, sTable, sTableTypes); + + sdbcx::ObjectType xRet; + if (xResult.is()) + { + Reference<XRow> xRow(xResult, UNO_QUERY); + if (xResult->next()) // there can be only one table with this name + { + sal_Int32 const nPrivileges = Privilege::DROP | Privilege::REFERENCE | Privilege::ALTER + | Privilege::CREATE | Privilege::READ | Privilege::DELETE + | Privilege::UPDATE | Privilege::INSERT + | Privilege::SELECT; + + xRet = new OMySQLTable(this, static_cast<OMySQLCatalog&>(m_rParent).getConnection(), + sTable, xRow->getString(4), xRow->getString(5), sSchema, + sCatalog, nPrivileges); + } + ::comphelper::disposeComponent(xResult); + } + + return xRet; +} + +void OTables::impl_refresh() { static_cast<OMySQLCatalog&>(m_rParent).refreshTables(); } + +void OTables::disposing() +{ + m_xMetaData.clear(); + OCollection::disposing(); +} + +Reference<XPropertySet> OTables::createDescriptor() +{ + return new OMySQLTable(this, static_cast<OMySQLCatalog&>(m_rParent).getConnection()); +} + +// XAppend +sdbcx::ObjectType OTables::appendObject(const OUString& _rForName, + const Reference<XPropertySet>& descriptor) +{ + createTable(descriptor); + return createObject(_rForName); +} + +// XDrop +void OTables::dropObject(sal_Int32 _nPos, const OUString& _sElementName) +{ + Reference<XInterface> xObject(getObject(_nPos)); + bool bIsNew = connectivity::sdbcx::ODescriptor::isNew(xObject); + if (bIsNew) + return; + + Reference<XConnection> xConnection = static_cast<OMySQLCatalog&>(m_rParent).getConnection(); + + OUString sCatalog, sSchema, sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData, _sElementName, sCatalog, sSchema, sTable, + ::dbtools::EComposeRule::InDataManipulation); + + OUString aSql("DROP "); + + Reference<XPropertySet> xProp(xObject, UNO_QUERY); + bool bIsView = xProp.is() + && ::comphelper::getString(xProp->getPropertyValue( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))) + == "VIEW"; + if (bIsView) // here we have a view + aSql += "VIEW "; + else + aSql += "TABLE "; + + OUString sComposedName(::dbtools::composeTableName( + m_xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InDataManipulation)); + aSql += sComposedName; + Reference<XStatement> xStmt = xConnection->createStatement(); + if (xStmt.is()) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } + // if no exception was thrown we must delete it from the views + if (bIsView) + { + OViews* pViews + = static_cast<OViews*>(static_cast<OMySQLCatalog&>(m_rParent).getPrivateViews()); + if (pViews && pViews->hasByName(_sElementName)) + pViews->dropByNameImpl(_sElementName); + } +} + +OUString OTables::adjustSQL(const OUString& _sSql) +{ + OUString sSQL = _sSql; + static const char s_sUNSIGNED[] = "UNSIGNED"; + sal_Int32 nIndex = sSQL.indexOf(s_sUNSIGNED); + while (nIndex != -1) + { + sal_Int32 nParen = sSQL.indexOf(')', nIndex); + sal_Int32 nPos = nIndex + strlen(s_sUNSIGNED); + OUString sNewUnsigned(sSQL.copy(nPos, nParen - nPos + 1)); + sSQL = sSQL.replaceAt(nIndex, strlen(s_sUNSIGNED) + sNewUnsigned.getLength(), + rtl::OUStringConcatenation(sNewUnsigned + s_sUNSIGNED)); + nIndex = sSQL.indexOf(s_sUNSIGNED, nIndex + strlen(s_sUNSIGNED) + sNewUnsigned.getLength()); + } + return sSQL; +} + +void OTables::createTable(const Reference<XPropertySet>& descriptor) +{ + const Reference<XConnection> xConnection + = static_cast<OMySQLCatalog&>(m_rParent).getConnection(); + const OUString aSql + = adjustSQL(::dbtools::createSqlCreateTableStatement(descriptor, xConnection)); + Reference<XStatement> xStmt = xConnection->createStatement(); + if (xStmt.is()) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } +} + +void OTables::appendNew(const OUString& _rsNewTable) +{ + insertElement(_rsNewTable, nullptr); + + // notify our container listeners + ContainerEvent aEvent(static_cast<XContainer*>(this), Any(_rsNewTable), Any(), Any()); + OInterfaceIteratorHelper3 aListenerLoop(m_aContainerListeners); + while (aListenerLoop.hasMoreElements()) + aListenerLoop.next()->elementInserted(aEvent); +} + +OUString OTables::getNameForObject(const sdbcx::ObjectType& _xObject) +{ + OSL_ENSURE(_xObject.is(), "OTables::getNameForObject: Object is NULL!"); + return ::dbtools::composeTableName(m_xMetaData, _xObject, + ::dbtools::EComposeRule::InDataManipulation, false); +} + +void OTables::addComment(const Reference<XPropertySet>& descriptor, OUStringBuffer& _rOut) +{ + OUString sDesc; + descriptor->getPropertyValue( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION)) + >>= sDesc; + if (!sDesc.isEmpty()) + { + _rOut.append(" COMMENT '"); + _rOut.append(sDesc); + _rOut.append("'"); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysql_jdbc/YUser.cxx b/connectivity/source/drivers/mysql_jdbc/YUser.cxx new file mode 100644 index 000000000..b683fe2b2 --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/YUser.cxx @@ -0,0 +1,325 @@ +/* -*- 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 <mysql/YUser.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <connectivity/dbtools.hxx> +#include <connectivity/dbexception.hxx> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <com/sun/star/sdbcx/PrivilegeObject.hpp> +#include <TConnection.hxx> +#include <strings.hrc> +#include <comphelper/types.hxx> + +using namespace connectivity; +using namespace connectivity::mysql; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +OMySQLUser::OMySQLUser(const css::uno::Reference<css::sdbc::XConnection>& _xConnection) + : connectivity::sdbcx::OUser(true) + , m_xConnection(_xConnection) +{ + construct(); +} + +OMySQLUser::OMySQLUser(const css::uno::Reference<css::sdbc::XConnection>& _xConnection, + const OUString& Name) + : connectivity::sdbcx::OUser(Name, true) + , m_xConnection(_xConnection) +{ + construct(); +} + +void OMySQLUser::refreshGroups() {} + +OUserExtend::OUserExtend(const css::uno::Reference<css::sdbc::XConnection>& _xConnection) + : OMySQLUser(_xConnection) +{ + construct(); +} + +void OUserExtend::construct() +{ + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), + PROPERTY_ID_PASSWORD, 0, &m_Password, ::cppu::UnoType<OUString>::get()); +} + +cppu::IPropertyArrayHelper* OUserExtend::createArrayHelper() const +{ + Sequence<Property> aProps; + describeProperties(aProps); + return new cppu::OPropertyArrayHelper(aProps); +} + +cppu::IPropertyArrayHelper& OUserExtend::getInfoHelper() +{ + return *OUserExtend_PROP::getArrayHelper(); +} +typedef connectivity::sdbcx::OUser_BASE OUser_BASE_RBHELPER; + +sal_Int32 SAL_CALL OMySQLUser::getPrivileges(const OUString& objName, sal_Int32 objType) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed); + + sal_Int32 nRights, nRightsWithGrant; + findPrivilegesAndGrantPrivileges(objName, objType, nRights, nRightsWithGrant); + return nRights; +} + +void OMySQLUser::findPrivilegesAndGrantPrivileges(const OUString& objName, sal_Int32 objType, + sal_Int32& nRights, sal_Int32& nRightsWithGrant) +{ + nRightsWithGrant = nRights = 0; + // first we need to create the sql stmt to select the privs + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + OUString sCatalog, sSchema, sTable; + ::dbtools::qualifiedNameComponents(xMeta, objName, sCatalog, sSchema, sTable, + ::dbtools::EComposeRule::InDataManipulation); + Reference<XResultSet> xRes; + switch (objType) + { + case PrivilegeObject::TABLE: + case PrivilegeObject::VIEW: + { + Any aCatalog; + if (!sCatalog.isEmpty()) + aCatalog <<= sCatalog; + xRes = xMeta->getTablePrivileges(aCatalog, sSchema, sTable); + } + break; + + case PrivilegeObject::COLUMN: + { + Any aCatalog; + if (!sCatalog.isEmpty()) + aCatalog <<= sCatalog; + xRes = xMeta->getColumnPrivileges(aCatalog, sSchema, sTable, "%"); + } + break; + } + + if (!xRes.is()) + return; + + static const char sYes[] = "YES"; + + nRightsWithGrant = nRights = 0; + + Reference<XRow> xCurrentRow(xRes, UNO_QUERY); + while (xCurrentRow.is() && xRes->next()) + { + OUString sGrantee = xCurrentRow->getString(5); + OUString sPrivilege = xCurrentRow->getString(6); + OUString sGrantable = xCurrentRow->getString(7); + + if (!m_Name.equalsIgnoreAsciiCase(sGrantee)) + continue; + + if (sPrivilege.equalsIgnoreAsciiCase("SELECT")) + { + nRights |= Privilege::SELECT; + if (sGrantable.equalsIgnoreAsciiCase(sYes)) + nRightsWithGrant |= Privilege::SELECT; + } + else if (sPrivilege.equalsIgnoreAsciiCase("INSERT")) + { + nRights |= Privilege::INSERT; + if (sGrantable.equalsIgnoreAsciiCase(sYes)) + nRightsWithGrant |= Privilege::INSERT; + } + else if (sPrivilege.equalsIgnoreAsciiCase("UPDATE")) + { + nRights |= Privilege::UPDATE; + if (sGrantable.equalsIgnoreAsciiCase(sYes)) + nRightsWithGrant |= Privilege::UPDATE; + } + else if (sPrivilege.equalsIgnoreAsciiCase("DELETE")) + { + nRights |= Privilege::DELETE; + if (sGrantable.equalsIgnoreAsciiCase(sYes)) + nRightsWithGrant |= Privilege::DELETE; + } + else if (sPrivilege.equalsIgnoreAsciiCase("READ")) + { + nRights |= Privilege::READ; + if (sGrantable.equalsIgnoreAsciiCase(sYes)) + nRightsWithGrant |= Privilege::READ; + } + else if (sPrivilege.equalsIgnoreAsciiCase("CREATE")) + { + nRights |= Privilege::CREATE; + if (sGrantable.equalsIgnoreAsciiCase(sYes)) + nRightsWithGrant |= Privilege::CREATE; + } + else if (sPrivilege.equalsIgnoreAsciiCase("ALTER")) + { + nRights |= Privilege::ALTER; + if (sGrantable.equalsIgnoreAsciiCase(sYes)) + nRightsWithGrant |= Privilege::ALTER; + } + else if (sPrivilege.equalsIgnoreAsciiCase("REFERENCES")) + { + nRights |= Privilege::REFERENCE; + if (sGrantable.equalsIgnoreAsciiCase(sYes)) + nRightsWithGrant |= Privilege::REFERENCE; + } + else if (sPrivilege.equalsIgnoreAsciiCase("DROP")) + { + nRights |= Privilege::DROP; + if (sGrantable.equalsIgnoreAsciiCase(sYes)) + nRightsWithGrant |= Privilege::DROP; + } + } + ::comphelper::disposeComponent(xRes); +} + +sal_Int32 SAL_CALL OMySQLUser::getGrantablePrivileges(const OUString& objName, sal_Int32 objType) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed); + + sal_Int32 nRights, nRightsWithGrant; + findPrivilegesAndGrantPrivileges(objName, objType, nRights, nRightsWithGrant); + return nRightsWithGrant; +} + +void SAL_CALL OMySQLUser::grantPrivileges(const OUString& objName, sal_Int32 objType, + sal_Int32 objPrivileges) +{ + if (objType != PrivilegeObject::TABLE) + { + ::connectivity::SharedResources aResources; + const OUString sError(aResources.getResourceString(STR_PRIVILEGE_NOT_GRANTED)); + ::dbtools::throwGenericSQLException(sError, *this); + } // if ( objType != PrivilegeObject::TABLE ) + + ::osl::MutexGuard aGuard(m_aMutex); + + OUString sPrivs = getPrivilegeString(objPrivileges); + if (sPrivs.isEmpty()) + return; + + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + OUString sGrant + = "GRANT " + sPrivs + " ON " + + ::dbtools::quoteTableName(xMeta, objName, ::dbtools::EComposeRule::InDataManipulation) + + " TO " + m_Name; + + Reference<XStatement> xStmt = m_xConnection->createStatement(); + if (xStmt.is()) + xStmt->execute(sGrant); + ::comphelper::disposeComponent(xStmt); +} + +void SAL_CALL OMySQLUser::revokePrivileges(const OUString& objName, sal_Int32 objType, + sal_Int32 objPrivileges) +{ + if (objType != PrivilegeObject::TABLE) + { + ::connectivity::SharedResources aResources; + const OUString sError(aResources.getResourceString(STR_PRIVILEGE_NOT_REVOKED)); + ::dbtools::throwGenericSQLException(sError, *this); + } + + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed); + OUString sPrivs = getPrivilegeString(objPrivileges); + if (sPrivs.isEmpty()) + return; + + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + OUString sGrant + = "REVOKE " + sPrivs + " ON " + + ::dbtools::quoteTableName(xMeta, objName, ::dbtools::EComposeRule::InDataManipulation) + + " FROM " + m_Name; + + Reference<XStatement> xStmt = m_xConnection->createStatement(); + if (xStmt.is()) + xStmt->execute(sGrant); + ::comphelper::disposeComponent(xStmt); +} + +// XUser +void SAL_CALL OMySQLUser::changePassword(const OUString& /*oldPassword*/, + const OUString& newPassword) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed); + OUString sAlterPwd = "SET PASSWORD FOR " + m_Name + "@\"%\" = PASSWORD('" + newPassword + "')"; + + Reference<XStatement> xStmt = m_xConnection->createStatement(); + if (xStmt.is()) + { + xStmt->execute(sAlterPwd); + ::comphelper::disposeComponent(xStmt); + } +} + +OUString OMySQLUser::getPrivilegeString(sal_Int32 nRights) +{ + OUString sPrivs; + if ((nRights & Privilege::INSERT) == Privilege::INSERT) + sPrivs += "INSERT"; + + if ((nRights & Privilege::DELETE) == Privilege::DELETE) + { + if (!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "DELETE"; + } + + if ((nRights & Privilege::UPDATE) == Privilege::UPDATE) + { + if (!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "UPDATE"; + } + + if ((nRights & Privilege::ALTER) == Privilege::ALTER) + { + if (!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "ALTER"; + } + + if ((nRights & Privilege::SELECT) == Privilege::SELECT) + { + if (!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "SELECT"; + } + + if ((nRights & Privilege::REFERENCE) == Privilege::REFERENCE) + { + if (!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "REFERENCES"; + } + + return sPrivs; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysql_jdbc/YUsers.cxx b/connectivity/source/drivers/mysql_jdbc/YUsers.cxx new file mode 100644 index 000000000..ed33cb0e2 --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/YUsers.cxx @@ -0,0 +1,91 @@ +/* -*- 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 <mysql/YUsers.hxx> +#include <mysql/YUser.hxx> +#include <connectivity/sdbcx/IRefreshable.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbtools.hxx> +#include <TConnection.hxx> + +using namespace ::comphelper; +using namespace connectivity; +using namespace connectivity::mysql; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +OUsers::OUsers(::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector<OUString>& _rVector, + const css::uno::Reference<css::sdbc::XConnection>& _xConnection, + connectivity::sdbcx::IRefreshableUsers* _pParent) + : sdbcx::OCollection(_rParent, true, _rMutex, _rVector) + , m_xConnection(_xConnection) + , m_pParent(_pParent) +{ +} + +sdbcx::ObjectType OUsers::createObject(const OUString& _rName) +{ + return new OMySQLUser(m_xConnection, _rName); +} + +void OUsers::impl_refresh() { m_pParent->refreshUsers(); } + +Reference<XPropertySet> OUsers::createDescriptor() { return new OUserExtend(m_xConnection); } + +// XAppend +sdbcx::ObjectType OUsers::appendObject(const OUString& _rForName, + const Reference<XPropertySet>& descriptor) +{ + OUString aSql("GRANT USAGE ON * TO "); + OUString aQuote = m_xConnection->getMetaData()->getIdentifierQuoteString(); + aSql += ::dbtools::quoteName(aQuote, _rForName) + " @\"%\" "; + OUString sPassword; + descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) + >>= sPassword; + if (!sPassword.isEmpty()) + { + aSql += " IDENTIFIED BY '" + sPassword + "'"; + } + + Reference<XStatement> xStmt = m_xConnection->createStatement(); + if (xStmt.is()) + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + + return createObject(_rForName); +} + +// XDrop +void OUsers::dropObject(sal_Int32 /*_nPos*/, const OUString& _sElementName) +{ + OUString aSql("DROP USER "); + OUString aQuote = m_xConnection->getMetaData()->getIdentifierQuoteString(); + aSql += ::dbtools::quoteName(aQuote, _sElementName); + + Reference<XStatement> xStmt = m_xConnection->createStatement(); + if (xStmt.is()) + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysql_jdbc/YViews.cxx b/connectivity/source/drivers/mysql_jdbc/YViews.cxx new file mode 100644 index 000000000..3dba721c0 --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/YViews.cxx @@ -0,0 +1,138 @@ +/* -*- 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 <mysql/YViews.hxx> +#include <mysql/YTables.hxx> +#include <mysql/YCatalog.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/sdbcx/VView.hxx> +#include <comphelper/types.hxx> +#include <TConnection.hxx> + +using namespace ::comphelper; + +using namespace ::cppu; +using namespace connectivity; +using namespace connectivity::mysql; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace dbtools; +typedef connectivity::sdbcx::OCollection OCollection_TYPE; + +sdbcx::ObjectType OViews::createObject(const OUString& _rName) +{ + OUString sCatalog, sSchema, sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData, _rName, sCatalog, sSchema, sTable, + ::dbtools::EComposeRule::InDataManipulation); + return new ::connectivity::sdbcx::OView(isCaseSensitive(), sTable, m_xMetaData, OUString(), + sSchema, sCatalog); +} + +void OViews::impl_refresh() { static_cast<OMySQLCatalog&>(m_rParent).refreshTables(); } + +void OViews::disposing() +{ + m_xMetaData.clear(); + OCollection::disposing(); +} + +Reference<XPropertySet> OViews::createDescriptor() +{ + Reference<XConnection> xConnection = static_cast<OMySQLCatalog&>(m_rParent).getConnection(); + rtl::Reference<connectivity::sdbcx::OView> pNew + = new connectivity::sdbcx::OView(true, xConnection->getMetaData()); + return pNew; +} + +// XAppend +sdbcx::ObjectType OViews::appendObject(const OUString& _rForName, + const Reference<XPropertySet>& descriptor) +{ + createView(descriptor); + return createObject(_rForName); +} + +// XDrop +void OViews::dropObject(sal_Int32 _nPos, const OUString& /*_sElementName*/) +{ + if (m_bInDrop) + return; + + Reference<XInterface> xObject(getObject(_nPos)); + bool bIsNew = connectivity::sdbcx::ODescriptor::isNew(xObject); + if (bIsNew) + return; + + OUString aSql("DROP VIEW"); + + Reference<XPropertySet> xProp(xObject, UNO_QUERY); + aSql += ::dbtools::composeTableName(m_xMetaData, xProp, + ::dbtools::EComposeRule::InTableDefinitions, true); + + Reference<XConnection> xConnection = static_cast<OMySQLCatalog&>(m_rParent).getConnection(); + Reference<XStatement> xStmt = xConnection->createStatement(); + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); +} + +void OViews::dropByNameImpl(const OUString& elementName) +{ + m_bInDrop = true; + OCollection_TYPE::dropByName(elementName); + m_bInDrop = false; +} + +void OViews::createView(const Reference<XPropertySet>& descriptor) +{ + Reference<XConnection> xConnection = static_cast<OMySQLCatalog&>(m_rParent).getConnection(); + + OUString aSql("CREATE VIEW "); + OUString sCommand; + + aSql += ::dbtools::composeTableName(m_xMetaData, descriptor, + ::dbtools::EComposeRule::InTableDefinitions, true) + + " AS "; + + descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_COMMAND)) + >>= sCommand; + aSql += sCommand; + + Reference<XStatement> xStmt = xConnection->createStatement(); + if (xStmt.is()) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } + + // insert the new view also in the tables collection + OTables* pTables + = static_cast<OTables*>(static_cast<OMySQLCatalog&>(m_rParent).getPrivateTables()); + if (pTables) + { + OUString sName = ::dbtools::composeTableName( + m_xMetaData, descriptor, ::dbtools::EComposeRule::InDataManipulation, false); + pTables->appendNew(sName); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysql_jdbc/mysql_jdbc.component b/connectivity/source/drivers/mysql_jdbc/mysql_jdbc.component new file mode 100644 index 000000000..7ecd7a441 --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/mysql_jdbc.component @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="org.openoffice.comp.drivers.MySQL.Driver" + constructor="connectivity_mysql_ODriverDelegator_get_implementation"> + <service name="com.sun.star.sdbc.Driver"/> + <service name="com.sun.star.sdbcx.Driver"/> + </implementation> +</component> |