388 lines
12 KiB
C++
388 lines
12 KiB
C++
/* -*- 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::container;
|
|
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())
|
|
{
|
|
m_xResultSet->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(
|
|
u"executeQuery called on SQL command that does not return a ResultSet"_ustr, "02000", 0,
|
|
*this);
|
|
if (!m_xResultSet.is())
|
|
mysqlc_sdbc_driver::throwSQLExceptionWithMsg(
|
|
u"internal MySQL-SDBC error: executeQuery: no ResultSet after execute() returned true."_ustr,
|
|
"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(
|
|
u"mysql_store_result indicated success and SQL command was supposed to return a "
|
|
"ResultSet, but did not."_ustr,
|
|
"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{
|
|
{ { u"CursorName"_ustr, PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0 },
|
|
{ u"EscapeProcessing"_ustr, PROPERTY_ID_ESCAPEPROCESSING, cppu::UnoType<bool>::get(), 0 },
|
|
{ u"FetchDirection"_ustr, PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(),
|
|
0 },
|
|
{ u"FetchSize"_ustr, PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0 },
|
|
{ u"MaxFieldSize"_ustr, PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0 },
|
|
{ u"MaxRows"_ustr, PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0 },
|
|
{ u"QueryTimeOut"_ustr, PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0 },
|
|
{ u"ResultSetConcurrency"_ustr, PROPERTY_ID_RESULTSETCONCURRENCY,
|
|
cppu::UnoType<sal_Int32>::get(), 0 },
|
|
{ u"ResultSetType"_ustr, PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0 },
|
|
{ u"UseBookmarks"_ustr, 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 u"com.sun.star.sdbcx.OStatement"_ustr; }
|
|
|
|
css::uno::Sequence<OUString> OStatement::getSupportedServiceNames()
|
|
{
|
|
return { u"com.sun.star.sdbc.Statement"_ustr };
|
|
}
|
|
|
|
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: */
|