/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include 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 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 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(str), len, enc); } inline OUString toUString(const SQLCHAR* str) { return OUString::createFromAscii(reinterpret_cast(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(str), len); else { auto* codepoints = reinterpret_cast(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 class CHARS {}; template 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 class CHARS : public SIZED { 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::max())); } C* get() { return reinterpret_cast(const_cast(m_string.getStr())); } private: OString m_string; // ref-counted CoW, but in practice always created ad-hoc }; template class CHARS : public SIZED { public: CHARS() = default; CHARS(const OUString& str) : m_string(str) { m_len = std::min(m_string.getLength(), sal_Int32(std::numeric_limits::max())); } C* get() { return reinterpret_cast(const_cast(m_string.getStr())); } private: OUString m_string; // ref-counted CoW }; template class CHARS : public SIZED { public: CHARS() = default; CHARS(std::u16string_view str) { auto size = std::min(str.size(), size_t(std::numeric_limits::max())); m_buf = std::make_unique(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(str)) {} C* get() { return reinterpret_cast(m_buf.get()); } private: std::unique_ptr m_buf; }; using SQLChars = CHARS; using SQLWChars = CHARS; // 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: */