From 940b4d1848e8c70ab7642901a68594e8016caffc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 18:51:28 +0200 Subject: Adding upstream version 1:7.0.4. Signed-off-by: Daniel Baumann --- connectivity/source/drivers/mysqlc/DataAccess.xcu | 35 + .../source/drivers/mysqlc/mysqlc.component | 15 + .../source/drivers/mysqlc/mysqlc_connection.cxx | 489 +++++++++ .../source/drivers/mysqlc/mysqlc_connection.hxx | 187 ++++ .../drivers/mysqlc/mysqlc_databasemetadata.cxx | 1076 +++++++++++++++++++ .../drivers/mysqlc/mysqlc_databasemetadata.hxx | 239 +++++ .../source/drivers/mysqlc/mysqlc_driver.cxx | 139 +++ .../source/drivers/mysqlc/mysqlc_driver.hxx | 94 ++ .../source/drivers/mysqlc/mysqlc_general.cxx | 340 ++++++ .../source/drivers/mysqlc/mysqlc_general.hxx | 119 +++ .../drivers/mysqlc/mysqlc_prepared_resultset.cxx | 1084 +++++++++++++++++++ .../drivers/mysqlc/mysqlc_prepared_resultset.hxx | 257 +++++ .../drivers/mysqlc/mysqlc_preparedstatement.cxx | 578 ++++++++++ .../drivers/mysqlc/mysqlc_preparedstatement.hxx | 161 +++ .../source/drivers/mysqlc/mysqlc_propertyids.hxx | 49 + .../source/drivers/mysqlc/mysqlc_resultset.cxx | 1114 ++++++++++++++++++++ .../source/drivers/mysqlc/mysqlc_resultset.hxx | 279 +++++ .../drivers/mysqlc/mysqlc_resultsetmetadata.cxx | 211 ++++ .../drivers/mysqlc/mysqlc_resultsetmetadata.hxx | 109 ++ .../source/drivers/mysqlc/mysqlc_services.cxx | 110 ++ .../source/drivers/mysqlc/mysqlc_statement.cxx | 404 +++++++ .../source/drivers/mysqlc/mysqlc_statement.hxx | 180 ++++ .../source/drivers/mysqlc/mysqlc_subcomponent.hxx | 160 +++ .../source/drivers/mysqlc/mysqlc_types.cxx | 679 ++++++++++++ .../source/drivers/mysqlc/mysqlc_types.hxx | 48 + 25 files changed, 8156 insertions(+) create mode 100644 connectivity/source/drivers/mysqlc/DataAccess.xcu create mode 100644 connectivity/source/drivers/mysqlc/mysqlc.component create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_connection.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_connection.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_driver.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_driver.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_general.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_general.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_propertyids.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_services.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_statement.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_statement.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_subcomponent.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_types.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_types.hxx (limited to 'connectivity/source/drivers/mysqlc') diff --git a/connectivity/source/drivers/mysqlc/DataAccess.xcu b/connectivity/source/drivers/mysqlc/DataAccess.xcu new file mode 100644 index 000000000..2b652ec87 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/DataAccess.xcu @@ -0,0 +1,35 @@ + + + + + + org.openoffice.comp.connectivity.mysql_native.Driver + + + MySQL native driver + + + MySQL native driver + + + sdbc:mysqlc: + + + + diff --git a/connectivity/source/drivers/mysqlc/mysqlc.component b/connectivity/source/drivers/mysqlc/mysqlc.component new file mode 100644 index 000000000..e4295110f --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc.component @@ -0,0 +1,15 @@ + + + + + + + diff --git a/connectivity/source/drivers/mysqlc/mysqlc_connection.cxx b/connectivity/source/drivers/mysqlc/mysqlc_connection.cxx new file mode 100644 index 000000000..600e131b8 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_connection.cxx @@ -0,0 +1,489 @@ +/* -*- 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 "mysqlc_connection.hxx" +#include "mysqlc_databasemetadata.hxx" + +#include "mysqlc_driver.hxx" +#include "mysqlc_statement.hxx" +#include "mysqlc_preparedstatement.hxx" +#include "mysqlc_general.hxx" + +#include + +#include +#include + +using namespace connectivity::mysqlc; + +using namespace com::sun::star::uno; +using namespace com::sun::star::container; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; +using ::osl::MutexGuard; + +#define MYSQLC_URI_PREFIX "sdbc:mysqlc:" + +namespace +{ +void lcl_executeUpdate(MYSQL* pMySql, const OString& sql) +{ + mysql_real_query(pMySql, sql.getStr(), sql.getLength()); + // TODO handle error +} +} + +OConnection::OConnection(MysqlCDriver& _rDriver) + : OMetaConnection_BASE(m_aMutex) + , m_mysql() + , m_xMetaData(nullptr) + , m_xDriver(&_rDriver) +{ +} + +OConnection::~OConnection() +{ + if (!isClosed()) + { + close(); + } +} + +void OConnection::construct(const OUString& url, const Sequence& info) +{ + MutexGuard aGuard(m_aMutex); + + mysql_library_init(0, nullptr, nullptr); + mysql_init(&m_mysql); + + // use TCP as connection + mysql_protocol_type protocol = MYSQL_PROTOCOL_TCP; + mysql_options(&m_mysql, MYSQL_OPT_PROTOCOL, &protocol); + OString charset_name{ "utf8mb4" }; + mysql_options(&m_mysql, MYSQL_SET_CHARSET_NAME, charset_name.getStr()); + + sal_Int32 nIndex; + OUString token; + OUString aHostName("localhost"); + sal_Int32 nPort = 3306; + OUString aDbName; + + m_settings.encoding = MysqlCDriver::getDefaultEncoding(); + + // parse url. Url has the following format: + // external server: sdbc:mysqlc:[hostname]:[port]/[dbname] + + if (url.startsWith(MYSQLC_URI_PREFIX)) + { + nIndex = 12; + } + else + { + // sdbc:mysql:mysqlc:[hostname]:[port]/[dbname] + nIndex = 18; + } + + token = url.getToken(0, '/', nIndex); + if (!token.isEmpty()) + { + sal_Int32 nIndex1 = 0; + OUString hostandport = token.getToken(0, ':', nIndex1); + if (!hostandport.isEmpty()) + { + aHostName = hostandport; + hostandport = token.getToken(0, ':', nIndex1); + if (!hostandport.isEmpty() && nIndex1) + { + nPort = hostandport.toInt32(); + } + token = url.getToken(0, '/', nIndex); + if (!token.isEmpty() && nIndex) + { + aDbName = token; + } + } + } + + // get user and password for mysql connection + const PropertyValue* pIter = info.getConstArray(); + const PropertyValue* pEnd = pIter + info.getLength(); + OUString aUser, aPass, sUnixSocket, sNamedPipe; + bool unixSocketPassed = false; + bool namedPipePassed = false; + + m_settings.connectionURL = url; + for (; pIter != pEnd; ++pIter) + { + if (pIter->Name == "user") + { + OSL_VERIFY(pIter->Value >>= aUser); + } + else if (pIter->Name == "password") + { + OSL_VERIFY(pIter->Value >>= aPass); + } + else if (pIter->Name == "LocalSocket") + { + OSL_VERIFY(pIter->Value >>= sUnixSocket); + unixSocketPassed = !sUnixSocket.isEmpty(); + } + else if (pIter->Name == "NamedPipe") + { + OSL_VERIFY(pIter->Value >>= sNamedPipe); + namedPipePassed = !sNamedPipe.isEmpty(); + } + else if (pIter->Name == "PublicConnectionURL") + { + OSL_VERIFY(pIter->Value >>= m_settings.connectionURL); + } + else if (pIter->Name == "NewURL") + { // legacy name for "PublicConnectionURL" + OSL_VERIFY(pIter->Value >>= m_settings.connectionURL); + } + } + + OString host_str = OUStringToOString(aHostName, m_settings.encoding); + OString user_str = OUStringToOString(aUser, m_settings.encoding); + OString pass_str = OUStringToOString(aPass, m_settings.encoding); + OString schema_str = OUStringToOString(aDbName, m_settings.encoding); + OString socket_str; + if (unixSocketPassed) + { + socket_str = OUStringToOString(sUnixSocket, m_settings.encoding); + } + else if (namedPipePassed) + { + socket_str = OUStringToOString(sNamedPipe, m_settings.encoding); + } + + // flags can also be passed as last parameter + if (!mysql_real_connect(&m_mysql, host_str.getStr(), user_str.getStr(), pass_str.getStr(), + schema_str.getStr(), nPort, socket_str.getStr(), + CLIENT_MULTI_STATEMENTS)) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg( + mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this, + getConnectionEncoding()); + + // Check if the server is 4.1 or above + if (getMysqlVersion() < 40100) + { + throw SQLException("MariaDB LibreOffice Connector requires MySQL Server 4.1 or above", + *this, OUString(), 0, Any()); + } + + lcl_executeUpdate(&m_mysql, + OString{ "SET session sql_mode='ANSI_QUOTES,NO_AUTO_VALUE_ON_ZERO'" }); + lcl_executeUpdate(&m_mysql, OString{ "SET NAMES utf8mb4" }); +} + +OUString OConnection::getImplementationName() +{ + return "com.sun.star.sdbc.drivers.mysqlc.OConnection"; +} + +css::uno::Sequence OConnection::getSupportedServiceNames() +{ + return { "com.sun.star.sdbc.Connection" }; +} + +sal_Bool OConnection::supportsService(OUString const& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +Reference SAL_CALL OConnection::createStatement() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + // create a statement + // the statement can only be executed once + Reference xReturn = new OStatement(this); + m_aStatements.push_back(WeakReferenceHelper(xReturn)); + + return xReturn; +} + +Reference SAL_CALL OConnection::prepareStatement(const OUString& _sSql) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + const OString sSqlStatement + = OUStringToOString(_sSql, getConnectionEncoding()); // FIXME transform statement ? + + MYSQL_STMT* pStmt = mysql_stmt_init(&m_mysql); + mysql_stmt_prepare(pStmt, sSqlStatement.getStr(), sSqlStatement.getLength()); + + unsigned int nErrorNum = mysql_errno(&m_mysql); + if (nErrorNum != 0) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(&m_mysql), + mysql_sqlstate(&m_mysql), nErrorNum, *this, + getConnectionEncoding()); + + Reference xStatement = new OPreparedStatement(this, pStmt); + m_aStatements.push_back(WeakReferenceHelper(xStatement)); + return xStatement; +} + +Reference SAL_CALL OConnection::prepareCall(const OUString& /*_sSql*/) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OConnection::prepareCall", *this); + return Reference(); +} + +OUString SAL_CALL OConnection::nativeSQL(const OUString& /*_sSql*/) +{ + MutexGuard aGuard(m_aMutex); + + // const OUString sSqlStatement = transFormPreparedStatement( _sSql ); + // TODO + return OUString(); +} + +void SAL_CALL OConnection::setAutoCommit(sal_Bool autoCommit) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + if (!mysql_autocommit(&m_mysql, autoCommit)) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg( + mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this, + getConnectionEncoding()); +} + +sal_Bool SAL_CALL OConnection::getAutoCommit() +{ + // you have to distinguish which if you are in autocommit mode or not + // at normal case true should be fine here + + // TODO use SELECT @@autocommit query for that + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + return false; +} + +void SAL_CALL OConnection::commit() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + if (!mysql_commit(&m_mysql)) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg( + mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this, + getConnectionEncoding()); +} + +void SAL_CALL OConnection::rollback() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + if (!mysql_rollback(&m_mysql)) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg( + mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this, + getConnectionEncoding()); +} + +sal_Bool SAL_CALL OConnection::isClosed() +{ + MutexGuard aGuard(m_aMutex); + + // just simple -> we are close when we are disposed that means someone called dispose(); (XComponent) + return OConnection_BASE::rBHelper.bDisposed; +} + +Reference SAL_CALL OConnection::getMetaData() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + Reference xMetaData = m_xMetaData; + if (!xMetaData.is()) + { + xMetaData = new ODatabaseMetaData(*this, &m_mysql); + m_xMetaData = xMetaData; + } + + return xMetaData; +} + +void SAL_CALL OConnection::setReadOnly(sal_Bool readOnly) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + m_settings.readOnly = readOnly; +} + +sal_Bool SAL_CALL OConnection::isReadOnly() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + // return if your connection to readonly + return m_settings.readOnly; +} + +void SAL_CALL OConnection::setCatalog(const OUString& /*catalog*/) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + // TODO How? +} + +OUString SAL_CALL OConnection::getCatalog() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + // TODO How? + return OUString{}; +} + +void SAL_CALL OConnection::setTransactionIsolation(sal_Int32 /*level*/) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + // TODO +} + +sal_Int32 SAL_CALL OConnection::getTransactionIsolation() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + return 0; // TODO +} + +Reference SAL_CALL OConnection::getTypeMap() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + Reference t = m_typeMap; + return t; +} + +void SAL_CALL OConnection::setTypeMap(const Reference& typeMap) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + m_typeMap = typeMap; +} + +// XCloseable +void SAL_CALL OConnection::close() +{ + /* + we need block, because the mutex is a local variable, + which will guard the block + */ + { + // we just dispose us + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + } + mysql_close(&m_mysql); + mysql_library_end(); + dispose(); +} + +// XWarningsSupplier +Any SAL_CALL OConnection::getWarnings() +{ + Any x; + // when you collected some warnings -> return it + return x; +} + +void SAL_CALL OConnection::clearWarnings() +{ + // you should clear your collected warnings here# +} + +void OConnection::disposing() +{ + // we noticed that we should be destroyed in near future so we have to dispose our statements + MutexGuard aGuard(m_aMutex); + + for (auto const& statement : m_aStatements) + { + Reference xComp(statement.get(), UNO_QUERY); + if (xComp.is()) + { + xComp->dispose(); + } + } + m_aStatements.clear(); + + m_xMetaData = WeakReference(); + + OConnection_BASE::disposing(); +} + +sal_Int32 OConnection::getMysqlVersion() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + unsigned long version = mysql_get_server_version(&m_mysql); + return static_cast(version); +} + +OUString OConnection::transFormPreparedStatement(const OUString& _sSQL) +{ + OUString sSqlStatement = _sSQL; + if (!m_xParameterSubstitution.is()) + { + try + { + Sequence aArgs(1); + Reference xCon = this; + aArgs[0] <<= NamedValue("ActiveConnection", makeAny(xCon)); + + m_xParameterSubstitution.set( + m_xDriver->getFactory()->createInstanceWithArguments( + "org.openoffice.comp.helper.ParameterSubstitution", aArgs), + UNO_QUERY); + } + catch (const Exception&) + { + } + } + if (m_xParameterSubstitution.is()) + { + try + { + sSqlStatement = m_xParameterSubstitution->substituteVariables(sSqlStatement, true); + } + catch (const Exception&) + { + } + } + return sSqlStatement; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_connection.hxx b/connectivity/source/drivers/mysqlc/mysqlc_connection.hxx new file mode 100644 index 000000000..283b1d964 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_connection.hxx @@ -0,0 +1,187 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_MYSQLC_SOURCE_MYSQLC_CONNECTION_HXX +#define INCLUDED_MYSQLC_SOURCE_MYSQLC_CONNECTION_HXX + +#include +#include "mysqlc_subcomponent.hxx" +#include "mysqlc_types.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +namespace sql +{ +class SQLException; +} + +namespace connectivity +{ +class OMetaConnection; +class ODatabaseMetaData; + +namespace mysqlc +{ +using ::com::sun::star::sdbc::SQLException; +using ::com::sun::star::sdbc::SQLWarning; +using ::com::sun::star::uno::RuntimeException; + +typedef ::cppu::WeakComponentImplHelper3 + OMetaConnection_BASE; + +struct ConnectionSettings +{ + rtl_TextEncoding encoding; + OUString connectionURL; + bool readOnly; + ConnectionSettings() + : encoding(RTL_TEXTENCODING_DONTKNOW) + , readOnly(false) + { + } +}; + +class MysqlCDriver; + +typedef OMetaConnection_BASE OConnection_BASE; + +typedef std::vector OWeakRefArray; + +class OConnection final : public OBase_Mutex, public OConnection_BASE +{ +private: + MYSQL m_mysql; + ConnectionSettings m_settings; + css::uno::Reference m_typeMap; + css::uno::Reference m_xParameterSubstitution; + + // Data attributes + + css::uno::WeakReference m_xMetaData; + + OWeakRefArray m_aStatements; // vector containing a list + // of all the Statement objects + // for this Connection + + rtl::Reference m_xDriver; // Pointer to the owning driver object +public: + MYSQL* getMysqlConnection() { return &m_mysql; } + + /// @throws SQLException + /// @throws RuntimeException + sal_Int32 getMysqlVersion(); + + /// @throws SQLException + void construct(const OUString& url, const css::uno::Sequence& info); + + OConnection(MysqlCDriver& _rDriver); + virtual ~OConnection() override; + + rtl_TextEncoding getConnectionEncoding() const { return m_settings.encoding; } + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override; + + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XConnection + css::uno::Reference SAL_CALL createStatement() override; + + css::uno::Reference + SAL_CALL prepareStatement(const OUString& sql) override; + + css::uno::Reference + SAL_CALL prepareCall(const OUString& sql) override; + + OUString SAL_CALL nativeSQL(const OUString& sql) override; + + void SAL_CALL setAutoCommit(sal_Bool autoCommit) override; + + sal_Bool SAL_CALL getAutoCommit() override; + + void SAL_CALL commit() override; + + void SAL_CALL rollback() override; + + sal_Bool SAL_CALL isClosed() override; + + css::uno::Reference SAL_CALL getMetaData() override; + + void SAL_CALL setReadOnly(sal_Bool readOnly) override; + + sal_Bool SAL_CALL isReadOnly() override; + + void SAL_CALL setCatalog(const OUString& catalog) override; + + OUString SAL_CALL getCatalog() override; + + void SAL_CALL setTransactionIsolation(sal_Int32 level) override; + + sal_Int32 SAL_CALL getTransactionIsolation() override; + + css::uno::Reference SAL_CALL getTypeMap() override; + + void SAL_CALL + setTypeMap(const css::uno::Reference& typeMap) override; + // XCloseable + void SAL_CALL close() override; + // XWarningsSupplier + css::uno::Any SAL_CALL getWarnings() override; + void SAL_CALL clearWarnings() override; + + // TODO: Not used + //sal_Int32 sdbcColumnType(OUString typeName); + const ConnectionSettings& getConnectionSettings() const { return m_settings; } + OUString transFormPreparedStatement(const OUString& _sSQL); + + const MysqlCDriver& getDriver() const { return *m_xDriver; } + +}; /* OConnection */ +// TODO: Not used. +//inline OUString getPattern(OUString p) { return (p.getLength()) ? p : ASC2OU("%"); } +} /* mysqlc */ +} /* connectivity */ +#endif // INCLUDED_MYSQLC_SOURCE_MYSQLC_CONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.cxx b/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.cxx new file mode 100644 index 000000000..a30e5d618 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.cxx @@ -0,0 +1,1076 @@ +/* -*- 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 "mysqlc_databasemetadata.hxx" +#include +#include +#include +#include +#include + +#include +#include +#include "mysqlc_general.hxx" +#include "mysqlc_driver.hxx" +#include "mysqlc_preparedstatement.hxx" + +using namespace connectivity::mysqlc; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; + +static std::string wild("%"); + +static void lcl_setRows_throw(const Reference& _xResultSet, sal_Int32 _nType, + const std::vector>& _rRows) +{ + Reference xIni(_xResultSet, UNO_QUERY); + Sequence aArgs(2); + aArgs[0] <<= _nType; + + Sequence> aRows(_rRows.size()); + + Sequence* pRowsIter = aRows.getArray(); + for (const auto& rRow : _rRows) + { + if (!rRow.empty()) + { + (*pRowsIter) = comphelper::containerToSequence(rRow); + } + ++pRowsIter; + } + aArgs[1] <<= aRows; + xIni->initialize(aArgs); +} + +ODatabaseMetaData::ODatabaseMetaData(OConnection& _rCon, MYSQL* pMySql) + : m_rConnection(_rCon) + , m_pMySql(pMySql) +{ +} + +ODatabaseMetaData::~ODatabaseMetaData() {} + +OUString SAL_CALL ODatabaseMetaData::getCatalogSeparator() { return OUString(); } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxBinaryLiteralLength() { return 16777208L; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxRowSize() +{ + return 2147483647L - 8; // Max buffer size - HEADER +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCatalogNameLength() { return 32; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCharLiteralLength() { return 16777208; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnNameLength() { return 64; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInIndex() { return 16; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCursorNameLength() { return 64; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxConnections() +{ + SAL_WARN("connectivity.mysqlc", "method not implemented"); + // TODO + // SELECT @@max_connections + return 100; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInTable() { return 512; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatementLength() +{ + SAL_WARN("connectivity.mysqlc", "method not implemented"); + // TODO + // "SHOW VARIABLES LIKE 'max_allowed_packet'" + return 32767; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTableNameLength() { return 64; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTablesInSelect() { return 256; } + +sal_Bool SAL_CALL ODatabaseMetaData::doesMaxRowSizeIncludeBlobs() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseQuotedIdentifiers() +{ + SAL_WARN("connectivity.mysqlc", "method not implemented"); + // TODO + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseIdentifiers() +{ + SAL_WARN("connectivity.mysqlc", "method not implemented"); + //TODO; + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseQuotedIdentifiers() +{ + SAL_WARN("connectivity.mysqlc", "method not implemented"); + // TODO + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseIdentifiers() +{ + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseQuotedIdentifiers() +{ + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseIdentifiers() +{ + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsAlterTableWithAddColumn() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsAlterTableWithDropColumn() { return true; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxIndexLength() { return 256; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsNonNullableColumns() { return true; } + +OUString SAL_CALL ODatabaseMetaData::getCatalogTerm() { return "n/a"; } + +OUString SAL_CALL ODatabaseMetaData::getIdentifierQuoteString() { return "\""; } + +OUString SAL_CALL ODatabaseMetaData::getExtraNameCharacters() { return "#@"; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDifferentTableCorrelationNames() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::isCatalogAtStart() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionIgnoredInTransactions() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionCausesTransactionCommit() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDataManipulationTransactionsOnly() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedDelete() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedUpdate() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossRollback() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossCommit() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossCommit() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossRollback() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactionIsolationLevel(sal_Int32 /*level*/) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInDataManipulation() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92FullSQL() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92EntryLevelSQL() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsIntegrityEnhancementFacility() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInIndexDefinitions() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInTableDefinitions() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInTableDefinitions() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInIndexDefinitions() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInDataManipulation() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOuterJoins() { return true; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatements() { return 0; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxProcedureNameLength() { return 64; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxSchemaNameLength() { return 64; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactions() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::allProceduresAreCallable() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsStoredProcedures() +{ + return m_rConnection.getMysqlVersion() >= 50000; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSelectForUpdate() +{ + return m_rConnection.getMysqlVersion() >= 40000; +} + +sal_Bool SAL_CALL ODatabaseMetaData::allTablesAreSelectable() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::isReadOnly() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFiles() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFilePerTable() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTypeConversion() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::nullPlusNonNullIsNull() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsColumnAliasing() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTableCorrelationNames() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsConvert(sal_Int32 /*fromType*/, sal_Int32 /*toType*/) +{ + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsExpressionsInOrderBy() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupBy() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByBeyondSelect() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByUnrelated() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleTransactions() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleResultSets() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsLikeEscapeClause() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOrderByUnrelated() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsUnion() +{ + return m_rConnection.getMysqlVersion() >= 40000; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsUnionAll() +{ + return m_rConnection.getMysqlVersion() >= 40000; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseIdentifiers() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseQuotedIdentifiers() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtEnd() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtStart() +{ + return m_rConnection.getMysqlVersion() > 40001 && m_rConnection.getMysqlVersion() < 40011; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedHigh() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedLow() { return !nullsAreSortedHigh(); } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInProcedureCalls() +{ + return m_rConnection.getMysqlVersion() >= 32200; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInPrivilegeDefinitions() +{ + return m_rConnection.getMysqlVersion() >= 32200; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInProcedureCalls() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInPrivilegeDefinitions() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCorrelatedSubqueries() +{ + return m_rConnection.getMysqlVersion() >= 40100; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInComparisons() +{ + return m_rConnection.getMysqlVersion() >= 40100; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInExists() +{ + return m_rConnection.getMysqlVersion() >= 40100; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInIns() +{ + return m_rConnection.getMysqlVersion() >= 40100; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInQuantifieds() +{ + return m_rConnection.getMysqlVersion() >= 40100; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92IntermediateSQL() { return false; } + +OUString SAL_CALL ODatabaseMetaData::getURL() +{ + return m_rConnection.getConnectionSettings().connectionURL; +} + +OUString SAL_CALL ODatabaseMetaData::getUserName() +{ + Reference statement = m_rConnection.createStatement(); + Reference rs = statement->executeQuery("select user()"); + Reference xRow(rs, UNO_QUERY_THROW); + (void)rs->next(); // the first and only result + // e.g. root@localhost + OUString userWithConnection = xRow->getString(1); + sal_Int32 nIndexOfAt = userWithConnection.indexOf("@"); + if (nIndexOfAt > 0) + { + OUString user = userWithConnection.copy(0, nIndexOfAt); + return user; + } + return userWithConnection; +} + +OUString SAL_CALL ODatabaseMetaData::getDriverName() { return "MySQL Connector/OO.org"; } + +OUString SAL_CALL ODatabaseMetaData::getDriverVersion() { return "0.9.2"; } + +OUString SAL_CALL ODatabaseMetaData::getDatabaseProductVersion() +{ + return OStringToOUString(mysql_get_server_info(m_pMySql), + m_rConnection.getConnectionEncoding()); +} + +OUString SAL_CALL ODatabaseMetaData::getDatabaseProductName() { return "MySQL"; } + +OUString SAL_CALL ODatabaseMetaData::getProcedureTerm() { return "procedure"; } + +OUString SAL_CALL ODatabaseMetaData::getSchemaTerm() { return "database"; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMajorVersion() +{ + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + return MARIADBC_VERSION_MAJOR; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDefaultTransactionIsolation() +{ + return TransactionIsolation::REPEATABLE_READ; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMinorVersion() +{ + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + return MARIADBC_VERSION_MINOR; +} + +OUString SAL_CALL ODatabaseMetaData::getSQLKeywords() +{ + return "ACCESSIBLE, ADD, ALL," + "ALTER, ANALYZE, AND, AS, ASC, ASENSITIVE, BEFORE," + "BETWEEN, BIGINT, BINARY, BLOB, BOTH, BY, CALL," + "CASCADE, CASE, CHANGE, CHAR, CHARACTER, CHECK," + "COLLATE, COLUMN, CONDITION, CONNECTION, CONSTRAINT," + "CONTINUE, CONVERT, CREATE, CROSS, CURRENT_DATE," + "CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, CURSOR," + "DATABASE, DATABASES, DAY_HOUR, DAY_MICROSECOND," + "DAY_MINUTE, DAY_SECOND, DEC, DECIMAL, DECLARE," + "DEFAULT, DELAYED, DELETE, DESC, DESCRIBE," + "DETERMINISTIC, DISTINCT, DISTINCTROW, DIV, DOUBLE," + "DROP, DUAL, EACH, ELSE, ELSEIF, ENCLOSED," + "ESCAPED, EXISTS, EXIT, EXPLAIN, FALSE, FETCH," + "FLOAT, FLOAT4, FLOAT8, FOR, FORCE, FOREIGN, FROM," + "FULLTEXT, GRANT, GROUP, HAVING, HIGH_PRIORITY," + "HOUR_MICROSECOND, HOUR_MINUTE, HOUR_SECOND, IF," + "IGNORE, IN, INDEX, INFILE, INNER, INOUT," + "INSENSITIVE, INSERT, INT, INT1, INT2, INT3, INT4," + "INT8, INTEGER, INTERVAL, INTO, IS, ITERATE, JOIN," + "KEY, KEYS, KILL, LEADING, LEAVE, LEFT, LIKE," + "LOCALTIMESTAMP, LOCK, LONG, LONGBLOB, LONGTEXT," + "LOOP, LOW_PRIORITY, MATCH, MEDIUMBLOB, MEDIUMINT," + "MEDIUMTEXT, MIDDLEINT, MINUTE_MICROSECOND," + "MINUTE_SECOND, MOD, MODIFIES, NATURAL, NOT," + "NO_WRITE_TO_BINLOG, NULL, NUMERIC, ON, OPTIMIZE," + "OPTION, OPTIONALLY, OR, ORDER, OUT, OUTER," + "OUTFILE, PRECISION, PRIMARY, PROCEDURE, PURGE," + "RANGE, READ, READS, READ_ONLY, READ_WRITE, REAL," + "REFERENCES, REGEXP, RELEASE, RENAME, REPEAT," + "REPLACE, REQUIRE, RESTRICT, RETURN, REVOKE, RIGHT," + "RLIKE, SCHEMA, SCHEMAS, SECOND_MICROSECOND, SELECT," + "SENSITIVE, SEPARATOR, SET, SHOW, SMALLINT, SPATIAL," + "SPECIFIC, SQL, SQLEXCEPTION, SQLSTATE, SQLWARNING," + "SQL_BIG_RESULT, SQL_CALC_FOUND_ROWS, SQL_SMALL_RESULT," + "SSL, STARTING, STRAIGHT_JOIN, TABLE, TERMINATED," + "THEN, TINYBLOB, TINYINT, TINYTEXT, TO, TRAILING," + "TRIGGER, TRUE, UNDO, UNION, UNIQUE, UNLOCK," + "UNSIGNED, UPDATE, USAGE, USE, USING, UTC_DATE," + "UTC_TIME, UTC_TIMESTAMP, VALUES, VARBINARY, VARCHAR," + "VARCHARACTER, VARYING, WHEN, WHERE, WHILE, WITH," + "WRITE, X509, XOR, YEAR_MONTH, ZEROFILL" + "GENERAL, IGNORE_SERVER_IDS, MASTER_HEARTBEAT_PERIOD," + "MAXVALUE, RESIGNAL, SIGNAL, SLOW"; +} + +OUString SAL_CALL ODatabaseMetaData::getSearchStringEscape() { return "\\"; } + +OUString SAL_CALL ODatabaseMetaData::getStringFunctions() +{ + return "ASCII,BIN,BIT_LENGTH,CHAR,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT," + "CONCAT_WS,CONV,ELT,EXPORT_SET,FIELD,FIND_IN_SET,HEX,INSERT," + "INSTR,LCASE,LEFT,LENGTH,LOAD_FILE,LOCATE,LOCATE,LOWER,LPAD," + "LTRIM,MAKE_SET,MATCH,MID,OCT,OCTET_LENGTH,ORD,POSITION," + "QUOTE,REPEAT,REPLACE,REVERSE,RIGHT,RPAD,RTRIM,SOUNDEX," + "SPACE,STRCMP,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING," + "SUBSTRING_INDEX,TRIM,UCASE,UPPER"; +} + +OUString SAL_CALL ODatabaseMetaData::getTimeDateFunctions() +{ + return "DAYOFWEEK,WEEKDAY,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME," + "MONTHNAME,QUARTER,WEEK,YEAR,HOUR,MINUTE,SECOND,PERIOD_ADD," + "PERIOD_DIFF,TO_DAYS,FROM_DAYS,DATE_FORMAT,TIME_FORMAT," + "CURDATE,CURRENT_DATE,CURTIME,CURRENT_TIME,NOW,SYSDATE," + "CURRENT_TIMESTAMP,UNIX_TIMESTAMP,FROM_UNIXTIME," + "SEC_TO_TIME,TIME_TO_SEC"; +} + +OUString SAL_CALL ODatabaseMetaData::getSystemFunctions() +{ + return "DATABASE,USER,SYSTEM_USER," + "SESSION_USER,PASSWORD,ENCRYPT,LAST_INSERT_ID,VERSION"; +} + +OUString SAL_CALL ODatabaseMetaData::getNumericFunctions() +{ + return "ABS,ACOS,ASIN,ATAN,ATAN2,BIT_COUNT,CEILING,COS," + "COT,DEGREES,EXP,FLOOR,LOG,LOG10,MAX,MIN,MOD,PI,POW," + "POWER,RADIANS,RAND,ROUND,SIN,SQRT,TAN,TRUNCATE"; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsExtendedSQLGrammar() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCoreSQLGrammar() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMinimumSQLGrammar() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsFullOuterJoins() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsLimitedOuterJoins() { return true; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInGroupBy() { return 64; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInOrderBy() { return 64; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInSelect() { return 256; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxUserNameLength() { return 16; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetType(sal_Int32 setType) +{ + return setType == ResultSetType::SCROLL_SENSITIVE; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetConcurrency(sal_Int32 /*setType*/, + sal_Int32 /*concurrency*/) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::ownUpdatesAreVisible(sal_Int32 /*setType*/) { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::ownDeletesAreVisible(sal_Int32 /*setType*/) { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::ownInsertsAreVisible(sal_Int32 /*setType*/) { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::othersUpdatesAreVisible(sal_Int32 /*setType*/) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersDeletesAreVisible(sal_Int32 /*setType*/) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersInsertsAreVisible(sal_Int32 /*setType*/) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::updatesAreDetected(sal_Int32 /*setType*/) { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::deletesAreDetected(sal_Int32 /*setType*/) { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::insertsAreDetected(sal_Int32 /*setType*/) { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsBatchUpdates() { return false; } + +Reference SAL_CALL ODatabaseMetaData::getConnection() { return &m_rConnection; } + +/* + Here follow all methods which return(a resultset + the first methods is an example implementation how to use this resultset + of course you could implement it on your and you should do this because + the general way is more memory expensive +*/ + +Reference SAL_CALL ODatabaseMetaData::getTableTypes() +{ + const char* const table_types[] = { "TABLE", "VIEW" }; + sal_Int32 const requiredVersion[] = { 0, 50000 }; + + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector> rRows; + rtl_TextEncoding encoding = m_rConnection.getConnectionEncoding(); + + for (sal_uInt32 i = 0; i < 2; i++) + { + if (m_rConnection.getMysqlVersion() >= requiredVersion[i]) + { + std::vector aRow{ Any() }; + aRow.push_back(makeAny(mysqlc_sdbc_driver::convert(table_types[i], encoding))); + rRows.push_back(aRow); + } + } + lcl_setRows_throw(xResultSet, 5, rRows); + return xResultSet; +} + +Reference SAL_CALL ODatabaseMetaData::getTypeInfo() +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + + std::vector> rRows; + + rtl_TextEncoding encoding = m_rConnection.getConnectionEncoding(); + unsigned int i = 0; + while (mysqlc_types[i].typeName) + { + std::vector aRow{ Any() }; + + aRow.push_back(makeAny(mysqlc_sdbc_driver::convert(mysqlc_types[i].typeName, encoding))); + aRow.push_back(makeAny(mysqlc_types[i].dataType)); + aRow.push_back(makeAny(mysqlc_types[i].precision)); + aRow.push_back( + makeAny(mysqlc_sdbc_driver::convert(mysqlc_types[i].literalPrefix, encoding))); + aRow.push_back( + makeAny(mysqlc_sdbc_driver::convert(mysqlc_types[i].literalSuffix, encoding))); + aRow.push_back( + makeAny(mysqlc_sdbc_driver::convert(mysqlc_types[i].createParams, encoding))); + aRow.push_back(makeAny(mysqlc_types[i].nullable)); + aRow.push_back(makeAny(mysqlc_types[i].caseSensitive)); + aRow.push_back(makeAny(mysqlc_types[i].searchable)); + aRow.push_back(makeAny(mysqlc_types[i].isUnsigned)); + aRow.push_back(makeAny(mysqlc_types[i].fixedPrecScale)); + aRow.push_back(makeAny(mysqlc_types[i].autoIncrement)); + aRow.push_back( + makeAny(mysqlc_sdbc_driver::convert(mysqlc_types[i].localTypeName, encoding))); + aRow.push_back(makeAny(mysqlc_types[i].minScale)); + aRow.push_back(makeAny(mysqlc_types[i].maxScale)); + aRow.push_back(makeAny(sal_Int32(0))); + aRow.push_back(makeAny(sal_Int32(0))); + aRow.push_back(makeAny(sal_Int32(10))); + + rRows.push_back(aRow); + i++; + } + + lcl_setRows_throw(xResultSet, 14, rRows); + return xResultSet; +} + +Reference SAL_CALL ODatabaseMetaData::getCatalogs() +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + return xResultSet; +} + +Reference SAL_CALL ODatabaseMetaData::getSchemas() +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector> rRows; + + OUString sSql + = m_rConnection.getMysqlVersion() > 49999 + ? OUString{ "SELECT SCHEMA_NAME AS TABLE_SCHEM, CATALOG_NAME AS TABLE_CATALOG " + "FROM INFORMATION_SCHEMA.SCHEMATA ORDER BY SCHEMA_NAME" } + : OUString{ "SHOW DATABASES" }; + + Reference statement = m_rConnection.createStatement(); + Reference executed = statement->executeQuery(sSql); + Reference rs(executed, UNO_QUERY_THROW); + Reference supp(executed, UNO_QUERY_THROW); + Reference rs_meta = supp->getMetaData(); + + Reference xRow(rs, UNO_QUERY_THROW); + sal_uInt32 columns = rs_meta->getColumnCount(); + while (rs->next()) + { + std::vector aRow{ Any() }; + bool informationSchema = false; + for (sal_uInt32 i = 1; i <= columns; i++) + { + OUString columnStringValue = xRow->getString(i); + if (i == 1) + { // TABLE_SCHEM + informationSchema = columnStringValue.equalsIgnoreAsciiCase("information_schema"); + } + aRow.push_back(makeAny(columnStringValue)); + } + if (!informationSchema) + { + rRows.push_back(aRow); + } + } + + lcl_setRows_throw(xResultSet, 1, rRows); + return xResultSet; +} + +Reference + SAL_CALL ODatabaseMetaData::getColumnPrivileges(const Any& /*catalog*/, const OUString& schema, + const OUString& table, + const OUString& columnNamePattern) +{ + OUString query("SELECT TABLE_CATALOG AS TABLE_CAT, TABLE_SCHEMA AS " + "TABLE_SCHEM, TABLE_NAME, COLUMN_NAME, NULL AS GRANTOR, " + "GRANTEE, PRIVILEGE_TYPE AS PRIVILEGE, IS_GRANTABLE FROM " + "INFORMATION_SCHEMA.COLUMN_PRIVILEGES WHERE TABLE_SCHEMA LIKE " + "'?' AND TABLE_NAME='?' AND COLUMN_NAME LIKE '?' ORDER BY " + "COLUMN_NAME, PRIVILEGE_TYPE"); + + query = query.replaceFirst("?", schema); + query = query.replaceFirst("?", table); + query = query.replaceFirst("?", columnNamePattern); + + Reference statement = m_rConnection.createStatement(); + Reference rs = statement->executeQuery(query); + return rs; +} + +Reference SAL_CALL ODatabaseMetaData::getColumns(const Any& /*catalog*/, + const OUString& schemaPattern, + const OUString& tableNamePattern, + const OUString& columnNamePattern) +{ + OUStringBuffer queryBuf("SELECT TABLE_CATALOG, " // 1 + "TABLE_SCHEMA, " // 2 + "TABLE_NAME, " // 3 + "COLUMN_NAME, " // 4 + "DATA_TYPE, " // 5 + // TYPE_NAME missing + "CHARACTER_MAXIMUM_LENGTH, " // 6 + "NUMERIC_PRECISION, " // 7 + // buffer length missing + "NUMERIC_SCALE AS DECIMAL_DIGITS, " // 8 + // NUM_PREC_RADIX missing + // NULLABLE missing + "COLUMN_COMMENT AS REMARKS, " // 9 + "COLUMN_DEFAULT AS COLUMN_DEF," // 10 + "CHARACTER_OCTET_LENGTH, " // 11 + "ORDINAL_POSITION, " // 12 + "IS_NULLABLE, " // 13 + "COLUMN_TYPE " // 14 + "FROM INFORMATION_SCHEMA.COLUMNS " + "WHERE (1 = 1) "); + if (!tableNamePattern.isEmpty()) + { + OUString sAppend; + if (tableNamePattern.match("%")) + sAppend = "AND TABLE_NAME LIKE '%' "; + else + sAppend = "AND TABLE_NAME = '%' "; + queryBuf.append(sAppend.replaceAll("%", tableNamePattern)); + } + if (!schemaPattern.isEmpty()) + { + OUString sAppend; + if (schemaPattern.match("%")) + sAppend = "AND TABLE_SCHEMA LIKE '%' "; + else + sAppend = "AND TABLE_SCHEMA = '%' "; + queryBuf.append(sAppend.replaceAll("%", schemaPattern)); + } + if (!columnNamePattern.isEmpty()) + { + OUString sAppend; + if (columnNamePattern.match("%")) + sAppend = "AND COLUMN_NAME LIKE '%' "; + else + sAppend = "AND COLUMN_NAME = '%' "; + queryBuf.append(sAppend.replaceAll("%", columnNamePattern)); + } + + OUString query = queryBuf.makeStringAndClear(); + Reference statement = m_rConnection.createStatement(); + Reference rs = statement->executeQuery(query.getStr()); + Reference xRow(rs, UNO_QUERY_THROW); + + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector> aRows; + while (rs->next()) + { + std::vector aRow{ Any() }; // 0. element is unused + + // catalog name + aRow.push_back(makeAny(xRow->getString(1))); + // schema name + aRow.push_back(makeAny(xRow->getString(2))); + // table name + aRow.push_back(makeAny(xRow->getString(3))); + // column name + aRow.push_back(makeAny(xRow->getString(4))); + // data type + OUString sDataType = xRow->getString(5); + aRow.push_back(makeAny(mysqlc_sdbc_driver::mysqlStrToOOOType(sDataType))); + // type name + aRow.push_back(makeAny(sDataType)); // TODO + // column size + sal_Int32 nColumnSize = 0; + OUString sColumnType = xRow->getString(14); + sal_Int32 nCharMaxLen = xRow->getShort(6); + bool bIsCharMax = !xRow->wasNull(); + if (sDataType.equalsIgnoreAsciiCase("year")) + nColumnSize = sColumnType.copy(6, 1).toInt32(); // 'year(' length is 5 + else if (sDataType.equalsIgnoreAsciiCase("date")) + nColumnSize = 10; + else if (sDataType.equalsIgnoreAsciiCase("time")) + nColumnSize = 8; + else if (sDataType.equalsIgnoreAsciiCase("datetime") + || sDataType.equalsIgnoreAsciiCase("timestamp")) + nColumnSize = 19; + else if (!bIsCharMax) + nColumnSize = xRow->getShort(7); // numeric precision + else + nColumnSize = nCharMaxLen; + aRow.push_back(makeAny(nColumnSize)); + aRow.push_back(Any()); // buffer length - unused + // decimal digits (scale) + aRow.push_back(makeAny(xRow->getShort(8))); + // num_prec_radix + aRow.push_back(makeAny(sal_Int32(10))); + // nullable + OUString sIsNullable = xRow->getString(13); + if (xRow->wasNull()) + aRow.push_back(makeAny(ColumnValue::NULLABLE_UNKNOWN)); + else if (sIsNullable.equalsIgnoreAsciiCase("YES")) + aRow.push_back(makeAny(ColumnValue::NULLABLE)); + else + aRow.push_back(makeAny(ColumnValue::NO_NULLS)); + // remarks + aRow.push_back(makeAny(xRow->getString(9))); + // default + aRow.push_back(makeAny(xRow->getString(10))); + + aRow.push_back(Any{}); // sql_data_type - unused + aRow.push_back(Any{}); // sql_datetime_sub - unused + + // character octet length + aRow.push_back(makeAny(xRow->getString(11))); + // ordinal position + aRow.push_back(makeAny(xRow->getString(12))); + // is nullable + aRow.push_back(makeAny(sIsNullable)); + aRows.push_back(aRow); + } + lcl_setRows_throw(xResultSet, 1, aRows); + return xResultSet; +} + +Reference SAL_CALL ODatabaseMetaData::getTables(const Any& /*catalog*/, + const OUString& schemaPattern, + const OUString& tableNamePattern, + const Sequence& types) +{ + OUStringBuffer buffer{ + "SELECT TABLE_CATALOG AS TABLE_CAT, TABLE_SCHEMA AS TABLE_SCHEM, TABLE_NAME," + "IF(STRCMP(TABLE_TYPE,'BASE TABLE'), TABLE_TYPE, 'TABLE') AS TABLE_TYPE, TABLE_COMMENT AS " + "REMARKS " + "FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA LIKE '?' AND TABLE_NAME LIKE '?' " + }; + + if (types.getLength() == 1) + { + buffer.append("AND TABLE_TYPE LIKE '"); + buffer.append(types[0]); + buffer.append("'"); + } + else if (types.getLength() > 1) + { + buffer.append("AND (TABLE_TYPE LIKE '"); + buffer.append(types[0]); + buffer.append("'"); + for (sal_Int32 i = 1; i < types.getLength(); ++i) + { + buffer.append(" OR TABLE_TYPE LIKE '"); + buffer.append(types[i]); + buffer.append("'"); + } + buffer.append(")"); + } + + buffer.append(" ORDER BY TABLE_TYPE, TABLE_SCHEMA, TABLE_NAME"); + OUString query = buffer.makeStringAndClear(); + + // TODO use prepared stmt instead + // TODO escape schema, table name ? + query = query.replaceFirst("?", schemaPattern); + query = query.replaceFirst("?", tableNamePattern); + + Reference statement = m_rConnection.createStatement(); + Reference rs = statement->executeQuery(query); + return rs; +} + +Reference SAL_CALL ODatabaseMetaData::getProcedureColumns( + const Any& /* catalog */, const OUString& /* schemaPattern */, + const OUString& /* procedureNamePattern */, const OUString& /* columnNamePattern */) +{ + // Currently there is no information available + return nullptr; +} + +Reference + SAL_CALL ODatabaseMetaData::getProcedures(const Any& /*catalog*/, + const OUString& /*schemaPattern*/, + const OUString& /*procedureNamePattern*/) +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector> rRows; + // TODO IMPL + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 7, rRows); + return xResultSet; +} + +Reference SAL_CALL ODatabaseMetaData::getVersionColumns(const Any& /* catalog */, + const OUString& /* schema */, + const OUString& /* table */) +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector> rRows; + lcl_setRows_throw(xResultSet, 16, rRows); + return xResultSet; +} + +Reference SAL_CALL ODatabaseMetaData::getExportedKeys(const Any& /*catalog */, + const OUString& /*schema */, + const OUString& /*table */) +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector> rRows; + // TODO implement + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 8, rRows); + return xResultSet; +} + +Reference SAL_CALL ODatabaseMetaData::getImportedKeys(const Any& /*catalog*/, + const OUString& schema, + const OUString& table) +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + + OUString query("SELECT refi.CONSTRAINT_CATALOG," // 1: foreign catalog + " k.COLUMN_NAME," // 2: foreign column name + " refi.UNIQUE_CONSTRAINT_CATALOG," // 3: primary catalog FIXME + " k.REFERENCED_TABLE_SCHEMA," // 4: primary schema + " refi.REFERENCED_TABLE_NAME," // 5: primary table name + " k.REFERENCED_COLUMN_NAME," // 6: primary column name + " refi.UPDATE_RULE, refi.DELETE_RULE," // 7,8: update, delete rule + " refi.CONSTRAINT_NAME, " // 9: name of constraint itself + " refi.TABLE_NAME, " // 10: foreign table name + " refi.CONSTRAINT_SCHEMA " // 11: foreign schema name FIXME + " FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as refi" + " INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE as k ON k.CONSTRAINT_NAME = " + "refi.CONSTRAINT_NAME " + " and k.TABLE_NAME = refi.TABLE_NAME " + " WHERE k.REFERENCED_TABLE_SCHEMA LIKE " + "'?' AND refi.TABLE_NAME='?'"); + query = query.replaceFirst("?", schema); // TODO what if schema is NULL? + query = query.replaceFirst("?", table); + + std::vector> aRows; + Reference statement = m_rConnection.createStatement(); + Reference rs = statement->executeQuery(query.getStr()); + Reference xRow(rs, UNO_QUERY_THROW); + + while (rs->next()) + { + std::vector aRow{ Any() }; // 0. element is unused + + // primary key catalog + aRow.push_back(makeAny(xRow->getString(3))); + // primary key schema + aRow.push_back(makeAny(xRow->getString(4))); + // primary key table + aRow.push_back(makeAny(xRow->getString(5))); + // primary column name + aRow.push_back(makeAny(xRow->getString(6))); + + // fk table catalog + aRow.push_back(makeAny(xRow->getString(1))); + // fk schema + aRow.push_back(makeAny(xRow->getString(11))); + // fk table + aRow.push_back(makeAny(xRow->getString(10))); + // fk column name + aRow.push_back(makeAny(xRow->getString(2))); + // KEY_SEQ + aRow.push_back(makeAny(sal_Int32{ 0 })); // TODO + // update rule + aRow.push_back(makeAny(xRow->getShort(7))); + // delete rule + aRow.push_back(makeAny(xRow->getShort(8))); + // foreign key name + aRow.push_back(makeAny(xRow->getString(9))); + // primary key name + aRow.push_back(makeAny(OUString{})); // TODO + // deferrability + aRow.push_back(makeAny(Deferrability::NONE)); + aRows.push_back(aRow); + } + lcl_setRows_throw(xResultSet, 1, aRows); + return xResultSet; +} + +Reference SAL_CALL ODatabaseMetaData::getPrimaryKeys(const Any& /*catalog*/, + const OUString& schema, + const OUString& table) +{ + OUString query("SELECT TABLE_CATALOG AS TABLE_CAT, TABLE_SCHEMA " + "AS TABLE_SCHEM, TABLE_NAME, " + "COLUMN_NAME, SEQ_IN_INDEX AS KEY_SEQ," + "INDEX_NAME AS PK_NAME FROM INFORMATION_SCHEMA.STATISTICS " + "WHERE TABLE_SCHEMA LIKE '?' AND TABLE_NAME LIKE '?' AND INDEX_NAME='PRIMARY' " + "ORDER BY TABLE_SCHEMA, TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX"); + + // TODO use prepared stmt instead + // TODO escape schema, table name ? + query = query.replaceFirst("?", schema); + query = query.replaceFirst("?", table); + + Reference statement = m_rConnection.createStatement(); + Reference rs = statement->executeQuery(query); + return rs; +} + +Reference SAL_CALL ODatabaseMetaData::getIndexInfo(const Any& /*catalog*/, + const OUString& /*schema*/, + const OUString& /*table*/, + sal_Bool /*unique*/, + sal_Bool /*approximate*/) +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector> rRows; + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 11, rRows); + return xResultSet; +} + +Reference SAL_CALL ODatabaseMetaData::getBestRowIdentifier(const Any& /*catalog*/, + const OUString& /*schema*/, + const OUString& /*table*/, + sal_Int32 /*scope*/, + sal_Bool /*nullable*/) +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector> rRows; + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 15, rRows); + return xResultSet; +} + +Reference SAL_CALL ODatabaseMetaData::getTablePrivileges( + const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& /*tableNamePattern*/) +{ + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + throw SQLException("getTablePrivileges method not implemented", *this, "IM001", 0, Any()); +} + +Reference SAL_CALL ODatabaseMetaData::getCrossReference( + const Any& /*primaryCatalog*/, const OUString& /*primarySchema_*/, + const OUString& /*primaryTable_*/, const Any& /*foreignCatalog*/, + const OUString& /*foreignSchema*/, const OUString& /*foreignTable*/) +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector> rRows; + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 13, rRows); + return xResultSet; +} + +Reference SAL_CALL ODatabaseMetaData::getUDTs(const Any& /* catalog */, + const OUString& /* schemaPattern */, + const OUString& /* typeNamePattern */, + const Sequence& /* types */) +{ + mysqlc_sdbc_driver::throwFeatureNotImplementedException("ODatabaseMetaData::getUDTs", *this); + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.hxx b/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.hxx new file mode 100644 index 000000000..6814a574c --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.hxx @@ -0,0 +1,239 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_MYSQLC_SOURCE_MYSQLC_DATABASEMETADATA_HXX +#define INCLUDED_MYSQLC_SOURCE_MYSQLC_DATABASEMETADATA_HXX + +#include "mysqlc_connection.hxx" + +#include +#include + +namespace connectivity +{ +namespace mysqlc +{ +using ::com::sun::star::uno::Any; + +//************ Class: ODatabaseMetaData + +typedef ::cppu::WeakImplHelper1 ODatabaseMetaData_BASE; + +class ODatabaseMetaData final : public ODatabaseMetaData_BASE +{ + OConnection& m_rConnection; + MYSQL* m_pMySql; + +public: + const OConnection& getOwnConnection() const { return m_rConnection; } + + explicit ODatabaseMetaData(OConnection& _rCon, MYSQL* pMySql); + virtual ~ODatabaseMetaData() override; + + // as I mentioned before this interface is really BIG + // XDatabaseMetaData + sal_Bool SAL_CALL allProceduresAreCallable() override; + sal_Bool SAL_CALL allTablesAreSelectable() override; + OUString SAL_CALL getURL() override; + OUString SAL_CALL getUserName() override; + sal_Bool SAL_CALL isReadOnly() override; + sal_Bool SAL_CALL nullsAreSortedHigh() override; + sal_Bool SAL_CALL nullsAreSortedLow() override; + sal_Bool SAL_CALL nullsAreSortedAtStart() override; + sal_Bool SAL_CALL nullsAreSortedAtEnd() override; + OUString SAL_CALL getDatabaseProductName() override; + OUString SAL_CALL getDatabaseProductVersion() override; + OUString SAL_CALL getDriverName() override; + OUString SAL_CALL getDriverVersion() override; + sal_Int32 SAL_CALL getDriverMajorVersion() override; + sal_Int32 SAL_CALL getDriverMinorVersion() override; + sal_Bool SAL_CALL usesLocalFiles() override; + sal_Bool SAL_CALL usesLocalFilePerTable() override; + sal_Bool SAL_CALL supportsMixedCaseIdentifiers() override; + sal_Bool SAL_CALL storesUpperCaseIdentifiers() override; + sal_Bool SAL_CALL storesLowerCaseIdentifiers() override; + sal_Bool SAL_CALL storesMixedCaseIdentifiers() override; + sal_Bool SAL_CALL supportsMixedCaseQuotedIdentifiers() override; + sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers() override; + sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers() override; + sal_Bool SAL_CALL storesMixedCaseQuotedIdentifiers() override; + OUString SAL_CALL getIdentifierQuoteString() override; + OUString SAL_CALL getSQLKeywords() override; + OUString SAL_CALL getNumericFunctions() override; + OUString SAL_CALL getStringFunctions() override; + OUString SAL_CALL getSystemFunctions() override; + OUString SAL_CALL getTimeDateFunctions() override; + OUString SAL_CALL getSearchStringEscape() override; + OUString SAL_CALL getExtraNameCharacters() override; + sal_Bool SAL_CALL supportsAlterTableWithAddColumn() override; + sal_Bool SAL_CALL supportsAlterTableWithDropColumn() override; + sal_Bool SAL_CALL supportsColumnAliasing() override; + sal_Bool SAL_CALL nullPlusNonNullIsNull() override; + sal_Bool SAL_CALL supportsTypeConversion() override; + sal_Bool SAL_CALL supportsConvert(sal_Int32 fromType, sal_Int32 toType) override; + sal_Bool SAL_CALL supportsTableCorrelationNames() override; + sal_Bool SAL_CALL supportsDifferentTableCorrelationNames() override; + sal_Bool SAL_CALL supportsExpressionsInOrderBy() override; + sal_Bool SAL_CALL supportsOrderByUnrelated() override; + sal_Bool SAL_CALL supportsGroupBy() override; + sal_Bool SAL_CALL supportsGroupByUnrelated() override; + sal_Bool SAL_CALL supportsGroupByBeyondSelect() override; + sal_Bool SAL_CALL supportsLikeEscapeClause() override; + sal_Bool SAL_CALL supportsMultipleResultSets() override; + sal_Bool SAL_CALL supportsMultipleTransactions() override; + sal_Bool SAL_CALL supportsNonNullableColumns() override; + sal_Bool SAL_CALL supportsMinimumSQLGrammar() override; + sal_Bool SAL_CALL supportsCoreSQLGrammar() override; + sal_Bool SAL_CALL supportsExtendedSQLGrammar() override; + sal_Bool SAL_CALL supportsANSI92EntryLevelSQL() override; + sal_Bool SAL_CALL supportsANSI92IntermediateSQL() override; + sal_Bool SAL_CALL supportsANSI92FullSQL() override; + sal_Bool SAL_CALL supportsIntegrityEnhancementFacility() override; + sal_Bool SAL_CALL supportsOuterJoins() override; + sal_Bool SAL_CALL supportsFullOuterJoins() override; + sal_Bool SAL_CALL supportsLimitedOuterJoins() override; + OUString SAL_CALL getSchemaTerm() override; + OUString SAL_CALL getProcedureTerm() override; + OUString SAL_CALL getCatalogTerm() override; + sal_Bool SAL_CALL isCatalogAtStart() override; + OUString SAL_CALL getCatalogSeparator() override; + sal_Bool SAL_CALL supportsSchemasInDataManipulation() override; + sal_Bool SAL_CALL supportsSchemasInProcedureCalls() override; + sal_Bool SAL_CALL supportsSchemasInTableDefinitions() override; + sal_Bool SAL_CALL supportsSchemasInIndexDefinitions() override; + sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions() override; + sal_Bool SAL_CALL supportsCatalogsInDataManipulation() override; + sal_Bool SAL_CALL supportsCatalogsInProcedureCalls() override; + sal_Bool SAL_CALL supportsCatalogsInTableDefinitions() override; + sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions() override; + sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions() override; + sal_Bool SAL_CALL supportsPositionedDelete() override; + sal_Bool SAL_CALL supportsPositionedUpdate() override; + sal_Bool SAL_CALL supportsSelectForUpdate() override; + sal_Bool SAL_CALL supportsStoredProcedures() override; + sal_Bool SAL_CALL supportsSubqueriesInComparisons() override; + sal_Bool SAL_CALL supportsSubqueriesInExists() override; + sal_Bool SAL_CALL supportsSubqueriesInIns() override; + sal_Bool SAL_CALL supportsSubqueriesInQuantifieds() override; + sal_Bool SAL_CALL supportsCorrelatedSubqueries() override; + sal_Bool SAL_CALL supportsUnion() override; + sal_Bool SAL_CALL supportsUnionAll() override; + sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit() override; + sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback() override; + sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit() override; + sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback() override; + sal_Int32 SAL_CALL getMaxBinaryLiteralLength() override; + sal_Int32 SAL_CALL getMaxCharLiteralLength() override; + sal_Int32 SAL_CALL getMaxColumnNameLength() override; + sal_Int32 SAL_CALL getMaxColumnsInGroupBy() override; + sal_Int32 SAL_CALL getMaxColumnsInIndex() override; + sal_Int32 SAL_CALL getMaxColumnsInOrderBy() override; + sal_Int32 SAL_CALL getMaxColumnsInSelect() override; + sal_Int32 SAL_CALL getMaxColumnsInTable() override; + sal_Int32 SAL_CALL getMaxConnections() override; + sal_Int32 SAL_CALL getMaxCursorNameLength() override; + sal_Int32 SAL_CALL getMaxIndexLength() override; + sal_Int32 SAL_CALL getMaxSchemaNameLength() override; + sal_Int32 SAL_CALL getMaxProcedureNameLength() override; + sal_Int32 SAL_CALL getMaxCatalogNameLength() override; + sal_Int32 SAL_CALL getMaxRowSize() override; + sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs() override; + sal_Int32 SAL_CALL getMaxStatementLength() override; + sal_Int32 SAL_CALL getMaxStatements() override; + sal_Int32 SAL_CALL getMaxTableNameLength() override; + sal_Int32 SAL_CALL getMaxTablesInSelect() override; + sal_Int32 SAL_CALL getMaxUserNameLength() override; + sal_Int32 SAL_CALL getDefaultTransactionIsolation() override; + sal_Bool SAL_CALL supportsTransactions() override; + sal_Bool SAL_CALL supportsTransactionIsolationLevel(sal_Int32 level) override; + sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions() override; + sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly() override; + sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit() override; + sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions() override; + css::uno::Reference + SAL_CALL getProcedures(const Any& catalog, const OUString& schemaPattern, + const OUString& procedureNamePattern) override; + css::uno::Reference + SAL_CALL getProcedureColumns(const Any& catalog, const OUString& schemaPattern, + const OUString& procedureNamePattern, + const OUString& columnNamePattern) override; + css::uno::Reference + SAL_CALL getTables(const Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern, + const css::uno::Sequence& types) override; + css::uno::Reference SAL_CALL getSchemas() override; + css::uno::Reference SAL_CALL getCatalogs() override; + css::uno::Reference SAL_CALL getTableTypes() override; + css::uno::Reference + SAL_CALL getColumns(const Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern, + const OUString& columnNamePattern) override; + css::uno::Reference + SAL_CALL getColumnPrivileges(const Any& catalog, const OUString& schema, + const OUString& table, + const OUString& columnNamePattern) override; + css::uno::Reference + SAL_CALL getTablePrivileges(const Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern) override; + css::uno::Reference + SAL_CALL getBestRowIdentifier(const Any& catalog, const OUString& schema, + const OUString& table, sal_Int32 scope, + sal_Bool nullable) override; + css::uno::Reference SAL_CALL + getVersionColumns(const Any& catalog, const OUString& schema, const OUString& table) override; + css::uno::Reference SAL_CALL + getPrimaryKeys(const Any& catalog, const OUString& schema, const OUString& table) override; + css::uno::Reference SAL_CALL + getImportedKeys(const Any& catalog, const OUString& schema, const OUString& table) override; + css::uno::Reference SAL_CALL + getExportedKeys(const Any& catalog, const OUString& schema, const OUString& table) override; + css::uno::Reference + SAL_CALL getCrossReference(const Any& primaryCatalog, const OUString& primarySchema, + const OUString& primaryTable, const Any& foreignCatalog, + const OUString& foreignSchema, + const OUString& foreignTable) override; + css::uno::Reference SAL_CALL getTypeInfo() override; + css::uno::Reference + SAL_CALL getIndexInfo(const Any& catalog, const OUString& schema, const OUString& table, + sal_Bool unique, sal_Bool approximate) override; + sal_Bool SAL_CALL supportsResultSetType(sal_Int32 setType) override; + sal_Bool SAL_CALL supportsResultSetConcurrency(sal_Int32 setType, + sal_Int32 concurrency) override; + sal_Bool SAL_CALL ownUpdatesAreVisible(sal_Int32 setType) override; + sal_Bool SAL_CALL ownDeletesAreVisible(sal_Int32 setType) override; + sal_Bool SAL_CALL ownInsertsAreVisible(sal_Int32 setType) override; + sal_Bool SAL_CALL othersUpdatesAreVisible(sal_Int32 setType) override; + sal_Bool SAL_CALL othersDeletesAreVisible(sal_Int32 setType) override; + sal_Bool SAL_CALL othersInsertsAreVisible(sal_Int32 setType) override; + sal_Bool SAL_CALL updatesAreDetected(sal_Int32 setType) override; + sal_Bool SAL_CALL deletesAreDetected(sal_Int32 setType) override; + sal_Bool SAL_CALL insertsAreDetected(sal_Int32 setType) override; + sal_Bool SAL_CALL supportsBatchUpdates() override; + css::uno::Reference + SAL_CALL getUDTs(const Any& catalog, const OUString& schemaPattern, + const OUString& typeNamePattern, + const css::uno::Sequence& types) override; + css::uno::Reference SAL_CALL getConnection() override; +}; +} +} + +#endif // INCLUDED_MYSQLC_SOURCE_MYSQLC_DATABASEMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_driver.cxx b/connectivity/source/drivers/mysqlc/mysqlc_driver.cxx new file mode 100644 index 000000000..c7c88d03e --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_driver.cxx @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 "mysqlc_driver.hxx" +#include "mysqlc_connection.hxx" + +using namespace css::uno; +using namespace css::lang; +using namespace css::beans; +using namespace css::sdbc; +using namespace connectivity::mysqlc; + +#include + +MysqlCDriver::MysqlCDriver(const Reference& _rxFactory) + : ODriver_BASE(m_aMutex) + , m_xFactory(_rxFactory) +{ +} + +void MysqlCDriver::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + // when driver will be destroyed so all our connections have to be destroyed as well + for (auto const& connection : m_xConnections) + { + Reference xComp(connection.get(), UNO_QUERY); + if (xComp.is()) + { + xComp->dispose(); + } + } + m_xConnections.clear(); + + ODriver_BASE::disposing(); +} + +// static ServiceInfo +OUString MysqlCDriver::getImplementationName_Static() +{ + return "com.sun.star.comp.sdbc.mysqlc.MysqlCDriver"; +} + +Sequence MysqlCDriver::getSupportedServiceNames_Static() +{ + return { "com.sun.star.sdbc.Driver" }; +} + +OUString SAL_CALL MysqlCDriver::getImplementationName() { return getImplementationName_Static(); } + +sal_Bool SAL_CALL MysqlCDriver::supportsService(const OUString& _rServiceName) +{ + return cppu::supportsService(this, _rServiceName); +} + +Sequence SAL_CALL MysqlCDriver::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +Reference SAL_CALL MysqlCDriver::connect(const OUString& url, + const Sequence& info) +{ + ::osl::MutexGuard aGuard(m_aMutex); + + if (!acceptsURL(url)) + { + return nullptr; + } + + Reference xConn; + // create a new connection with the given properties and append it to our vector + OConnection* pCon = new OConnection(*this); + xConn = pCon; + + pCon->construct(url, info); + m_xConnections.push_back(WeakReferenceHelper(*pCon)); + return xConn; +} + +sal_Bool SAL_CALL MysqlCDriver::acceptsURL(const OUString& url) +{ + return url.startsWith("sdbc:mysqlc:") || url.startsWith("sdbc:mysql:mysqlc:"); +} + +Sequence SAL_CALL +MysqlCDriver::getPropertyInfo(const OUString& url, const Sequence& /* info */) +{ + if (acceptsURL(url)) + { + ::std::vector aDriverInfo; + + aDriverInfo.push_back(DriverPropertyInfo("Hostname", "Name of host", true, "localhost", + Sequence())); + aDriverInfo.push_back( + DriverPropertyInfo("Port", "Port", true, "3306", Sequence())); + return Sequence(aDriverInfo.data(), aDriverInfo.size()); + } + + return Sequence(); +} + +sal_Int32 SAL_CALL MysqlCDriver::getMajorVersion() { return MARIADBC_VERSION_MAJOR; } + +sal_Int32 SAL_CALL MysqlCDriver::getMinorVersion() { return MARIADBC_VERSION_MINOR; } + +namespace connectivity::mysqlc +{ +Reference MysqlCDriver_CreateInstance(const Reference& _rxFactory) +{ + return (*(new MysqlCDriver(_rxFactory))); +} + +void checkDisposed(bool _bThrow) +{ + if (_bThrow) + { + throw DisposedException(); + } +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_driver.hxx b/connectivity/source/drivers/mysqlc/mysqlc_driver.hxx new file mode 100644 index 000000000..b55d9cfee --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_driver.hxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 . + */ +#ifndef INCLUDED_MYSQLC_SOURCE_MYSQLC_DRIVER_HXX +#define INCLUDED_MYSQLC_SOURCE_MYSQLC_DRIVER_HXX + +#include "mysqlc_connection.hxx" + +#include +#include +#include + +#include +#include + +namespace connectivity +{ +namespace mysqlc +{ +using css::sdbc::SQLException; +using css::uno::Exception; +using css::uno::Reference; +using css::uno::RuntimeException; +using css::uno::Sequence; + +Reference +MysqlCDriver_CreateInstance(const Reference& _rxFactory); + +typedef ::cppu::WeakComponentImplHelper2 ODriver_BASE; + +typedef void* (*OMysqlCConnection_CreateInstanceFunction)(void* _pDriver); + +class MysqlCDriver : public ODriver_BASE +{ +protected: + Reference m_xFactory; + ::osl::Mutex m_aMutex; // mutex is need to control member access + OWeakRefArray m_xConnections; // vector containing a list + // of all the Connection objects + // for this Driver +#ifdef BUNDLE_MARIADB + oslModule m_hCConnModule; + bool m_bAttemptedLoadCConn; +#endif +public: + explicit MysqlCDriver(const Reference& _rxFactory); + + // OComponentHelper + void SAL_CALL disposing() override; + // XInterface + static OUString getImplementationName_Static(); + static Sequence getSupportedServiceNames_Static(); + + // XServiceInfo + OUString SAL_CALL getImplementationName() override; + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + Sequence SAL_CALL getSupportedServiceNames() override; + + // XDriver + Reference SAL_CALL + connect(const OUString& url, const Sequence& info) override; + + sal_Bool SAL_CALL acceptsURL(const OUString& url) override; + Sequence SAL_CALL + getPropertyInfo(const OUString& url, const Sequence& info) override; + + sal_Int32 SAL_CALL getMajorVersion() override; + sal_Int32 SAL_CALL getMinorVersion() override; + + const Reference& getFactory() const { return m_xFactory; } + + static rtl_TextEncoding getDefaultEncoding() { return RTL_TEXTENCODING_UTF8; } +}; +} /* mysqlc */ +} /* connectivity */ + +#endif // INCLUDED_MYSQLC_SOURCE_MYSQLC_DRIVER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_general.cxx b/connectivity/source/drivers/mysqlc/mysqlc_general.cxx new file mode 100644 index 000000000..7ed11fe3f --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_general.cxx @@ -0,0 +1,340 @@ +/* -*- 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 "mysqlc_general.hxx" + +#include +#include + +#include + +using com::sun::star::sdbc::SQLException; + +using com::sun::star::uno::Any; +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; + +using namespace rtl; + +namespace mysqlc_sdbc_driver +{ +void allocateSqlVar(void** mem, enum_field_types eType, unsigned nSize) +{ + assert(mem); + switch (eType) + { + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_INT24: + *mem = malloc(sizeof(sal_Int32)); + break; + case MYSQL_TYPE_SHORT: + *mem = malloc(sizeof(sal_Int16)); + break; + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_TINY: + *mem = malloc(sizeof(sal_Int8)); + break; + case MYSQL_TYPE_LONGLONG: + *mem = malloc(sizeof(sal_Int64)); + break; + case MYSQL_TYPE_FLOAT: + *mem = malloc(sizeof(float)); + break; + case MYSQL_TYPE_DOUBLE: + *mem = malloc(sizeof(double)); + break; + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_YEAR: // FIXME below + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_GEOMETRY: + *mem = malloc(sizeof(MYSQL_TIME)); + break; + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + *mem = malloc(sizeof(char) * nSize); + break; + case MYSQL_TYPE_NULL: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + *mem = nullptr; + break; + default: + SAL_WARN("connectivity.mysqlc", "unknown enum_field_type"); + } +} + +void throwFeatureNotImplementedException(const char* _pAsciiFeatureName, + const css::uno::Reference& _rxContext) +{ + const OUString sMessage + = OUString::createFromAscii(_pAsciiFeatureName) + ": feature not implemented."; + throw SQLException(sMessage, _rxContext, "HYC00", 0, Any()); +} + +void throwInvalidArgumentException(const char* _pAsciiFeatureName, + const css::uno::Reference& _rxContext) +{ + const OUString sMessage + = OUString::createFromAscii(_pAsciiFeatureName) + ": invalid arguments."; + throw SQLException(sMessage, _rxContext, "HYC00", 0, Any()); +} + +void throwSQLExceptionWithMsg(const char* msg, const char* SQLSTATE, unsigned int errorNum, + const css::uno::Reference& _context, + const rtl_TextEncoding encoding) +{ + OString errorMsg{ msg }; + throwSQLExceptionWithMsg(OStringToOUString(errorMsg, encoding), SQLSTATE, errorNum, _context); +} + +void throwSQLExceptionWithMsg(const OUString& msg, const char* SQLSTATE, unsigned int errorNum, + const css::uno::Reference& _context) +{ + throw SQLException(msg, _context, OStringToOUString(SQLSTATE, RTL_TEXTENCODING_ASCII_US), + errorNum, Any()); +} + +sal_Int32 mysqlToOOOType(int eType, int charsetnr) noexcept +{ + // charset number 63 indicates binary + switch (eType) + { + case MYSQL_TYPE_BIT: + return css::sdbc::DataType::VARCHAR; + + case MYSQL_TYPE_TINY: + return css::sdbc::DataType::TINYINT; + + case MYSQL_TYPE_SHORT: + return css::sdbc::DataType::SMALLINT; + + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: + return css::sdbc::DataType::INTEGER; + + case MYSQL_TYPE_LONGLONG: + return css::sdbc::DataType::BIGINT; + + case MYSQL_TYPE_FLOAT: + return css::sdbc::DataType::REAL; + + case MYSQL_TYPE_DOUBLE: + return css::sdbc::DataType::DOUBLE; + + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + return css::sdbc::DataType::DECIMAL; + + case MYSQL_TYPE_STRING: + if (charsetnr == 63) + return css::sdbc::DataType::BINARY; + return css::sdbc::DataType::CHAR; + + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_VAR_STRING: + if (charsetnr == 63) + return css::sdbc::DataType::VARBINARY; + return css::sdbc::DataType::VARCHAR; + + case MYSQL_TYPE_BLOB: + if (charsetnr == 63) + return css::sdbc::DataType::LONGVARBINARY; + return css::sdbc::DataType::LONGVARCHAR; + + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATETIME: + return css::sdbc::DataType::TIMESTAMP; + + case MYSQL_TYPE_DATE: + return css::sdbc::DataType::DATE; + + case MYSQL_TYPE_TIME: + return css::sdbc::DataType::TIME; + + case MYSQL_TYPE_GEOMETRY: + return css::sdbc::DataType::VARCHAR; + + case MYSQL_TYPE_NULL: + return css::sdbc::DataType::SQLNULL; + } + + OSL_FAIL("mysqlToOOOType: unhandled case, falling back to VARCHAR"); + return css::sdbc::DataType::VARCHAR; +} + +sal_Int32 mysqlStrToOOOType(const OUString& sType) +{ + // TODO other types. + if (sType.equalsIgnoreAsciiCase("tiny") || sType.equalsIgnoreAsciiCase("tinyint")) + return css::sdbc::DataType::TINYINT; + if (sType.equalsIgnoreAsciiCase("smallint") || sType.equalsIgnoreAsciiCase("mediumint")) + return css::sdbc::DataType::SMALLINT; + if (sType.equalsIgnoreAsciiCase("longtext")) + return css::sdbc::DataType::LONGVARCHAR; + if (sType.equalsIgnoreAsciiCase("int")) + return css::sdbc::DataType::INTEGER; + if (sType.equalsIgnoreAsciiCase("varchar") || sType.equalsIgnoreAsciiCase("set") + || sType.equalsIgnoreAsciiCase("enum")) + return css::sdbc::DataType::VARCHAR; + if (sType.equalsIgnoreAsciiCase("bigint")) + return css::sdbc::DataType::BIGINT; + if (sType.equalsIgnoreAsciiCase("blob") || sType.equalsIgnoreAsciiCase("longblob")) + return css::sdbc::DataType::BLOB; + if (sType.equalsIgnoreAsciiCase("varbinary")) + return css::sdbc::DataType::VARBINARY; + if (sType.equalsIgnoreAsciiCase("char")) + return css::sdbc::DataType::CHAR; + if (sType.equalsIgnoreAsciiCase("text")) + return css::sdbc::DataType::CLOB; + if (sType.equalsIgnoreAsciiCase("binary")) + return css::sdbc::DataType::BINARY; + if (sType.equalsIgnoreAsciiCase("time")) + return css::sdbc::DataType::TIME; + if (sType.equalsIgnoreAsciiCase("date")) + return css::sdbc::DataType::DATE; + if (sType.equalsIgnoreAsciiCase("datetime") || sType.equalsIgnoreAsciiCase("timestamp")) + return css::sdbc::DataType::TIMESTAMP; + if (sType.equalsIgnoreAsciiCase("decimal")) + return css::sdbc::DataType::DECIMAL; + if (sType.equalsIgnoreAsciiCase("real") || sType.equalsIgnoreAsciiCase("float")) + return css::sdbc::DataType::REAL; + if (sType.equalsIgnoreAsciiCase("double")) + return css::sdbc::DataType::DOUBLE; + if (sType.equalsIgnoreAsciiCase("bit") || sType.equalsIgnoreAsciiCase("bool") + || sType.equalsIgnoreAsciiCase("boolean")) + return css::sdbc::DataType::BOOLEAN; + OSL_FAIL("Unknown type name from string, failing back to varchar."); + return css::sdbc::DataType::VARCHAR; +} + +OUString mysqlTypeToStr(unsigned type, unsigned flags) +{ + bool isUnsigned = (flags & UNSIGNED_FLAG) != 0; + bool isZerofill = (flags & ZEROFILL_FLAG) != 0; + switch (type) + { + case MYSQL_TYPE_BIT: + return OUString{ "BIT" }; + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + return isUnsigned ? (isZerofill ? OUString{ "DECIMAL UNSIGNED ZEROFILL" } + : OUString{ "DECIMAL UNSIGNED" }) + : OUString{ "DECIMAL" }; + case MYSQL_TYPE_TINY: + return isUnsigned ? (isZerofill ? OUString{ "TINYINT UNSIGNED ZEROFILL" } + : OUString{ "TINYINT UNSIGNED" }) + : OUString{ "TINYINT" }; + case MYSQL_TYPE_SHORT: + return isUnsigned ? (isZerofill ? OUString{ "SMALLINT UNSIGNED ZEROFILL" } + : OUString{ "SMALLINT UNSIGNED" }) + : OUString{ "SMALLINT" }; + case MYSQL_TYPE_LONG: + return isUnsigned ? (isZerofill ? OUString{ "INT UNSIGNED ZEROFILL" } + : OUString{ "INT UNSIGNED" }) + : OUString{ "INT" }; + case MYSQL_TYPE_FLOAT: + return isUnsigned ? (isZerofill ? OUString{ "FLOAT UNSIGNED ZEROFILL" } + : OUString{ "FLOAT UNSIGNED" }) + : OUString{ "FLOAT" }; + case MYSQL_TYPE_DOUBLE: + return isUnsigned ? (isZerofill ? OUString{ "DOUBLE UNSIGNED ZEROFILL" } + : OUString{ "DOUBLE UNSIGNED" }) + : OUString{ "DOUBLE" }; + case MYSQL_TYPE_NULL: + return OUString{ "NULL" }; + case MYSQL_TYPE_TIMESTAMP: + return OUString{ "TIMESTAMP" }; + case MYSQL_TYPE_LONGLONG: + return isUnsigned ? (isZerofill ? OUString{ "BIGINT UNSIGNED ZEROFILL" } + : OUString{ "BIGINT UNSIGNED" }) + : OUString{ "BIGINT" }; + case MYSQL_TYPE_INT24: + return isUnsigned ? (isZerofill ? OUString{ "MEDIUMINT UNSIGNED ZEROFILL" } + : OUString{ "MEDIUMINT UNSIGNED" }) + : OUString{ "MEDIUMINT" }; + case MYSQL_TYPE_DATE: + return OUString{ "DATE" }; + case MYSQL_TYPE_TIME: + return OUString{ "TIME" }; + case MYSQL_TYPE_DATETIME: + return OUString{ "DATETIME" }; + case MYSQL_TYPE_TINY_BLOB: + { + return OUString{ "TINYBLOB" }; + } + case MYSQL_TYPE_MEDIUM_BLOB: + { + return OUString{ "MEDIUMBLOB" }; + } + case MYSQL_TYPE_LONG_BLOB: + { + return OUString{ "LONGBLOB" }; + } + case MYSQL_TYPE_BLOB: + { + return OUString{ "BLOB" }; + } + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_VAR_STRING: + if (flags & ENUM_FLAG) + { + return OUString{ "ENUM" }; + } + if (flags & SET_FLAG) + { + return OUString{ "SET" }; + } + return OUString{ "VARCHAR" }; + case MYSQL_TYPE_STRING: + if (flags & ENUM_FLAG) + { + return OUString{ "ENUM" }; + } + if (flags & SET_FLAG) + { + return OUString{ "SET" }; + } + return OUString{ "CHAR" }; + case MYSQL_TYPE_YEAR: + return OUString{ "YEAR" }; + case MYSQL_TYPE_GEOMETRY: + return OUString{ "GEOMETRY" }; + default: + return OUString{ "UNKNOWN" }; + } +} + +OUString convert(const ::std::string& _string, const rtl_TextEncoding encoding) +{ + return OUString(_string.c_str(), _string.size(), encoding); +} + +} /* namespace */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_general.hxx b/connectivity/source/drivers/mysqlc/mysqlc_general.hxx new file mode 100644 index 000000000..c00a11f41 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_general.hxx @@ -0,0 +1,119 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_MYSQLC_SOURCE_MYSQLC_GENERAL_HXX +#define INCLUDED_MYSQLC_SOURCE_MYSQLC_GENERAL_HXX + +#include + +#include +#include + +#include +#include + +#if defined __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated" +#endif + +#if defined __GNUC__ +#pragma GCC diagnostic pop +#endif + +namespace mysqlc_sdbc_driver +{ +template +void resetSqlVar(void** target, T* pValue, enum_field_types type, sal_Int32 nSize = 0) +{ + if (*target) + { + free(*target); + *target = nullptr; + } + constexpr auto nUnitSize = sizeof(T); + switch (type) + { + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_GEOMETRY: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + *target = malloc(nUnitSize); + memcpy(*target, pValue, nUnitSize); + break; + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_NEWDECIMAL: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + *target = malloc(nUnitSize * nSize); + memcpy(*target, pValue, nUnitSize * nSize); + break; + case MYSQL_TYPE_NULL: + // nothing I guess + break; + default: + OSL_FAIL("resetSqlVar: unknown enum_field_type"); + } +} + +void allocateSqlVar(void** mem, enum_field_types eType, unsigned nSize = 0); + +void throwFeatureNotImplementedException( + const char* _pAsciiFeatureName, const css::uno::Reference& _rxContext); + +void throwInvalidArgumentException(const char* _pAsciiFeatureName, + const css::uno::Reference& _rxContext); + +void throwSQLExceptionWithMsg(const char* msg, const char* SQLSTATE, unsigned int errorNum, + const css::uno::Reference& _context, + const rtl_TextEncoding encoding); + +void throwSQLExceptionWithMsg(const OUString& msg, const char* SQLSTATE, unsigned int errorNum, + const css::uno::Reference& _context); + +sal_Int32 mysqlToOOOType(int eType, int charsetnr) noexcept; + +OUString mysqlTypeToStr(unsigned mysql_type, unsigned mysql_flags); + +sal_Int32 mysqlStrToOOOType(const OUString& sType); + +OUString convert(const ::std::string& _string, const rtl_TextEncoding encoding); +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx new file mode 100644 index 000000000..8031bfdf2 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx @@ -0,0 +1,1084 @@ +/* -*- 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 "mysqlc_propertyids.hxx" +#include "mysqlc_general.hxx" +#include "mysqlc_prepared_resultset.hxx" +#include "mysqlc_resultsetmetadata.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace rtl; + +#include + +using namespace connectivity::mysqlc; +using namespace connectivity; +using namespace cppu; +using namespace com::sun::star; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::sdbcx; +using namespace com::sun::star::container; +using namespace com::sun::star::io; +using namespace com::sun::star::util; +using namespace ::comphelper; +using ::osl::MutexGuard; + +#include + +namespace +{ +std::type_index getTypeFromMysqlType(enum_field_types type) +{ + switch (type) + { + case MYSQL_TYPE_TINY: + return std::type_index(typeid(sal_Int8)); + case MYSQL_TYPE_SHORT: + return std::type_index(typeid(sal_Int16)); + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_INT24: + return std::type_index(typeid(sal_Int32)); + case MYSQL_TYPE_LONGLONG: + return std::type_index(typeid(sal_Int64)); + case MYSQL_TYPE_FLOAT: + return std::type_index(typeid(float)); + case MYSQL_TYPE_DOUBLE: + return std::type_index(typeid(double)); + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATETIME: + return std::type_index(typeid(DateTime)); + case MYSQL_TYPE_DATE: + return std::type_index(typeid(Date)); + case MYSQL_TYPE_TIME: + return std::type_index(typeid(Time)); + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + return std::type_index(typeid(OUString)); + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_GEOMETRY: + case MYSQL_TYPE_NULL: + default: + return std::type_index(typeid(nullptr)); + } +} +} + +bool OPreparedResultSet::fetchResult() +{ + // allocate array if it does not exist + if (m_aData == nullptr) + { + m_aData.reset(new MYSQL_BIND[m_nColumnCount]); + memset(m_aData.get(), 0, m_nColumnCount * sizeof(MYSQL_BIND)); + m_aMetaData.reset(new BindMetaData[m_nColumnCount]); + } + for (sal_Int32 i = 0; i < m_nColumnCount; ++i) + { + m_aMetaData[i].is_null = false; + m_aMetaData[i].length = 0l; + m_aMetaData[i].error = false; + + m_aData[i].is_null = &m_aMetaData[i].is_null; + m_aData[i].buffer_length = m_aFields[i].type == MYSQL_TYPE_BLOB ? 0 : m_aFields[i].length; + m_aData[i].length = &m_aMetaData[i].length; + m_aData[i].error = &m_aMetaData[i].error; + m_aData[i].buffer = nullptr; + m_aData[i].buffer_type = m_aFields[i].type; + + // allocates memory, if it is a fixed size type. If not then nullptr + mysqlc_sdbc_driver::allocateSqlVar(&m_aData[i].buffer, m_aData[i].buffer_type, + m_aFields[i].length); + } + mysql_stmt_bind_result(m_pStmt, m_aData.get()); + int failure = mysql_stmt_fetch(m_pStmt); + + for (sal_Int32 i = 0; i < m_nColumnCount; ++i) + { + if (*m_aData[i].error) + { + // expected if we have a BLOB, as buffer_length is set to 0. We want to + // fetch it piece by piece + // see https://bugs.mysql.com/file.php?id=12361&bug_id=33086 + if (m_aData[i].buffer == nullptr) + { + m_aData[i].buffer_length = *m_aData[i].length; + m_aData[i].buffer = malloc(*m_aData[i].length); + mysql_stmt_fetch_column(m_pStmt, &m_aData[i], i, 0); + } + } + } + + if (failure == 1) + { + MYSQL* pMysql = m_rConnection.getMysqlConnection(); + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(pMysql), mysql_sqlstate(pMysql), + mysql_errno(pMysql), *this, m_encoding); + } + else if (failure == MYSQL_NO_DATA) + return false; + return true; +} + +OUString SAL_CALL OPreparedResultSet::getImplementationName() +{ + return "com.sun.star.sdbcx.mysqlc.ResultSet"; +} + +uno::Sequence SAL_CALL OPreparedResultSet::getSupportedServiceNames() +{ + return { "com.sun.star.sdbc.ResultSet", "com.sun.star.sdbcx.ResultSet" }; +} + +sal_Bool SAL_CALL OPreparedResultSet::supportsService(const OUString& _rServiceName) +{ + return cppu::supportsService(this, _rServiceName); +} +OPreparedResultSet::OPreparedResultSet(OConnection& rConn, OPreparedStatement* pStmt, + MYSQL_STMT* pMyStmt) + : OPreparedResultSet_BASE(m_aMutex) + , OPropertySetHelper(OPreparedResultSet_BASE::rBHelper) + , m_rConnection(rConn) + , m_aStatement(static_cast(pStmt)) + , m_pStmt(pMyStmt) + , m_encoding(rConn.getConnectionEncoding()) + , m_nColumnCount(mysql_stmt_field_count(pMyStmt)) +{ + m_pResult = mysql_stmt_result_metadata(m_pStmt); + if (m_pResult != nullptr) + mysql_stmt_store_result(m_pStmt); + m_aFields = mysql_fetch_fields(m_pResult); + m_nRowCount = mysql_stmt_num_rows(pMyStmt); +} + +void OPreparedResultSet::disposing() +{ + OPropertySetHelper::disposing(); + + MutexGuard aGuard(m_aMutex); + + m_aStatement = nullptr; + m_xMetaData = nullptr; +} + +Any SAL_CALL OPreparedResultSet::queryInterface(const Type& rType) +{ + Any aRet = OPropertySetHelper::queryInterface(rType); + if (!aRet.hasValue()) + { + aRet = OPreparedResultSet_BASE::queryInterface(rType); + } + return aRet; +} + +uno::Sequence SAL_CALL OPreparedResultSet::getTypes() +{ + OTypeCollection aTypes(cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get()); + + return concatSequences(aTypes.getTypes(), OPreparedResultSet_BASE::getTypes()); +} + +sal_Int32 SAL_CALL OPreparedResultSet::findColumn(const OUString& columnName) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + MYSQL_FIELD* pFields = mysql_fetch_fields(m_pResult); + for (sal_Int32 i = 0; i < m_nColumnCount; ++i) + { + if (columnName.equalsIgnoreAsciiCaseAscii(pFields[i].name)) + return i + 1; // sdbc indexes from 1 + } + + throw SQLException("The column name '" + columnName + "' is not valid.", *this, "42S22", 0, + Any()); +} + +template T OPreparedResultSet::safelyRetrieveValue(sal_Int32 nColumnIndex) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(nColumnIndex); + if (*m_aData[nColumnIndex - 1].is_null) + { + m_bWasNull = true; + return T(); + } + m_bWasNull = false; + + return retrieveValue(nColumnIndex); +} + +template T OPreparedResultSet::retrieveValue(sal_Int32 nColumnIndex) +{ + if (getTypeFromMysqlType(m_aFields[nColumnIndex - 1].type) == std::type_index(typeid(T))) + return *static_cast(m_aData[nColumnIndex - 1].buffer); + else + return getRowSetValue(nColumnIndex); +} + +template <> uno::Sequence OPreparedResultSet::retrieveValue(sal_Int32 column) +{ + // TODO make conversion possible + return uno::Sequence(static_cast(m_aData[column - 1].buffer), + *m_aData[column - 1].length); +} + +template <> Date OPreparedResultSet::retrieveValue(sal_Int32 column) +{ + if (getTypeFromMysqlType(m_aFields[column - 1].type) != std::type_index(typeid(Date))) + return getRowSetValue(column); + const MYSQL_TIME* pTime = static_cast(m_aData[column - 1].buffer); + + Date d; + d.Year = pTime->year; + d.Month = pTime->month; + d.Day = pTime->day; + return d; +} + +template <> Time OPreparedResultSet::retrieveValue(sal_Int32 column) +{ + if (getTypeFromMysqlType(m_aFields[column - 1].type) != std::type_index(typeid(Time))) + return getRowSetValue(column); + const MYSQL_TIME* pTime = static_cast(m_aData[column - 1].buffer); + + Time t; + t.Hours = pTime->hour; + t.Minutes = pTime->minute; + t.Seconds = pTime->second; + return t; +} + +template <> DateTime OPreparedResultSet::retrieveValue(sal_Int32 column) +{ + if (getTypeFromMysqlType(m_aFields[column - 1].type) != std::type_index(typeid(DateTime))) + return getRowSetValue(column); + const MYSQL_TIME* pTime = static_cast(m_aData[column - 1].buffer); + + DateTime t; + t.Year = pTime->year; + t.Month = pTime->month; + t.Day = pTime->day; + t.Hours = pTime->hour; + t.Minutes = pTime->minute; + t.Seconds = pTime->second; + return t; +} + +template <> OUString OPreparedResultSet::retrieveValue(sal_Int32 column) +{ + // redirect call to the appropriate method if needed + // BLOB can be simply read out as string + if (getTypeFromMysqlType(m_aFields[column - 1].type) != std::type_index(typeid(OUString)) + && m_aFields[column - 1].type != MYSQL_TYPE_BLOB) + return getRowSetValue(column); + const char* sStr = static_cast(m_aData[column - 1].buffer); + + return OUString(sStr, *m_aData[column - 1].length, m_encoding); +} + +ORowSetValue OPreparedResultSet::getRowSetValue(sal_Int32 nColumnIndex) +{ + switch (m_aFields[nColumnIndex - 1].type) + { + case MYSQL_TYPE_TINY: + return getByte(nColumnIndex); + case MYSQL_TYPE_SHORT: + return getShort(nColumnIndex); + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_INT24: + return getInt(nColumnIndex); + case MYSQL_TYPE_LONGLONG: + return getLong(nColumnIndex); + case MYSQL_TYPE_FLOAT: + return getFloat(nColumnIndex); + case MYSQL_TYPE_DOUBLE: + return getDouble(nColumnIndex); + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATETIME: + return getTimestamp(nColumnIndex); + case MYSQL_TYPE_DATE: + return getDate(nColumnIndex); + case MYSQL_TYPE_TIME: + return getTime(nColumnIndex); + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + return getString(nColumnIndex); + case MYSQL_TYPE_BLOB: + throw SQLException("Column with type BLOB cannot be converted", *this, "22000", 1, + Any()); + default: + SAL_WARN("connectivity.mysqlc", "OPreparedResultSet::getRowSetValue: unknown type: " + << m_aFields[nColumnIndex - 1].type); + throw SQLException("Unknown column type when fetching result", *this, "22000", 1, + Any()); + } +} + +uno::Reference SAL_CALL OPreparedResultSet::getBinaryStream(sal_Int32 /*column*/) +{ + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getBinaryStream", + *this); + return nullptr; +} + +uno::Reference SAL_CALL OPreparedResultSet::getCharacterStream(sal_Int32 /*column*/) +{ + mysqlc_sdbc_driver::throwFeatureNotImplementedException( + "OPreparedResultSet::getCharacterStream", *this); + return nullptr; +} + +sal_Bool SAL_CALL OPreparedResultSet::getBoolean(sal_Int32 column) +{ + return safelyRetrieveValue(column); +} + +sal_Int8 SAL_CALL OPreparedResultSet::getByte(sal_Int32 column) +{ + return safelyRetrieveValue(column); +} + +uno::Sequence SAL_CALL OPreparedResultSet::getBytes(sal_Int32 column) +{ + return safelyRetrieveValue>(column); +} + +Date SAL_CALL OPreparedResultSet::getDate(sal_Int32 column) +{ + return safelyRetrieveValue(column); +} + +double SAL_CALL OPreparedResultSet::getDouble(sal_Int32 column) +{ + return safelyRetrieveValue(column); +} + +float SAL_CALL OPreparedResultSet::getFloat(sal_Int32 column) +{ + return safelyRetrieveValue(column); +} + +sal_Int32 SAL_CALL OPreparedResultSet::getInt(sal_Int32 column) +{ + return safelyRetrieveValue(column); +} + +sal_Int32 SAL_CALL OPreparedResultSet::getRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return static_cast(mysql_field_tell(m_pResult)); +} + +sal_Int64 SAL_CALL OPreparedResultSet::getLong(sal_Int32 column) +{ + return safelyRetrieveValue(column); +} + +uno::Reference SAL_CALL OPreparedResultSet::getMetaData() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + if (!m_xMetaData.is()) + { + m_xMetaData = new OResultSetMetaData(m_rConnection, m_pResult); + } + return m_xMetaData; +} + +uno::Reference SAL_CALL OPreparedResultSet::getArray(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getArray", *this); + return nullptr; +} + +uno::Reference SAL_CALL OPreparedResultSet::getClob(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getClob", *this); + return nullptr; +} + +uno::Reference SAL_CALL OPreparedResultSet::getBlob(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getBlob", *this); + return nullptr; +} + +uno::Reference SAL_CALL OPreparedResultSet::getRef(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getRef", *this); + return nullptr; +} + +Any SAL_CALL OPreparedResultSet::getObject(sal_Int32 column, + const uno::Reference& /* typeMap */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + + Any aRet; + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getObject", *this); + return aRet; +} + +sal_Int16 SAL_CALL OPreparedResultSet::getShort(sal_Int32 column) +{ + return safelyRetrieveValue(column); +} + +OUString SAL_CALL OPreparedResultSet::getString(sal_Int32 column) +{ + return safelyRetrieveValue(column); +} + +Time SAL_CALL OPreparedResultSet::getTime(sal_Int32 column) +{ + return safelyRetrieveValue