/* -*- 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/odbc.hxx>
#include <odbc/odbcbasedllapi.hxx>
#include <com/sun/star/sdbc/SQLException.hpp>
#include <com/sun/star/util/Date.hpp>
#include <com/sun/star/util/Time.hpp>
#include <com/sun/star/util/DateTime.hpp>
#include <o3tl/safeint.hxx>
#include <o3tl/string_view.hxx>
#include <osl/thread.h>
#include <rtl/ustring.hxx>
#include <com/sun/star/uno/Sequence.hxx>
#include <rtl/textenc.h>
enum class ODBC3SQLFunctionId
{
FIRST,
AllocHandle,
DriverConnect,
DriverConnectW,
GetInfo,
GetInfoW,
GetFunctions,
GetTypeInfo,
SetConnectAttr,
SetConnectAttrW,
GetConnectAttr,
GetConnectAttrW,
SetEnvAttr,
GetEnvAttr,
SetStmtAttr,
GetStmtAttr,
Prepare,
PrepareW,
BindParameter,
SetCursorName,
SetCursorNameW,
Execute,
ExecDirect,
ExecDirectW,
DescribeParam,
NumParams,
ParamData,
PutData,
RowCount,
NumResultCols,
ColAttribute,
ColAttributeW,
BindCol,
Fetch,
FetchScroll,
GetData,
SetPos,
BulkOperations,
MoreResults,
GetDiagRec,
GetDiagRecW,
ColumnPrivileges,
ColumnPrivilegesW,
Columns,
ColumnsW,
ForeignKeys,
ForeignKeysW,
PrimaryKeys,
PrimaryKeysW,
ProcedureColumns,
ProcedureColumnsW,
Procedures,
ProceduresW,
SpecialColumns,
SpecialColumnsW,
Statistics,
StatisticsW,
TablePrivileges,
TablePrivilegesW,
Tables,
TablesW,
FreeStmt,
CloseCursor,
Cancel,
EndTran,
Disconnect,
FreeHandle,
GetCursorName,
GetCursorNameW,
NativeSql,
NativeSqlW,
LAST
};
namespace connectivity::odbc
{
class OConnection;
const sal_Int32 MAX_PUT_DATA_LENGTH = 2000;
class OOO_DLLPUBLIC_ODBCBASE OTools
{
public:
/// @throws css::sdbc::SQLException
static void ThrowException( const OConnection* _pConnection,
SQLRETURN _rRetCode,
SQLHANDLE _pContext,
SQLSMALLINT _nHandleType,
const css::uno::Reference< css::uno::XInterface >& _xInterface,
bool _bNoFound=true);
/// @throws css::sdbc::SQLException
/// @throws css::uno::RuntimeException
static void GetInfo(OConnection const * _pConnection,
SQLHANDLE _aConnectionHandle,
SQLUSMALLINT _nInfo,
OUString &_rValue,
const css::uno::Reference< css::uno::XInterface >& _xInterface,
rtl_TextEncoding _nTextEncoding);
/// @throws css::sdbc::SQLException
/// @throws css::uno::RuntimeException
static void GetInfo(OConnection const * _pConnection,
SQLHANDLE _aConnectionHandle,
SQLUSMALLINT _nInfo,
sal_Int32 &_rValue,
const css::uno::Reference< css::uno::XInterface >& _xInterface);
/// @throws css::sdbc::SQLException
/// @throws css::uno::RuntimeException
static void GetInfo(OConnection const * _pConnection,
SQLHANDLE _aConnectionHandle,
SQLUSMALLINT _nInfo,
SQLUSMALLINT &_rValue,
const css::uno::Reference< css::uno::XInterface >& _xInterface);
/// @throws css::sdbc::SQLException
/// @throws css::uno::RuntimeException
static void GetInfo(OConnection const * _pConnection,
SQLHANDLE _aConnectionHandle,
SQLUSMALLINT _nInfo,
SQLUINTEGER &_rValue,
const css::uno::Reference< css::uno::XInterface >& _xInterface);
static sal_Int32 MapOdbcType2Jdbc(SQLSMALLINT _nType);
static SQLSMALLINT jdbcTypeToOdbc(sal_Int32 jdbcType);
static DATE_STRUCT DateToOdbcDate(const css::util::Date& x)
{
DATE_STRUCT aVal;
aVal.year = x.Year;
aVal.month = x.Month;
aVal.day = x.Day;
return aVal;
}
static TIME_STRUCT TimeToOdbcTime(const css::util::Time& x)
{
TIME_STRUCT aVal;
aVal.hour = x.Hours;
aVal.minute = x.Minutes;
aVal.second = x.Seconds;
return aVal;
}
static TIMESTAMP_STRUCT DateTimeToTimestamp(const css::util::DateTime& x)
{
TIMESTAMP_STRUCT aVal;
aVal.year = x.Year;
aVal.month = x.Month;
aVal.day = x.Day;
aVal.hour = x.Hours;
aVal.minute = x.Minutes;
aVal.second = x.Seconds;
aVal.fraction = x.NanoSeconds;
return aVal;
}
/**
getBindTypes set the ODBC type for C
@param _bUseOldTimeDate true when the old datetime format should be used
@param _nOdbcType the ODBC sql type
@param fCType the C type for the ODBC type
@param fSqlType the SQL type for the ODBC type
*/
static void getBindTypes(bool _bUseOldTimeDate,
SQLSMALLINT _nOdbcType,
SQLSMALLINT& fCType,
SQLSMALLINT& fSqlType);
/// @throws css::sdbc::SQLException
/// @throws css::uno::RuntimeException
static OUString getStringValue( OConnection const * _pConnection,
SQLHANDLE _aStatementHandle,
sal_Int32 columnIndex,
SQLSMALLINT _fSqlType,
bool &_bWasNull,
const css::uno::Reference< css::uno::XInterface >& _xInterface,
rtl_TextEncoding _nTextEncoding);
/// @throws css::sdbc::SQLException
/// @throws css::uno::RuntimeException
static css::uno::Sequence<sal_Int8> getBytesValue(const OConnection* _pConnection,
SQLHANDLE _aStatementHandle,
sal_Int32 columnIndex,
SQLSMALLINT _fSqlType,
bool &_bWasNull,
const css::uno::Reference< css::uno::XInterface >& _xInterface);
/// @throws css::sdbc::SQLException
/// @throws css::uno::RuntimeException
static void getValue( OConnection const * _pConnection,
SQLHANDLE _aStatementHandle,
sal_Int32 columnIndex,
SQLSMALLINT _nType,
bool &_bWasNull,
const css::uno::Reference< css::uno::XInterface >& _xInterface,
void* _pValue,
SQLLEN _nSize);
};
/// @throws css::sdbc::SQLException
/// @throws css::uno::RuntimeException
template <class T> void getValue( const OConnection* _pConnection,
SQLHANDLE _aStatementHandle,
sal_Int32 columnIndex,
SQLSMALLINT _nType,
bool &_bWasNull,
const css::uno::Reference< css::uno::XInterface >& _xInterface,
T& _rValue)
{
OTools::getValue(_pConnection,_aStatementHandle,columnIndex,_nType,_bWasNull,_xInterface,&_rValue,sizeof _rValue);
}
// Keep const_ and reinterpret_cast required to convert strings in one place
inline OUString toUString(const SQLCHAR* str, sal_Int32 len, rtl_TextEncoding enc)
{
return OUString(reinterpret_cast<const char*>(str), len, enc);
}
inline OUString toUString(const SQLCHAR* str)
{
return OUString::createFromAscii(reinterpret_cast<const char*>(str));
}
inline OUString toUString(const SQLWCHAR* str, sal_Int32 len)
{
static_assert(sizeof(SQLWCHAR) == sizeof(sal_Unicode) || sizeof(SQLWCHAR) == sizeof(sal_uInt32));
if constexpr (sizeof(SQLWCHAR) == sizeof(sal_Unicode))
return OUString(reinterpret_cast<const sal_Unicode*>(str), len);
else
{
auto* codepoints = reinterpret_cast<const sal_uInt32*>(str);
return OUString(codepoints, len);
}
}
// A templated class to encapsulate conversion from our string types into arrays of
// SQLCHAR / SQLWCHAR (non-const, even if used as input values, and not modified),
// that ODBC functions take. It owns its buffer (important for delayed reads/writes)
template <typename C, size_t CHAR_SIZE = sizeof(C)> class CHARS {};
template <size_t CHAR_SIZE> class SIZED
{
public:
SQLSMALLINT cch() const { return m_len; } // count of characters
bool empty() const { return m_len == 0; }
SQLSMALLINT cb() const { return m_len * CHAR_SIZE; } // count of bytes
protected:
SQLSMALLINT m_len = 0;
};
template <typename C> class CHARS<C, sizeof(char)> : public SIZED<sizeof(char)>
{
public:
CHARS() = default;
CHARS(std::u16string_view str, rtl_TextEncoding encoding)
: CHARS(OUStringToOString(str, encoding))
{
}
CHARS(const OString& str)
: m_string(str)
{
m_len = std::min(m_string.getLength(), sal_Int32(std::numeric_limits<SQLSMALLINT>::max()));
}
C* get() { return reinterpret_cast<C*>(const_cast<char*>(m_string.getStr())); }
private:
OString m_string; // ref-counted CoW, but in practice always created ad-hoc
};
template <typename C> class CHARS<C, sizeof(sal_Unicode)> : public SIZED<sizeof(sal_Unicode)>
{
public:
CHARS() = default;
CHARS(const OUString& str)
: m_string(str)
{
m_len = std::min(m_string.getLength(), sal_Int32(std::numeric_limits<SQLSMALLINT>::max()));
}
C* get() { return reinterpret_cast<C*>(const_cast<sal_Unicode*>(m_string.getStr())); }
private:
OUString m_string; // ref-counted CoW
};
template <typename C> class CHARS<C, sizeof(sal_uInt32)> : public SIZED<sizeof(sal_uInt32)>
{
public:
CHARS() = default;
CHARS(std::u16string_view str)
{
auto size = std::min(str.size(), size_t(std::numeric_limits<SQLSMALLINT>::max()));
m_buf = std::make_unique<sal_uInt32[]>(size + 1);
auto p = m_buf.get();
for (size_t i = 0; i < str.size() && o3tl::make_unsigned(p - m_buf.get()) < size; ++p)
*p = o3tl::iterateCodePoints(str, &i);
m_len = p - m_buf.get();
*p = 0;
}
// Explicitly define a redundant overload for OUString to avoid certain loplugin warnings in
// code prepared to work with SQLWCHAR being either 16-bit unsigned short (Linux) or 32-bit
// wchar_t (macOS):
CHARS(OUString const & str): CHARS(static_cast<std::u16string_view>(str)) {}
C* get() { return reinterpret_cast<C*>(m_buf.get()); }
private:
std::unique_ptr<sal_uInt32[]> m_buf;
};
using SQLChars = CHARS<SQLCHAR>;
using SQLWChars = CHARS<SQLWCHAR>;
// for now, use wchar only on Windows (see comment in OPreparedStatement::setParameter)
#ifdef _WIN32
const bool bUseWChar = true;
#else
const volatile inline bool bUseWChar = false; // volatile to avoid "unreachabe code" warnings
#endif
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V1032 The pointer 'str' is cast to a more strictly aligned pointer type.