diff options
Diffstat (limited to 'connectivity/source/drivers/mysqlc')
44 files changed, 9362 insertions, 0 deletions
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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * +--> +<component xmlns="http://openoffice.org/2010/uno-components" + loader="com.sun.star.loader.SharedLibrary"> + <implementation name="com.sun.star.comp.sdbc.mysqlc.MysqlCDriver"> + <service name="com.sun.star.sdbc.Driver"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/mysqlc/mysqlc_catalog.cxx b/connectivity/source/drivers/mysqlc/mysqlc_catalog.cxx new file mode 100644 index 000000000..d8b9db742 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_catalog.cxx @@ -0,0 +1,70 @@ +/* -*- 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/. + */ + +#include "mysqlc_catalog.hxx" +#include "mysqlc_tables.hxx" +#include "mysqlc_views.hxx" + +connectivity::mysqlc::Catalog::Catalog( + const css::uno::Reference<css::sdbc::XConnection>& rConnection) + : OCatalog(rConnection) + , m_xConnection(rConnection) +{ +} + +//----- OCatalog ------------------------------------------------------------- +void connectivity::mysqlc::Catalog::refreshTables() +{ + css::uno::Reference<css::sdbc::XResultSet> xTables + = m_xMetaData->getTables(css::uno::Any(), "%", "%", {}); + + if (!xTables.is()) + return; + + ::std::vector<OUString> aTableNames; + + fillNames(xTables, aTableNames); + + if (!m_pTables) + m_pTables.reset(new Tables(m_xConnection->getMetaData(), *this, m_aMutex, aTableNames)); + else + m_pTables->reFill(aTableNames); +} + +void connectivity::mysqlc::Catalog::refreshViews() +{ + css::uno::Reference<css::sdbc::XResultSet> xViews + = m_xMetaData->getTables(css::uno::Any(), "%", "%", { "VIEW" }); + + if (!xViews.is()) + return; + + ::std::vector<OUString> aViewNames; + + fillNames(xViews, aViewNames); + + if (!m_pViews) + m_pViews.reset(new Views(m_xConnection, *this, m_aMutex, aViewNames)); + else + m_pViews->reFill(aViewNames); +} + +//----- IRefreshableGroups --------------------------------------------------- +void connectivity::mysqlc::Catalog::refreshGroups() +{ + // TODO: implement me +} + +//----- IRefreshableUsers ---------------------------------------------------- +void connectivity::mysqlc::Catalog::refreshUsers() +{ + // TODO: implement me +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_catalog.hxx b/connectivity/source/drivers/mysqlc/mysqlc_catalog.hxx new file mode 100644 index 000000000..1bea18c76 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_catalog.hxx @@ -0,0 +1,38 @@ +/* -*- 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/. + */ + +#pragma once + +#include <sdbcx/VCatalog.hxx> + +namespace connectivity::mysqlc +{ +class Catalog : public ::connectivity::sdbcx::OCatalog +{ + css::uno::Reference<css::sdbc::XConnection> m_xConnection; + +public: + explicit Catalog(const css::uno::Reference<css::sdbc::XConnection>& rConnection); + + // OCatalog + virtual void refreshTables() override; + virtual void refreshViews() override; + + // IRefreshableGroups + virtual void refreshGroups() override; + + // IRefreshableUsers + virtual void refreshUsers() override; + + sdbcx::OCollection* getPrivateTables() const { return m_pTables.get(); } +}; + +} // namespace connectivity::mysqlc + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_column.cxx b/connectivity/source/drivers/mysqlc/mysqlc_column.cxx new file mode 100644 index 000000000..ceb743738 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_column.cxx @@ -0,0 +1,45 @@ +/* -*- 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/. + */ + +#include "mysqlc_column.hxx" + +#include <TConnection.hxx> + +connectivity::mysqlc::Column::Column() + : OColumn(true) // case sensitive +{ + construct(); +} + +void connectivity::mysqlc::Column::construct() +{ + m_sAutoIncrement = "auto_increment"; + registerProperty( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION), + PROPERTY_ID_AUTOINCREMENTCREATION, 0, &m_sAutoIncrement, + cppu::UnoType<decltype(m_sAutoIncrement)>::get()); +} + +::cppu::IPropertyArrayHelper* + connectivity::mysqlc::Column::createArrayHelper(sal_Int32 /*_nId*/) const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper& SAL_CALL connectivity::mysqlc::Column::getInfoHelper() +{ + return *Column_PROP::getArrayHelper(isNew() ? 1 : 0); +} + +css::uno::Sequence<OUString> SAL_CALL connectivity::mysqlc::Column::getSupportedServiceNames() +{ + return { "com.sun.star.sdbcx.Column" }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_column.hxx b/connectivity/source/drivers/mysqlc/mysqlc_column.hxx new file mode 100644 index 000000000..f69ef1afc --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_column.hxx @@ -0,0 +1,32 @@ +/* -*- 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/. + */ +#pragma once + +#include <connectivity/sdbcx/VColumn.hxx> + +namespace connectivity::mysqlc +{ +class Column; +typedef ::comphelper::OIdPropertyArrayUsageHelper<Column> Column_PROP; +class Column : public sdbcx::OColumn, public Column_PROP +{ + OUString m_sAutoIncrement; + +protected: + virtual ::cppu::IPropertyArrayHelper* createArrayHelper(sal_Int32 _nId) const override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + +public: + Column(); + virtual void construct() override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_columns.cxx b/connectivity/source/drivers/mysqlc/mysqlc_columns.cxx new file mode 100644 index 000000000..b34b36b45 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_columns.cxx @@ -0,0 +1,28 @@ +/* -*- 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/. + */ + +#include "mysqlc_columns.hxx" +#include "mysqlc_column.hxx" + +connectivity::mysqlc::Columns::Columns(Table& rTable, osl::Mutex& rMutex, + const ::std::vector<OUString>& rVector) + : OColumnsHelper(rTable, + true, // case sensitivity + rMutex, rVector, + /*bUseHardRef*/ true) +{ + OColumnsHelper::setParent(&rTable); +} + +css::uno::Reference<css::beans::XPropertySet> connectivity::mysqlc::Columns::createDescriptor() +{ + return new Column; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_columns.hxx b/connectivity/source/drivers/mysqlc/mysqlc_columns.hxx new file mode 100644 index 000000000..34230db37 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_columns.hxx @@ -0,0 +1,29 @@ +/* -*- 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/. + */ + +#pragma once + +#include "mysqlc_table.hxx" + +#include <connectivity/TColumnsHelper.hxx> + +namespace connectivity::mysqlc +{ +class Columns : public ::connectivity::OColumnsHelper +{ +protected: + virtual css::uno::Reference<css::beans::XPropertySet> createDescriptor() override; + +public: + Columns(Table& rTable, ::osl::Mutex& rMutex, const ::std::vector<OUString>& _rVector); +}; + +} // namespace connectivity::mysqlc + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_connection.cxx b/connectivity/source/drivers/mysqlc/mysqlc_connection.cxx new file mode 100644 index 000000000..d56993f89 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_connection.cxx @@ -0,0 +1,524 @@ +/* -*- 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_catalog.hxx" +#include "mysqlc_connection.hxx" +#include "mysqlc_databasemetadata.hxx" +#include <com/sun/star/sdbc/SQLException.hpp> + +#include "mysqlc_driver.hxx" +#include "mysqlc_statement.hxx" +#include "mysqlc_preparedstatement.hxx" +#include "mysqlc_general.hxx" + +#include <com/sun/star/beans/NamedValue.hpp> + +#include <comphelper/servicehelper.hxx> + +using namespace connectivity::mysqlc; + +using namespace com::sun::star::uno; +using namespace com::sun::star::container; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::sdbcx; +using ::osl::MutexGuard; + +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_xCatalog(nullptr) + , m_xMetaData(nullptr) + , m_xDriver(&_rDriver) +{ +} + +OConnection::~OConnection() +{ + if (!isClosed()) + { + close(); + } +} + +void OConnection::construct(const OUString& url, const Sequence<PropertyValue>& info) +{ + MutexGuard aGuard(m_aMutex); + + mysql_library_init(0, nullptr, nullptr); + mysql_init(&m_mysql); + + 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("sdbc:mysqlc:")) + { + 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; + + // use TCP as connection by default + mysql_protocol_type protocol = MYSQL_PROTOCOL_TCP; + if (unixSocketPassed) + { + socket_str = OUStringToOString(sUnixSocket, m_settings.encoding); + protocol = MYSQL_PROTOCOL_SOCKET; + } + else if (namedPipePassed) + { + socket_str = OUStringToOString(sNamedPipe, m_settings.encoding); + protocol = MYSQL_PROTOCOL_PIPE; + } + + mysql_options(&m_mysql, MYSQL_OPT_PROTOCOL, &protocol); + + // 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<OUString> OConnection::getSupportedServiceNames() +{ + return { "com.sun.star.sdbc.Connection" }; +} + +sal_Bool OConnection::supportsService(OUString const& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +Reference<XStatement> SAL_CALL OConnection::createStatement() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + // create a statement + // the statement can only be executed once + Reference<XStatement> xReturn = new OStatement(this); + m_aStatements.push_back(WeakReferenceHelper(xReturn)); + + return xReturn; +} + +Reference<XPreparedStatement> 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<XPreparedStatement> xStatement = new OPreparedStatement(this, pStmt); + m_aStatements.push_back(WeakReferenceHelper(xStatement)); + return xStatement; +} + +Reference<XPreparedStatement> 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<XPreparedStatement>(); +} + +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<XDatabaseMetaData> SAL_CALL OConnection::getMetaData() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + Reference<XDatabaseMetaData> 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<XNameAccess> SAL_CALL OConnection::getTypeMap() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + Reference<XNameAccess> t = m_typeMap; + return t; +} + +void SAL_CALL OConnection::setTypeMap(const Reference<XNameAccess>& 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<XComponent> xComp(statement.get(), UNO_QUERY); + if (xComp.is()) + { + xComp->dispose(); + } + } + m_aStatements.clear(); + + m_xMetaData = WeakReference<XDatabaseMetaData>(); + + 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<sal_Int32>(version); +} + +OUString OConnection::transFormPreparedStatement(const OUString& _sSQL) +{ + OUString sSqlStatement = _sSQL; + if (!m_xParameterSubstitution.is()) + { + try + { + Reference<XConnection> xCon = this; + Sequence<Any> aArgs{ Any(NamedValue("ActiveConnection", Any(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; +} + +//----- XUnoTunnel ---------------------------------------------------------- +// virtual +sal_Int64 SAL_CALL OConnection::getSomething(const css::uno::Sequence<sal_Int8>& rId) +{ + return comphelper::getSomethingImpl(rId, this); +} + +// static +const Sequence<sal_Int8>& OConnection::getUnoTunnelId() +{ + static const comphelper::UnoIdInit implId; + return implId.getSeq(); +} + +Reference<XTablesSupplier> OConnection::createCatalog() +{ + MutexGuard aGuard(m_aMutex); + + // m_xCatalog is a weak reference. Reuse it if it still exists. + Reference<XTablesSupplier> xCatalog = m_xCatalog; + if (xCatalog.is()) + { + return xCatalog; + } + else + { + xCatalog = new Catalog(this); + m_xCatalog = xCatalog; + return m_xCatalog; + } +} + +/* 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..3a0ccf36b --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_connection.hxx @@ -0,0 +1,190 @@ +/* -*- 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 . + */ + +#pragma once + +#include <memory> +#include "mysqlc_subcomponent.hxx" +#include "mysqlc_types.hxx" + +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/util/XStringSubstitution.hpp> + +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> + +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/compbase.hxx> +#include <rtl/ref.hxx> + +#include <mysql.h> + +#include <map> + +namespace sql +{ +class SQLException; +} + +namespace connectivity +{ +class OMetaConnection; +class ODatabaseMetaData; + +namespace mysqlc +{ +typedef ::cppu::WeakComponentImplHelper<css::sdbc::XConnection, css::sdbc::XWarningsSupplier, + css::lang::XUnoTunnel, css::lang::XServiceInfo> + 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<css::uno::WeakReferenceHelper> OWeakRefArray; + +class OConnection final : public cppu::BaseMutex, public OConnection_BASE +{ +private: + MYSQL m_mysql; + ConnectionSettings m_settings; + css::uno::Reference<css::container::XNameAccess> m_typeMap; + css::uno::Reference<css::util::XStringSubstitution> m_xParameterSubstitution; + + // Data attributes + + css::uno::WeakReference<css::sdbcx::XTablesSupplier> m_xCatalog; + css::uno::WeakReference<css::sdbc::XDatabaseMetaData> m_xMetaData; + + OWeakRefArray m_aStatements; // vector containing a list + // of all the Statement objects + // for this Connection + + rtl::Reference<MysqlCDriver> 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<css::beans::PropertyValue>& info); + + OConnection(MysqlCDriver& _rDriver); + virtual ~OConnection() override; + + rtl_TextEncoding getConnectionEncoding() const { return m_settings.encoding; } + + /** + * Create and/or connect to the sdbcx Catalog. This is completely + * unrelated to the SQL "Catalog". + */ + css::uno::Reference<css::sdbcx::XTablesSupplier> createCatalog(); + + // 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<OUString> SAL_CALL getSupportedServiceNames() override; + + // XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething(const css::uno::Sequence<sal_Int8>& rId) override; + static const css::uno::Sequence<sal_Int8>& getUnoTunnelId(); + + // XConnection + css::uno::Reference<css::sdbc::XStatement> SAL_CALL createStatement() override; + + css::uno::Reference<css::sdbc::XPreparedStatement> + SAL_CALL prepareStatement(const OUString& sql) override; + + css::uno::Reference<css::sdbc::XPreparedStatement> + 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<css::sdbc::XDatabaseMetaData> 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<css::container::XNameAccess> SAL_CALL getTypeMap() override; + + void SAL_CALL + setTypeMap(const css::uno::Reference<css::container::XNameAccess>& 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 */ + +/* 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..109ae2c1c --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.cxx @@ -0,0 +1,1051 @@ +/* -*- 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 <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/TransactionIsolation.hpp> +#include <com/sun/star/sdbc/Deferrability.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <comphelper/sequence.hxx> +#include <o3tl/string_view.hxx> + +#include <sal/log.hxx> +#include <rtl/ustrbuf.hxx> +#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>& _xResultSet, sal_Int32 _nType, + const std::vector<std::vector<Any>>& _rRows) +{ + Reference<XInitialization> xIni(_xResultSet, UNO_QUERY); + + Sequence<Sequence<Any>> aRows(_rRows.size()); + + Sequence<Any>* pRowsIter = aRows.getArray(); + for (const auto& rRow : _rRows) + { + if (!rRow.empty()) + { + (*pRowsIter) = comphelper::containerToSequence(rRow); + } + ++pRowsIter; + } + Sequence<Any> aArgs{ Any(_nType), Any(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<XStatement> statement = m_rConnection.createStatement(); + Reference<XResultSet> rs = statement->executeQuery("select user()"); + Reference<XRow> 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<XConnection> 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<XResultSet> SAL_CALL ODatabaseMetaData::getTableTypes() +{ + const char* const table_types[] = { "TABLE", "VIEW" }; + sal_Int32 const requiredVersion[] = { 0, 50000 }; + + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector<std::vector<Any>> rRows; + rtl_TextEncoding encoding = m_rConnection.getConnectionEncoding(); + + for (sal_uInt32 i = 0; i < 2; i++) + { + if (m_rConnection.getMysqlVersion() >= requiredVersion[i]) + { + rRows.push_back( + { { Any(), Any(mysqlc_sdbc_driver::convert(table_types[i], encoding)) } }); + } + } + lcl_setRows_throw(xResultSet, 5, rRows); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getTypeInfo() +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + + std::vector<std::vector<Any>> rRows; + + rtl_TextEncoding encoding = m_rConnection.getConnectionEncoding(); + unsigned int i = 0; + while (mysqlc_types[i].typeName) + { + rRows.push_back( + { { Any(), Any(mysqlc_sdbc_driver::convert(mysqlc_types[i].typeName, encoding)), + Any(mysqlc_types[i].dataType), Any(mysqlc_types[i].precision), + Any(mysqlc_sdbc_driver::convert(mysqlc_types[i].literalPrefix, encoding)), + Any(mysqlc_sdbc_driver::convert(mysqlc_types[i].literalSuffix, encoding)), + Any(mysqlc_sdbc_driver::convert(mysqlc_types[i].createParams, encoding)), + Any(mysqlc_types[i].nullable), Any(mysqlc_types[i].caseSensitive), + Any(mysqlc_types[i].searchable), Any(mysqlc_types[i].isUnsigned), + Any(mysqlc_types[i].fixedPrecScale), Any(mysqlc_types[i].autoIncrement), + Any(mysqlc_sdbc_driver::convert(mysqlc_types[i].localTypeName, encoding)), + Any(mysqlc_types[i].minScale), Any(mysqlc_types[i].maxScale), Any(sal_Int32(0)), + Any(sal_Int32(0)), Any(sal_Int32(10)) } }); + + i++; + } + + lcl_setRows_throw(xResultSet, 14, rRows); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getCatalogs() +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getSchemas() +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector<std::vector<Any>> rRows; + + Reference<XStatement> statement = m_rConnection.createStatement(); + Reference<XInterface> executed = statement->executeQuery( + u"SELECT SCHEMA_NAME AS TABLE_SCHEM, CATALOG_NAME AS TABLE_CATALOG FROM INFORMATION_SCHEMA.SCHEMATA \ + WHERE SCHEMA_NAME NOT IN ('information_schema', 'mysql', 'performance_schema') \ + ORDER BY SCHEMA_NAME"); + Reference<XResultSet> rs(executed, UNO_QUERY_THROW); + Reference<XResultSetMetaDataSupplier> supp(executed, UNO_QUERY_THROW); + Reference<XResultSetMetaData> rs_meta = supp->getMetaData(); + + Reference<XRow> xRow(rs, UNO_QUERY_THROW); + sal_uInt32 columns = rs_meta->getColumnCount(); + while (rs->next()) + { + std::vector<Any> aRow{ Any() }; + for (sal_uInt32 i = 1; i <= columns; i++) + { + OUString columnStringValue = xRow->getString(i); + aRow.push_back(Any(columnStringValue)); + } + rRows.push_back(aRow); + } + + lcl_setRows_throw(xResultSet, 1, rRows); + return xResultSet; +} + +Reference<XResultSet> + 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<XStatement> statement = m_rConnection.createStatement(); + Reference<XResultSet> rs = statement->executeQuery(query); + return rs; +} + +Reference<XResultSet> 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<XStatement> statement = m_rConnection.createStatement(); + Reference<XResultSet> rs = statement->executeQuery(query); + Reference<XRow> xRow(rs, UNO_QUERY_THROW); + + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector<std::vector<Any>> aRows; + while (rs->next()) + { + std::vector<Any> aRow{ Any() }; // 0. element is unused + + // catalog name + aRow.push_back(Any(xRow->getString(1))); + // schema name + aRow.push_back(Any(xRow->getString(2))); + // table name + aRow.push_back(Any(xRow->getString(3))); + // column name + aRow.push_back(Any(xRow->getString(4))); + // data type + OUString sDataType = xRow->getString(5); + aRow.push_back(Any(mysqlc_sdbc_driver::mysqlStrToOOOType(sDataType))); + // type name + aRow.push_back(Any(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 = o3tl::toInt32(sColumnType.subView(6, 1)); // '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(Any(nColumnSize)); + aRow.push_back(Any()); // buffer length - unused + // decimal digits (scale) + aRow.push_back(Any(xRow->getShort(8))); + // num_prec_radix + aRow.push_back(Any(sal_Int32(10))); + // nullable + OUString sIsNullable = xRow->getString(13); + if (xRow->wasNull()) + aRow.push_back(Any(ColumnValue::NULLABLE_UNKNOWN)); + else if (sIsNullable.equalsIgnoreAsciiCase("YES")) + aRow.push_back(Any(ColumnValue::NULLABLE)); + else + aRow.push_back(Any(ColumnValue::NO_NULLS)); + // remarks + aRow.push_back(Any(xRow->getString(9))); + // default + aRow.push_back(Any(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(Any(xRow->getString(11))); + // ordinal position + aRow.push_back(Any(xRow->getString(12))); + // is nullable + aRow.push_back(Any(sIsNullable)); + aRows.push_back(aRow); + } + lcl_setRows_throw(xResultSet, 1, aRows); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getTables(const Any& /*catalog*/, + const OUString& schemaPattern, + const OUString& tableNamePattern, + const Sequence<OUString>& 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 NOT IN ('information_schema', 'mysql', " + "'performance_schema') AND 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<XStatement> statement = m_rConnection.createStatement(); + Reference<XResultSet> rs = statement->executeQuery(query); + return rs; +} + +Reference<XResultSet> 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<XResultSet> + SAL_CALL ODatabaseMetaData::getProcedures(const Any& /*catalog*/, + const OUString& /*schemaPattern*/, + const OUString& /*procedureNamePattern*/) +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector<std::vector<Any>> rRows; + // TODO IMPL + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 7, rRows); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getVersionColumns(const Any& /* catalog */, + const OUString& /* schema */, + const OUString& /* table */) +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector<std::vector<Any>> rRows; + lcl_setRows_throw(xResultSet, 16, rRows); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getExportedKeys(const Any& /*catalog */, + const OUString& /*schema */, + const OUString& /*table */) +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector<std::vector<Any>> rRows; + // TODO implement + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 8, rRows); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getImportedKeys(const Any& /*catalog*/, + const OUString& schema, + const OUString& table) +{ + Reference<XResultSet> 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<std::vector<Any>> aRows; + Reference<XStatement> statement = m_rConnection.createStatement(); + Reference<XResultSet> rs = statement->executeQuery(query); + Reference<XRow> xRow(rs, UNO_QUERY_THROW); + + while (rs->next()) + { + std::vector<Any> aRow{ Any() }; // 0. element is unused + + // primary key catalog + aRow.push_back(Any(xRow->getString(3))); + // primary key schema + aRow.push_back(Any(xRow->getString(4))); + // primary key table + aRow.push_back(Any(xRow->getString(5))); + // primary column name + aRow.push_back(Any(xRow->getString(6))); + + // fk table catalog + aRow.push_back(Any(xRow->getString(1))); + // fk schema + aRow.push_back(Any(xRow->getString(11))); + // fk table + aRow.push_back(Any(xRow->getString(10))); + // fk column name + aRow.push_back(Any(xRow->getString(2))); + // KEY_SEQ + aRow.push_back(Any(sal_Int32{ 0 })); // TODO + // update rule + aRow.push_back(Any(xRow->getShort(7))); + // delete rule + aRow.push_back(Any(xRow->getShort(8))); + // foreign key name + aRow.push_back(Any(xRow->getString(9))); + // primary key name + aRow.push_back(Any(OUString{})); // TODO + // deferrability + aRow.push_back(Any(Deferrability::NONE)); + aRows.push_back(aRow); + } + lcl_setRows_throw(xResultSet, 1, aRows); + return xResultSet; +} + +Reference<XResultSet> 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<XStatement> statement = m_rConnection.createStatement(); + Reference<XResultSet> rs = statement->executeQuery(query); + return rs; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getIndexInfo(const Any& /*catalog*/, + const OUString& /*schema*/, + const OUString& /*table*/, + sal_Bool /*unique*/, + sal_Bool /*approximate*/) +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector<std::vector<Any>> rRows; + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 11, rRows); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getBestRowIdentifier(const Any& /*catalog*/, + const OUString& /*schema*/, + const OUString& /*table*/, + sal_Int32 /*scope*/, + sal_Bool /*nullable*/) +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector<std::vector<Any>> rRows; + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 15, rRows); + return xResultSet; +} + +Reference<XResultSet> 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<XResultSet> SAL_CALL ODatabaseMetaData::getCrossReference( + const Any& /*primaryCatalog*/, const OUString& /*primarySchema_*/, + const OUString& /*primaryTable_*/, const Any& /*foreignCatalog*/, + const OUString& /*foreignSchema*/, const OUString& /*foreignTable*/) +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector<std::vector<Any>> rRows; + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 13, rRows); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getUDTs(const Any& /* catalog */, + const OUString& /* schemaPattern */, + const OUString& /* typeNamePattern */, + const Sequence<sal_Int32>& /* 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..caed92f20 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.hxx @@ -0,0 +1,233 @@ +/* -*- 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 . + */ + +#pragma once + +#include "mysqlc_connection.hxx" + +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <cppuhelper/implbase1.hxx> + +namespace connectivity::mysqlc +{ +using ::com::sun::star::uno::Any; + +//************ Class: ODatabaseMetaData + +typedef ::cppu::WeakImplHelper1<css::sdbc::XDatabaseMetaData> 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<css::sdbc::XResultSet> + SAL_CALL getProcedures(const Any& catalog, const OUString& schemaPattern, + const OUString& procedureNamePattern) override; + css::uno::Reference<css::sdbc::XResultSet> + SAL_CALL getProcedureColumns(const Any& catalog, const OUString& schemaPattern, + const OUString& procedureNamePattern, + const OUString& columnNamePattern) override; + css::uno::Reference<css::sdbc::XResultSet> + SAL_CALL getTables(const Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern, + const css::uno::Sequence<OUString>& types) override; + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL getSchemas() override; + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL getCatalogs() override; + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL getTableTypes() override; + virtual css::uno::Reference<css::sdbc::XResultSet> + SAL_CALL getColumns(const Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern, + const OUString& columnNamePattern) override; + css::uno::Reference<css::sdbc::XResultSet> + SAL_CALL getColumnPrivileges(const Any& catalog, const OUString& schema, + const OUString& table, + const OUString& columnNamePattern) override; + css::uno::Reference<css::sdbc::XResultSet> + SAL_CALL getTablePrivileges(const Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern) override; + css::uno::Reference<css::sdbc::XResultSet> + SAL_CALL getBestRowIdentifier(const Any& catalog, const OUString& schema, + const OUString& table, sal_Int32 scope, + sal_Bool nullable) override; + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL + getVersionColumns(const Any& catalog, const OUString& schema, const OUString& table) override; + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL + getPrimaryKeys(const Any& catalog, const OUString& schema, const OUString& table) override; + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL + getImportedKeys(const Any& catalog, const OUString& schema, const OUString& table) override; + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL + getExportedKeys(const Any& catalog, const OUString& schema, const OUString& table) override; + css::uno::Reference<css::sdbc::XResultSet> + 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<css::sdbc::XResultSet> SAL_CALL getTypeInfo() override; + css::uno::Reference<css::sdbc::XResultSet> + 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<css::sdbc::XResultSet> + SAL_CALL getUDTs(const Any& catalog, const OUString& schemaPattern, + const OUString& typeNamePattern, + const css::uno::Sequence<sal_Int32>& types) override; + css::uno::Reference<css::sdbc::XConnection> SAL_CALL getConnection() override; +}; +} + +/* 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..37a14e822 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_driver.cxx @@ -0,0 +1,149 @@ +/* -*- 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 css::sdbcx; +using namespace connectivity::mysqlc; + +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/servicehelper.hxx> + +MysqlCDriver::MysqlCDriver(const Reference<XMultiServiceFactory>& _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<XComponent> 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<OUString> MysqlCDriver::getSupportedServiceNames_Static() +{ + return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" }; +} + +OUString SAL_CALL MysqlCDriver::getImplementationName() { return getImplementationName_Static(); } + +sal_Bool SAL_CALL MysqlCDriver::supportsService(const OUString& _rServiceName) +{ + return cppu::supportsService(this, _rServiceName); +} + +Sequence<OUString> SAL_CALL MysqlCDriver::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +Reference<XConnection> SAL_CALL MysqlCDriver::connect(const OUString& url, + const Sequence<PropertyValue>& info) +{ + ::osl::MutexGuard aGuard(m_aMutex); + + if (!acceptsURL(url)) + { + return nullptr; + } + + // create a new connection with the given properties and append it to our vector + rtl::Reference<OConnection> pCon = new OConnection(*this); + + pCon->construct(url, info); + m_xConnections.push_back(WeakReferenceHelper(*pCon)); + return pCon; +} + +sal_Bool SAL_CALL MysqlCDriver::acceptsURL(const OUString& url) +{ + return url.startsWith("sdbc:mysqlc:") || url.startsWith("sdbc:mysql:mysqlc:"); +} + +Sequence<DriverPropertyInfo> SAL_CALL +MysqlCDriver::getPropertyInfo(const OUString& url, const Sequence<PropertyValue>& /* info */) +{ + if (acceptsURL(url)) + { + return { { "Hostname", "Name of host", true, "localhost", {} }, + { "Port", "Port", true, "3306", {} } }; + } + + return Sequence<DriverPropertyInfo>(); +} + +sal_Int32 SAL_CALL MysqlCDriver::getMajorVersion() { return MARIADBC_VERSION_MAJOR; } + +sal_Int32 SAL_CALL MysqlCDriver::getMinorVersion() { return MARIADBC_VERSION_MINOR; } + +Reference<XTablesSupplier> + SAL_CALL MysqlCDriver::getDataDefinitionByConnection(const Reference<XConnection>& rConnection) +{ + if (OConnection* pConnection = comphelper::getFromUnoTunnel<OConnection>(rConnection)) + return pConnection->createCatalog(); + return {}; +} + +Reference<XTablesSupplier> SAL_CALL +MysqlCDriver::getDataDefinitionByURL(const OUString& rURL, const Sequence<PropertyValue>& rInfo) +{ + Reference<XConnection> xConnection = connect(rURL, rInfo); + return getDataDefinitionByConnection(xConnection); +} + +namespace connectivity::mysqlc +{ +Reference<XInterface> MysqlCDriver_CreateInstance(const Reference<XMultiServiceFactory>& _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..a29040892 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_driver.hxx @@ -0,0 +1,88 @@ +/* -*- 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 . + */ +#pragma once + +#include "mysqlc_connection.hxx" + +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp> +#include <cppuhelper/compbase.hxx> + +namespace connectivity::mysqlc +{ +using css::uno::Reference; +using css::uno::Sequence; + +Reference<css::uno::XInterface> +MysqlCDriver_CreateInstance(const Reference<css::lang::XMultiServiceFactory>& _rxFactory); + +typedef ::cppu::WeakComponentImplHelper<css::sdbc::XDriver, css::sdbcx::XDataDefinitionSupplier, + css::lang::XServiceInfo> + ODriver_BASE; + +typedef void* (*OMysqlCConnection_CreateInstanceFunction)(void* _pDriver); + +class MysqlCDriver : public ODriver_BASE +{ +protected: + Reference<css::lang::XMultiServiceFactory> 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 +public: + explicit MysqlCDriver(const Reference<css::lang::XMultiServiceFactory>& _rxFactory); + + // OComponentHelper + void SAL_CALL disposing() override; + // XInterface + static OUString getImplementationName_Static(); + static Sequence<OUString> getSupportedServiceNames_Static(); + + // XServiceInfo + OUString SAL_CALL getImplementationName() override; + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + // XDriver + Reference<css::sdbc::XConnection> SAL_CALL + connect(const OUString& url, const Sequence<css::beans::PropertyValue>& info) override; + + sal_Bool SAL_CALL acceptsURL(const OUString& url) override; + Sequence<css::sdbc::DriverPropertyInfo> SAL_CALL + getPropertyInfo(const OUString& url, const Sequence<css::beans::PropertyValue>& info) override; + + sal_Int32 SAL_CALL getMajorVersion() override; + sal_Int32 SAL_CALL getMinorVersion() override; + + const Reference<css::lang::XMultiServiceFactory>& getFactory() const { return m_xFactory; } + + static rtl_TextEncoding getDefaultEncoding() { return RTL_TEXTENCODING_UTF8; } + + // XDataDefinitionSupplier + virtual css::uno::Reference<css::sdbcx::XTablesSupplier> SAL_CALL getDataDefinitionByConnection( + const css::uno::Reference<css::sdbc::XConnection>& rxConnection) override; + virtual css::uno::Reference<css::sdbcx::XTablesSupplier> SAL_CALL getDataDefinitionByURL( + const OUString& rsURL, const css::uno::Sequence<css::beans::PropertyValue>& rInfo) override; +}; + +} /* connectivity::mysqlc */ + +/* 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..bc5777041 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_general.cxx @@ -0,0 +1,357 @@ +/* -*- 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 <sal/log.hxx> +#include <rtl/ustring.hxx> +#include <o3tl/string_view.hxx> + +#include <com/sun/star/sdbc/DataType.hpp> + +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: + case MYSQL_TYPE_YEAR: + *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_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<XInterface>& _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<XInterface>& _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<css::uno::XInterface>& _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<css::uno::XInterface>& _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::BIT; + + case MYSQL_TYPE_TINY: + return css::sdbc::DataType::TINYINT; + + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_YEAR: + 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: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_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(std::u16string_view sType) +{ + // TODO other types. + if (o3tl::equalsIgnoreAsciiCase(sType, u"tiny") + || o3tl::equalsIgnoreAsciiCase(sType, u"tinyint")) + return css::sdbc::DataType::TINYINT; + if (o3tl::equalsIgnoreAsciiCase(sType, u"smallint") + || o3tl::equalsIgnoreAsciiCase(sType, u"year")) + return css::sdbc::DataType::SMALLINT; + if (o3tl::equalsIgnoreAsciiCase(sType, u"int") + || o3tl::equalsIgnoreAsciiCase(sType, u"mediumint")) + return css::sdbc::DataType::INTEGER; + if (o3tl::equalsIgnoreAsciiCase(sType, u"varchar") || o3tl::equalsIgnoreAsciiCase(sType, u"set") + || o3tl::equalsIgnoreAsciiCase(sType, u"enum")) + return css::sdbc::DataType::VARCHAR; + if (o3tl::equalsIgnoreAsciiCase(sType, u"bigint")) + return css::sdbc::DataType::BIGINT; + if (o3tl::equalsIgnoreAsciiCase(sType, u"blob") + || o3tl::equalsIgnoreAsciiCase(sType, u"longblob") + || o3tl::equalsIgnoreAsciiCase(sType, u"tinyblob") + || o3tl::equalsIgnoreAsciiCase(sType, u"mediumblob")) + return css::sdbc::DataType::BLOB; + if (o3tl::equalsIgnoreAsciiCase(sType, u"varbinary")) + return css::sdbc::DataType::VARBINARY; + if (o3tl::equalsIgnoreAsciiCase(sType, u"char")) + return css::sdbc::DataType::CHAR; + if (o3tl::equalsIgnoreAsciiCase(sType, u"tinytext")) + return css::sdbc::DataType::VARCHAR; + if (o3tl::equalsIgnoreAsciiCase(sType, u"text")) + return css::sdbc::DataType::LONGVARCHAR; + if (o3tl::equalsIgnoreAsciiCase(sType, u"mediumtext") + || o3tl::equalsIgnoreAsciiCase(sType, u"longtext")) + return css::sdbc::DataType::CLOB; + if (o3tl::equalsIgnoreAsciiCase(sType, u"binary")) + return css::sdbc::DataType::BINARY; + if (o3tl::equalsIgnoreAsciiCase(sType, u"time")) + return css::sdbc::DataType::TIME; + if (o3tl::equalsIgnoreAsciiCase(sType, u"date")) + return css::sdbc::DataType::DATE; + if (o3tl::equalsIgnoreAsciiCase(sType, u"datetime") + || o3tl::equalsIgnoreAsciiCase(sType, u"timestamp")) + return css::sdbc::DataType::TIMESTAMP; + if (o3tl::equalsIgnoreAsciiCase(sType, u"decimal")) + return css::sdbc::DataType::DECIMAL; + if (o3tl::equalsIgnoreAsciiCase(sType, u"real") || o3tl::equalsIgnoreAsciiCase(sType, u"float")) + return css::sdbc::DataType::REAL; + if (o3tl::equalsIgnoreAsciiCase(sType, u"double")) + return css::sdbc::DataType::DOUBLE; + if (o3tl::equalsIgnoreAsciiCase(sType, u"bit")) + return css::sdbc::DataType::BIT; + if (o3tl::equalsIgnoreAsciiCase(sType, u"bool") + || o3tl::equalsIgnoreAsciiCase(sType, u"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..16236e153 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_general.hxx @@ -0,0 +1,116 @@ +/* -*- 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 . + */ + +#pragma once + +#include <config_lgpl.h> + +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + +#include <osl/diagnose.h> +#include <mysql.h> + +#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 <typename T> +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<css::uno::XInterface>& _rxContext); + +void throwInvalidArgumentException(const char* _pAsciiFeatureName, + const css::uno::Reference<css::uno::XInterface>& _rxContext); + +void throwSQLExceptionWithMsg(const char* msg, const char* SQLSTATE, unsigned int errorNum, + const css::uno::Reference<css::uno::XInterface>& _context, + const rtl_TextEncoding encoding); + +void throwSQLExceptionWithMsg(const OUString& msg, const char* SQLSTATE, unsigned int errorNum, + const css::uno::Reference<css::uno::XInterface>& _context); + +sal_Int32 mysqlToOOOType(int eType, int charsetnr) noexcept; + +OUString mysqlTypeToStr(unsigned mysql_type, unsigned mysql_flags); + +sal_Int32 mysqlStrToOOOType(std::u16string_view sType); + +OUString convert(const ::std::string& _string, const rtl_TextEncoding encoding); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_indexes.cxx b/connectivity/source/drivers/mysqlc/mysqlc_indexes.cxx new file mode 100644 index 000000000..c496f9c21 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_indexes.cxx @@ -0,0 +1,25 @@ +/* -*- 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/. + */ + +#include "mysqlc_indexes.hxx" + +connectivity::mysqlc::Indexes::Indexes(Table* pTable, osl::Mutex& rMutex, + const std::vector<OUString>& rVector) + : OIndexesHelper(pTable, rMutex, rVector) +{ +} + +// XDrop +void connectivity::mysqlc::Indexes::dropObject(sal_Int32 /*nPosition*/, + const OUString& /* sIndexName */) +{ + // TODO: implement +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_indexes.hxx b/connectivity/source/drivers/mysqlc/mysqlc_indexes.hxx new file mode 100644 index 000000000..4c918d184 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_indexes.hxx @@ -0,0 +1,34 @@ +/* -*- 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/. + */ + +#pragma once + +#include "mysqlc_table.hxx" + +#include <connectivity/TIndexes.hxx> + +namespace connectivity::mysqlc +{ +class Indexes : public ::connectivity::OIndexesHelper +{ +private: + // TODO: useful? + // Table* m_pTable; + +protected: + // XDrop + void dropObject(sal_Int32 nPosition, const OUString& sIndexName); + +public: + Indexes(Table* pTable, ::osl::Mutex& rMutex, const std::vector<OUString>& rVector); +}; + +} // namespace connectivity::mysqlc + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_keys.cxx b/connectivity/source/drivers/mysqlc/mysqlc_keys.cxx new file mode 100644 index 000000000..7706844f2 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_keys.cxx @@ -0,0 +1,19 @@ +/* -*- 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/. + */ + +#include "mysqlc_keys.hxx" +#include "mysqlc_table.hxx" + +connectivity::mysqlc::Keys::Keys(Table* pTable, osl::Mutex& rMutex, + const ::std::vector<OUString>& rNames) + : OKeysHelper(pTable, rMutex, rNames) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_keys.hxx b/connectivity/source/drivers/mysqlc/mysqlc_keys.hxx new file mode 100644 index 000000000..9d0a9ef1c --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_keys.hxx @@ -0,0 +1,25 @@ +/* -*- 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/. + */ + +#pragma once + +#include <connectivity/TKeys.hxx> + +namespace connectivity::mysqlc +{ +class Table; + +class Keys : public ::connectivity::OKeysHelper +{ +public: + Keys(Table* pTable, ::osl::Mutex& rMutex, const ::std::vector<OUString>& rNames); +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ 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..90d0e3d87 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx @@ -0,0 +1,1129 @@ +/* -*- 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 <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/sdbcx/CompareBookmark.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <sal/log.hxx> + +using namespace rtl; + +#include <cstdlib> + +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 <typeindex> + +namespace +{ +std::type_index getTypeFromMysqlType(enum_field_types type) +{ + switch (type) + { + case MYSQL_TYPE_BIT: + return std::type_index(typeid(bool)); + case MYSQL_TYPE_TINY: + return std::type_index(typeid(sal_Int8)); + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_YEAR: + 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_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) + { + bool bIsBlobType = false; + switch (m_aFields[i].type) + { + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + bIsBlobType = true; + break; + default: + bIsBlobType = false; + } + 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 = bIsBlobType ? 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<OUString> 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(css::uno::Reference<css::uno::XWeak>(static_cast<OWeakObject*>(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.clear(); + 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<Type> SAL_CALL OPreparedResultSet::getTypes() +{ + OTypeCollection aTypes(cppu::UnoType<XMultiPropertySet>::get(), + cppu::UnoType<XFastPropertySet>::get(), + cppu::UnoType<XPropertySet>::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 <typename T> 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<T>(nColumnIndex); +} + +template <typename T> T OPreparedResultSet::retrieveValue(sal_Int32 nColumnIndex) +{ + if (getTypeFromMysqlType(m_aFields[nColumnIndex - 1].type) == std::type_index(typeid(T))) + return *static_cast<T*>(m_aData[nColumnIndex - 1].buffer); + else + { + auto const& row = getRowSetValue(nColumnIndex); + if constexpr (std::is_same_v<sal_Int64, T>) + return row.getLong(); + else if constexpr (std::is_same_v<sal_Int32, T>) + return row.getInt32(); + else if constexpr (std::is_same_v<sal_Int16, T>) + return row.getInt16(); + else if constexpr (std::is_same_v<sal_Int8, T>) + return row.getInt8(); + else if constexpr (std::is_same_v<double, T>) + return row.getDouble(); + else if constexpr (std::is_same_v<float, T>) + return row.getFloat(); + else if constexpr (std::is_same_v<bool, T>) + return row.getBool(); + else + return row; + } +} + +template <> uno::Sequence<sal_Int8> OPreparedResultSet::retrieveValue(sal_Int32 column) +{ + // TODO make conversion possible + return uno::Sequence<sal_Int8>(static_cast<sal_Int8 const*>(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).getDate(); + const MYSQL_TIME* pTime = static_cast<MYSQL_TIME*>(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).getTime(); + const MYSQL_TIME* pTime = static_cast<MYSQL_TIME*>(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).getDateTime(); + const MYSQL_TIME* pTime = static_cast<MYSQL_TIME*>(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 + bool bIsBlobType = false; + switch (m_aFields[column - 1].type) + { + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + bIsBlobType = true; + break; + default: + bIsBlobType = false; + } + + if (getTypeFromMysqlType(m_aFields[column - 1].type) != std::type_index(typeid(OUString)) + && !bIsBlobType) + return getRowSetValue(column).getString(); + const char* sStr = static_cast<const char*>(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: + case MYSQL_TYPE_YEAR: + return getShort(nColumnIndex); + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_INT24: + return getInt(nColumnIndex); + case MYSQL_TYPE_BIT: + return ORowSetValue(bool(getBoolean(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: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_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<XInputStream> SAL_CALL OPreparedResultSet::getBinaryStream(sal_Int32 /*column*/) +{ + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getBinaryStream", + *this); + return nullptr; +} + +uno::Reference<XInputStream> 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<bool>(column); +} + +sal_Int8 SAL_CALL OPreparedResultSet::getByte(sal_Int32 column) +{ + return safelyRetrieveValue<sal_Int8>(column); +} + +uno::Sequence<sal_Int8> SAL_CALL OPreparedResultSet::getBytes(sal_Int32 column) +{ + return safelyRetrieveValue<uno::Sequence<sal_Int8>>(column); +} + +Date SAL_CALL OPreparedResultSet::getDate(sal_Int32 column) +{ + return safelyRetrieveValue<Date>(column); +} + +double SAL_CALL OPreparedResultSet::getDouble(sal_Int32 column) +{ + return safelyRetrieveValue<double>(column); +} + +float SAL_CALL OPreparedResultSet::getFloat(sal_Int32 column) +{ + return safelyRetrieveValue<float>(column); +} + +sal_Int32 SAL_CALL OPreparedResultSet::getInt(sal_Int32 column) +{ + return safelyRetrieveValue<sal_Int32>(column); +} + +sal_Int32 SAL_CALL OPreparedResultSet::getRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return static_cast<sal_Int32>(mysql_field_tell(m_pResult)); +} + +sal_Int64 SAL_CALL OPreparedResultSet::getLong(sal_Int32 column) +{ + return safelyRetrieveValue<sal_Int64>(column); +} + +uno::Reference<XResultSetMetaData> 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<XArray> 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<XClob> 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<XBlob> 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<XRef> 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<XNameAccess>& /* 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<sal_Int16>(column); +} + +OUString SAL_CALL OPreparedResultSet::getString(sal_Int32 column) +{ + return safelyRetrieveValue<OUString>(column); +} + +Time SAL_CALL OPreparedResultSet::getTime(sal_Int32 column) +{ + return safelyRetrieveValue<Time>(column); +} + +DateTime SAL_CALL OPreparedResultSet::getTimestamp(sal_Int32 column) +{ + return safelyRetrieveValue<DateTime>(column); +} + +sal_Bool SAL_CALL OPreparedResultSet::isBeforeFirst() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return m_nCurrentRow == 0; +} + +sal_Bool SAL_CALL OPreparedResultSet::isAfterLast() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return m_nCurrentRow > m_nRowCount; +} + +sal_Bool SAL_CALL OPreparedResultSet::isFirst() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return m_nCurrentRow == 1 && !isAfterLast(); +} + +sal_Bool SAL_CALL OPreparedResultSet::isLast() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return m_nCurrentRow == m_nRowCount; +} + +void SAL_CALL OPreparedResultSet::beforeFirst() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + mysql_stmt_data_seek(m_pStmt, 0); + + m_nCurrentRow = 0; + m_aData.reset(); +} + +void SAL_CALL OPreparedResultSet::afterLast() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::afterLast", *this); +} + +void SAL_CALL OPreparedResultSet::close() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + m_aData.reset(); + m_aMetaData.reset(); + + if (m_pResult) + mysql_free_result(m_pResult); + mysql_stmt_free_result(m_pStmt); + dispose(); +} + +sal_Bool SAL_CALL OPreparedResultSet::first() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + mysql_stmt_data_seek(m_pStmt, 0); + m_nCurrentRow = 0; + next(); + + return true; +} + +sal_Bool SAL_CALL OPreparedResultSet::last() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + mysql_stmt_data_seek(m_pStmt, m_nRowCount - 1); + next(); + + return true; +} + +sal_Bool SAL_CALL OPreparedResultSet::absolute(sal_Int32 row) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + sal_Int32 nToGo = row < 0 ? m_nRowCount - row : row - 1; + + if (nToGo >= m_nRowCount) + nToGo = m_nRowCount - 1; + if (nToGo < 0) + nToGo = 0; + + mysql_stmt_data_seek(m_pStmt, nToGo); + next(); + + return true; +} + +sal_Bool SAL_CALL OPreparedResultSet::relative(sal_Int32 row) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + if (row == 0) + return true; + + sal_Int32 nToGo = m_nCurrentRow + row; + if (nToGo >= m_nRowCount) + nToGo = m_nRowCount - 1; + if (nToGo < 0) + nToGo = 0; + + mysql_stmt_data_seek(m_pStmt, nToGo); + next(); + m_nCurrentRow += row; + + return true; +} + +sal_Bool SAL_CALL OPreparedResultSet::previous() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + if (m_nCurrentRow <= 1) + return false; + + mysql_stmt_data_seek(m_pStmt, m_nCurrentRow - 2); + next(); + --m_nCurrentRow; + return true; +} + +uno::Reference<uno::XInterface> SAL_CALL OPreparedResultSet::getStatement() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return m_aStatement.get(); +} + +sal_Bool SAL_CALL OPreparedResultSet::rowDeleted() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL OPreparedResultSet::rowInserted() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL OPreparedResultSet::rowUpdated() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL OPreparedResultSet::next() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + bool hasData = fetchResult(); + + // current field cannot be asked as a number. We have to keep track it + // manually. + m_nCurrentRow += 1; + + return hasData; +} + +sal_Bool SAL_CALL OPreparedResultSet::wasNull() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return m_bWasNull; +} + +void SAL_CALL OPreparedResultSet::cancel() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL OPreparedResultSet::clearWarnings() {} + +Any SAL_CALL OPreparedResultSet::getWarnings() { return Any(); } + +void SAL_CALL OPreparedResultSet::insertRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + // you only have to implement this if you want to insert new rows + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::insertRow", *this); +} + +void SAL_CALL OPreparedResultSet::updateRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + // only when you allow updates + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateRow", *this); +} + +void SAL_CALL OPreparedResultSet::deleteRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::deleteRow", *this); +} + +void SAL_CALL OPreparedResultSet::cancelRowUpdates() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::cancelRowUpdates", + *this); +} + +void SAL_CALL OPreparedResultSet::moveToInsertRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + // only when you allow insert's + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::moveToInsertRow", + *this); +} + +void SAL_CALL OPreparedResultSet::moveToCurrentRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL OPreparedResultSet::updateNull(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateNull", + *this); +} + +void SAL_CALL OPreparedResultSet::updateBoolean(sal_Int32 column, sal_Bool /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateBoolean", + *this); +} + +void SAL_CALL OPreparedResultSet::updateByte(sal_Int32 column, sal_Int8 /* x */) +{ + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + MutexGuard aGuard(m_aMutex); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateByte", + *this); +} + +void SAL_CALL OPreparedResultSet::updateShort(sal_Int32 column, sal_Int16 /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateShort", + *this); +} + +void SAL_CALL OPreparedResultSet::updateInt(sal_Int32 column, sal_Int32 /* x */) +{ + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + MutexGuard aGuard(m_aMutex); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateInt", *this); +} + +void SAL_CALL OPreparedResultSet::updateLong(sal_Int32 column, sal_Int64 /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateLong", + *this); +} + +void SAL_CALL OPreparedResultSet::updateFloat(sal_Int32 column, float /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateFloat", + *this); +} + +void SAL_CALL OPreparedResultSet::updateDouble(sal_Int32 column, double /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateDouble", + *this); +} + +void SAL_CALL OPreparedResultSet::updateString(sal_Int32 column, const OUString& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateString", + *this); +} + +void SAL_CALL OPreparedResultSet::updateBytes(sal_Int32 column, + const uno::Sequence<sal_Int8>& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateBytes", + *this); +} + +void SAL_CALL OPreparedResultSet::updateDate(sal_Int32 column, const Date& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateDate", + *this); +} + +void SAL_CALL OPreparedResultSet::updateTime(sal_Int32 column, const Time& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateTime", + *this); +} + +void SAL_CALL OPreparedResultSet::updateTimestamp(sal_Int32 column, const DateTime& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateTimestamp", + *this); +} + +void SAL_CALL OPreparedResultSet::updateBinaryStream(sal_Int32 column, + const uno::Reference<XInputStream>& /* x */, + sal_Int32 /* length */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException( + "OPreparedResultSet::updateBinaryStream", *this); +} + +void SAL_CALL OPreparedResultSet::updateCharacterStream(sal_Int32 column, + const uno::Reference<XInputStream>& /* x */, + sal_Int32 /* length */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException( + "OPreparedResultSet::updateCharacterStream", *this); +} + +void SAL_CALL OPreparedResultSet::refreshRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::refreshRow", + *this); +} + +void SAL_CALL OPreparedResultSet::updateObject(sal_Int32 column, const Any& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateObject", + *this); +} + +void SAL_CALL OPreparedResultSet::updateNumericObject(sal_Int32 column, const Any& /* x */, + sal_Int32 /* scale */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException( + "OPreparedResultSet::updateNumericObject", *this); +} + +// XRowLocate +Any SAL_CALL OPreparedResultSet::getBookmark() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + // if you don't want to support bookmark you must remove the XRowLocate interface + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getBookmark", + *this); + + return Any(); +} + +sal_Bool SAL_CALL OPreparedResultSet::moveToBookmark(const Any& /* bookmark */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL OPreparedResultSet::moveRelativeToBookmark(const Any& /* bookmark */, + sal_Int32 /* rows */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException( + "OPreparedResultSet::moveRelativeToBookmark", *this); + return false; +} + +sal_Int32 SAL_CALL OPreparedResultSet::compareBookmarks(const Any& /* n1 */, const Any& /* n2 */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::compareBookmarks", + *this); + + return CompareBookmark::NOT_EQUAL; +} + +sal_Bool SAL_CALL OPreparedResultSet::hasOrderedBookmarks() { return false; } + +sal_Int32 SAL_CALL OPreparedResultSet::hashBookmark(const Any& /* bookmark */) +{ + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::hashBookmark", + *this); + return 0; +} + +// XDeleteRows +uno::Sequence<sal_Int32> + SAL_CALL OPreparedResultSet::deleteRows(const uno::Sequence<Any>& /* rows */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::deleteRows", + *this); + return uno::Sequence<sal_Int32>(); +} + +IPropertyArrayHelper* OPreparedResultSet::createArrayHelper() const +{ + return new OPropertyArrayHelper{ + { { "FetchDirection", PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0 }, + { "FetchSize", PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0 }, + { "IsBookmarkable", PROPERTY_ID_ISBOOKMARKABLE, cppu::UnoType<bool>::get(), + PropertyAttribute::READONLY }, + { "ResultSetConcurrency", PROPERTY_ID_RESULTSETCONCURRENCY, + cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY }, + { "ResultSetType", PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), + PropertyAttribute::READONLY } } + }; +} + +IPropertyArrayHelper& OPreparedResultSet::getInfoHelper() { return *getArrayHelper(); } + +sal_Bool OPreparedResultSet::convertFastPropertyValue(Any& /* rConvertedValue */, + Any& /* rOldValue */, sal_Int32 nHandle, + const Any& /* rValue */) +{ + switch (nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw css::lang::IllegalArgumentException(); + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + default:; + } + return false; +} + +void OPreparedResultSet::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, + const Any& /* rValue */) +{ + switch (nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw uno::Exception("cannot set prop " + OUString::number(nHandle), nullptr); + case PROPERTY_ID_FETCHDIRECTION: + break; + case PROPERTY_ID_FETCHSIZE: + break; + default:; + } +} + +void OPreparedResultSet::getFastPropertyValue(Any& _rValue, sal_Int32 nHandle) const +{ + switch (nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + _rValue <<= false; + break; + case PROPERTY_ID_CURSORNAME: + break; + case PROPERTY_ID_RESULTSETCONCURRENCY: + _rValue <<= ResultSetConcurrency::READ_ONLY; + break; + case PROPERTY_ID_RESULTSETTYPE: + _rValue <<= ResultSetType::SCROLL_INSENSITIVE; + break; + case PROPERTY_ID_FETCHDIRECTION: + _rValue <<= FetchDirection::FORWARD; + break; + case PROPERTY_ID_FETCHSIZE: + _rValue <<= sal_Int32(50); + break; + ; + default:; + } +} + +void SAL_CALL OPreparedResultSet::acquire() noexcept { OPreparedResultSet_BASE::acquire(); } + +void SAL_CALL OPreparedResultSet::release() noexcept { OPreparedResultSet_BASE::release(); } + +css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL OPreparedResultSet::getPropertySetInfo() +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +void OPreparedResultSet::checkColumnIndex(sal_Int32 index) +{ + if (!m_aData) + throw SQLException("Cursor out of range", *this, "HY109", 1, Any()); + if (index < 1 || index > static_cast<int>(m_nColumnCount)) + { + /* static object for efficiency or thread safety is a problem ? */ + throw SQLException("index out of range", *this, "42S22", 1, Any()); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx new file mode 100644 index 000000000..0be8e2ab3 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx @@ -0,0 +1,253 @@ +/* -*- 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 . + */ + +#pragma once + +#include "mysqlc_preparedstatement.hxx" +#include "mysqlc_statement.hxx" +#include "mysqlc_subcomponent.hxx" +#include "mysqlc_connection.hxx" + +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbcx/XDeleteRows.hpp> +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <connectivity/FValue.hxx> + +#include <cppuhelper/compbase12.hxx> + +namespace connectivity::mysqlc +{ +using ::com::sun::star::sdbc::SQLException; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::RuntimeException; + +typedef ::cppu::WeakComponentImplHelper12< + css::sdbc::XResultSet, css::sdbc::XRow, css::sdbc::XResultSetMetaDataSupplier, + css::util::XCancellable, css::sdbc::XWarningsSupplier, css::sdbc::XResultSetUpdate, + css::sdbc::XRowUpdate, css::sdbcx::XRowLocate, css::sdbcx::XDeleteRows, css::sdbc::XCloseable, + css::sdbc::XColumnLocate, css::lang::XServiceInfo> + OPreparedResultSet_BASE; + +class OPreparedResultSet final : public cppu::BaseMutex, + public OPreparedResultSet_BASE, + public ::cppu::OPropertySetHelper, + public OPropertyArrayUsageHelper<OPreparedResultSet> +{ + OConnection& m_rConnection; + css::uno::WeakReferenceHelper m_aStatement; + css::uno::Reference<css::sdbc::XResultSetMetaData> m_xMetaData; + + // non-owning pointers + MYSQL_RES* m_pResult; + MYSQL_STMT* m_pStmt; + MYSQL_FIELD* m_aFields; + + rtl_TextEncoding m_encoding; + sal_Int32 m_nCurrentRow = 0; + sal_Int32 m_nColumnCount; + sal_Int32 m_nRowCount; + + // Use c style arrays, because we have to work with pointers + // on these. + std::unique_ptr<MYSQL_BIND[]> m_aData; + std::unique_ptr<BindMetaData[]> m_aMetaData; + + bool m_bWasNull = false; + + // OPropertyArrayUsageHelper + ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + // OPropertySetHelper + ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + sal_Bool SAL_CALL convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue, + sal_Int32 nHandle, const Any& rValue) override; + + void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) override; + + void SAL_CALL getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const override; + + template <typename T> T safelyRetrieveValue(const sal_Int32 nColumnIndex); + template <typename T> T retrieveValue(const sal_Int32 nColumnIndex); + connectivity::ORowSetValue getRowSetValue(sal_Int32 nColumnIndex); + + bool fetchResult(); + + // you can't delete objects of this type + virtual ~OPreparedResultSet() override = default; + +public: + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override; + + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + OPreparedResultSet(OConnection& rConn, OPreparedStatement* pStmt, MYSQL_STMT* pMyStmt); + + // ::cppu::OComponentHelper + void SAL_CALL disposing() override; + + // XInterface + Any SAL_CALL queryInterface(const css::uno::Type& rType) override; + + void SAL_CALL acquire() noexcept override; + void SAL_CALL release() noexcept override; + + //XTypeProvider + css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override; + + // XPropertySet + css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + + // XResultSet + sal_Bool SAL_CALL next() override; + sal_Bool SAL_CALL isBeforeFirst() override; + sal_Bool SAL_CALL isAfterLast() override; + sal_Bool SAL_CALL isFirst() override; + sal_Bool SAL_CALL isLast() override; + + void SAL_CALL beforeFirst() override; + void SAL_CALL afterLast() override; + + sal_Bool SAL_CALL first() override; + sal_Bool SAL_CALL last() override; + + sal_Int32 SAL_CALL getRow() override; + + sal_Bool SAL_CALL absolute(sal_Int32 row) override; + sal_Bool SAL_CALL relative(sal_Int32 rows) override; + sal_Bool SAL_CALL previous() override; + + void SAL_CALL refreshRow() override; + + sal_Bool SAL_CALL rowUpdated() override; + sal_Bool SAL_CALL rowInserted() override; + sal_Bool SAL_CALL rowDeleted() override; + + css::uno::Reference<css::uno::XInterface> SAL_CALL getStatement() override; + // XRow + sal_Bool SAL_CALL wasNull() override; + + OUString SAL_CALL getString(sal_Int32 column) override; + + sal_Bool SAL_CALL getBoolean(sal_Int32 column) override; + sal_Int8 SAL_CALL getByte(sal_Int32 column) override; + sal_Int16 SAL_CALL getShort(sal_Int32 column) override; + sal_Int32 SAL_CALL getInt(sal_Int32 column) override; + sal_Int64 SAL_CALL getLong(sal_Int32 column) override; + + float SAL_CALL getFloat(sal_Int32 column) override; + double SAL_CALL getDouble(sal_Int32 column) override; + + css::uno::Sequence<sal_Int8> SAL_CALL getBytes(sal_Int32 column) override; + css::util::Date SAL_CALL getDate(sal_Int32 column) override; + css::util::Time SAL_CALL getTime(sal_Int32 column) override; + css::util::DateTime SAL_CALL getTimestamp(sal_Int32 column) override; + + css::uno::Reference<css::io::XInputStream> SAL_CALL getBinaryStream(sal_Int32 column) override; + css::uno::Reference<css::io::XInputStream> + SAL_CALL getCharacterStream(sal_Int32 column) override; + + Any SAL_CALL getObject( + sal_Int32 column, const css::uno::Reference<css::container::XNameAccess>& typeMap) override; + + css::uno::Reference<css::sdbc::XRef> SAL_CALL getRef(sal_Int32 column) override; + css::uno::Reference<css::sdbc::XBlob> SAL_CALL getBlob(sal_Int32 column) override; + css::uno::Reference<css::sdbc::XClob> SAL_CALL getClob(sal_Int32 column) override; + css::uno::Reference<css::sdbc::XArray> SAL_CALL getArray(sal_Int32 column) override; + + // XResultSetMetaDataSupplier + css::uno::Reference<css::sdbc::XResultSetMetaData> SAL_CALL getMetaData() override; + + // XCancellable + void SAL_CALL cancel() override; + + // XCloseable + void SAL_CALL close() override; + + // XWarningsSupplier + Any SAL_CALL getWarnings() override; + + void SAL_CALL clearWarnings() override; + + // XResultSetUpdate + void SAL_CALL insertRow() override; + void SAL_CALL updateRow() override; + void SAL_CALL deleteRow() override; + void SAL_CALL cancelRowUpdates() override; + void SAL_CALL moveToInsertRow() override; + void SAL_CALL moveToCurrentRow() override; + + // XRowUpdate + void SAL_CALL updateNull(sal_Int32 column) override; + void SAL_CALL updateBoolean(sal_Int32 column, sal_Bool x) override; + void SAL_CALL updateByte(sal_Int32 column, sal_Int8 x) override; + void SAL_CALL updateShort(sal_Int32 column, sal_Int16 x) override; + void SAL_CALL updateInt(sal_Int32 column, sal_Int32 x) override; + void SAL_CALL updateLong(sal_Int32 column, sal_Int64 x) override; + void SAL_CALL updateFloat(sal_Int32 column, float x) override; + void SAL_CALL updateDouble(sal_Int32 column, double x) override; + void SAL_CALL updateString(sal_Int32 column, const OUString& x) override; + void SAL_CALL updateBytes(sal_Int32 column, const css::uno::Sequence<sal_Int8>& x) override; + void SAL_CALL updateDate(sal_Int32 column, const css::util::Date& x) override; + void SAL_CALL updateTime(sal_Int32 column, const css::util::Time& x) override; + void SAL_CALL updateTimestamp(sal_Int32 column, const css::util::DateTime& x) override; + void SAL_CALL updateBinaryStream(sal_Int32 column, + const css::uno::Reference<css::io::XInputStream>& x, + sal_Int32 length) override; + void SAL_CALL updateCharacterStream(sal_Int32 column, + const css::uno::Reference<css::io::XInputStream>& x, + sal_Int32 length) override; + void SAL_CALL updateObject(sal_Int32 column, const Any& x) override; + void SAL_CALL updateNumericObject(sal_Int32 column, const Any& x, sal_Int32 scale) override; + + // XColumnLocate + sal_Int32 SAL_CALL findColumn(const OUString& columnName) override; + + // XRowLocate + Any SAL_CALL getBookmark() override; + + sal_Bool SAL_CALL moveToBookmark(const Any& bookmark) override; + sal_Bool SAL_CALL moveRelativeToBookmark(const Any& bookmark, sal_Int32 rows) override; + sal_Int32 SAL_CALL compareBookmarks(const Any& first, const Any& second) override; + sal_Bool SAL_CALL hasOrderedBookmarks() override; + sal_Int32 SAL_CALL hashBookmark(const Any& bookmark) override; + + // XDeleteRows + css::uno::Sequence<sal_Int32> SAL_CALL deleteRows(const css::uno::Sequence<Any>& rows) override; + + /// @throws SQLException + /// @throws RuntimeException + void checkColumnIndex(sal_Int32 index); + +private: + using ::cppu::OPropertySetHelper::getFastPropertyValue; +}; + +} /* connectivity::mysqlc */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.cxx b/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.cxx new file mode 100644 index 000000000..3c1c6d88e --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.cxx @@ -0,0 +1,580 @@ +/* -*- 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 "mysqlc_prepared_resultset.hxx" +#include "mysqlc_preparedstatement.hxx" +#include "mysqlc_propertyids.hxx" +#include "mysqlc_resultsetmetadata.hxx" + +#include <o3tl/safeint.hxx> +#include <sal/log.hxx> + +#include <com/sun/star/sdbc/DataType.hpp> + +#include <stdio.h> + +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; +using namespace com::sun::star::container; +using namespace com::sun::star::io; +using namespace com::sun::star::util; +using ::osl::MutexGuard; + +OUString OPreparedStatement::getImplementationName() +{ + return "com.sun.star.sdbcx.mysqlc.PreparedStatement"; +} + +css::uno::Sequence<OUString> OPreparedStatement::getSupportedServiceNames() +{ + return { "com.sun.star.sdbc.PreparedStatement" }; +} + +sal_Bool OPreparedStatement::supportsService(OUString const& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +OPreparedStatement::OPreparedStatement(OConnection* _pConnection, MYSQL_STMT* pStmt) + : OCommonStatement(_pConnection) + , m_pStmt(pStmt) +{ + m_paramCount = mysql_stmt_param_count(m_pStmt); + m_binds.reserve(m_paramCount); + m_bindMetas.reserve(m_paramCount); + for (unsigned i = 0; i < m_paramCount; ++i) + { + m_binds.push_back(MYSQL_BIND{}); + m_bindMetas.push_back(BindMetaData{}); + m_binds.back().is_null = &m_bindMetas.back().is_null; + m_binds.back().length = &m_bindMetas.back().length; + m_binds.back().buffer = nullptr; + } +} + +OPreparedStatement::~OPreparedStatement() {} + +void SAL_CALL OPreparedStatement::acquire() noexcept { OCommonStatement::acquire(); } + +void SAL_CALL OPreparedStatement::release() noexcept { OCommonStatement::release(); } + +Any SAL_CALL OPreparedStatement::queryInterface(const Type& rType) +{ + Any aRet = OCommonStatement::queryInterface(rType); + if (!aRet.hasValue()) + { + aRet = OPreparedStatement_BASE::queryInterface(rType); + } + return aRet; +} + +Sequence<Type> SAL_CALL OPreparedStatement::getTypes() +{ + return concatSequences(OPreparedStatement_BASE::getTypes(), OCommonStatement::getTypes()); +} + +Reference<XResultSetMetaData> SAL_CALL OPreparedStatement::getMetaData() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + if (!m_xMetaData.is()) + { + MYSQL_RES* pRes = mysql_stmt_result_metadata(m_pStmt); + // TODO warning or error if no meta data. + m_xMetaData = new OResultSetMetaData(*m_xConnection, pRes); + } + return m_xMetaData; +} + +void SAL_CALL OPreparedStatement::close() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + if (mysql_stmt_close(m_pStmt)) + { + SAL_WARN("connectivity.mysqlc", "failed to close mysql prepared statement"); + } + m_pStmt = nullptr; // it's deallocated already + clearWarnings(); + clearParameters(); + OCommonStatement::close(); +} + +sal_Bool SAL_CALL OPreparedStatement::execute() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + if (!m_binds.empty() && mysql_stmt_bind_param(m_pStmt, m_binds.data())) + { + MYSQL* pMysql = m_xConnection->getMysqlConnection(); + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt), + mysql_sqlstate(pMysql), mysql_errno(pMysql), + *this, m_xConnection->getConnectionEncoding()); + } + + int nFail = mysql_stmt_execute(m_pStmt); + if (nFail != 0) + { + MYSQL* pMysql = m_xConnection->getMysqlConnection(); + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt), + mysql_sqlstate(pMysql), mysql_errno(pMysql), + *this, m_xConnection->getConnectionEncoding()); + } + + return !nFail; +} + +sal_Int32 SAL_CALL OPreparedStatement::executeUpdate() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + if (!m_binds.empty() && mysql_stmt_bind_param(m_pStmt, m_binds.data())) + { + MYSQL* pMysql = m_xConnection->getMysqlConnection(); + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt), + mysql_sqlstate(pMysql), mysql_errno(pMysql), + *this, m_xConnection->getConnectionEncoding()); + } + + int nFail = mysql_stmt_execute(m_pStmt); + + if (nFail != 0) + { + MYSQL* pMysql = m_xConnection->getMysqlConnection(); + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt), + mysql_sqlstate(pMysql), mysql_errno(pMysql), + *this, m_xConnection->getConnectionEncoding()); + } + + sal_Int32 affectedRows = mysql_stmt_affected_rows(m_pStmt); + return affectedRows; +} + +void SAL_CALL OPreparedStatement::setString(sal_Int32 parameter, const OUString& x) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + OString stringie(OUStringToOString(x, m_xConnection->getConnectionEncoding())); + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_STRING; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, stringie.getStr(), MYSQL_TYPE_STRING, + stringie.getLength()); + m_bindMetas[nIndex].is_null = false; + m_bindMetas[nIndex].length = stringie.getLength(); +} + +Reference<XConnection> SAL_CALL OPreparedStatement::getConnection() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection; +} + +Reference<XResultSet> SAL_CALL OPreparedStatement::executeQuery() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + if (!m_binds.empty() && mysql_stmt_bind_param(m_pStmt, m_binds.data())) + { + MYSQL* pMysql = m_xConnection->getMysqlConnection(); + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt), + mysql_sqlstate(pMysql), mysql_errno(pMysql), + *this, m_xConnection->getConnectionEncoding()); + } + + int nFail = mysql_stmt_execute(m_pStmt); + + if (nFail != 0) + { + MYSQL* pMysql = m_xConnection->getMysqlConnection(); + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt), + mysql_sqlstate(pMysql), mysql_errno(pMysql), + *this, m_xConnection->getConnectionEncoding()); + } + + Reference<XResultSet> xResultSet = new OPreparedResultSet(*m_xConnection, this, m_pStmt); + return xResultSet; +} + +void SAL_CALL OPreparedStatement::setBoolean(sal_Int32 parameter, sal_Bool x) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_TINY; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_TINY); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setByte(sal_Int32 parameter, sal_Int8 x) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_TINY; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_TINY); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setDate(sal_Int32 parameter, const Date& aData) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + MYSQL_TIME my_time = {}; + + my_time.year = aData.Year; + my_time.month = aData.Month; + my_time.day = aData.Day; + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_DATE; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &my_time, MYSQL_TYPE_DATE); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setTime(sal_Int32 parameter, const Time& aVal) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + MYSQL_TIME my_time = {}; + + my_time.hour = aVal.Hours; + my_time.minute = aVal.Minutes; + my_time.second = aVal.Seconds; + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_TIME; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &my_time, MYSQL_TYPE_TIME); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setTimestamp(sal_Int32 parameter, const DateTime& aVal) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + MYSQL_TIME my_time = {}; + + my_time.hour = aVal.Hours; + my_time.minute = aVal.Minutes; + my_time.second = aVal.Seconds; + my_time.year = aVal.Year; + my_time.month = aVal.Month; + my_time.day = aVal.Day; + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_DATETIME; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &my_time, MYSQL_TYPE_DATETIME); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setDouble(sal_Int32 parameter, double x) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_DOUBLE; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_DOUBLE); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setFloat(sal_Int32 parameter, float x) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_FLOAT; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_FLOAT); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setInt(sal_Int32 parameter, sal_Int32 x) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_LONG; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_LONG); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setLong(sal_Int32 parameter, sal_Int64 aVal) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_LONGLONG; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &aVal, MYSQL_TYPE_LONGLONG); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setNull(sal_Int32 parameter, sal_Int32 /*sqlType*/) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + const sal_Int32 nIndex = parameter - 1; + m_bindMetas[nIndex].is_null = true; + free(m_binds[nIndex].buffer); + m_binds[nIndex].buffer = nullptr; +} + +void SAL_CALL OPreparedStatement::setClob(sal_Int32 parameter, const Reference<XClob>& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setClob", *this); +} + +void SAL_CALL OPreparedStatement::setBlob(sal_Int32 parameter, const Reference<XBlob>& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setBlob", *this); +} + +void SAL_CALL OPreparedStatement::setArray(sal_Int32 parameter, const Reference<XArray>& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setArray", *this); +} + +void SAL_CALL OPreparedStatement::setRef(sal_Int32 parameter, const Reference<XRef>& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setRef", *this); +} + +void SAL_CALL OPreparedStatement::setObjectWithInfo(sal_Int32 parameterIndex, const Any& value, + sal_Int32 targetSqlType, sal_Int32 /* scale */) +{ + checkDisposed(rBHelper.bDisposed); + MutexGuard aGuard(m_aMutex); + checkParameterIndex(parameterIndex); + + const sal_Int32 nIndex = parameterIndex - 1; + if (!value.hasValue()) + { + free(m_binds[nIndex].buffer); + m_binds[nIndex].buffer = nullptr; + m_bindMetas[parameterIndex - 1].is_null = true; + return; + } + + switch (targetSqlType) + { + case DataType::DECIMAL: + case DataType::NUMERIC: + { + double nValue(0.0); + OUString sValue; + if (value >>= nValue) + { + setDouble(parameterIndex, nValue); + break; + } + else if (value >>= sValue) + { + OString sAscii + = OUStringToOString(sValue, getOwnConnection()->getConnectionEncoding()); + std::stringstream sStream{ sAscii.getStr() }; + sStream >> nValue; + m_binds[nIndex].buffer_type = MYSQL_TYPE_DOUBLE; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &nValue, MYSQL_TYPE_DOUBLE, + sValue.getLength()); + m_bindMetas[nIndex].is_null = false; + break; + } + + [[fallthrough]]; + } + + // TODO other types + + default: + mysqlc_sdbc_driver::throwInvalidArgumentException( + "OPreparedStatement::setObjectWithInfo", *this); + break; + } +} + +void SAL_CALL OPreparedStatement::setObjectNull(sal_Int32 parameter, sal_Int32 /* sqlType */, + const OUString& /* typeName */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setObjectNull", + *this); +} + +void SAL_CALL OPreparedStatement::setObject(sal_Int32 parameter, const Any& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setObject", *this); +} + +void SAL_CALL OPreparedStatement::setShort(sal_Int32 parameter, sal_Int16 x) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_SHORT; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_SHORT); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setBytes(sal_Int32 parameter, const Sequence<sal_Int8>& x) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_BLOB; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x[0], MYSQL_TYPE_BLOB, x.getLength()); + m_bindMetas[nIndex].is_null = false; + m_bindMetas[nIndex].length = x.getLength(); +} + +void SAL_CALL OPreparedStatement::setCharacterStream(sal_Int32 parameter, + const Reference<XInputStream>& /* x */, + sal_Int32 /* length */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException( + "OPreparedStatement::setCharacterStream", *this); +} + +void SAL_CALL OPreparedStatement::setBinaryStream(sal_Int32 parameter, + const Reference<XInputStream>& /* x */, + sal_Int32 /* length */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + checkParameterIndex(parameter); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setBinaryStream", + *this); +} + +void SAL_CALL OPreparedStatement::clearParameters() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + for (size_t i = 0; i < m_binds.size(); ++i) + { + m_bindMetas[i].is_null = true; + free(m_binds[i].buffer); + m_binds[i].buffer = nullptr; + } +} + +// void SAL_CALL OPreparedStatement::clearBatch() +// { +// mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::clearBatch", +// *this); +// } + +// void SAL_CALL OPreparedStatement::addBatch() +// { +// mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::addBatch", *this); +// } + +// Sequence<sal_Int32> SAL_CALL OPreparedStatement::executeBatch() { +// mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::executeBatch", *this); +// } + +void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) +{ + switch (nHandle) + { + case PROPERTY_ID_RESULTSETCONCURRENCY: + break; + case PROPERTY_ID_RESULTSETTYPE: + break; + case PROPERTY_ID_FETCHDIRECTION: + break; + case PROPERTY_ID_USEBOOKMARKS: + break; + default: + /* XXX: Recursion ?? */ + OPreparedStatement::setFastPropertyValue_NoBroadcast(nHandle, rValue); + } +} + +void OPreparedStatement::checkParameterIndex(sal_Int32 column) +{ + if (column < 1 || o3tl::make_unsigned(column) > m_paramCount) + { + throw SQLException("Parameter index out of range", *this, OUString(), 1, Any()); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.hxx b/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.hxx new file mode 100644 index 000000000..d280bd935 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.hxx @@ -0,0 +1,157 @@ +/* -*- 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 . + */ + +#pragma once +#include "mysqlc_statement.hxx" +#include "mysqlc_resultset.hxx" + +#include <com/sun/star/sdbc/XPreparedStatement.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XPreparedBatchExecution.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <cppuhelper/compbase4.hxx> + +namespace connectivity::mysqlc +{ +using ::com::sun::star::sdbc::SQLException; +using ::com::sun::star::sdbc::XResultSetMetaData; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::uno::Type; + +#if defined MYSQL_VERSION_ID && (MYSQL_VERSION_ID >= 80000) && !defined MARIADB_BASE_VERSION +using my_bool = bool; +#else +using my_bool = char; +#endif + +struct BindMetaData +{ + my_bool is_null = false; + unsigned long length = 0; + my_bool error = false; +}; + +typedef ::cppu::ImplHelper4<css::sdbc::XPreparedStatement, css::sdbc::XParameters, + css::sdbc::XResultSetMetaDataSupplier, css::lang::XServiceInfo> + OPreparedStatement_BASE; + +class OPreparedStatement final : public OCommonStatement, public OPreparedStatement_BASE +{ + unsigned int m_paramCount = 0; // number of placeholders + Reference<XResultSetMetaData> m_xMetaData; + MYSQL_STMT* m_pStmt; + std::vector<MYSQL_BIND> m_binds; + std::vector<BindMetaData> m_bindMetas; + + void checkParameterIndex(sal_Int32 parameter); + + void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) override; + virtual ~OPreparedStatement() override; + +public: + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override; + + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + OPreparedStatement(OConnection* _pConnection, MYSQL_STMT* pStmt); + + //XInterface + Any SAL_CALL queryInterface(const Type& rType) override; + void SAL_CALL acquire() noexcept override; + void SAL_CALL release() noexcept override; + + //XTypeProvider + css::uno::Sequence<Type> SAL_CALL getTypes() override; + + // XPreparedStatement + Reference<css::sdbc::XResultSet> SAL_CALL executeQuery() override; + sal_Int32 SAL_CALL executeUpdate() override; + sal_Bool SAL_CALL execute() override; + Reference<css::sdbc::XConnection> SAL_CALL getConnection() override; + + // XParameters + void SAL_CALL setNull(sal_Int32 parameter, sal_Int32 sqlType) override; + + void SAL_CALL setObjectNull(sal_Int32 parameter, sal_Int32 sqlType, + const OUString& typeName) override; + + void SAL_CALL setBoolean(sal_Int32 parameter, sal_Bool x) override; + + void SAL_CALL setByte(sal_Int32 parameter, sal_Int8 x) override; + + void SAL_CALL setShort(sal_Int32 parameter, sal_Int16 x) override; + + void SAL_CALL setInt(sal_Int32 parameter, sal_Int32 x) override; + + void SAL_CALL setLong(sal_Int32 parameter, sal_Int64 x) override; + + void SAL_CALL setFloat(sal_Int32 parameter, float x) override; + + void SAL_CALL setDouble(sal_Int32 parameter, double x) override; + + void SAL_CALL setString(sal_Int32 parameter, const OUString& x) override; + + void SAL_CALL setBytes(sal_Int32 parameter, const css::uno::Sequence<sal_Int8>& x) override; + + void SAL_CALL setDate(sal_Int32 parameter, const css::util::Date& x) override; + + void SAL_CALL setTime(sal_Int32 parameter, const css::util::Time& x) override; + void SAL_CALL setTimestamp(sal_Int32 parameter, const css::util::DateTime& x) override; + + void SAL_CALL setBinaryStream(sal_Int32 parameter, const Reference<css::io::XInputStream>& x, + sal_Int32 length) override; + + void SAL_CALL setCharacterStream(sal_Int32 parameter, const Reference<css::io::XInputStream>& x, + sal_Int32 length) override; + + void SAL_CALL setObject(sal_Int32 parameter, const Any& x) override; + + void SAL_CALL setObjectWithInfo(sal_Int32 parameter, const Any& x, sal_Int32 targetSqlType, + sal_Int32 scale) override; + + void SAL_CALL setRef(sal_Int32 parameter, const Reference<css::sdbc::XRef>& x) override; + + void SAL_CALL setBlob(sal_Int32 parameter, const Reference<css::sdbc::XBlob>& x) override; + + void SAL_CALL setClob(sal_Int32 parameter, const Reference<css::sdbc::XClob>& x) override; + + void SAL_CALL setArray(sal_Int32 parameter, const Reference<css::sdbc::XArray>& x) override; + + void SAL_CALL clearParameters() override; + + // XPreparedBatchExecution + // void SAL_CALL addBatch() override; + // void SAL_CALL clearBatch() override; + // css::uno::Sequence<sal_Int32> SAL_CALL executeBatch() override; + + // XCloseable + void SAL_CALL close() override; + + // XResultSetMetaDataSupplier + Reference<css::sdbc::XResultSetMetaData> SAL_CALL getMetaData() override; +}; + +} /* connectivity::mysqlc */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_propertyids.hxx b/connectivity/source/drivers/mysqlc/mysqlc_propertyids.hxx new file mode 100644 index 000000000..113b28a2f --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_propertyids.hxx @@ -0,0 +1,44 @@ +/* -*- 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 . + */ + +#pragma once + +// this define has to be set to split the names into different dll's or so's +// every dll has his own set of property names + +namespace connectivity::mysqlc +{ +enum +{ + PROPERTY_ID_QUERYTIMEOUT = 1, + PROPERTY_ID_MAXFIELDSIZE, + PROPERTY_ID_MAXROWS, + PROPERTY_ID_CURSORNAME, + PROPERTY_ID_RESULTSETCONCURRENCY, + PROPERTY_ID_RESULTSETTYPE, + PROPERTY_ID_FETCHDIRECTION, + PROPERTY_ID_FETCHSIZE, + PROPERTY_ID_ESCAPEPROCESSING, + PROPERTY_ID_USEBOOKMARKS, + PROPERTY_ID_ISBOOKMARKABLE +}; + +} /* connectivity::mysqlc */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx b/connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx new file mode 100644 index 000000000..f1c23ca48 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx @@ -0,0 +1,1112 @@ +/* -*- 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_resultset.hxx" +#include "mysqlc_resultsetmetadata.hxx" + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/sdbcx/CompareBookmark.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <comphelper/seqstream.hxx> +#include <o3tl/safeint.hxx> +#include <o3tl/string_view.hxx> + +using namespace rtl; + +using namespace connectivity::mysqlc; +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::uno; +using namespace com::sun::star::util; +using namespace ::comphelper; +using ::osl::MutexGuard; + +namespace +{ +// copied from string misc, it should be replaced when library is not an +// extension anymore +std::vector<OString> lcl_split(std::string_view rStr, char cSeparator) +{ + std::vector<OString> vec; + sal_Int32 idx = 0; + do + { + OString kw(o3tl::trim(o3tl::getToken(rStr, 0, cSeparator, idx))); + if (!kw.isEmpty()) + { + vec.push_back(kw); + } + } while (idx >= 0); + return vec; +} +} + +void OResultSet::checkRowIndex() +{ + if (m_nRowPosition < 0 || m_nRowPosition >= m_nRowCount) + { + throw SQLException("Cursor position out of range", *this, OUString(), 1, Any()); + } +} + +bool OResultSet::checkNull(sal_Int32 column) +{ + if (m_aRows[m_nRowPosition][column - 1].isEmpty()) + { + m_bWasNull = true; + return true; + } + m_bWasNull = false; + return false; +} + +OUString SAL_CALL OResultSet::getImplementationName() +{ + return "com.sun.star.sdbcx.mysqlc.ResultSet"; +} + +uno::Sequence<OUString> SAL_CALL OResultSet::getSupportedServiceNames() +{ + return { "com.sun.star.sdbc.ResultSet", "com.sun.star.sdbcx.ResultSet" }; +} + +sal_Bool SAL_CALL OResultSet::supportsService(const OUString& _rServiceName) +{ + return cppu::supportsService(this, _rServiceName); +} + +OResultSet::OResultSet(OConnection& rConn, OCommonStatement* pStmt, MYSQL_RES* pResult, + rtl_TextEncoding _encoding) + : OResultSet_BASE(m_aMutex) + , OPropertySetHelper(OResultSet_BASE::rBHelper) + , m_pMysql(rConn.getMysqlConnection()) + , m_aStatement(css::uno::Reference<css::uno::XWeak>(static_cast<OWeakObject*>(pStmt))) + , m_pResult(pResult) + , m_encoding(_encoding) +{ + assert(m_pResult); + m_xMetaData = new OResultSetMetaData(rConn, m_pResult); +} + +void OResultSet::ensureResultFetched() +{ + if (m_pResult) + { + fetchResult(); + } +} + +void OResultSet::ensureFieldInfoFetched() +{ + if (m_pResult == nullptr) + return; // already fetched + + // it works only if result set is produced via mysql_store_result + // TODO ensure that + m_nRowCount = mysql_num_rows(m_pResult); + + if (!m_aFields.empty()) + return; + unsigned nFieldCount = mysql_num_fields(m_pResult); + MYSQL_FIELD* pFields = mysql_fetch_fields(m_pResult); + m_aFields.reserve(nFieldCount); + for (unsigned i = 0; i < nFieldCount; ++i) + m_aFields.push_back(OUString{ + pFields[i].name, static_cast<sal_Int32>(strlen(pFields[i].name)), m_encoding }); +} + +void OResultSet::fetchResult() +{ + // Mysql C API does not allow simultaneously opened result sets, but sdbc does. + // Because of that we need to fetch all of the data ASAP + ensureFieldInfoFetched(); + + // fetch all the data + m_aRows.reserve(m_nRowCount); + + for (sal_Int32 row = 0; row < m_nRowCount; ++row) + { + MYSQL_ROW data = mysql_fetch_row(m_pResult); + unsigned long* lengths = mysql_fetch_lengths(m_pResult); + m_aRows.push_back(DataFields{}); + // MYSQL_ROW is char**, array of strings + for (std::size_t col = 0; col < m_aFields.size(); ++col) + { + m_aRows.back().push_back(OString{ data[col], static_cast<sal_Int32>(lengths[col]) }); + } + } + unsigned errorNum = mysql_errno(m_pMysql); + if (errorNum) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg( + mysql_error(m_pMysql), mysql_sqlstate(m_pMysql), errorNum, *this, m_encoding); + mysql_free_result(m_pResult); + m_pResult = nullptr; +} + +void OResultSet::disposing() +{ + OPropertySetHelper::disposing(); + + MutexGuard aGuard(m_aMutex); + + if (m_pResult != nullptr) + { + mysql_free_result(m_pResult); + m_pResult = nullptr; + } + m_aStatement.clear(); + m_xMetaData = nullptr; +} + +Any SAL_CALL OResultSet::queryInterface(const Type& rType) +{ + Any aRet = OPropertySetHelper::queryInterface(rType); + if (!aRet.hasValue()) + { + aRet = OResultSet_BASE::queryInterface(rType); + } + return aRet; +} + +uno::Sequence<Type> SAL_CALL OResultSet::getTypes() +{ + OTypeCollection aTypes(cppu::UnoType<XMultiPropertySet>::get(), + cppu::UnoType<XFastPropertySet>::get(), + cppu::UnoType<XPropertySet>::get()); + + return concatSequences(aTypes.getTypes(), OResultSet_BASE::getTypes()); +} + +sal_Int32 SAL_CALL OResultSet::findColumn(const OUString& columnName) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); + + for (std::size_t i = 0; i < m_aFields.size(); ++i) + { + if (columnName.equalsIgnoreAsciiCase(m_aFields[i])) + return static_cast<sal_Int32>(i) + 1; // sdbc indexes from 1 + } + + throw SQLException("The column name '" + columnName + "' is not valid.", *this, "42S22", 0, + Any()); +} + +uno::Reference<XInputStream> SAL_CALL OResultSet::getBinaryStream(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + if (checkNull(column)) + return nullptr; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + return new SequenceInputStream{ uno::Sequence<sal_Int8>( + reinterpret_cast<sal_Int8 const*>(sVal.getStr()), getDataLength(column)) }; +} + +uno::Reference<XInputStream> SAL_CALL OResultSet::getCharacterStream(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getCharacterStream", + *this); + return nullptr; +} + +sal_Bool SAL_CALL OResultSet::getBoolean(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + if (checkNull(column)) + return false; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + return sVal.toInt32() != 0; +} + +sal_Int8 SAL_CALL OResultSet::getByte(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + if (checkNull(column)) + return 0; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + + return static_cast<sal_Int8>(sVal.toInt32()); +} + +uno::Sequence<sal_Int8> SAL_CALL OResultSet::getBytes(sal_Int32 column) +{ + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + MutexGuard aGuard(m_aMutex); + checkBordersAndEnsureFetched(column); + OString sVal = m_aRows[m_nRowPosition][column - 1]; + if (checkNull(column)) + return uno::Sequence<sal_Int8>(); + + return uno::Sequence<sal_Int8>(reinterpret_cast<sal_Int8 const*>(sVal.getStr()), + getDataLength(column)); +} + +Date SAL_CALL OResultSet::getDate(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + + Date d; + + if (checkNull(column)) + return d; + + const OString& dateStr = m_aRows[m_nRowPosition][column - 1]; + + std::string_view dateString(dateStr); + sal_Int32 nIndex = 0, i = 0; + do + { + std::string_view token = o3tl::getToken(dateString, 0, '-', nIndex); + switch (i) + { + case 0: + d.Year = static_cast<sal_uInt16>(o3tl::toUInt32(token)); + break; + case 1: + d.Month = static_cast<sal_uInt16>(o3tl::toUInt32(token)); + break; + case 2: + d.Day = static_cast<sal_uInt16>(o3tl::toUInt32(token)); + break; + default:; + } + i++; + } while (nIndex >= 0); + return d; +} + +double SAL_CALL OResultSet::getDouble(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + + if (checkNull(column)) + return 0.0; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + return sVal.toDouble(); +} + +float SAL_CALL OResultSet::getFloat(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + if (checkNull(column)) + return 0.0f; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + return sVal.toFloat(); +} + +sal_Int32 SAL_CALL OResultSet::getInt(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + if (checkNull(column)) + return 0; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + return sVal.toInt32(); +} + +sal_Int32 SAL_CALL OResultSet::getRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_nRowPosition + 1; // indexed from 1 +} + +sal_Int64 SAL_CALL OResultSet::getLong(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + if (checkNull(column)) + return 0LL; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + return sVal.toInt64(); +} + +uno::Reference<XResultSetMetaData> SAL_CALL OResultSet::getMetaData() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + return m_xMetaData; +} + +uno::Reference<XArray> SAL_CALL OResultSet::getArray(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getArray", *this); + return nullptr; +} + +uno::Reference<XClob> SAL_CALL OResultSet::getClob(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getClob", *this); + return nullptr; +} + +uno::Reference<XBlob> SAL_CALL OResultSet::getBlob(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getBlob", *this); + return nullptr; +} + +uno::Reference<XRef> SAL_CALL OResultSet::getRef(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getRef", *this); + return nullptr; +} + +Any SAL_CALL OResultSet::getObject(sal_Int32 column, + const uno::Reference<XNameAccess>& /* typeMap */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getObject", *this); + return Any(); +} + +sal_Int16 SAL_CALL OResultSet::getShort(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + if (checkNull(column)) + return 0; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + return sVal.toInt32(); +} + +OUString SAL_CALL OResultSet::getString(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + if (checkNull(column)) + return rtl::OUString{}; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + return OStringToOUString(sVal, m_encoding); +} + +Time SAL_CALL OResultSet::getTime(sal_Int32 column) +{ + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + MutexGuard aGuard(m_aMutex); + checkBordersAndEnsureFetched(column); + + Time t; + if (checkNull(column)) + return t; + + const OString& sVal = m_aRows[m_nRowPosition][column - 1]; + std::string_view timeString{ sVal.getStr(), o3tl::make_unsigned(getDataLength(column)) }; + sal_Int32 nIndex, i = 0; + + size_t idx = timeString.find(' '); + if (idx == std::string_view::npos) + nIndex = 0; + else + nIndex = idx + 1; + do + { + std::string_view token = o3tl::getToken(timeString, 0, ':', nIndex); + switch (i) + { + case 0: + t.Hours = static_cast<sal_uInt16>(o3tl::toUInt32(token)); + break; + case 1: + t.Minutes = static_cast<sal_uInt16>(o3tl::toUInt32(token)); + break; + case 2: + t.Seconds = static_cast<sal_uInt16>(o3tl::toUInt32(token)); + break; + } + i++; + } while (nIndex >= 0); + + return t; +} + +DateTime SAL_CALL OResultSet::getTimestamp(sal_Int32 column) +{ + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + MutexGuard aGuard(m_aMutex); + checkBordersAndEnsureFetched(column); + + if (checkNull(column)) + return DateTime{}; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + + // YY-MM-DD HH:MM:SS + std::vector<OString> dateAndTime + = lcl_split(std::string_view(sVal.getStr(), getDataLength(column)), ' '); + + auto dateParts = lcl_split(dateAndTime.at(0), '-'); + auto timeParts = lcl_split(dateAndTime.at(1), ':'); + + if (dateParts.size() < 2 || timeParts.size() < 2) + throw SQLException("Timestamp has a wrong format", *this, OUString(), 1, Any()); + + DateTime dt; + + dt.Year = dateParts.at(0).toUInt32(); + dt.Month = dateParts.at(1).toUInt32(); + dt.Day = dateParts.at(2).toUInt32(); + dt.Hours = timeParts.at(0).toUInt32(); + dt.Minutes = timeParts.at(1).toUInt32(); + dt.Seconds = timeParts.at(2).toUInt32(); + return dt; +} + +sal_Bool SAL_CALL OResultSet::isBeforeFirst() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_nRowPosition < 0; +} + +sal_Bool SAL_CALL OResultSet::isAfterLast() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); + + return m_nRowPosition >= m_nRowCount; +} + +sal_Bool SAL_CALL OResultSet::isFirst() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); + + return m_nRowPosition == 0 && !isAfterLast(); +} + +sal_Bool SAL_CALL OResultSet::isLast() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); + + return m_nRowPosition == m_nRowCount - 1; +} + +void SAL_CALL OResultSet::beforeFirst() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + m_nRowPosition = -1; +} + +void SAL_CALL OResultSet::afterLast() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); + m_nRowPosition = m_nRowCount; +} + +void SAL_CALL OResultSet::close() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if (m_pResult != nullptr) + { + mysql_free_result(m_pResult); + m_pResult = nullptr; + } + dispose(); +} + +sal_Bool SAL_CALL OResultSet::first() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + m_nRowPosition = 0; + + return true; +} + +sal_Bool SAL_CALL OResultSet::last() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); + m_nRowPosition = m_nRowCount - 1; + + return true; +} + +sal_Bool SAL_CALL OResultSet::absolute(sal_Int32 row) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); + + sal_Int32 nToGo = row < 0 ? (m_nRowCount - 1) - row : row - 1; + + if (nToGo >= m_nRowCount) + nToGo = m_nRowCount - 1; + if (nToGo < 0) + nToGo = 0; + + m_nRowPosition = nToGo; + + return true; +} + +sal_Bool SAL_CALL OResultSet::relative(sal_Int32 row) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); + + if (row == 0) + return true; + + sal_Int32 nToGo = m_nRowPosition + row; + if (nToGo >= m_nRowCount) + nToGo = m_nRowCount - 1; + if (nToGo < 0) + nToGo = 0; + + m_nRowPosition = nToGo; + + return true; +} + +sal_Bool SAL_CALL OResultSet::previous() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if (m_nRowPosition == 0) + { + m_nRowPosition--; + return false; + } + else if (m_nRowPosition < 0) + { + return false; + } + + m_nRowPosition--; + return true; +} + +uno::Reference<uno::XInterface> SAL_CALL OResultSet::getStatement() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_aStatement.get(); +} + +sal_Bool SAL_CALL OResultSet::rowDeleted() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL OResultSet::rowInserted() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL OResultSet::rowUpdated() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL OResultSet::next() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); + if (m_nRowPosition + 1 > m_nRowCount) // afterlast + return false; + if (m_nRowPosition + 1 == m_nRowCount) // last + { + // return false but take it to afterlast anyway + ++m_nRowPosition; + return false; + } + ++m_nRowPosition; + return true; +} + +sal_Bool SAL_CALL OResultSet::wasNull() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_bWasNull; +} + +void SAL_CALL OResultSet::cancel() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL OResultSet::clearWarnings() {} + +Any SAL_CALL OResultSet::getWarnings() { return Any(); } + +void SAL_CALL OResultSet::insertRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + // you only have to implement this if you want to insert new rows + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::insertRow", *this); +} + +void SAL_CALL OResultSet::updateRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + // only when you allow updates + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateRow", *this); +} + +void SAL_CALL OResultSet::deleteRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::deleteRow", *this); +} + +void SAL_CALL OResultSet::cancelRowUpdates() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::cancelRowUpdates", *this); +} + +void SAL_CALL OResultSet::moveToInsertRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + // only when you allow insert's + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::moveToInsertRow", *this); +} + +void SAL_CALL OResultSet::moveToCurrentRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL OResultSet::updateNull(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateNull", *this); +} + +void SAL_CALL OResultSet::updateBoolean(sal_Int32 column, sal_Bool /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateBoolean", *this); +} + +void SAL_CALL OResultSet::updateByte(sal_Int32 column, sal_Int8 /* x */) +{ + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + MutexGuard aGuard(m_aMutex); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateByte", *this); +} + +void SAL_CALL OResultSet::updateShort(sal_Int32 column, sal_Int16 /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateShort", *this); +} + +void SAL_CALL OResultSet::updateInt(sal_Int32 column, sal_Int32 /* x */) +{ + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + MutexGuard aGuard(m_aMutex); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateInt", *this); +} + +void SAL_CALL OResultSet::updateLong(sal_Int32 column, sal_Int64 /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateLong", *this); +} + +void SAL_CALL OResultSet::updateFloat(sal_Int32 column, float /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateFloat", *this); +} + +void SAL_CALL OResultSet::updateDouble(sal_Int32 column, double /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateDouble", *this); +} + +void SAL_CALL OResultSet::updateString(sal_Int32 column, const OUString& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateString", *this); +} + +void SAL_CALL OResultSet::updateBytes(sal_Int32 column, const uno::Sequence<sal_Int8>& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateBytes", *this); +} + +void SAL_CALL OResultSet::updateDate(sal_Int32 column, const Date& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateDate", *this); +} + +void SAL_CALL OResultSet::updateTime(sal_Int32 column, const Time& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateTime", *this); +} + +void SAL_CALL OResultSet::updateTimestamp(sal_Int32 column, const DateTime& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateTimestamp", *this); +} + +void SAL_CALL OResultSet::updateBinaryStream(sal_Int32 column, + const uno::Reference<XInputStream>& /* x */, + sal_Int32 /* length */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateBinaryStream", + *this); +} + +void SAL_CALL OResultSet::updateCharacterStream(sal_Int32 column, + const uno::Reference<XInputStream>& /* x */, + sal_Int32 /* length */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateCharacterStream", + *this); +} + +void SAL_CALL OResultSet::refreshRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::refreshRow", *this); +} + +void SAL_CALL OResultSet::updateObject(sal_Int32 column, const Any& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateObject", *this); +} + +void SAL_CALL OResultSet::updateNumericObject(sal_Int32 column, const Any& /* x */, + sal_Int32 /* scale */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateNumericObject", + *this); +} + +// XRowLocate +Any SAL_CALL OResultSet::getBookmark() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + // if you don't want to support bookmark you must remove the XRowLocate interface + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getBookmark", *this); + + return Any(); +} + +sal_Bool SAL_CALL OResultSet::moveToBookmark(const Any& /* bookmark */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL OResultSet::moveRelativeToBookmark(const Any& /* bookmark */, + sal_Int32 /* rows */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::moveRelativeToBookmark", + *this); + return false; +} + +sal_Int32 SAL_CALL OResultSet::compareBookmarks(const Any& /* n1 */, const Any& /* n2 */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::compareBookmarks", *this); + + return CompareBookmark::NOT_EQUAL; +} + +sal_Bool SAL_CALL OResultSet::hasOrderedBookmarks() { return false; } + +sal_Int32 SAL_CALL OResultSet::hashBookmark(const Any& /* bookmark */) +{ + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::hashBookmark", *this); + return 0; +} + +// XDeleteRows +uno::Sequence<sal_Int32> SAL_CALL OResultSet::deleteRows(const uno::Sequence<Any>& /* rows */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::deleteRows", *this); + return uno::Sequence<sal_Int32>(); +} + +IPropertyArrayHelper* OResultSet::createArrayHelper() const +{ + return new OPropertyArrayHelper{ + { { "FetchDirection", PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0 }, + { "FetchSize", PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0 }, + { "IsBookmarkable", PROPERTY_ID_ISBOOKMARKABLE, cppu::UnoType<bool>::get(), + PropertyAttribute::READONLY }, + { "ResultSetConcurrency", PROPERTY_ID_RESULTSETCONCURRENCY, + cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY }, + { "ResultSetType", PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), + PropertyAttribute::READONLY } } + }; +} + +IPropertyArrayHelper& OResultSet::getInfoHelper() { return *getArrayHelper(); } + +sal_Bool OResultSet::convertFastPropertyValue(Any& /* rConvertedValue */, Any& /* rOldValue */, + sal_Int32 nHandle, const Any& /* rValue */) +{ + switch (nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw css::lang::IllegalArgumentException(); + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + default:; + } + return false; +} + +void OResultSet::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& /* rValue */) +{ + switch (nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw uno::Exception("cannot set prop " + OUString::number(nHandle), nullptr); + case PROPERTY_ID_FETCHDIRECTION: + break; + case PROPERTY_ID_FETCHSIZE: + break; + default:; + } +} + +void OResultSet::getFastPropertyValue(Any& _rValue, sal_Int32 nHandle) const +{ + switch (nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + _rValue <<= false; + break; + case PROPERTY_ID_CURSORNAME: + break; + case PROPERTY_ID_RESULTSETCONCURRENCY: + _rValue <<= ResultSetConcurrency::READ_ONLY; + break; + case PROPERTY_ID_RESULTSETTYPE: + _rValue <<= ResultSetType::SCROLL_INSENSITIVE; + break; + case PROPERTY_ID_FETCHDIRECTION: + _rValue <<= FetchDirection::FORWARD; + break; + case PROPERTY_ID_FETCHSIZE: + _rValue <<= sal_Int32(50); + break; + ; + default:; + } +} + +void SAL_CALL OResultSet::acquire() noexcept { OResultSet_BASE::acquire(); } + +void SAL_CALL OResultSet::release() noexcept { OResultSet_BASE::release(); } + +css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL OResultSet::getPropertySetInfo() +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +void OResultSet::checkColumnIndex(sal_Int32 index) +{ + if (index < 1 || o3tl::make_unsigned(index) > m_aFields.size()) + { + /* static object for efficiency or thread safety is a problem ? */ + throw SQLException("index out of range", *this, OUString(), 1, Any()); + } +} + +void OResultSet::checkBordersAndEnsureFetched(sal_Int32 index) +{ + ensureResultFetched(); + checkColumnIndex(index); + checkRowIndex(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx b/connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx new file mode 100644 index 000000000..8114cddc9 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx @@ -0,0 +1,275 @@ +/* -*- 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 . + */ + +#pragma once + +#include "mysqlc_preparedstatement.hxx" +#include "mysqlc_statement.hxx" +#include "mysqlc_subcomponent.hxx" +#include "mysqlc_connection.hxx" + +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbcx/XDeleteRows.hpp> +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#include <com/sun/star/util/XCancellable.hpp> + +#include <cppuhelper/compbase12.hxx> + +namespace connectivity::mysqlc +{ +using ::com::sun::star::sdbc::SQLException; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::RuntimeException; + +/* + ** OResultSet + */ +typedef ::cppu::WeakComponentImplHelper12< + css::sdbc::XResultSet, css::sdbc::XRow, css::sdbc::XResultSetMetaDataSupplier, + css::util::XCancellable, css::sdbc::XWarningsSupplier, css::sdbc::XResultSetUpdate, + css::sdbc::XRowUpdate, css::sdbcx::XRowLocate, css::sdbcx::XDeleteRows, css::sdbc::XCloseable, + css::sdbc::XColumnLocate, css::lang::XServiceInfo> + OResultSet_BASE; + +class OResultSet final : public cppu::BaseMutex, + public OResultSet_BASE, + public ::cppu::OPropertySetHelper, + public OPropertyArrayUsageHelper<OResultSet> +{ + using DataFields = std::vector<OString>; + std::vector<DataFields> m_aRows; + std::vector<OUString> m_aFields; + MYSQL* m_pMysql = nullptr; + css::uno::WeakReferenceHelper m_aStatement; + css::uno::Reference<css::sdbc::XResultSetMetaData> m_xMetaData; + MYSQL_RES* m_pResult; + rtl_TextEncoding m_encoding; + bool m_bWasNull = false; // did the last getXXX result null? + + sal_Int32 getDataLength(sal_Int32 column) + { + return m_aRows[m_nRowPosition][column - 1].getLength(); + } + bool checkNull(sal_Int32 column); + + /** + * Position of cursor indexed from 0 + */ + sal_Int32 m_nRowPosition = -1; + sal_Int32 m_nRowCount = 0; + + // OPropertyArrayUsageHelper + ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + // OPropertySetHelper + ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + sal_Bool SAL_CALL convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue, + sal_Int32 nHandle, const Any& rValue) override; + + void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) override; + + void SAL_CALL getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const override; + + virtual ~OResultSet() override = default; + + /** + * Ensures that the results of the query has already been fetched. + */ + void ensureResultFetched(); + + /** + * Ensures that meta data of the corresponding result set has been already + * queried. It should be called before freeing the result set, unless the + * information is lost. + */ + void ensureFieldInfoFetched(); + + /** + * Check the following things: + * - cursor is out of range. Throws exception if true. + * - column index is out of range. Throws exception if true. + * - result set is fetched. If no, then it fetches the result. + */ + void checkBordersAndEnsureFetched(sal_Int32 index); + + /** + * Fetches all the data from the MYSQL_RES object related to the class. It + * frees the MYSQL_RES object afterwards, so it cannot be used anymore. + */ + void fetchResult(); + +public: + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override; + + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + OResultSet(OConnection& rConn, OCommonStatement* pStmt, MYSQL_RES* pResult, + rtl_TextEncoding _encoding); + + // ::cppu::OComponentHelper + void SAL_CALL disposing() override; + + // XInterface + Any SAL_CALL queryInterface(const css::uno::Type& rType) override; + + void SAL_CALL acquire() noexcept override; + void SAL_CALL release() noexcept override; + + //XTypeProvider + css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override; + + // XPropertySet + css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + + // XResultSet + sal_Bool SAL_CALL next() override; + sal_Bool SAL_CALL isBeforeFirst() override; + sal_Bool SAL_CALL isAfterLast() override; + sal_Bool SAL_CALL isFirst() override; + sal_Bool SAL_CALL isLast() override; + + void SAL_CALL beforeFirst() override; + void SAL_CALL afterLast() override; + + sal_Bool SAL_CALL first() override; + sal_Bool SAL_CALL last() override; + + sal_Int32 SAL_CALL getRow() override; + + sal_Bool SAL_CALL absolute(sal_Int32 row) override; + sal_Bool SAL_CALL relative(sal_Int32 rows) override; + sal_Bool SAL_CALL previous() override; + + void SAL_CALL refreshRow() override; + + sal_Bool SAL_CALL rowUpdated() override; + sal_Bool SAL_CALL rowInserted() override; + sal_Bool SAL_CALL rowDeleted() override; + + css::uno::Reference<css::uno::XInterface> SAL_CALL getStatement() override; + // XRow + sal_Bool SAL_CALL wasNull() override; + + OUString SAL_CALL getString(sal_Int32 column) override; + + sal_Bool SAL_CALL getBoolean(sal_Int32 column) override; + sal_Int8 SAL_CALL getByte(sal_Int32 column) override; + sal_Int16 SAL_CALL getShort(sal_Int32 column) override; + sal_Int32 SAL_CALL getInt(sal_Int32 column) override; + sal_Int64 SAL_CALL getLong(sal_Int32 column) override; + + float SAL_CALL getFloat(sal_Int32 column) override; + double SAL_CALL getDouble(sal_Int32 column) override; + + css::uno::Sequence<sal_Int8> SAL_CALL getBytes(sal_Int32 column) override; + css::util::Date SAL_CALL getDate(sal_Int32 column) override; + css::util::Time SAL_CALL getTime(sal_Int32 column) override; + css::util::DateTime SAL_CALL getTimestamp(sal_Int32 column) override; + + css::uno::Reference<css::io::XInputStream> SAL_CALL getBinaryStream(sal_Int32 column) override; + css::uno::Reference<css::io::XInputStream> + SAL_CALL getCharacterStream(sal_Int32 column) override; + + Any SAL_CALL getObject( + sal_Int32 column, const css::uno::Reference<css::container::XNameAccess>& typeMap) override; + + css::uno::Reference<css::sdbc::XRef> SAL_CALL getRef(sal_Int32 column) override; + css::uno::Reference<css::sdbc::XBlob> SAL_CALL getBlob(sal_Int32 column) override; + css::uno::Reference<css::sdbc::XClob> SAL_CALL getClob(sal_Int32 column) override; + css::uno::Reference<css::sdbc::XArray> SAL_CALL getArray(sal_Int32 column) override; + + // XResultSetMetaDataSupplier + css::uno::Reference<css::sdbc::XResultSetMetaData> SAL_CALL getMetaData() override; + + // XCancellable + void SAL_CALL cancel() override; + + // XCloseable + void SAL_CALL close() override; + + // XWarningsSupplier + Any SAL_CALL getWarnings() override; + + void SAL_CALL clearWarnings() override; + + // XResultSetUpdate + void SAL_CALL insertRow() override; + void SAL_CALL updateRow() override; + void SAL_CALL deleteRow() override; + void SAL_CALL cancelRowUpdates() override; + void SAL_CALL moveToInsertRow() override; + void SAL_CALL moveToCurrentRow() override; + + // XRowUpdate + void SAL_CALL updateNull(sal_Int32 column) override; + void SAL_CALL updateBoolean(sal_Int32 column, sal_Bool x) override; + void SAL_CALL updateByte(sal_Int32 column, sal_Int8 x) override; + void SAL_CALL updateShort(sal_Int32 column, sal_Int16 x) override; + void SAL_CALL updateInt(sal_Int32 column, sal_Int32 x) override; + void SAL_CALL updateLong(sal_Int32 column, sal_Int64 x) override; + void SAL_CALL updateFloat(sal_Int32 column, float x) override; + void SAL_CALL updateDouble(sal_Int32 column, double x) override; + void SAL_CALL updateString(sal_Int32 column, const OUString& x) override; + void SAL_CALL updateBytes(sal_Int32 column, const css::uno::Sequence<sal_Int8>& x) override; + void SAL_CALL updateDate(sal_Int32 column, const css::util::Date& x) override; + void SAL_CALL updateTime(sal_Int32 column, const css::util::Time& x) override; + void SAL_CALL updateTimestamp(sal_Int32 column, const css::util::DateTime& x) override; + void SAL_CALL updateBinaryStream(sal_Int32 column, + const css::uno::Reference<css::io::XInputStream>& x, + sal_Int32 length) override; + void SAL_CALL updateCharacterStream(sal_Int32 column, + const css::uno::Reference<css::io::XInputStream>& x, + sal_Int32 length) override; + void SAL_CALL updateObject(sal_Int32 column, const Any& x) override; + void SAL_CALL updateNumericObject(sal_Int32 column, const Any& x, sal_Int32 scale) override; + + // XColumnLocate + sal_Int32 SAL_CALL findColumn(const OUString& columnName) override; + + // XRowLocate + Any SAL_CALL getBookmark() override; + + sal_Bool SAL_CALL moveToBookmark(const Any& bookmark) override; + sal_Bool SAL_CALL moveRelativeToBookmark(const Any& bookmark, sal_Int32 rows) override; + sal_Int32 SAL_CALL compareBookmarks(const Any& first, const Any& second) override; + sal_Bool SAL_CALL hasOrderedBookmarks() override; + sal_Int32 SAL_CALL hashBookmark(const Any& bookmark) override; + + // XDeleteRows + css::uno::Sequence<sal_Int32> SAL_CALL deleteRows(const css::uno::Sequence<Any>& rows) override; + + void checkColumnIndex(sal_Int32 index); + void checkRowIndex(); + +private: + using ::cppu::OPropertySetHelper::getFastPropertyValue; +}; + +} /* connectivity::mysqlc */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.cxx b/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.cxx new file mode 100644 index 000000000..84cd6be2a --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.cxx @@ -0,0 +1,212 @@ +/* -*- 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_resultsetmetadata.hxx" +#include "mysqlc_general.hxx" + +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <o3tl/safeint.hxx> + +using namespace connectivity::mysqlc; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::sdbc; + +OResultSetMetaData::OResultSetMetaData(OConnection& rConn, MYSQL_RES* pResult) + : m_rConnection(rConn) +{ + MYSQL_FIELD* fields = mysql_fetch_field(pResult); + unsigned nFieldCount = mysql_num_fields(pResult); + for (unsigned i = 0; i < nFieldCount; ++i) + { + MySqlFieldInfo fieldInfo; + { + fieldInfo.columnName + = OUString{ fields[i].name, static_cast<sal_Int32>(fields[i].name_length), + m_rConnection.getConnectionEncoding() }; + fieldInfo.length = static_cast<sal_Int32>(fields[i].length); + fieldInfo.type + = mysqlc_sdbc_driver::mysqlToOOOType(fields[i].type, fields[i].charsetnr); + fieldInfo.mysql_type = fields[i].type; + fieldInfo.charsetNumber = fields[i].charsetnr; + fieldInfo.flags = fields[i].flags; + fieldInfo.schemaName + = OUString{ fields[i].db, static_cast<sal_Int32>(fields[i].db_length), + m_rConnection.getConnectionEncoding() }; + fieldInfo.tableName + = OUString{ fields[i].table, static_cast<sal_Int32>(fields[i].table_length), + m_rConnection.getConnectionEncoding() }; + fieldInfo.catalogName + = OUString{ fields[i].catalog, static_cast<sal_Int32>(fields[i].catalog_length), + m_rConnection.getConnectionEncoding() }; + fieldInfo.decimals = static_cast<sal_Int32>(fields[i].decimals); + fieldInfo.max_length = static_cast<sal_Int32>(fields[i].max_length); + } + m_fields.push_back(std::move(fieldInfo)); + } +} + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnDisplaySize(sal_Int32 column) +{ + checkColumnIndex(column); + return m_fields.at(column - 1).length; +} + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnType(sal_Int32 column) +{ + checkColumnIndex(column); + return m_fields.at(column - 1).type; +} + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnCount() { return m_fields.size(); } + +sal_Bool SAL_CALL OResultSetMetaData::isCaseSensitive(sal_Int32 column) +{ + // MYSQL_FIELD::charsetnr is the collation identifier + // _ci postfix means it's insensitive + OUString sql + = "SHOW COLLATION WHERE Id =" + OUString::number(m_fields.at(column - 1).charsetNumber); + + Reference<XStatement> stmt = m_rConnection.createStatement(); + Reference<XResultSet> rs = stmt->executeQuery(sql); + Reference<XRow> xRow(rs, UNO_QUERY_THROW); + + if (!rs->next()) // fetch first and only row + return false; + + OUString sColName = xRow->getString(1); // first column is Collation name + + return !sColName.isEmpty() && !sColName.endsWith("_ci"); +} + +OUString SAL_CALL OResultSetMetaData::getSchemaName(sal_Int32 column) +{ + checkColumnIndex(column); + return m_fields.at(column - 1).schemaName; +} + +OUString SAL_CALL OResultSetMetaData::getColumnName(sal_Int32 column) +{ + checkColumnIndex(column); + return m_fields.at(column - 1).columnName; +} + +OUString SAL_CALL OResultSetMetaData::getTableName(sal_Int32 column) +{ + checkColumnIndex(column); + return m_fields.at(column - 1).tableName; +} + +OUString SAL_CALL OResultSetMetaData::getCatalogName(sal_Int32 column) +{ + checkColumnIndex(column); + return m_fields.at(column - 1).catalogName; +} + +OUString SAL_CALL OResultSetMetaData::getColumnTypeName(sal_Int32 column) +{ + checkColumnIndex(column); + return mysqlc_sdbc_driver::mysqlTypeToStr(m_fields.at(column - 1).mysql_type, + m_fields.at(column - 1).flags); +} + +OUString SAL_CALL OResultSetMetaData::getColumnLabel(sal_Int32 column) +{ + checkColumnIndex(column); + return getColumnName(column); +} + +OUString SAL_CALL OResultSetMetaData::getColumnServiceName(sal_Int32 /*column*/) +{ + return OUString{}; +} + +sal_Bool SAL_CALL OResultSetMetaData::isCurrency(sal_Int32 /*column*/) +{ + return false; // TODO +} + +sal_Bool SAL_CALL OResultSetMetaData::isAutoIncrement(sal_Int32 column) +{ + checkColumnIndex(column); + return (m_fields.at(column - 1).flags & AUTO_INCREMENT_FLAG) != 0; +} + +sal_Bool SAL_CALL OResultSetMetaData::isSigned(sal_Int32 column) +{ + checkColumnIndex(column); + return !(m_fields.at(column - 1).flags & UNSIGNED_FLAG); +} + +sal_Int32 SAL_CALL OResultSetMetaData::getPrecision(sal_Int32 column) +{ + checkColumnIndex(column); + return m_fields.at(column - 1).max_length - m_fields.at(column - 1).decimals; +} + +sal_Int32 SAL_CALL OResultSetMetaData::getScale(sal_Int32 column) +{ + checkColumnIndex(column); + return m_fields.at(column - 1).decimals; +} + +sal_Int32 SAL_CALL OResultSetMetaData::isNullable(sal_Int32 column) +{ + checkColumnIndex(column); + return (m_fields.at(column - 1).flags & NOT_NULL_FLAG) ? 0 : 1; +} + +sal_Bool SAL_CALL OResultSetMetaData::isSearchable(sal_Int32 column) +{ + checkColumnIndex(column); + return true; +} + +sal_Bool SAL_CALL OResultSetMetaData::isReadOnly(sal_Int32 column) +{ + checkColumnIndex(column); + return m_fields.at(column - 1).schemaName.isEmpty(); +} + +sal_Bool SAL_CALL OResultSetMetaData::isDefinitelyWritable(sal_Int32 column) +{ + checkColumnIndex(column); + return !isReadOnly(column); +} + +sal_Bool SAL_CALL OResultSetMetaData::isWritable(sal_Int32 column) +{ + checkColumnIndex(column); + return !isReadOnly(column); +} + +void OResultSetMetaData::checkColumnIndex(sal_Int32 columnIndex) +{ + auto nColCount = m_fields.size(); + if (columnIndex < 1 || o3tl::make_unsigned(columnIndex) > nColCount) + { + OUString str = "Column index out of range (expected 1 to " + + OUString::number(sal_Int32(nColCount)) + ", got " + + OUString::number(columnIndex) + "."; + throw SQLException(str, *this, OUString(), 1, Any()); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.hxx b/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.hxx new file mode 100644 index 000000000..c2e5db5f3 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.hxx @@ -0,0 +1,103 @@ +/* -*- 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 . + */ + +#pragma once + +#include "mysqlc_connection.hxx" + +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + +#include <cppuhelper/implbase1.hxx> +#include <mysql.h> + +namespace connectivity::mysqlc +{ +using ::com::sun::star::sdbc::SQLException; +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::uno::RuntimeException; + +struct MySqlFieldInfo +{ + OUString columnName; + sal_Int32 length = 0; + sal_Int32 type = 0; + enum_field_types mysql_type = {}; + unsigned charsetNumber = 0; + unsigned flags = 0; + OUString schemaName; + OUString tableName; + OUString catalogName; + sal_Int32 decimals; + sal_Int32 max_length; +}; + +//************ Class: ResultSetMetaData + +typedef ::cppu::WeakImplHelper1<css::sdbc::XResultSetMetaData> OResultSetMetaData_BASE; + +class OResultSetMetaData final : public OResultSetMetaData_BASE +{ +private: + OConnection& m_rConnection; + std::vector<MySqlFieldInfo> m_fields; + + void checkColumnIndex(sal_Int32 columnIndex); + virtual ~OResultSetMetaData() override = default; + +public: + OResultSetMetaData(OConnection& rConn, MYSQL_RES* pResult); + + sal_Int32 SAL_CALL getColumnCount() override; + + sal_Bool SAL_CALL isAutoIncrement(sal_Int32 column) override; + sal_Bool SAL_CALL isCaseSensitive(sal_Int32 column) override; + sal_Bool SAL_CALL isSearchable(sal_Int32 column) override; + sal_Bool SAL_CALL isCurrency(sal_Int32 column) override; + + sal_Int32 SAL_CALL isNullable(sal_Int32 column) override; + + sal_Bool SAL_CALL isSigned(sal_Int32 column) override; + + sal_Int32 SAL_CALL getColumnDisplaySize(sal_Int32 column) override; + + OUString SAL_CALL getColumnLabel(sal_Int32 column) override; + OUString SAL_CALL getColumnName(sal_Int32 column) override; + OUString SAL_CALL getSchemaName(sal_Int32 column) override; + + sal_Int32 SAL_CALL getPrecision(sal_Int32 column) override; + sal_Int32 SAL_CALL getScale(sal_Int32 column) override; + + OUString SAL_CALL getTableName(sal_Int32 column) override; + OUString SAL_CALL getCatalogName(sal_Int32 column) override; + + sal_Int32 SAL_CALL getColumnType(sal_Int32 column) override; + + OUString SAL_CALL getColumnTypeName(sal_Int32 column) override; + + sal_Bool SAL_CALL isReadOnly(sal_Int32 column) override; + sal_Bool SAL_CALL isWritable(sal_Int32 column) override; + sal_Bool SAL_CALL isDefinitelyWritable(sal_Int32 column) override; + + OUString SAL_CALL getColumnServiceName(sal_Int32 column) override; +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_services.cxx b/connectivity/source/drivers/mysqlc/mysqlc_services.cxx new file mode 100644 index 000000000..6e4e2fbb5 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_services.cxx @@ -0,0 +1,110 @@ +/* -*- 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_driver.hxx" + +#include <cppuhelper/factory.hxx> +#include <uno/lbnames.h> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +using namespace connectivity::mysqlc; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::com::sun::star::lang::XSingleServiceFactory; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +typedef Reference<XSingleServiceFactory> (*createFactoryFunc)( + const Reference<XMultiServiceFactory>& rServiceManager, const OUString& rComponentName, + ::cppu::ComponentInstantiation pCreateFunction, const Sequence<OUString>& rServiceNames, + rtl_ModuleCount*); + +namespace +{ +struct ProviderRequest +{ + Reference<XSingleServiceFactory> xRet; + Reference<XMultiServiceFactory> const xServiceManager; + OUString const sImplementationName; + + ProviderRequest(void* pServiceManager, char const* pImplementationName) + : xServiceManager(static_cast<XMultiServiceFactory*>(pServiceManager)) + , sImplementationName(OUString::createFromAscii(pImplementationName)) + { + } + + bool CREATE_PROVIDER(std::u16string_view Implname, const Sequence<OUString>& Services, + ::cppu::ComponentInstantiation Factory, createFactoryFunc creator) + { + if (!xRet.is() && (Implname == sImplementationName)) + { + try + { + xRet = creator(xServiceManager, sImplementationName, Factory, Services, nullptr); + } + catch (...) + { + } + } + return xRet.is(); + } + + void* getProvider() const { return xRet.get(); } +}; +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* component_getFactory(const char* pImplementationName, + void* pServiceManager, + void* /* pRegistryKey */) +{ + void* pRet = nullptr; + if (pServiceManager) + { + ProviderRequest aReq(pServiceManager, pImplementationName); + + aReq.CREATE_PROVIDER(MysqlCDriver::getImplementationName_Static(), + MysqlCDriver::getSupportedServiceNames_Static(), + MysqlCDriver_CreateInstance, ::cppu::createSingleFactory); + + if (aReq.xRet.is()) + { + aReq.xRet->acquire(); + } + + pRet = aReq.getProvider(); + } + + return pRet; +}; + +extern "C" SAL_DLLPUBLIC_EXPORT void +component_getImplementationEnvironment(char const** ppEnvTypeName, uno_Environment**) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_statement.cxx b/connectivity/source/drivers/mysqlc/mysqlc_statement.cxx new file mode 100644 index 000000000..ea3783a95 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_statement.cxx @@ -0,0 +1,390 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include "mysqlc_connection.hxx" +#include "mysqlc_propertyids.hxx" +#include "mysqlc_resultset.hxx" +#include "mysqlc_statement.hxx" +#include "mysqlc_general.hxx" + +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/supportsservice.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; +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 ::osl::MutexGuard; + +OCommonStatement::OCommonStatement(OConnection* _pConnection) + : OCommonStatement_IBase(m_aMutex) + , OPropertySetHelper(OCommonStatement_IBase::rBHelper) + , m_xConnection(_pConnection) +{ +} + +OCommonStatement::~OCommonStatement() {} + +void OCommonStatement::closeResultSet() +{ + if (m_xResultSet.is()) + { + css::uno::Reference<css::sdbc::XCloseable> xClose(m_xResultSet, UNO_QUERY_THROW); + xClose->close(); + m_xResultSet.clear(); + } +} + +void OCommonStatement::disposing() +{ + MutexGuard aGuard(m_aMutex); + + m_xConnection.clear(); + OCommonStatement_IBase::disposing(); +} + +Any SAL_CALL OCommonStatement::queryInterface(const Type& rType) +{ + Any aRet = OCommonStatement_IBase::queryInterface(rType); + if (!aRet.hasValue()) + { + aRet = OPropertySetHelper::queryInterface(rType); + } + return aRet; +} + +Sequence<Type> SAL_CALL OCommonStatement::getTypes() +{ + ::cppu::OTypeCollection aTypes(cppu::UnoType<XMultiPropertySet>::get(), + cppu::UnoType<XFastPropertySet>::get(), + cppu::UnoType<XPropertySet>::get()); + + return concatSequences(aTypes.getTypes(), OCommonStatement_IBase::getTypes()); +} + +Sequence<Type> SAL_CALL OStatement::getTypes() +{ + return concatSequences(OStatement_BASE::getTypes(), OCommonStatement::getTypes()); +} + +void SAL_CALL OCommonStatement::cancel() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + // cancel the current sql statement +} + +void SAL_CALL OCommonStatement::close() +{ + /* + We need a block for the checkDisposed call. + After the check we can call dispose() as we are not under lock ?? + */ + { + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + } + dispose(); + closeResultSet(); +} + +// void SAL_CALL OStatement::clearBatch() +// { +// mysqlc_sdbc_driver::throwFeatureNotImplementedException("com:sun:star:sdbc:XBatchExecution"); +// } + +sal_Bool SAL_CALL OStatement::execute(const OUString& sql) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + closeResultSet(); + m_nAffectedRows = -1; + + OString toExec = OUStringToOString(sql, m_xConnection->getConnectionSettings().encoding); + + MYSQL* pMySql = m_xConnection->getMysqlConnection(); + + // NOTE: differs from MySQL C API, where mysql_real_escape_string_quote() + // should be used. + // toExec = mysqlc_sdbc_driver::escapeSql(toExec); + int failure = mysql_real_query(pMySql, toExec.getStr(), toExec.getLength()); + + if (failure || mysql_errno(pMySql)) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(pMySql), mysql_sqlstate(pMySql), + mysql_errno(pMySql), *this, + m_xConnection->getConnectionEncoding()); + + return getResult(); +} + +Reference<XResultSet> SAL_CALL OStatement::executeQuery(const OUString& sql) +{ + bool isRS(execute(sql)); + // if a MySQL error occurred, it was already thrown and the below is not executed + assert(isRS == m_xResultSet.is()); + if (!isRS) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg( + "executeQuery called on SQL command that does not return a ResultSet", "02000", 0, + *this); + if (!m_xResultSet.is()) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg( + "internal MySQL-SDBC error: executeQuery: no ResultSet after execute() returned true.", + "02000", 0, *this); + + return m_xResultSet; +} + +Reference<XConnection> SAL_CALL OStatement::getConnection() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + // just return our connection here + return m_xConnection; +} + +sal_Int32 SAL_CALL OStatement::getUpdateCount() { return m_nAffectedRows; } + +Any SAL_CALL OStatement::queryInterface(const Type& rType) +{ + Any aRet = OCommonStatement::queryInterface(rType); + if (!aRet.hasValue()) + { + aRet = OStatement_BASE::queryInterface(rType); + } + return aRet; +} + +// void SAL_CALL OStatement::addBatch(const OUString&) +// { +// MutexGuard aGuard(m_aMutex); +// checkDisposed(rBHelper.bDisposed); + +// mysqlc_sdbc_driver::throwFeatureNotImplementedException("com:sun:star:sdbc:XBatchExecution"); +// } + +// Sequence<sal_Int32> SAL_CALL OStatement::executeBatch() +// { +// MutexGuard aGuard(m_aMutex); +// checkDisposed(rBHelper.bDisposed); + +// mysqlc_sdbc_driver::throwFeatureNotImplementedException("com:sun:star:sdbc:XBatchExecution"); +// } + +sal_Int32 SAL_CALL OStatement::executeUpdate(const OUString& sql) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + execute(sql); + return m_nAffectedRows; +} + +Reference<XResultSet> SAL_CALL OStatement::getResultSet() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + return m_xResultSet; +} + +bool OStatement::getResult() +{ + // all callers already reset that + assert(!m_xResultSet.is()); + assert(m_nAffectedRows == -1); + + MYSQL* pMySql = m_xConnection->getMysqlConnection(); + MYSQL_RES* pMysqlResult = mysql_store_result(pMySql); + if (pMysqlResult != nullptr) + { + // MariaDB/MySQL will return the number of rows in the ResultSet from mysql_affected_rows(); + // sdbc mandates -1 when the command (query) returns a ResultSet + assert(m_nAffectedRows == -1); + m_xResultSet = new OResultSet(*getOwnConnection(), this, pMysqlResult, + m_xConnection->getConnectionEncoding()); + return true; + } + else if (mysql_field_count(pMySql) == 0) + { + m_nAffectedRows = mysql_affected_rows(pMySql); + return false; + } + else + { + mysqlc_sdbc_driver::throwSQLExceptionWithMsg( + "mysql_store_result indicated success and SQL command was supposed to return a " + "ResultSet, but did not.", + "02000", 0, *this); + } + //unreachable + assert(false); + // keep -Werror=return-type happy + return false; +} + +sal_Bool SAL_CALL OStatement::getMoreResults() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + closeResultSet(); + m_nAffectedRows = -1; + + MYSQL* pMySql = m_xConnection->getMysqlConnection(); + int status = mysql_next_result(pMySql); + + if (status > 0 || mysql_errno(pMySql)) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(pMySql), mysql_sqlstate(pMySql), + mysql_errno(pMySql), *this, + m_xConnection->getConnectionEncoding()); + + if (status == -1) + return false; + + if (status != 0) + { + const OUString errMsg("mysql_next_result returned unexpected value: " + + OUString::number(status)); + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(errMsg, "02000", 0, *this); + } + + return getResult(); +} + +Any SAL_CALL OCommonStatement::getWarnings() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + return Any(m_aLastWarning); +} + +void SAL_CALL OCommonStatement::clearWarnings() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + m_aLastWarning = SQLWarning(); +} + +::cppu::IPropertyArrayHelper* OCommonStatement::createArrayHelper() const +{ + // this properties are define by the service statement + // they must in alphabetic order + return new ::cppu::OPropertyArrayHelper{ + { { "CursorName", PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0 }, + { "EscapeProcessing", PROPERTY_ID_ESCAPEPROCESSING, cppu::UnoType<bool>::get(), 0 }, + { "FetchDirection", PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0 }, + { "FetchSize", PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0 }, + { "MaxFieldSize", PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0 }, + { "MaxRows", PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0 }, + { "QueryTimeOut", PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0 }, + { "ResultSetConcurrency", PROPERTY_ID_RESULTSETCONCURRENCY, + cppu::UnoType<sal_Int32>::get(), 0 }, + { "ResultSetType", PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0 }, + { "UseBookmarks", PROPERTY_ID_USEBOOKMARKS, cppu::UnoType<bool>::get(), 0 } } + }; +} + +::cppu::IPropertyArrayHelper& OCommonStatement::getInfoHelper() { return *getArrayHelper(); } + +sal_Bool OCommonStatement::convertFastPropertyValue(Any& /* rConvertedValue */, + Any& /* rOldValue */, sal_Int32 /* nHandle */, + const Any& /* rValue */) +{ + // here we have to try to convert + return false; +} + +void OCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& /* rValue */) +{ + // set the value to whatever is necessary + switch (nHandle) + { + case PROPERTY_ID_QUERYTIMEOUT: + case PROPERTY_ID_MAXFIELDSIZE: + case PROPERTY_ID_MAXROWS: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + case PROPERTY_ID_ESCAPEPROCESSING: + case PROPERTY_ID_USEBOOKMARKS: + default:; + } +} + +void OCommonStatement::getFastPropertyValue(Any& _rValue, sal_Int32 nHandle) const +{ + switch (nHandle) + { + case PROPERTY_ID_QUERYTIMEOUT: + case PROPERTY_ID_MAXFIELDSIZE: + case PROPERTY_ID_MAXROWS: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + case PROPERTY_ID_ESCAPEPROCESSING: + break; + case PROPERTY_ID_USEBOOKMARKS: + _rValue <<= false; + break; + default:; + } +} + +OUString OStatement::getImplementationName() { return "com.sun.star.sdbcx.OStatement"; } + +css::uno::Sequence<OUString> OStatement::getSupportedServiceNames() +{ + return { "com.sun.star.sdbc.Statement" }; +} + +sal_Bool OStatement::supportsService(OUString const& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +void SAL_CALL OCommonStatement::acquire() noexcept { OCommonStatement_IBase::acquire(); } + +void SAL_CALL OCommonStatement::release() noexcept { OCommonStatement_IBase::release(); } + +void SAL_CALL OStatement::acquire() noexcept { OCommonStatement::acquire(); } + +void SAL_CALL OStatement::release() noexcept { OCommonStatement::release(); } + +Reference<css::beans::XPropertySetInfo> SAL_CALL OCommonStatement::getPropertySetInfo() +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_statement.hxx b/connectivity/source/drivers/mysqlc/mysqlc_statement.hxx new file mode 100644 index 000000000..464051b72 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_statement.hxx @@ -0,0 +1,175 @@ +/* -*- 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 . + */ + +#pragma once + +#include "mysqlc_connection.hxx" +#include "mysqlc_subcomponent.hxx" + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/sdbc/XBatchExecution.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XMultipleResults.hpp> +#include <com/sun/star/sdbc/XStatement.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/util/XCancellable.hpp> + +#include <cppuhelper/compbase3.hxx> +#include <rtl/ref.hxx> + +namespace connectivity::mysqlc +{ +using ::com::sun::star::sdbc::SQLException; +using ::com::sun::star::sdbc::SQLWarning; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::uno::Type; + +typedef ::cppu::WeakComponentImplHelper3<css::sdbc::XWarningsSupplier, css::util::XCancellable, + css::sdbc::XCloseable> + OCommonStatement_IBase; + +//************ Class: OCommonStatement +// is a base class for the normal statement and for the prepared statement + +class OCommonStatement : public cppu::BaseMutex, + public OCommonStatement_IBase, + public ::cppu::OPropertySetHelper, + public OPropertyArrayUsageHelper<OCommonStatement> + +{ +private: + SQLWarning m_aLastWarning; + +protected: + rtl::Reference<OConnection> m_xConnection; // The owning Connection object + + css::uno::Reference<css::sdbc::XResultSet> m_xResultSet; + + // number of rows affected by an UPDATE, DELETE or INSERT statement. + sal_Int32 m_nAffectedRows = 0; + +protected: + void closeResultSet(); + + // OPropertyArrayUsageHelper + ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + + // OPropertySetHelper + ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + sal_Bool SAL_CALL convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue, + sal_Int32 nHandle, const Any& rValue) override; + + void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) override; + + void SAL_CALL getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const override; + virtual ~OCommonStatement() override; + +protected: + OCommonStatement(OConnection* _pConnection); + +public: + using OCommonStatement_IBase::rBHelper; + using OCommonStatement_IBase::operator css::uno::Reference<css::uno::XInterface>; + + // OComponentHelper + void SAL_CALL disposing() override; + + // XInterface + void SAL_CALL release() noexcept override; + void SAL_CALL acquire() noexcept override; + Any SAL_CALL queryInterface(const css::uno::Type& rType) override; + + //XTypeProvider + css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override; + + // XPropertySet + css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + + // XWarningsSupplier + Any SAL_CALL getWarnings() override; + + void SAL_CALL clearWarnings() override; + + // XCancellable + void SAL_CALL cancel() override; + + // XCloseable + void SAL_CALL close() override; + + // other methods + OConnection* getOwnConnection() const { return m_xConnection.get(); } + +private: + using ::cppu::OPropertySetHelper::getFastPropertyValue; +}; + +typedef ::cppu::ImplHelper3<css::lang::XServiceInfo, css::sdbc::XMultipleResults, + css::sdbc::XStatement> + OStatement_BASE; + +class OStatement final : public OCommonStatement, public OStatement_BASE +{ + virtual ~OStatement() override = default; + + bool getResult(); + +public: + // A constructor which is required for the return of the objects + OStatement(OConnection* _pConnection) + : OCommonStatement(_pConnection) + { + } + + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override; + + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + //XInterface + Any SAL_CALL queryInterface(const css::uno::Type& rType) override; + void SAL_CALL acquire() noexcept override; + void SAL_CALL release() noexcept override; + + //XTypeProvider + css::uno::Sequence<Type> SAL_CALL getTypes() override; + + // XStatement + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL executeQuery(const OUString& sql) override; + sal_Int32 SAL_CALL executeUpdate(const OUString& sql) override; + sal_Bool SAL_CALL execute(const OUString& sql) override; + css::uno::Reference<css::sdbc::XConnection> SAL_CALL getConnection() override; + + // XMultipleResults + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL getResultSet() override; + sal_Int32 SAL_CALL getUpdateCount() override; + sal_Bool SAL_CALL getMoreResults() override; + + // XBatchExecution + // void SAL_CALL addBatch(const OUString& sql) override; + + // void SAL_CALL clearBatch() override; + + // css::uno::Sequence<sal_Int32> SAL_CALL executeBatch() override; +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_subcomponent.hxx b/connectivity/source/drivers/mysqlc/mysqlc_subcomponent.hxx new file mode 100644 index 000000000..edba70a93 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_subcomponent.hxx @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <cppuhelper/propshlp.hxx> +#include <osl/diagnose.h> +#include <osl/mutex.hxx> + +namespace cppu +{ +class IPropertyArrayHelper; +} +namespace com::sun::star::lang +{ +class XComponent; +} + +namespace connectivity::mysqlc +{ +/// @throws css::lang::DisposedException +void checkDisposed(bool _bThrow); + +template <class TYPE> class OPropertyArrayUsageHelper +{ +protected: + static sal_Int32 s_nRefCount; + static ::cppu::IPropertyArrayHelper* s_pProps; + static ::osl::Mutex s_aMutex; + +public: + OPropertyArrayUsageHelper(); + virtual ~OPropertyArrayUsageHelper(); + + /** call this in the getInfoHelper method of your derived class. The method returns the array helper of the + class, which is created if necessary. + */ + ::cppu::IPropertyArrayHelper* getArrayHelper(); + +protected: + /** used to implement the creation of the array helper which is shared amongst all instances of the class. + This method needs to be implemented in derived classes. + <BR> + The method gets called with s_aMutex acquired. + @return a pointer to the newly created array helper. Must not be NULL. + */ + virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const = 0; +}; + +template <class TYPE> sal_Int32 OPropertyArrayUsageHelper<TYPE>::s_nRefCount = 0; + +template <class TYPE> +::cppu::IPropertyArrayHelper* OPropertyArrayUsageHelper<TYPE>::s_pProps = nullptr; + +template <class TYPE>::osl::Mutex OPropertyArrayUsageHelper<TYPE>::s_aMutex; + +template <class TYPE> OPropertyArrayUsageHelper<TYPE>::OPropertyArrayUsageHelper() +{ + ::osl::MutexGuard aGuard(s_aMutex); + ++s_nRefCount; +} + +template <class TYPE> OPropertyArrayUsageHelper<TYPE>::~OPropertyArrayUsageHelper() +{ + ::osl::MutexGuard aGuard(s_aMutex); + OSL_ENSURE(s_nRefCount > 0, "OPropertyArrayUsageHelper::~OPropertyArrayUsageHelper : " + "suspicious call : have a refcount of 0 !"); + if (!--s_nRefCount) + { + delete s_pProps; + s_pProps = nullptr; + } +} + +template <class TYPE>::cppu::IPropertyArrayHelper* OPropertyArrayUsageHelper<TYPE>::getArrayHelper() +{ + OSL_ENSURE( + s_nRefCount, + "OPropertyArrayUsageHelper::getArrayHelper : suspicious call : have a refcount of 0 !"); + if (!s_pProps) + { + ::osl::MutexGuard aGuard(s_aMutex); + if (!s_pProps) + { + s_pProps = createArrayHelper(); + OSL_ENSURE(s_pProps, "OPropertyArrayUsageHelper::getArrayHelper : createArrayHelper " + "returned nonsense !"); + } + } + return s_pProps; +} + +namespace internal +{ +template <class T> void implCopySequence(const T* _pSource, T*& _pDest, sal_Int32 _nSourceLen) +{ + for (sal_Int32 i = 0; i < _nSourceLen; ++i, ++_pSource, ++_pDest) + *_pDest = *_pSource; +} +} + +/// concat two sequences +template <class T> +css::uno::Sequence<T> concatSequences(const css::uno::Sequence<T>& _rLeft, + const css::uno::Sequence<T>& _rRight) +{ + sal_Int32 nLeft(_rLeft.getLength()), nRight(_rRight.getLength()); + const T* pLeft = _rLeft.getConstArray(); + const T* pRight = _rRight.getConstArray(); + + sal_Int32 nReturnLen(nLeft + nRight); + css::uno::Sequence<T> aReturn(nReturnLen); + T* pReturn = aReturn.getArray(); + + internal::implCopySequence(pLeft, pReturn, nLeft); + internal::implCopySequence(pRight, pReturn, nRight); + + return aReturn; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_table.cxx b/connectivity/source/drivers/mysqlc/mysqlc_table.cxx new file mode 100644 index 000000000..13d748099 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_table.cxx @@ -0,0 +1,160 @@ +/* -*- 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/. + */ + +#include "mysqlc_columns.hxx" +#include "mysqlc_indexes.hxx" +#include "mysqlc_keys.hxx" +#include "mysqlc_table.hxx" + +#include <TConnection.hxx> + +#include <comphelper/types.hxx> +#include <connectivity/dbtools.hxx> + +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> + +connectivity::mysqlc::Table::Table( + Tables* pTables, osl::Mutex& rMutex, + const css::uno::Reference<OMetaConnection::XConnection>& rConnection) + : OTableHelper(pTables, rConnection, true) + , m_rMutex(rMutex) + , m_nPrivileges(0) +{ + construct(); +} + +connectivity::mysqlc::Table::Table( + Tables* pTables, osl::Mutex& rMutex, + const css::uno::Reference<OMetaConnection::XConnection>& rConnection, const OUString& rCatalog, + const OUString& rSchema, const OUString& rName, const OUString& rType, + const OUString& rDescription) + : OTableHelper(pTables, rConnection, true, rName, rType, rDescription, rSchema, rCatalog) + , m_rMutex(rMutex) + , m_nPrivileges(0) +{ + construct(); +} + +void connectivity::mysqlc::Table::construct() +{ + OTableHelper::construct(); + if (isNew()) + return; + + // TODO: get privileges when in non-embedded mode. + m_nPrivileges = css::sdbcx::Privilege::DROP | css::sdbcx::Privilege::REFERENCE + | css::sdbcx::Privilege::ALTER | css::sdbcx::Privilege::CREATE + | css::sdbcx::Privilege::READ | css::sdbcx::Privilege::DELETE + | css::sdbcx::Privilege::UPDATE | css::sdbcx::Privilege::INSERT + | css::sdbcx::Privilege::SELECT; + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRIVILEGES), + PROPERTY_ID_PRIVILEGES, css::beans::PropertyAttribute::READONLY, + &m_nPrivileges, cppu::UnoType<decltype(m_nPrivileges)>::get()); +} +//----- OTableHelper --------------------------------------------------------- +connectivity::sdbcx::OCollection* +connectivity::mysqlc::Table::createColumns(const ::std::vector<OUString>& rNames) +{ + return new Columns(*this, m_rMutex, rNames); +} + +connectivity::sdbcx::OCollection* +connectivity::mysqlc::Table::createKeys(const ::std::vector<OUString>& rNames) +{ + return new Keys(this, m_rMutex, rNames); +} + +connectivity::sdbcx::OCollection* +connectivity::mysqlc::Table::createIndexes(const ::std::vector<OUString>& rNames) +{ + return new Indexes(this, m_rMutex, rNames); +} + +//----- XAlterTable ----------------------------------------------------------- +void SAL_CALL connectivity::mysqlc::Table::alterColumnByName( + const OUString& rColName, const css::uno::Reference<XPropertySet>& rDescriptor) +{ + osl::MutexGuard aGuard(m_rMutex); + checkDisposed(WeakComponentImplHelperBase::rBHelper.bDisposed); + + css::uno::Reference<XPropertySet> xColumn(m_xColumns->getByName(rColName), css::uno::UNO_QUERY); + + // sdbcx::Descriptor + const bool bNameChanged + = xColumn->getPropertyValue("Name") != rDescriptor->getPropertyValue("Name"); + // sdbcx::ColumnDescriptor + const bool bTypeChanged + = xColumn->getPropertyValue("Type") != rDescriptor->getPropertyValue("Type"); + const bool bTypeNameChanged = !comphelper::getString(xColumn->getPropertyValue("TypeName")) + .equalsIgnoreAsciiCase(comphelper::getString( + rDescriptor->getPropertyValue("TypeName"))); + const bool bPrecisionChanged + = xColumn->getPropertyValue("Precision") != rDescriptor->getPropertyValue("Precision"); + const bool bScaleChanged + = xColumn->getPropertyValue("Scale") != rDescriptor->getPropertyValue("Scale"); + + const bool bIsNullableChanged + = xColumn->getPropertyValue("IsNullable") != rDescriptor->getPropertyValue("IsNullable"); + + const bool bIsAutoIncrementChanged = xColumn->getPropertyValue("IsAutoIncrement") + != rDescriptor->getPropertyValue("IsAutoIncrement"); + + // there's also DefaultValue but not related to database directly, it seems completely internal to LO + // so no need to test it + // TODO: remainder -- these are all "optional" so have to detect presence and change. + if (bTypeChanged || bTypeNameChanged || bPrecisionChanged || bScaleChanged || bIsNullableChanged + || bIsAutoIncrementChanged) + { + // If bPrecisionChanged this will only succeed if we have increased the + // precision, otherwise an exception is thrown -- however the base + // gui then offers to delete and recreate the column. + OUStringBuffer sSql(300); + sSql.append("ALTER TABLE `" + getTableName() + "` MODIFY COLUMN `" + rColName + "` " + + ::dbtools::createStandardTypePart(rDescriptor, getConnection())); + + if (comphelper::getBOOL(rDescriptor->getPropertyValue("IsAutoIncrement"))) + sSql.append(" auto_increment"); + + // see ColumnValue: NO_NULLS = 0, NULLABLE = 1, NULLABLE_UNKNOWN + // so entry required = yes corresponds to NO_NULLS = 0 and only in this case + // NOT NULL + if (comphelper::getINT32(rDescriptor->getPropertyValue("IsNullable")) == 0) + sSql.append(" NOT NULL"); + + getConnection()->createStatement()->execute(sSql.makeStringAndClear()); + } + + if (bNameChanged) + { + OUString sNewColName; + rDescriptor->getPropertyValue("Name") >>= sNewColName; + OUString sSql("ALTER TABLE `" + getName() + "` RENAME COLUMN `" + rColName + "` TO `" + + sNewColName + "`"); + + getConnection()->createStatement()->execute(sSql); + } + + m_xColumns->refresh(); +} + +void SAL_CALL connectivity::mysqlc::Table::alterColumnByIndex( + sal_Int32 index, const css::uno::Reference<css::beans::XPropertySet>& descriptor) +{ + osl::MutexGuard aGuard(m_rMutex); + css::uno::Reference<XPropertySet> xColumn(m_xColumns->getByIndex(index), + css::uno::UNO_QUERY_THROW); + alterColumnByName(comphelper::getString(xColumn->getPropertyValue( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))), + descriptor); +} + +OUString connectivity::mysqlc::Table::getRenameStart() const { return "RENAME TABLE "; } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_table.hxx b/connectivity/source/drivers/mysqlc/mysqlc_table.hxx new file mode 100644 index 000000000..f17a32687 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_table.hxx @@ -0,0 +1,65 @@ +/* -*- 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/. + */ + +#pragma once + +#include "mysqlc_tables.hxx" + +#include <connectivity/TTableHelper.hxx> + +namespace connectivity::mysqlc +{ +class Table : public OTableHelper +{ +private: + ::osl::Mutex& m_rMutex; + sal_Int32 m_nPrivileges; + +protected: + void construct() override; + +public: + Table(Tables* pTables, ::osl::Mutex& rMutex, + const css::uno::Reference<css::sdbc::XConnection>& _xConnection); + Table(Tables* pTables, ::osl::Mutex& rMutex, + const css::uno::Reference<css::sdbc::XConnection>& _xConnection, const OUString& rCatalog, + const OUString& rSchema, const OUString& rName, const OUString& rType, + const OUString& rDescription); + + // OTableHelper + virtual ::connectivity::sdbcx::OCollection* + createColumns(const ::std::vector<OUString>& rNames) override; + virtual ::connectivity::sdbcx::OCollection* + createKeys(const ::std::vector<OUString>& rNames) override; + virtual ::connectivity::sdbcx::OCollection* + createIndexes(const ::std::vector<OUString>& rNames) override; + + /** Returns always "RENAME TABLE " even for views. + * + * \return The start of the rename statement. + * @see http://dev.mysql.com/doc/refman/5.1/de/rename-table.html + */ + virtual OUString getRenameStart() const override; + + // XAlterTable + /** + * See css::sdbcx::ColumnDescriptor for details of + * rDescriptor. + */ + virtual void SAL_CALL + alterColumnByName(const OUString& rColName, + const css::uno::Reference<css::beans::XPropertySet>& rDescriptor) override; + + virtual void SAL_CALL alterColumnByIndex( + sal_Int32 index, const css::uno::Reference<css::beans::XPropertySet>& descriptor) override; +}; + +} // namespace connectivity::mysqlc + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_tables.cxx b/connectivity/source/drivers/mysqlc/mysqlc_tables.cxx new file mode 100644 index 000000000..81498978d --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_tables.cxx @@ -0,0 +1,157 @@ +/* -*- 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/. + */ + +#include "mysqlc_table.hxx" +#include "mysqlc_tables.hxx" +#include "mysqlc_catalog.hxx" + +#include <TConnection.hxx> + +#include <connectivity/dbtools.hxx> + +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <comphelper/types.hxx> + +//----- OCollection ----------------------------------------------------------- +void connectivity::mysqlc::Tables::impl_refresh() +{ + static_cast<Catalog&>(m_rParent).refreshTables(); +} + +static void lcl_unescape(OUString& rName) +{ + // Remove ending ` if there's one + sal_Int32 nLastIndexBacktick = rName.lastIndexOf("`"); + if ((nLastIndexBacktick > 0) && (nLastIndexBacktick == (rName.getLength() - 1))) + { + rName = rName.copy(0, nLastIndexBacktick); + } + + // Remove beginning ` + nLastIndexBacktick = rName.indexOf("`"); + if (nLastIndexBacktick == 0) + { + rName = rName.copy(1, rName.getLength() - 1); + } + + // Replace double ` by simple ` + rName = rName.replaceAll("``", "`"); +} + +connectivity::sdbcx::ObjectType connectivity::mysqlc::Tables::createObject(const OUString& rName) +{ + OUString sCatalog, sSchema, sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData, rName, sCatalog, sSchema, sTable, + ::dbtools::EComposeRule::InDataManipulation); + + css::uno::Any aCatalog; + if (!sCatalog.isEmpty()) + { + lcl_unescape(sCatalog); + aCatalog <<= sCatalog; + } + + lcl_unescape(sSchema); + lcl_unescape(sTable); + + // Only retrieving a single table, so table type is irrelevant (param 4) + css::uno::Reference<css::sdbc::XResultSet> xTables + = m_xMetaData->getTables(aCatalog, sSchema, sTable, css::uno::Sequence<OUString>()); + + if (!xTables.is()) + throw css::uno::RuntimeException("Could not acquire table."); + + css::uno::Reference<css::sdbc::XRow> xRow(xTables, css::uno::UNO_QUERY_THROW); + + if (!xTables->next()) + throw css::uno::RuntimeException(); + + connectivity::sdbcx::ObjectType xRet( + new Table(this, m_rMutex, m_xMetaData->getConnection(), + xRow->getString(1), // Catalog + xRow->getString(2), // Schema + xRow->getString(3), // Name + xRow->getString(4), // Type + xRow->getString(5))); // Description / Remarks / Comments + + if (xTables->next()) + throw css::uno::RuntimeException("Found more tables than expected."); + + return xRet; +} + +css::uno::Reference<css::beans::XPropertySet> connectivity::mysqlc::Tables::createDescriptor() +{ + // There is some internal magic so that the same class can be used as either + // a descriptor or as a normal table. See VTable.cxx for the details. In our + // case we just need to ensure we use the correct constructor. + return new Table(this, m_rMutex, m_xMetaData->getConnection()); +} + +//----- XAppend --------------------------------------------------------------- +void connectivity::mysqlc::Tables::createTable( + const css::uno::Reference<css::beans::XPropertySet>& descriptor) +{ + const css::uno::Reference<css::sdbc::XConnection> xConnection = m_xMetaData->getConnection(); + OUString aSql = ::dbtools::createSqlCreateTableStatement(descriptor, xConnection); + + css::uno::Reference<css::sdbc::XStatement> xStmt = xConnection->createStatement(); + if (xStmt.is()) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } +} + +// XAppend +connectivity::sdbcx::ObjectType connectivity::mysqlc::Tables::appendObject( + const OUString& _rForName, const css::uno::Reference<css::beans::XPropertySet>& descriptor) +{ + createTable(descriptor); + return createObject(_rForName); +} + +void connectivity::mysqlc::Tables::appendNew(const OUString& _rsNewTable) +{ + insertElement(_rsNewTable, nullptr); + + // notify our container listeners + css::container::ContainerEvent aEvent(static_cast<XContainer*>(this), + css::uno::Any(_rsNewTable), css::uno::Any(), + css::uno::Any()); + comphelper::OInterfaceIteratorHelper3 aListenerLoop(m_aContainerListeners); + while (aListenerLoop.hasMoreElements()) + aListenerLoop.next()->elementInserted(aEvent); +} + +OUString +connectivity::mysqlc::Tables::getNameForObject(const connectivity::sdbcx::ObjectType& _xObject) +{ + OSL_ENSURE(_xObject.is(), "OTables::getNameForObject: Object is NULL!"); + return ::dbtools::composeTableName(m_xMetaData, _xObject, + ::dbtools::EComposeRule::InDataManipulation, false) + .replaceAll(u"`", u"Ì€ `"); +} + +//----- XDrop ----------------------------------------------------------------- +void connectivity::mysqlc::Tables::dropObject(sal_Int32 nPosition, const OUString& sName) +{ + css::uno::Reference<css::beans::XPropertySet> xTable(getObject(nPosition)); + + if (connectivity::sdbcx::ODescriptor::isNew(xTable)) + return; + + OUString sType; + xTable->getPropertyValue("Type") >>= sType; + + m_xMetaData->getConnection()->createStatement()->execute("DROP " + sType + " " + sName); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_tables.hxx b/connectivity/source/drivers/mysqlc/mysqlc_tables.hxx new file mode 100644 index 000000000..2d3c4c745 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_tables.hxx @@ -0,0 +1,56 @@ +/* -*- 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/. + */ + +#pragma once + +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> + +#include <connectivity/sdbcx/VCollection.hxx> + +namespace connectivity::mysqlc +{ +/** +* This implements com.sun.star.sdbcx.Container, which seems to be +* also known by the name of Tables and Collection. +*/ +class Tables : public ::connectivity::sdbcx::OCollection +{ +protected: + css::uno::Reference<css::sdbc::XDatabaseMetaData> m_xMetaData; + + // OCollection + virtual void impl_refresh() override; + virtual ::connectivity::sdbcx::ObjectType createObject(const OUString& rName) override; + virtual css::uno::Reference<css::beans::XPropertySet> createDescriptor() override; + virtual ::connectivity::sdbcx::ObjectType + appendObject(const OUString& rName, + const css::uno::Reference<css::beans::XPropertySet>& rDescriptor) override; + + void createTable(const css::uno::Reference<css::beans::XPropertySet>& descriptor); + virtual OUString getNameForObject(const sdbcx::ObjectType& _xObject) override; + // XDrop + virtual void dropObject(sal_Int32 nPosition, const OUString& rName) override; + +public: + Tables(const css::uno::Reference<css::sdbc::XDatabaseMetaData>& rMetaData, + ::cppu::OWeakObject& rParent, ::osl::Mutex& rMutex, + ::std::vector<OUString> const& rNames) + : sdbcx::OCollection(rParent, true, rMutex, rNames) + , m_xMetaData(rMetaData) + { + } + + void appendNew(const OUString& _rsNewTable); + // TODO: should we also implement XDataDescriptorFactory, XRefreshable, + // XAppend, etc. ? +}; + +} // namespace connectivity::mysqlc + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_types.cxx b/connectivity/source/drivers/mysqlc/mysqlc_types.cxx new file mode 100644 index 000000000..ca473cebd --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_types.cxx @@ -0,0 +1,700 @@ +/* -*- 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 <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/ColumnSearch.hpp> +#include "mysqlc_types.hxx" + +using namespace com::sun::star::sdbc; + +TypeInfoDef const mysqlc_types[] = { + + // ------------- MySQL-Type: BIT. SDBC-Type: Bit ------------- + { + "BIT", // Typename + com::sun::star::sdbc::DataType::BIT, // sdbc-type + 1, // Precision + "", // Literal prefix + "", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + true, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "BIT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ------------ MySQL-Type: BOOL. SDBC-Type: Bit ------------- + { + "BOOL", // Typename + com::sun::star::sdbc::DataType::BIT, // sdbc-type + 1, // Precision + "", // Literal prefix + "", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + true, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "BOOL", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // --------- MySQL-Type: TINYINT SDBC-Type: TINYINT ---------- + { + "TINYINT", // Typename + com::sun::star::sdbc::DataType::TINYINT, // sdbc-type + 3, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M)] [UNSIGNED] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + true, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "TINYINT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: BIGINT SDBC-Type: BIGINT ---------- + { + "BIGINT", // Typename + com::sun::star::sdbc::DataType::BIGINT, // sdbc-type + 19, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M)] [UNSIGNED] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + true, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "BIGINT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: LONG VARBINARY SDBC-Type: LONGVARBINARY ---------- + { + "LONG VARBINARY", // Typename + com::sun::star::sdbc::DataType::LONGVARBINARY, // sdbc-type + 16777215, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + true, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "LONG VARBINARY", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: MEDIUMBLOB SDBC-Type: LONGVARBINARY ---------- + { + "MEDIUMBLOB", // Typename + com::sun::star::sdbc::DataType::LONGVARBINARY, // sdbc-type + 16777215, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + true, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "MEDIUMBLOB", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: LONGBLOB SDBC-Type: LONGVARBINARY ---------- + { + "LONGBLOB", // Typename + com::sun::star::sdbc::DataType::LONGVARBINARY, // sdbc-type + -1, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + true, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "LONGBLOB", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: BLOB SDBC-Type: LONGVARBINARY ---------- + { + "BLOB", // Typename + com::sun::star::sdbc::DataType::LONGVARBINARY, // sdbc-type + 0xFFFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + true, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "BLOB", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: TINYBLOB SDBC-Type: LONGVARBINARY ---------- + { + "TINYBLOB", // Typename + com::sun::star::sdbc::DataType::LONGVARBINARY, // sdbc-type + 0xFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + true, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "TINYBLOB", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: VARBINARY SDBC-Type: VARBINARY ---------- + { + "VARBINARY", // Typename + com::sun::star::sdbc::DataType::VARBINARY, // sdbc-type + 0xFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "(M)", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + true, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "VARBINARY", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: BINARY SDBC-Type: BINARY ---------- + { + "BINARY", // Typename + com::sun::star::sdbc::DataType::BINARY, // sdbc-type + 0xFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "(M)", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + true, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "VARBINARY", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: LONG VARCHAR SDBC-Type: LONG VARCHAR ---------- + { + "LONG VARCHAR", // Typename + com::sun::star::sdbc::DataType::LONGVARCHAR, // sdbc-type + 0xFFFFFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "LONG VARCHAR", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: MEDIUMTEXT SDBC-Type: LONG VARCHAR ---------- + { + "MEDIUMTEXT", // Typename + com::sun::star::sdbc::DataType::LONGVARCHAR, // sdbc-type + 0xFFFFFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "MEDIUMTEXT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: LONGTEXT SDBC-Type: LONG VARCHAR ---------- + { + "LONGTEXT", // Typename + com::sun::star::sdbc::DataType::LONGVARCHAR, // sdbc-type + 0xFFFFFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "LONGTEXT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: TEXT SDBC-Type: LONG VARCHAR ---------- + { + "TEXT", // Typename + com::sun::star::sdbc::DataType::LONGVARCHAR, // sdbc-type + 0xFFFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "TEXT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: TINYTEXT SDBC-Type: LONG VARCHAR ---------- + { + "TINYTEXT", // Typename + com::sun::star::sdbc::DataType::LONGVARCHAR, // sdbc-type + 0xFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "TINYTEXT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: CHAR SDBC-Type: CHAR ---------- + { + "CHAR", // Typename + com::sun::star::sdbc::DataType::CHAR, // sdbc-type + 0xFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "(M)", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "NUMERIC", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: DECIMAL SDBC-Type: DECIMAL ---------- + { + "DECIMAL", // Typename + com::sun::star::sdbc::DataType::DECIMAL, // sdbc-type + 17, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M[,D])] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "DECIMAL", // local type name + -308, // minimum scale + 308 // maximum scale + }, + + // ----------- MySQL-Type: NUMERIC SDBC-Type: NUMERIC ---------- + { + "NUMERIC", // Typename + com::sun::star::sdbc::DataType::NUMERIC, // sdbc-type + 17, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M[,D])] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "NUMERIC", // local type name + -308, // minimum scale + 308 // maximum scale + }, + + // ----------- MySQL-Type: INTEGER SDBC-Type: INTEGER ---------- + { + "INTEGER", // Typename + com::sun::star::sdbc::DataType::INTEGER, // sdbc-type + 10, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M)] [UNSIGNED] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + true, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "INTEGER", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: INT SDBC-Type: INTEGER ---------- + { + "INT", // Typename + com::sun::star::sdbc::DataType::INTEGER, // sdbc-type + 10, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M)] [UNSIGNED] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + true, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "INT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: MEDIUMINT SDBC-Type: INTEGER ---------- + { + "MEDIUMINT", // Typename + com::sun::star::sdbc::DataType::INTEGER, // sdbc-type + 7, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M)] [UNSIGNED] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + true, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "MEDIUMINT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: SMALLINT SDBC-Type: INTEGER ---------- + { + "SMALLINT", // Typename + com::sun::star::sdbc::DataType::SMALLINT, // sdbc-type + 5, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M)] [UNSIGNED] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + true, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "SMALLINT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: FLOAT SDBC-Type: REAL ---------- + { + "FLOAT", // Typename + com::sun::star::sdbc::DataType::REAL, // sdbc-type + 10, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M,D)] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "FLOAT", // local type name + -38, // minimum scale + 38 // maximum scale + }, + + // ----------- MySQL-Type: DOUBLE SDBC-Type: DOUBLE ---------- + { + "DOUBLE", // Typename + com::sun::star::sdbc::DataType::DOUBLE, // sdbc-type + 17, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M,D)] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "DOUBLE", // local type name + -308, // minimum scale + 308 // maximum scale + }, + + // ----------- MySQL-Type: DOUBLE PRECISION SDBC-Type: DOUBLE ---------- + { + "DOUBLE PRECISION", // Typename + com::sun::star::sdbc::DataType::DOUBLE, // sdbc-type + 17, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M,D)] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "DOUBLE PRECISION", // local type name + -308, // minimum scale + 308 // maximum scale + }, + + // ----------- MySQL-Type: REAL SDBC-Type: DOUBLE ---------- + { + "REAL", // Typename + com::sun::star::sdbc::DataType::DOUBLE, // sdbc-type + 17, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M,D)] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "REAL", // local type name + -308, // minimum scale + 308 // maximum scale + }, + + // ----------- MySQL-Type: VARCHAR SDBC-Type: VARCHAR ---------- + { + "VARCHAR", // Typename + com::sun::star::sdbc::DataType::VARCHAR, // sdbc-type + 255, // Precision + "'", // Literal prefix + "'", // Literal suffix + "(M)", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "VARCHAR", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: ENUM SDBC-Type: VARCHAR ---------- + { + "ENUM", // Typename + com::sun::star::sdbc::DataType::VARCHAR, // sdbc-type + 0xFFFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "ENUM", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: SET SDBC-Type: VARCHAR ---------- + { + "SET", // Typename + com::sun::star::sdbc::DataType::VARCHAR, // sdbc-type + 64, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "SET", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: DATE SDBC-Type: DATE ---------- + { + "DATE", // Typename + com::sun::star::sdbc::DataType::DATE, // sdbc-type + 0, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "DATE", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: TIME SDBC-Type: TIME ---------- + { + "TIME", // Typename + com::sun::star::sdbc::DataType::TIME, // sdbc-type + 0, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "TIME", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: DATETIME SDBC-Type: TIMESTAMP ---------- + { + "DATETIME", // Typename + com::sun::star::sdbc::DataType::TIMESTAMP, // sdbc-type + 0, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "DATETIME", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: TIMESTAMP SDBC-Type: TIMESTAMP ---------- + { + "TIMESTAMP", // Typename + com::sun::star::sdbc::DataType::TIMESTAMP, // sdbc-type + 0, // Precision + "'", // Literal prefix + "'", // Literal suffix + "[(M)]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "TIMESTAMP", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: TIMESTAMP SDBC-Type: TIMESTAMP ---------- + + // ----------- MySQL-Type: YEAR SDBC-Type: INTEGER ---------- + { + "YEAR", // Typename + com::sun::star::sdbc::DataType::SMALLINT, // sdbc-type + 10, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M)] [UNSIGNED] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + true, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "YEAR", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: YEAR SDBC-Type: INTEGER ---------- + { nullptr, 0, 0, nullptr, nullptr, nullptr, 0, false, 0, false, false, false, nullptr, 0, 0 } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_types.hxx b/connectivity/source/drivers/mysqlc/mysqlc_types.hxx new file mode 100644 index 000000000..9f2db7715 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_types.hxx @@ -0,0 +1,45 @@ +/* -*- 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 . + */ + +#pragma once + +#include <sal/types.h> + +struct TypeInfoDef +{ + const char* typeName; + sal_Int32 dataType; + sal_Int32 precision; + const char* literalPrefix; + const char* literalSuffix; + const char* createParams; + sal_Int16 nullable; + bool caseSensitive; + sal_Int16 searchable; + bool isUnsigned; + bool fixedPrecScale; + bool autoIncrement; + const char* localTypeName; + sal_Int32 minScale; + sal_Int32 maxScale; +}; + +extern TypeInfoDef const mysqlc_types[]; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_user.cxx b/connectivity/source/drivers/mysqlc/mysqlc_user.cxx new file mode 100644 index 000000000..65470be59 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_user.cxx @@ -0,0 +1,55 @@ +/* -*- 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/. + */ + +#include "mysqlc_user.hxx" + +using namespace ::connectivity; +using namespace ::connectivity::mysqlc; +using namespace ::connectivity::sdbcx; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::sdbc; + +User::User(const css::uno::Reference<css::sdbc::XConnection>& rConnection) + : OUser(true) // Case Sensitive + , m_xConnection(rConnection) +{ +} + +User::User(const css::uno::Reference<css::sdbc::XConnection>& rConnection, const OUString& rName) + : OUser(rName, + true) // Case Sensitive + , m_xConnection(rConnection) +{ +} + +void User::changePassword(const OUString&, const OUString& /* newPassword */) +{ + // TODO: implement +} + +sal_Int32 User::getPrivileges(const OUString&, sal_Int32) +{ + // TODO: implement. + return 0; +} + +sal_Int32 User::getGrantablePrivileges(const OUString&, sal_Int32) +{ + // TODO: implement. + return 0; +} + +//----- IRefreshableGroups ---------------------------------------------------- +void User::refreshGroups() +{ + // TODO: implement. +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_user.hxx b/connectivity/source/drivers/mysqlc/mysqlc_user.hxx new file mode 100644 index 000000000..e9e37e3fa --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_user.hxx @@ -0,0 +1,45 @@ +/* -*- 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/. + */ + +#pragma once + +#include <sdbcx/VUser.hxx> +#include <com/sun/star/sdbc/XConnection.hpp> + +namespace connectivity::mysqlc +{ +/** +* This implements com.sun.star.sdbcx.Container. +*/ +class User : public ::connectivity::sdbcx::OUser +{ + css::uno::Reference<css::sdbc::XConnection> m_xConnection; + +public: + /** + * Create a "new" descriptor, which isn't yet in the database. + */ + User(const css::uno::Reference<css::sdbc::XConnection>& rConnection); + /** + * For a user that already exists in the db. + */ + User(const css::uno::Reference<css::sdbc::XConnection>& rConnection, const OUString& rName); + + // XAuthorizable + virtual void SAL_CALL changePassword(const OUString&, const OUString& newPassword) override; + virtual sal_Int32 SAL_CALL getPrivileges(const OUString&, sal_Int32) override; + virtual sal_Int32 SAL_CALL getGrantablePrivileges(const OUString&, sal_Int32) override; + + // IRefreshableGroups:: + virtual void refreshGroups() override; +}; + +} // namespace connectivity::mysqlc + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_view.cxx b/connectivity/source/drivers/mysqlc/mysqlc_view.cxx new file mode 100644 index 000000000..86837381d --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_view.cxx @@ -0,0 +1,98 @@ +/* -*- 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_view.hxx" + +#include <propertyids.hxx> + +#include <com/sun/star/sdbc/XRow.hpp> + +namespace connectivity::mysqlc +{ +View::View(const css::uno::Reference<css::sdbc::XConnection>& _rxConnection, bool _bCaseSensitive, + const OUString& _rSchemaName, const OUString& _rName) + : View_Base(_bCaseSensitive, _rName, _rxConnection->getMetaData(), OUString(), _rSchemaName, + OUString()) + , m_xConnection(_rxConnection) +{ +} + +View::~View() {} + +void SAL_CALL View::acquire() noexcept { View_Base::acquire(); }; +void SAL_CALL View::release() noexcept { View_Base::release(); }; +css::uno::Any SAL_CALL View::queryInterface(const css::uno::Type& _rType) +{ + css::uno::Any aReturn = View_Base::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = View_IBASE::queryInterface(_rType); + return aReturn; +} + +css::uno::Sequence<css::uno::Type> SAL_CALL View::getTypes() +{ + return ::comphelper::concatSequences(View_Base::getTypes(), View_IBASE::getTypes()); +} + +css::uno::Sequence<sal_Int8> SAL_CALL View::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +void SAL_CALL View::alterCommand(const OUString& _rNewCommand) +{ + OUString aCommand = "ALTER VIEW " + m_SchemaName + "." + m_Name + " AS " + _rNewCommand; + m_xMetaData->getConnection()->createStatement()->execute(aCommand); +} + +void SAL_CALL View::getFastPropertyValue(css::uno::Any& _rValue, sal_Int32 _nHandle) const +{ + if (_nHandle == PROPERTY_ID_COMMAND) + { + // retrieve the very current command, don't rely on the base classes cached value + // (which we initialized empty, anyway) + _rValue <<= impl_getCommand(); + return; + } + + View_Base::getFastPropertyValue(_rValue, _nHandle); +} + +OUString View::impl_getCommand() const +{ + OUString aCommand("SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA = '" + + m_SchemaName + "' AND TABLE_NAME = '" + m_Name + "'"); + //::utl::SharedUNOComponent< XStatement > xStatement; xStatement.set( m_xConnection->createStatement(), UNO_QUERY_THROW ); + css::uno::Reference<css::sdbc::XResultSet> xResult( + m_xMetaData->getConnection()->createStatement()->executeQuery(aCommand), + css::uno::UNO_SET_THROW); + if (!xResult->next()) + { + // hmm. There is no view the name as we know it. Can only mean some other instance + // dropped this view meanwhile... + std::abort(); + } + + css::uno::Reference<css::sdbc::XRow> xRow(xResult, css::uno::UNO_QUERY_THROW); + return xRow->getString(1); +} + +} // namespace connectivity::mysqlc + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_view.hxx b/connectivity/source/drivers/mysqlc/mysqlc_view.hxx new file mode 100644 index 000000000..845015249 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_view.hxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <connectivity/sdbcx/VView.hxx> + +#include <com/sun/star/sdbcx/XAlterView.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> + +#include <comphelper/sequence.hxx> +#include <cppuhelper/implbase1.hxx> + +namespace connectivity::mysqlc +{ +typedef ::connectivity::sdbcx::OView View_Base; +typedef ::cppu::ImplHelper1<css::sdbcx::XAlterView> View_IBASE; + +class View : public View_Base, public View_IBASE +{ +public: + View(const css::uno::Reference<css::sdbc::XConnection>& _rxConnection, bool _bCaseSensitive, + const OUString& _rSchemaName, const OUString& _rName); + + // UNO + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& aType) override; + virtual void SAL_CALL acquire() noexcept override; + virtual void SAL_CALL release() noexcept override; + + virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override; + virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override; + + // XAlterView + virtual void SAL_CALL alterCommand(const OUString& NewCommand) override; + +protected: + virtual ~View() override; + +protected: + // OPropertyContainer + virtual void SAL_CALL getFastPropertyValue(css::uno::Any& _rValue, + sal_Int32 _nHandle) const override; + +private: + /** retrieves the current command of the View */ + OUString impl_getCommand() const; + +private: + css::uno::Reference<css::sdbc::XConnection> m_xConnection; + + using View_Base::getFastPropertyValue; +}; + +} // namespace connectivity::mysqlc + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_views.cxx b/connectivity/source/drivers/mysqlc/mysqlc_views.cxx new file mode 100644 index 000000000..1c79c9225 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_views.cxx @@ -0,0 +1,113 @@ +/* -*- 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_tables.hxx" +#include "mysqlc_views.hxx" +#include "mysqlc_view.hxx" +#include "mysqlc_catalog.hxx" +#include <connectivity/dbtools.hxx> +#include <comphelper/types.hxx> +#include <TConnection.hxx> + +connectivity::mysqlc::Views::Views(const css::uno::Reference<css::sdbc::XConnection>& _rxConnection, + ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector<OUString>& _rVector) + : sdbcx::OCollection(_rParent, true, _rMutex, _rVector) + , m_xConnection(_rxConnection) + , m_xMetaData(_rxConnection->getMetaData()) +{ +} + +connectivity::sdbcx::ObjectType connectivity::mysqlc::Views::createObject(const OUString& _rName) +{ + OUString sCatalog, sSchema, sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData, _rName, sCatalog, sSchema, sTable, + ::dbtools::EComposeRule::InDataManipulation); + return new View(m_xConnection, isCaseSensitive(), sSchema, sTable); +} + +void connectivity::mysqlc::Views::impl_refresh() +{ + static_cast<Catalog&>(m_rParent).refreshViews(); +} + +css::uno::Reference<css::beans::XPropertySet> connectivity::mysqlc::Views::createDescriptor() +{ + return new connectivity::sdbcx::OView(true, m_xMetaData); +} + +// XAppend +connectivity::sdbcx::ObjectType connectivity::mysqlc::Views::appendObject( + const OUString& _rForName, const css::uno::Reference<css::beans::XPropertySet>& descriptor) +{ + createView(descriptor); + return createObject(_rForName); +} + +// XDrop +void connectivity::mysqlc::Views::dropObject(sal_Int32 _nPos, const OUString& /*_sElementName*/) +{ + css::uno::Reference<XInterface> xObject(getObject(_nPos)); + bool bIsNew = connectivity::sdbcx::ODescriptor::isNew(xObject); + if (!bIsNew) + { + OUString aSql("DROP VIEW"); + + css::uno::Reference<css::beans::XPropertySet> xProp(xObject, css::uno::UNO_QUERY); + aSql += ::dbtools::composeTableName(m_xMetaData, xProp, + ::dbtools::EComposeRule::InTableDefinitions, true); + + css::uno::Reference<css::sdbc::XConnection> xConnection = m_xMetaData->getConnection(); + css::uno::Reference<css::sdbc::XStatement> xStmt = xConnection->createStatement(); + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } +} + +void connectivity::mysqlc::Views::createView( + const css::uno::Reference<css::beans::XPropertySet>& descriptor) +{ + css::uno::Reference<css::sdbc::XConnection> xConnection = m_xMetaData->getConnection(); + + OUString sCommand; + descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_COMMAND)) + >>= sCommand; + + OUString aSql = "CREATE VIEW " + + ::dbtools::composeTableName(m_xMetaData, descriptor, + ::dbtools::EComposeRule::InTableDefinitions, true) + + " AS " + sCommand; + + css::uno::Reference<css::sdbc::XStatement> xStmt = xConnection->createStatement(); + if (xStmt.is()) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } + connectivity::mysqlc::Tables* pTables = static_cast<connectivity::mysqlc::Tables*>( + static_cast<connectivity::mysqlc::Catalog&>(m_rParent).getPrivateTables()); + if (pTables) + { + OUString sName = ::dbtools::composeTableName( + m_xMetaData, descriptor, ::dbtools::EComposeRule::InDataManipulation, false); + pTables->appendNew(sName); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_views.hxx b/connectivity/source/drivers/mysqlc/mysqlc_views.hxx new file mode 100644 index 000000000..14570fc8d --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_views.hxx @@ -0,0 +1,50 @@ +/* -*- 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 . + */ +#pragma once + +#include <connectivity/sdbcx/VCollection.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +namespace connectivity::mysqlc +{ +class Views final : public connectivity::sdbcx::OCollection +{ + css::uno::Reference<css::sdbc::XConnection> m_xConnection; + css::uno::Reference<css::sdbc::XDatabaseMetaData> m_xMetaData; + + // OCollection + virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + virtual css::uno::Reference<css::beans::XPropertySet> createDescriptor() override; + virtual sdbcx::ObjectType + appendObject(const OUString& _rForName, + const css::uno::Reference<css::beans::XPropertySet>& descriptor) override; + + void createView(const css::uno::Reference<css::beans::XPropertySet>& descriptor); + +public: + Views(const css::uno::Reference<css::sdbc::XConnection>& _rxConnection, + ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector<OUString>& _rVector); + + // XDrop + virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override; +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |