connectivity/source/drivers/odbc/OConnection.cxx | 127 + connectivity/source/drivers/odbc/ODatabaseMetaDataResultSet.cxx | 761 ++++++---- connectivity/source/drivers/odbc/ODriver.cxx | 202 ++ connectivity/source/drivers/odbc/OPreparedStatement.cxx | 61 connectivity/source/drivers/odbc/OResultSet.cxx | 355 ++-- connectivity/source/drivers/odbc/OResultSetMetaData.cxx | 136 + connectivity/source/drivers/odbc/OStatement.cxx | 70 connectivity/source/drivers/odbc/OTools.cxx | 252 --- connectivity/source/inc/odbc/ODatabaseMetaDataResultSet.hxx | 22 connectivity/source/inc/odbc/OFunctions.hxx | 145 + connectivity/source/inc/odbc/OResultSet.hxx | 7 connectivity/source/inc/odbc/OStatement.hxx | 2 connectivity/source/inc/odbc/OTools.hxx | 144 + 13 files changed, 1471 insertions(+), 813 deletions(-)
New commits: commit 5ed1415d1cf03a3d671ebd11582dfaa90f1168bd Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Tue Jul 23 16:40:19 2024 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Sat Jul 27 14:10:37 2024 +0200 tdf#68676, tdf#131238: implement and use Unicode ODBC functions on Windows It also prepares for using it on other platforms as well; the code is generic, and should work with 32-bit SQLWCHAR, too. But I can't test it, so it is not enabled on other platforms for now (see bUseWChar, which was moved to connectivity/source/inc/odbc/OTools.hxx). Change-Id: I29fe117910bbab62aba37e85dd27d65a742d28c7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171081 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/connectivity/source/drivers/odbc/OConnection.cxx b/connectivity/source/drivers/odbc/OConnection.cxx index 70e2f782c97e..e3e685cb772d 100644 --- a/connectivity/source/drivers/odbc/OConnection.cxx +++ b/connectivity/source/drivers/odbc/OConnection.cxx @@ -90,11 +90,6 @@ SQLRETURN OConnection::OpenConnection(const OUString& aConnectStr, sal_Int32 nTi return -1; SQLRETURN nSQLRETURN = 0; - SDB_ODBC_CHAR szConnStrOut[4096] = {}; - SDB_ODBC_CHAR szConnStrIn[2048] = {}; - SQLSMALLINT cbConnStrOut; - OString aConStr(OUStringToOString(aConnectStr,getTextEncoding())); - memcpy(szConnStrIn, aConStr.getStr(), std::min<sal_Int32>(sal_Int32(2048),aConStr.getLength())); #ifndef MACOSX functions().SetConnectAttr(m_aConnectionHandle,SQL_ATTR_LOGIN_TIMEOUT,reinterpret_cast<SQLPOINTER>(static_cast<sal_IntPtr>(nTimeOut)),SQL_IS_UINTEGER); @@ -103,35 +98,47 @@ SQLRETURN OConnection::OpenConnection(const OUString& aConnectStr, sal_Int32 nTi #endif #ifdef LINUX - (void) bSilent; - nSQLRETURN = functions().DriverConnect(m_aConnectionHandle, - nullptr, - szConnStrIn, - static_cast<SQLSMALLINT>(std::min(sal_Int32(2048),aConStr.getLength())), - szConnStrOut, - SQLSMALLINT(sizeof(szConnStrOut)/sizeof(SDB_ODBC_CHAR)) -1, - &cbConnStrOut, - SQL_DRIVER_NOPROMPT); + bSilent = true; +#endif //LINUX + SQLUSMALLINT nSilent = bSilent ? SQL_DRIVER_NOPROMPT : SQL_DRIVER_COMPLETE; + + if (bUseWChar && functions().has(ODBC3SQLFunctionId::DriverConnectW)) + { + SQLWChars sqlConnectStr(aConnectStr); + SQLWCHAR szConnStrOut[4096] = {}; + SQLSMALLINT cchConnStrOut; + nSQLRETURN = functions().DriverConnectW(m_aConnectionHandle, + nullptr, + sqlConnectStr.get(), + sqlConnectStr.cch(), + szConnStrOut, + std::size(szConnStrOut) - 1, + &cchConnStrOut, + nSilent); + } + else + { + SQLChars sqlConnectStr(aConnectStr, getTextEncoding()); + SQLCHAR szConnStrOut[4096] = {}; + SQLSMALLINT cbConnStrOut; + nSQLRETURN = functions().DriverConnect(m_aConnectionHandle, + nullptr, + sqlConnectStr.get(), + sqlConnectStr.cch(), + szConnStrOut, + std::size(szConnStrOut) - 1, + &cbConnStrOut, + nSilent); + } +#ifdef LINUX if (nSQLRETURN == SQL_ERROR || nSQLRETURN == SQL_NO_DATA || SQL_SUCCESS_WITH_INFO == nSQLRETURN) - return nSQLRETURN; #else - - SQLUSMALLINT nSilent = bSilent ? SQL_DRIVER_NOPROMPT : SQL_DRIVER_COMPLETE; - nSQLRETURN = functions().DriverConnect(m_aConnectionHandle, - nullptr, - szConnStrIn, - static_cast<SQLSMALLINT>(std::min<sal_Int32>(sal_Int32(2048),aConStr.getLength())), - szConnStrOut, - SQLSMALLINT(sizeof szConnStrOut), - &cbConnStrOut, - nSilent); if (nSQLRETURN == SQL_ERROR || nSQLRETURN == SQL_NO_DATA) +#endif return nSQLRETURN; m_bClosed = false; -#endif //LINUX - try { OUString aVal; @@ -298,11 +305,27 @@ OUString SAL_CALL OConnection::nativeSQL( const OUString& sql ) { ::osl::MutexGuard aGuard( m_aMutex ); - OString aSql(OUStringToOString(sql,getTextEncoding())); - char pOut[2048]; SQLINTEGER nOutLen; - OTools::ThrowException(this,functions().NativeSql(m_aConnectionHandle,reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(aSql.getStr())),aSql.getLength(),reinterpret_cast<SDB_ODBC_CHAR*>(pOut),sizeof pOut - 1,&nOutLen),m_aConnectionHandle,SQL_HANDLE_DBC,*this); - return OUString(pOut,nOutLen,getTextEncoding()); + if (bUseWChar && functions().has(ODBC3SQLFunctionId::NativeSqlW)) + { + SQLWChars nativeSQL(sql); + SQLWCHAR pOut[2048]; + SQLRETURN ret = functions().NativeSqlW(m_aConnectionHandle, + nativeSQL.get(), nativeSQL.cch(), + pOut, std::size(pOut) - 1, &nOutLen); + OTools::ThrowException(this, ret, m_aConnectionHandle, SQL_HANDLE_DBC, *this); + return toUString(pOut, nOutLen); + } + else + { + SQLChars nativeSQL(sql, getTextEncoding()); + SQLCHAR pOut[2048]; + SQLRETURN ret = functions().NativeSql(m_aConnectionHandle, + nativeSQL.get(), nativeSQL.cch(), + pOut, std::size(pOut) - 1, &nOutLen); + OTools::ThrowException(this, ret, m_aConnectionHandle, SQL_HANDLE_DBC, *this); + return toUString(pOut, nOutLen, getTextEncoding()); + } } void SAL_CALL OConnection::setAutoCommit( sal_Bool autoCommit ) @@ -391,11 +414,20 @@ void SAL_CALL OConnection::setCatalog( const OUString& catalog ) ::osl::MutexGuard aGuard( m_aMutex ); checkDisposed(OConnection_BASE::rBHelper.bDisposed); - - OString aCat(OUStringToOString(catalog,getTextEncoding())); - OTools::ThrowException(this, - functions().SetConnectAttr(m_aConnectionHandle,SQL_ATTR_CURRENT_CATALOG,const_cast<char *>(aCat.getStr()),SQL_NTS), - m_aConnectionHandle,SQL_HANDLE_DBC,*this); + if (bUseWChar && functions().has(ODBC3SQLFunctionId::SetConnectAttrW)) + { + SQLWChars sqlCatalog(catalog); + OTools::ThrowException(this, + functions().SetConnectAttrW(m_aConnectionHandle, SQL_ATTR_CURRENT_CATALOG, sqlCatalog.get(), SQL_NTSL), + m_aConnectionHandle,SQL_HANDLE_DBC,*this); + } + else + { + SQLChars sqlCatalog(catalog, getTextEncoding()); + OTools::ThrowException(this, + functions().SetConnectAttr(m_aConnectionHandle,SQL_ATTR_CURRENT_CATALOG,sqlCatalog.get(),SQL_NTS), + m_aConnectionHandle,SQL_HANDLE_DBC,*this); + } } OUString SAL_CALL OConnection::getCatalog( ) @@ -403,14 +435,25 @@ OUString SAL_CALL OConnection::getCatalog( ) ::osl::MutexGuard aGuard( m_aMutex ); checkDisposed(OConnection_BASE::rBHelper.bDisposed); - SQLINTEGER nValueLen; - char pCat[1024]; - OTools::ThrowException(this, - functions().GetConnectAttr(m_aConnectionHandle,SQL_ATTR_CURRENT_CATALOG,pCat,(sizeof pCat)-1,&nValueLen), - m_aConnectionHandle,SQL_HANDLE_DBC,*this); + if (bUseWChar && functions().has(ODBC3SQLFunctionId::GetConnectAttrW)) + { + SQLWCHAR pCat[1024]; + // SQLGetConnectAttrW gets/returns count of bytes, not characters + OTools::ThrowException(this, + functions().GetConnectAttrW(m_aConnectionHandle,SQL_ATTR_CURRENT_CATALOG,pCat,sizeof(pCat)-sizeof(SQLWCHAR),&nValueLen), + m_aConnectionHandle,SQL_HANDLE_DBC,*this); + return toUString(pCat, nValueLen / sizeof(SQLWCHAR)); + } + else + { + SQLCHAR pCat[1024]; + OTools::ThrowException(this, + functions().GetConnectAttr(m_aConnectionHandle,SQL_ATTR_CURRENT_CATALOG,pCat,sizeof(pCat)-1,&nValueLen), + m_aConnectionHandle,SQL_HANDLE_DBC,*this); - return OUString(pCat,nValueLen,getTextEncoding()); + return toUString(pCat, nValueLen, getTextEncoding()); + } } void SAL_CALL OConnection::setTransactionIsolation( sal_Int32 level ) diff --git a/connectivity/source/drivers/odbc/ODatabaseMetaDataResultSet.cxx b/connectivity/source/drivers/odbc/ODatabaseMetaDataResultSet.cxx index 665f94b95181..56b5cc237c66 100644 --- a/connectivity/source/drivers/odbc/ODatabaseMetaDataResultSet.cxx +++ b/connectivity/source/drivers/odbc/ODatabaseMetaDataResultSet.cxx @@ -24,6 +24,7 @@ #include <comphelper/property.hxx> #include <cppuhelper/typeprovider.hxx> #include <comphelper/sequence.hxx> +#include <comphelper/stl_types.hxx> #include <odbc/OResultSetMetaData.hxx> #include <odbc/OTools.hxx> #include <comphelper/types.hxx> @@ -831,48 +832,52 @@ void ODatabaseMetaDataResultSet::openTypeInfo() } void ODatabaseMetaDataResultSet::openTables(const Any& catalog, const OUString& schemaPattern, - std::u16string_view tableNamePattern, + const OUString& tableNamePattern, const Sequence< OUString >& types ) { - OString aPKQ,aPKO,aPKN,aCOL; - const OUString *pSchemaPat = nullptr; - - if(schemaPattern != "%") - pSchemaPat = &schemaPattern; - else - pSchemaPat = nullptr; - - if ( catalog.hasValue() ) - aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); - aPKO = OUStringToOString(schemaPattern,m_nTextEncoding); - aPKN = OUStringToOString(tableNamePattern,m_nTextEncoding); - - const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr, - *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr, - *pPKN = aPKN.getStr(); - - - const char *pCOL = nullptr; - const char* const pComma = ","; - const OUString* pBegin = types.getConstArray(); - const OUString* pEnd = pBegin + types.getLength(); - for(;pBegin != pEnd;++pBegin) + OUString uPKQ; + catalog >>= uPKQ; + OUStringBuffer uCOL; + comphelper::intersperse(types.begin(), types.end(), comphelper::OUStringBufferAppender(uCOL), u","); + SQLRETURN nRetcode; + if (bUseWChar && functions().has(ODBC3SQLFunctionId::TablesW)) { - aCOL += OUStringToOString(*pBegin,m_nTextEncoding) + pComma; + SQLWChars aPKQ, aPKO; + if (!uPKQ.isEmpty()) + aPKQ = SQLWChars(uPKQ); + if (!schemaPattern.isEmpty() && schemaPattern != "%") + aPKO = SQLWChars(schemaPattern); + SQLWChars aPKN(tableNamePattern); + SQLWChars aCOL = !uCOL.isEmpty() ? SQLWChars(uCOL.makeStringAndClear()) : SQLWChars(u"" SQL_ALL_TABLE_TYPES ""_ustr); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr, + pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + + nRetcode = functions().TablesW(m_aStatementHandle, + pPKQ, pPKQ ? SQL_NTSL : 0, + pPKO, pPKO ? SQL_NTSL : 0, + aPKN.get(), SQL_NTSL, + aCOL.get(), SQL_NTSL); } - if ( !aCOL.isEmpty() ) + else { - aCOL = aCOL.replaceAt(aCOL.getLength()-1,1,pComma); - pCOL = aCOL.getStr(); + SQLChars aPKQ, aPKO; + if (!uPKQ.isEmpty()) + aPKQ = SQLChars(uPKQ, m_nTextEncoding); + if (!schemaPattern.isEmpty() && schemaPattern != "%") + aPKO = SQLChars(schemaPattern, m_nTextEncoding); + SQLChars aPKN(tableNamePattern, m_nTextEncoding); + SQLChars aCOL = !uCOL.isEmpty() ? SQLChars(uCOL, m_nTextEncoding) : SQLChars(SQL_ALL_TABLE_TYPES ""_ostr); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr, + pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + + nRetcode = functions().Tables(m_aStatementHandle, + pPKQ, pPKQ ? SQL_NTS : 0, + pPKO, pPKO ? SQL_NTS : 0, + aPKN.get(), SQL_NTS, + aCOL.get(), SQL_NTS); } - else - pCOL = SQL_ALL_TABLE_TYPES; - - SQLRETURN nRetcode = functions().Tables(m_aStatementHandle, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pCOL)), pCOL ? SQL_NTS : 0); OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); checkColumnCount(); @@ -880,11 +885,23 @@ void ODatabaseMetaDataResultSet::openTables(const Any& catalog, const OUString& void ODatabaseMetaDataResultSet::openTablesTypes( ) { - SQLRETURN nRetcode = functions().Tables(m_aStatementHandle, - nullptr,0, - nullptr,0, - nullptr,0, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(SQL_ALL_TABLE_TYPES)),SQL_NTS); + SQLRETURN nRetcode; + if (bUseWChar && functions().has(ODBC3SQLFunctionId::TablesW)) + { + nRetcode = functions().TablesW(m_aStatementHandle, + nullptr, 0, + nullptr, 0, + nullptr, 0, + SQLWChars(u"" SQL_ALL_TABLE_TYPES ""_ustr).get(), SQL_NTSL); + } + else + { + nRetcode = functions().Tables(m_aStatementHandle, + nullptr,0, + nullptr,0, + nullptr,0, + SQLChars(SQL_ALL_TABLE_TYPES ""_ostr).get(), SQL_NTS); + } OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); m_aColMapping.clear(); @@ -896,12 +913,23 @@ void ODatabaseMetaDataResultSet::openTablesTypes( ) void ODatabaseMetaDataResultSet::openCatalogs() { - SQLRETURN nRetcode = functions().Tables(m_aStatementHandle, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(SQL_ALL_CATALOGS)),SQL_NTS, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>("")),SQL_NTS, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>("")),SQL_NTS, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>("")),SQL_NTS); - + SQLRETURN nRetcode; + if (bUseWChar && functions().has(ODBC3SQLFunctionId::TablesW)) + { + nRetcode = functions().TablesW(m_aStatementHandle, + SQLWChars(u"" SQL_ALL_CATALOGS ""_ustr).get(), SQL_NTSL, + SQLWChars(u""_ustr).get(), SQL_NTSL, + SQLWChars(u""_ustr).get(), SQL_NTSL, + SQLWChars(u""_ustr).get(), SQL_NTSL); + } + else + { + nRetcode = functions().Tables(m_aStatementHandle, + SQLChars(SQL_ALL_CATALOGS ""_ostr).get(), SQL_NTS, + SQLChars(""_ostr).get(), SQL_NTS, + SQLChars(""_ostr).get(), SQL_NTS, + SQLChars(""_ostr).get(), SQL_NTS); + } OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); m_aColMapping.clear(); @@ -913,11 +941,23 @@ void ODatabaseMetaDataResultSet::openCatalogs() void ODatabaseMetaDataResultSet::openSchemas() { - SQLRETURN nRetcode = functions().Tables(m_aStatementHandle, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>("")),SQL_NTS, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(SQL_ALL_SCHEMAS)),SQL_NTS, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>("")),SQL_NTS, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>("")),SQL_NTS); + SQLRETURN nRetcode; + if (bUseWChar && functions().has(ODBC3SQLFunctionId::TablesW)) + { + nRetcode = functions().TablesW(m_aStatementHandle, + SQLWChars(u""_ustr).get(), SQL_NTSL, + SQLWChars(u"" SQL_ALL_SCHEMAS ""_ustr).get(), SQL_NTSL, + SQLWChars(u""_ustr).get(),SQL_NTSL, + SQLWChars(u""_ustr).get(),SQL_NTSL); + } + else + { + nRetcode = functions().Tables(m_aStatementHandle, + SQLChars(""_ostr).get(), SQL_NTS, + SQLChars(SQL_ALL_SCHEMAS ""_ostr).get(), SQL_NTS, + SQLChars(""_ostr).get(), SQL_NTS, + SQLChars(""_ostr).get(), SQL_NTS); + } OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); m_aColMapping.clear(); @@ -928,69 +968,99 @@ void ODatabaseMetaDataResultSet::openSchemas() } void ODatabaseMetaDataResultSet::openColumnPrivileges( const Any& catalog, const OUString& schema, - std::u16string_view table, - std::u16string_view columnNamePattern ) + const OUString& table, + const OUString& columnNamePattern ) { - const OUString *pSchemaPat = nullptr; - - if(schema != "%") - pSchemaPat = &schema; + OUString uPKQ; + catalog >>= uPKQ; + SQLRETURN nRetcode; + if (bUseWChar && functions().has(ODBC3SQLFunctionId::ColumnPrivilegesW)) + { + SQLWChars aPKQ, aPKO; + if (!uPKQ.isEmpty()) + aPKQ = SQLWChars(uPKQ); + if (!schema.isEmpty() && schema != "%") + aPKO = SQLWChars(schema); + SQLWChars aPKN(table); + SQLWChars aCOL(columnNamePattern); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr, + pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + + nRetcode = functions().ColumnPrivilegesW(m_aStatementHandle, + pPKQ, pPKQ ? SQL_NTSL : 0, + pPKO, pPKO ? SQL_NTSL : 0, + aPKN.get(), SQL_NTSL, + aCOL.get(), SQL_NTSL); + } else - pSchemaPat = nullptr; - - OString aPKQ,aPKO,aPKN,aCOL; - - if ( catalog.hasValue() ) - aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); - aPKO = OUStringToOString(schema,m_nTextEncoding); - aPKN = OUStringToOString(table,m_nTextEncoding); - aCOL = OUStringToOString(columnNamePattern,m_nTextEncoding); - - const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr, - *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr, - *pPKN = aPKN.getStr(), - *pCOL = aCOL.getStr(); - - - SQLRETURN nRetcode = functions().ColumnPrivileges(m_aStatementHandle, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 , - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pCOL)), SQL_NTS); + { + SQLChars aPKQ, aPKO; + if (!uPKQ.isEmpty()) + aPKQ = SQLChars(uPKQ, m_nTextEncoding); + if (!schema.isEmpty() && schema != "%") + aPKO = SQLChars(schema, m_nTextEncoding); + SQLChars aPKN(table, m_nTextEncoding); + SQLChars aCOL(columnNamePattern, m_nTextEncoding); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr, + pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + + nRetcode = functions().ColumnPrivileges(m_aStatementHandle, + pPKQ, pPKQ ? SQL_NTS : 0, + pPKO, pPKO ? SQL_NTS : 0, + aPKN.get(), SQL_NTS, + aCOL.get(), SQL_NTS); + } OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); checkColumnCount(); } void ODatabaseMetaDataResultSet::openColumns( const Any& catalog, const OUString& schemaPattern, - std::u16string_view tableNamePattern, std::u16string_view columnNamePattern ) + const OUString& tableNamePattern, const OUString& columnNamePattern ) { - const OUString *pSchemaPat = nullptr; - - if(schemaPattern != "%") - pSchemaPat = &schemaPattern; + OUString uPKQ; + catalog >>= uPKQ; + SQLRETURN nRetcode; + if (bUseWChar && functions().has(ODBC3SQLFunctionId::ColumnsW)) + { + SQLWChars aPKQ, aPKO; + if (!uPKQ.isEmpty()) + aPKQ = SQLWChars(uPKQ); + if (!schemaPattern.isEmpty() && schemaPattern != "%") + aPKO = SQLWChars(schemaPattern); + SQLWChars aPKN(tableNamePattern); + SQLWChars aCOL(columnNamePattern); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr, + pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + + nRetcode = functions().ColumnsW(m_aStatementHandle, + pPKQ, pPKQ ? SQL_NTSL : 0, + pPKO, pPKO ? SQL_NTSL : 0, + aPKN.get(), SQL_NTSL, + aCOL.get(), SQL_NTSL); + } else - pSchemaPat = nullptr; - - OString aPKQ,aPKO,aPKN,aCOL; - if ( catalog.hasValue() ) - aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); - aPKO = OUStringToOString(schemaPattern,m_nTextEncoding); - aPKN = OUStringToOString(tableNamePattern,m_nTextEncoding); - aCOL = OUStringToOString(columnNamePattern,m_nTextEncoding); - - const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr, - *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr, - *pPKN = aPKN.getStr(), - *pCOL = aCOL.getStr(); - - - SQLRETURN nRetcode = functions().Columns(m_aStatementHandle, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pCOL)), SQL_NTS); - + { + SQLChars aPKQ, aPKO; + if (!uPKQ.isEmpty()) + aPKQ = SQLChars(uPKQ, m_nTextEncoding); + if (!schemaPattern.isEmpty() && schemaPattern != "%") + aPKO = SQLChars(schemaPattern, m_nTextEncoding); + SQLChars aPKN(tableNamePattern, m_nTextEncoding); + SQLChars aCOL(columnNamePattern, m_nTextEncoding); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr, + pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + + nRetcode = functions().Columns(m_aStatementHandle, + pPKQ, pPKQ ? SQL_NTS : 0, + pPKO, pPKO ? SQL_NTS : 0, + aPKN.get(), SQL_NTS, + aCOL.get(), SQL_NTS); + } OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); ::std::map<sal_Int32,sal_Int32> aMap; aMap[SQL_BIT] = DataType::BIT; @@ -1030,74 +1100,103 @@ void ODatabaseMetaDataResultSet::openColumns( const Any& catalog, } void ODatabaseMetaDataResultSet::openProcedureColumns( const Any& catalog, const OUString& schemaPattern, - std::u16string_view procedureNamePattern,std::u16string_view columnNamePattern ) + const OUString& procedureNamePattern,const OUString& columnNamePattern ) { - const OUString *pSchemaPat = nullptr; - - if(schemaPattern != "%") - pSchemaPat = &schemaPattern; + OUString uPKQ; + catalog >>= uPKQ; + SQLRETURN nRetcode; + if (bUseWChar && functions().has(ODBC3SQLFunctionId::ProcedureColumnsW)) + { + SQLWChars aPKQ, aPKO; + if (!uPKQ.isEmpty()) + aPKQ = SQLWChars(uPKQ); + if (!schemaPattern.isEmpty() && schemaPattern != "%") + aPKO = SQLWChars(schemaPattern); + SQLWChars aPKN(procedureNamePattern); + SQLWChars aCOL(columnNamePattern); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr, + pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + + nRetcode = functions().ProcedureColumnsW(m_aStatementHandle, + pPKQ, pPKQ ? SQL_NTSL : 0, + pPKO, pPKO ? SQL_NTSL : 0, + aPKN.get(), SQL_NTSL, + aCOL.get(), SQL_NTSL); + } else - pSchemaPat = nullptr; - - OString aPKQ,aPKO,aPKN,aCOL; - if ( catalog.hasValue() ) - aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); - aPKO = OUStringToOString(schemaPattern,m_nTextEncoding); - aPKN = OUStringToOString(procedureNamePattern,m_nTextEncoding); - aCOL = OUStringToOString(columnNamePattern,m_nTextEncoding); - - const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr, - *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr, - *pPKN = aPKN.getStr(), - *pCOL = aCOL.getStr(); - - - SQLRETURN nRetcode = functions().ProcedureColumns(m_aStatementHandle, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 , - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pCOL)), SQL_NTS); - + { + SQLChars aPKQ, aPKO; + if (!uPKQ.isEmpty()) + aPKQ = SQLChars(uPKQ, m_nTextEncoding); + if (!schemaPattern.isEmpty() && schemaPattern != "%") + aPKO = SQLChars(schemaPattern, m_nTextEncoding); + SQLChars aPKN(procedureNamePattern, m_nTextEncoding); + SQLChars aCOL(columnNamePattern, m_nTextEncoding); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr, + pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + + nRetcode = functions().ProcedureColumns(m_aStatementHandle, + pPKQ, pPKQ ? SQL_NTS : 0, + pPKO, pPKO ? SQL_NTS : 0, + aPKN.get(), SQL_NTS, + aCOL.get(), SQL_NTS); + } OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); checkColumnCount(); } void ODatabaseMetaDataResultSet::openProcedures(const Any& catalog, const OUString& schemaPattern, - std::u16string_view procedureNamePattern) + const OUString& procedureNamePattern) { - const OUString *pSchemaPat = nullptr; - - if(schemaPattern != "%") - pSchemaPat = &schemaPattern; + OUString uPKQ; + catalog >>= uPKQ; + SQLRETURN nRetcode; + if (bUseWChar && functions().has(ODBC3SQLFunctionId::ProceduresW)) + { + SQLWChars aPKQ, aPKO; + if (!uPKQ.isEmpty()) + aPKQ = SQLWChars(uPKQ); + if (!schemaPattern.isEmpty() && schemaPattern != "%") + aPKO = SQLWChars(schemaPattern); + SQLWChars aPKN(procedureNamePattern); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr, + pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + + nRetcode = functions().ProceduresW(m_aStatementHandle, + pPKQ, pPKQ ? SQL_NTSL : 0, + pPKO, pPKO ? SQL_NTSL : 0, + aPKN.get(), SQL_NTSL); + } else - pSchemaPat = nullptr; - - OString aPKQ,aPKO,aPKN; - - if ( catalog.hasValue() ) - aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); - aPKO = OUStringToOString(schemaPattern,m_nTextEncoding); - aPKN = OUStringToOString(procedureNamePattern,m_nTextEncoding); - - const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr, - *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr, - *pPKN = aPKN.getStr(); - - - SQLRETURN nRetcode = functions().Procedures(m_aStatementHandle, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 , - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS); + { + SQLChars aPKQ, aPKO; + if (!uPKQ.isEmpty()) + aPKQ = SQLChars(uPKQ, m_nTextEncoding); + if (!schemaPattern.isEmpty() && schemaPattern != "%") + aPKO = SQLChars(schemaPattern, m_nTextEncoding); + SQLChars aPKN(procedureNamePattern, m_nTextEncoding); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr, + pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + + nRetcode = functions().Procedures(m_aStatementHandle, + pPKQ, pPKQ ? SQL_NTS : 0, + pPKO, pPKO ? SQL_NTS : 0, + aPKN.get(), SQL_NTS); + } OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); checkColumnCount(); } void ODatabaseMetaDataResultSet::openSpecialColumns(bool _bRowVer,const Any& catalog, const OUString& schema, - std::u16string_view table,sal_Int32 scope, bool nullable ) + const OUString& table,sal_Int32 scope, bool nullable ) { // Some ODBC drivers really don't like getting an empty string as tableName // E.g. psqlodbc up to at least version 09.01.0100 segfaults - if (table.empty()) + if (table.isEmpty()) { static constexpr OUStringLiteral errMsg = u"ODBC: Trying to get special columns of empty table name"; @@ -1105,42 +1204,59 @@ void ODatabaseMetaDataResultSet::openSpecialColumns(bool _bRowVer,const Any& cat throw SQLException( errMsg, *this, SQLState, -1, Any() ); } - const OUString *pSchemaPat = nullptr; - - if(schema != "%") - pSchemaPat = &schema; + OUString uPKQ; + catalog >>= uPKQ; + SQLRETURN nRetcode; + if (bUseWChar && functions().has(ODBC3SQLFunctionId::SpecialColumnsW)) + { + SQLWChars aPKQ, aPKO; + if (!uPKQ.isEmpty()) + aPKQ = SQLWChars(uPKQ); + if (!schema.isEmpty() && schema != "%") + aPKO = SQLWChars(schema); + SQLWChars aPKN(table); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr, + pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + + nRetcode = functions().SpecialColumnsW(m_aStatementHandle, _bRowVer ? SQL_ROWVER : SQL_BEST_ROWID, + pPKQ, pPKQ ? SQL_NTSL : 0, + pPKO, pPKO ? SQL_NTSL : 0, + aPKN.get(), SQL_NTSL, + scope, + nullable ? SQL_NULLABLE : SQL_NO_NULLS); + } else - pSchemaPat = nullptr; - - OString aPKQ,aPKO,aPKN; - if ( catalog.hasValue() ) - aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); - aPKO = OUStringToOString(schema,m_nTextEncoding); - aPKN = OUStringToOString(table,m_nTextEncoding); - - const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr, - *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr, - *pPKN = aPKN.getStr(); - - - SQLRETURN nRetcode = functions().SpecialColumns(m_aStatementHandle,_bRowVer ? SQL_ROWVER : SQL_BEST_ROWID, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 , - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS, - static_cast<SQLSMALLINT>(scope), - nullable ? SQL_NULLABLE : SQL_NO_NULLS); + { + SQLChars aPKQ, aPKO; + if (!uPKQ.isEmpty()) + aPKQ = SQLChars(uPKQ, m_nTextEncoding); + if (!schema.isEmpty() && schema != "%") + aPKO = SQLChars(schema, m_nTextEncoding); + SQLChars aPKN(table, m_nTextEncoding); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr, + pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + + nRetcode = functions().SpecialColumns(m_aStatementHandle, _bRowVer ? SQL_ROWVER : SQL_BEST_ROWID, + pPKQ, pPKQ ? SQL_NTS : 0, + pPKO, pPKO ? SQL_NTS : 0, + aPKN.get(), SQL_NTS, + static_cast<SQLSMALLINT>(scope), + nullable ? SQL_NULLABLE : SQL_NO_NULLS); + } OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); checkColumnCount(); } void ODatabaseMetaDataResultSet::openVersionColumns(const Any& catalog, const OUString& schema, - std::u16string_view table) + const OUString& table) { openSpecialColumns(true,catalog,schema,table,SQL_SCOPE_TRANSACTION,false); } void ODatabaseMetaDataResultSet::openBestRowIdentifier( const Any& catalog, const OUString& schema, - std::u16string_view table,sal_Int32 scope,bool nullable ) + const OUString& table,sal_Int32 scope,bool nullable ) { openSpecialColumns(false,catalog,schema,table,scope,nullable); } @@ -1150,47 +1266,72 @@ void ODatabaseMetaDataResultSet::openForeignKeys( const Any& catalog, const OUSt const Any& catalog2, const OUString* schema2, const OUString* table2) { - OString aPKQ, aPKO, aPKN, aFKQ, aFKO, aFKN; - if ( catalog.hasValue() ) - aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); - if ( catalog2.hasValue() ) - aFKQ = OUStringToOString(comphelper::getString(catalog2),m_nTextEncoding); - - const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr; - const char *pPKO = nullptr; - if (schema && !schema->isEmpty()) - { - aPKO = OUStringToOString(*schema,m_nTextEncoding); - pPKO = aPKO.getStr(); - } - const char *pPKN = nullptr; - if (table) - { - aPKN = OUStringToOString(*table,m_nTextEncoding); - pPKN = aPKN.getStr(); - } - const char *pFKQ = catalog2.hasValue() && !aFKQ.isEmpty() ? aFKQ.getStr() : nullptr; - const char *pFKO = nullptr; - if (schema2 && !schema2->isEmpty()) + OUString uPKQ, uFKQ; + catalog >>= uPKQ; + catalog2 >>= uFKQ; + SQLRETURN nRetcode; + if (bUseWChar && functions().has(ODBC3SQLFunctionId::ForeignKeysW)) { - aFKO = OUStringToOString(*schema2,m_nTextEncoding); - pFKO = aFKO.getStr(); + SQLWChars aPKQ, aPKO, aPKN, aFKQ, aFKO, aFKN; + if (!uPKQ.isEmpty()) + aPKQ = SQLWChars(uPKQ); + if (!uFKQ.isEmpty()) + aFKQ = SQLWChars(uFKQ); + if (schema && !schema->isEmpty()) + aPKO = SQLWChars(*schema); + if (table) + aPKN = SQLWChars(*table); + if (schema2 && !schema2->isEmpty()) + aFKO = SQLWChars(*schema2); + if (table2) + aFKN = SQLWChars(*table2); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr; + auto pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + auto pPKN = !aPKN.empty() ? aPKN.get() : nullptr; + auto pFKQ = !aFKQ.empty() ? aFKQ.get() : nullptr; + auto pFKO = !aFKO.empty() ? aFKO.get() : nullptr; + auto pFKN = !aFKN.empty() ? aFKN.get() : nullptr; + + nRetcode = functions().ForeignKeysW(m_aStatementHandle, + pPKQ, pPKQ ? SQL_NTSL : 0, + pPKO, pPKO ? SQL_NTSL : 0, + pPKN, pPKN ? SQL_NTSL : 0, + pFKQ, pFKQ ? SQL_NTSL : 0, + pFKO, pFKO ? SQL_NTSL : 0, + pFKN, pFKN ? SQL_NTSL : 0); } - const char *pFKN = nullptr; - if (table2) + else { - aFKN = OUStringToOString(*table2,m_nTextEncoding); - pFKN = aFKN.getStr(); + SQLChars aPKQ, aPKO, aPKN, aFKQ, aFKO, aFKN; + if (!uPKQ.isEmpty()) + aPKQ = SQLChars(uPKQ, m_nTextEncoding); + if (!uFKQ.isEmpty()) + aFKQ = SQLChars(uFKQ, m_nTextEncoding); + if (schema && !schema->isEmpty()) + aPKO = SQLChars(*schema, m_nTextEncoding); + if (table) + aPKN = SQLChars(*table, m_nTextEncoding); + if (schema2 && !schema2->isEmpty()) + aFKO = SQLChars(*schema2, m_nTextEncoding); + if (table2) + aFKN = SQLChars(*table2, m_nTextEncoding); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr; + auto pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + auto pPKN = !aPKN.empty() ? aPKN.get() : nullptr; + auto pFKQ = !aFKQ.empty() ? aFKQ.get() : nullptr; + auto pFKO = !aFKO.empty() ? aFKO.get() : nullptr; + auto pFKN = !aFKN.empty() ? aFKN.get() : nullptr; + + nRetcode = functions().ForeignKeys(m_aStatementHandle, + pPKQ, pPKQ ? SQL_NTS : 0, + pPKO, pPKO ? SQL_NTS : 0, + pPKN, pPKN ? SQL_NTS : 0, + pFKQ, pFKQ ? SQL_NTS : 0, + pFKO, pFKO ? SQL_NTS : 0, + pFKN, pFKN ? SQL_NTS : 0); } - - SQLRETURN nRetcode = functions().ForeignKeys(m_aStatementHandle, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), pPKN ? SQL_NTS : 0, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pFKQ)), (catalog2.hasValue() && !aFKQ.isEmpty()) ? SQL_NTS : 0, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pFKO)), pFKO ? SQL_NTS : 0, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pFKN)), SQL_NTS - ); OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); checkColumnCount(); } @@ -1209,91 +1350,137 @@ void ODatabaseMetaDataResultSet::openExportedKeys(const Any& catalog, const OUSt } void ODatabaseMetaDataResultSet::openPrimaryKeys(const Any& catalog, const OUString& schema, - std::u16string_view table) + const OUString& table) { - const OUString *pSchemaPat = nullptr; - - if(schema != "%") - pSchemaPat = &schema; + OUString uPKQ; + catalog >>= uPKQ; + SQLRETURN nRetcode; + if (bUseWChar && functions().has(ODBC3SQLFunctionId::PrimaryKeysW)) + { + SQLWChars aPKQ, aPKO; + if (!uPKQ.isEmpty()) + aPKQ = SQLWChars(uPKQ); + if (!schema.isEmpty() && schema != "%") + aPKO = SQLWChars(schema); + SQLWChars aPKN(table); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr, + pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + + nRetcode = functions().PrimaryKeysW(m_aStatementHandle, + pPKQ, pPKQ ? SQL_NTSL : 0, + pPKO, pPKO ? SQL_NTSL : 0, + aPKN.get(), SQL_NTSL); + } else - pSchemaPat = nullptr; - - OString aPKQ,aPKO,aPKN; - - if ( catalog.hasValue() ) - aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); - aPKO = OUStringToOString(schema,m_nTextEncoding); - aPKN = OUStringToOString(table,m_nTextEncoding); - - const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr, - *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr, - *pPKN = aPKN.getStr(); - - - SQLRETURN nRetcode = functions().PrimaryKeys(m_aStatementHandle, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 , - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS); + { + SQLChars aPKQ, aPKO; + if (!uPKQ.isEmpty()) + aPKQ = SQLChars(uPKQ, m_nTextEncoding); + if (!schema.isEmpty() && schema != "%") + aPKO = SQLChars(schema, m_nTextEncoding); + SQLChars aPKN(table, m_nTextEncoding); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr, + pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + + nRetcode = functions().PrimaryKeys(m_aStatementHandle, + pPKQ, pPKQ ? SQL_NTS : 0, + pPKO, pPKO ? SQL_NTS : 0, + aPKN.get(), SQL_NTS); + } OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); checkColumnCount(); } void ODatabaseMetaDataResultSet::openTablePrivileges(const Any& catalog, const OUString& schemaPattern, - std::u16string_view tableNamePattern) + const OUString& tableNamePattern) { - const OUString *pSchemaPat = nullptr; - - if(schemaPattern != "%") - pSchemaPat = &schemaPattern; + OUString uPKQ; + catalog >>= uPKQ; + SQLRETURN nRetcode; + if (bUseWChar && functions().has(ODBC3SQLFunctionId::TablePrivilegesW)) + { + SQLWChars aPKQ, aPKO; + if (!uPKQ.isEmpty()) + aPKQ = SQLWChars(uPKQ); + if (!schemaPattern.isEmpty() && schemaPattern != "%") + aPKO = SQLWChars(schemaPattern); + SQLWChars aPKN(tableNamePattern); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr, + pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + + nRetcode = functions().TablePrivilegesW(m_aStatementHandle, + pPKQ, pPKQ ? SQL_NTSL : 0, + pPKO, pPKO ? SQL_NTSL : 0, + aPKN.get(), SQL_NTSL); + } else - pSchemaPat = nullptr; - - OString aPKQ,aPKO,aPKN; - - if ( catalog.hasValue() ) - aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); - aPKO = OUStringToOString(schemaPattern,m_nTextEncoding); - aPKN = OUStringToOString(tableNamePattern,m_nTextEncoding); - - const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr, - *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr, - *pPKN = aPKN.getStr(); - - SQLRETURN nRetcode = functions().TablePrivileges(m_aStatementHandle, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 , - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS); + { + SQLChars aPKQ, aPKO; + if (!uPKQ.isEmpty()) + aPKQ = SQLChars(uPKQ, m_nTextEncoding); + if (!schemaPattern.isEmpty() && schemaPattern != "%") + aPKO = SQLChars(schemaPattern, m_nTextEncoding); + SQLChars aPKN(tableNamePattern, m_nTextEncoding); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr, + pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + + nRetcode = functions().TablePrivileges(m_aStatementHandle, + pPKQ, pPKQ ? SQL_NTS : 0, + pPKO, pPKO ? SQL_NTS : 0, + aPKN.get(), SQL_NTS); + } OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); checkColumnCount(); } void ODatabaseMetaDataResultSet::openIndexInfo( const Any& catalog, const OUString& schema, - std::u16string_view table, bool unique, bool approximate ) + const OUString& table, bool unique, bool approximate ) { - const OUString *pSchemaPat = nullptr; - - if(schema != "%") - pSchemaPat = &schema; + OUString uPKQ; + catalog >>= uPKQ; + SQLRETURN nRetcode; + if (bUseWChar && functions().has(ODBC3SQLFunctionId::StatisticsW)) + { + SQLWChars aPKQ, aPKO; + if (!uPKQ.isEmpty()) + aPKQ = SQLWChars(uPKQ); + if (!schema.isEmpty() && schema != "%") + aPKO = SQLWChars(schema); + SQLWChars aPKN(table); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr, + pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + + nRetcode = functions().StatisticsW(m_aStatementHandle, + pPKQ, pPKQ ? SQL_NTSL : 0, + pPKO, pPKO ? SQL_NTSL : 0, + aPKN.get(), SQL_NTSL, + unique ? SQL_INDEX_UNIQUE : SQL_INDEX_ALL, + approximate ? 1 : 0); + } else - pSchemaPat = nullptr; - - OString aPKQ,aPKO,aPKN; - - if ( catalog.hasValue() ) - aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); - aPKO = OUStringToOString(schema,m_nTextEncoding); - aPKN = OUStringToOString(table,m_nTextEncoding); - - const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr, - *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr, - *pPKN = aPKN.getStr(); - - SQLRETURN nRetcode = functions().Statistics(m_aStatementHandle, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 , - reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS, - unique ? SQL_INDEX_UNIQUE : SQL_INDEX_ALL, - approximate ? 1 : 0); + { + SQLChars aPKQ, aPKO; + if (!uPKQ.isEmpty()) + aPKQ = SQLChars(uPKQ, m_nTextEncoding); + if (!schema.isEmpty() && schema != "%") + aPKO = SQLChars(schema, m_nTextEncoding); + SQLChars aPKN(table, m_nTextEncoding); + + auto pPKQ = !aPKQ.empty() ? aPKQ.get() : nullptr, + pPKO = !aPKO.empty() ? aPKO.get() : nullptr; + + nRetcode = functions().Statistics(m_aStatementHandle, + pPKQ, pPKQ ? SQL_NTS : 0, + pPKO, pPKO ? SQL_NTS : 0, + aPKN.get(), SQL_NTS, + unique ? SQL_INDEX_UNIQUE : SQL_INDEX_ALL, + approximate ? 1 : 0); + } OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); checkColumnCount(); } diff --git a/connectivity/source/drivers/odbc/ODriver.cxx b/connectivity/source/drivers/odbc/ODriver.cxx index 520f1ace0e86..9df42f2ae00f 100644 --- a/connectivity/source/drivers/odbc/ODriver.cxx +++ b/connectivity/source/drivers/odbc/ODriver.cxx @@ -202,6 +202,32 @@ bool LoadFunctions(oslModule pODBCso) return rpFunc != nullptr; }; + // Optional functions for Unicode support + if (bUseWChar) + { + load(ODBC3SQLFunctionId::DriverConnectW, u"SQLDriverConnectW"_ustr); + load(ODBC3SQLFunctionId::GetInfoW, u"SQLGetInfoW"_ustr); + load(ODBC3SQLFunctionId::SetConnectAttrW, u"SQLSetConnectAttrW"_ustr); + load(ODBC3SQLFunctionId::GetConnectAttrW, u"SQLGetConnectAttrW"_ustr); + load(ODBC3SQLFunctionId::PrepareW, u"SQLPrepareW"_ustr); + load(ODBC3SQLFunctionId::SetCursorNameW, u"SQLSetCursorNameW"_ustr); + load(ODBC3SQLFunctionId::ExecDirectW, u"SQLExecDirectW"_ustr); + load(ODBC3SQLFunctionId::ColAttributeW, u"SQLColAttributeW"_ustr); + load(ODBC3SQLFunctionId::GetDiagRecW, u"SQLGetDiagRecW"_ustr); + load(ODBC3SQLFunctionId::ColumnPrivilegesW, u"SQLColumnPrivilegesW"_ustr); + load(ODBC3SQLFunctionId::ColumnsW, u"SQLColumnsW"_ustr); + load(ODBC3SQLFunctionId::ForeignKeysW, u"SQLForeignKeysW"_ustr); + load(ODBC3SQLFunctionId::PrimaryKeysW, u"SQLPrimaryKeysW"_ustr); + load(ODBC3SQLFunctionId::ProcedureColumnsW, u"SQLProcedureColumnsW"_ustr); + load(ODBC3SQLFunctionId::ProceduresW, u"SQLProceduresW"_ustr); + load(ODBC3SQLFunctionId::SpecialColumnsW, u"SQLSpecialColumnsW"_ustr); + load(ODBC3SQLFunctionId::StatisticsW, u"SQLStatisticsW"_ustr); + load(ODBC3SQLFunctionId::TablePrivilegesW, u"SQLTablePrivilegesW"_ustr); + load(ODBC3SQLFunctionId::TablesW, u"SQLTablesW"_ustr); + load(ODBC3SQLFunctionId::GetCursorNameW, u"SQLGetCursorNameW"_ustr); + load(ODBC3SQLFunctionId::NativeSqlW, u"SQLNativeSqlW"_ustr); + } + return load(ODBC3SQLFunctionId::AllocHandle, u"SQLAllocHandle"_ustr) && load(ODBC3SQLFunctionId::DriverConnect, u"SQLDriverConnect"_ustr) && load(ODBC3SQLFunctionId::GetInfo, u"SQLGetInfo"_ustr) @@ -329,6 +355,17 @@ public: StringLength2Ptr, DriverCompletion); } + SQLRETURN DriverConnectW(SQLHDBC ConnectionHandle, HWND WindowHandle, + SQLWCHAR* InConnectionString, SQLSMALLINT StringLength1, + SQLWCHAR* OutConnectionString, SQLSMALLINT BufferLength, + SQLSMALLINT* StringLength2Ptr, + SQLUSMALLINT DriverCompletion) const override + { + return ODBCFunc(ODBC3SQLFunctionId::DriverConnectW, ConnectionHandle, WindowHandle, + InConnectionString, StringLength1, OutConnectionString, BufferLength, + StringLength2Ptr, DriverCompletion); + } + SQLRETURN GetInfo(SQLHDBC ConnectionHandle, SQLUSMALLINT InfoType, SQLPOINTER InfoValuePtr, SQLSMALLINT BufferLength, SQLSMALLINT* StringLengthPtr) const override { @@ -336,6 +373,13 @@ public: BufferLength, StringLengthPtr); } + SQLRETURN GetInfoW(SQLHDBC ConnectionHandle, SQLUSMALLINT InfoType, SQLPOINTER InfoValuePtr, + SQLSMALLINT BufferLength, SQLSMALLINT* StringLengthPtr) const override + { + return ODBCFunc(ODBC3SQLFunctionId::GetInfoW, ConnectionHandle, InfoType, InfoValuePtr, + BufferLength, StringLengthPtr); + } + SQLRETURN GetFunctions(SQLHDBC ConnectionHandle, SQLUSMALLINT FunctionId, SQLUSMALLINT* SupportedPtr) const override { @@ -355,6 +399,13 @@ public: StringLength); } + SQLRETURN SetConnectAttrW(SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, + SQLINTEGER StringLength) const override + { + return ODBCFunc(ODBC3SQLFunctionId::SetConnectAttrW, ConnectionHandle, Attribute, ValuePtr, + StringLength); + } + SQLRETURN GetConnectAttr(SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER BufferLength, SQLINTEGER* StringLength) const override { @@ -362,6 +413,13 @@ public: BufferLength, StringLength); } + SQLRETURN GetConnectAttrW(SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, + SQLINTEGER BufferLength, SQLINTEGER* StringLength) const override + { + return ODBCFunc(ODBC3SQLFunctionId::GetConnectAttrW, ConnectionHandle, Attribute, ValuePtr, + BufferLength, StringLength); + } + SQLRETURN SetEnvAttr(SQLHENV EnvironmentHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength) const override { @@ -396,6 +454,12 @@ public: return ODBCFunc(ODBC3SQLFunctionId::Prepare, StatementHandle, StatementText, TextLength); } + SQLRETURN PrepareW(SQLHSTMT StatementHandle, SQLWCHAR* StatementText, + SQLINTEGER TextLength) const override + { + return ODBCFunc(ODBC3SQLFunctionId::PrepareW, StatementHandle, StatementText, TextLength); + } + SQLRETURN BindParameter(SQLHSTMT StatementHandle, SQLUSMALLINT ParameterNumber, SQLSMALLINT InputOutputType, SQLSMALLINT ValueType, SQLSMALLINT ParameterType, SQLULEN ColumnSize, @@ -413,6 +477,12 @@ public: return ODBCFunc(ODBC3SQLFunctionId::SetCursorName, StatementHandle, CursorName, NameLength); } + SQLRETURN SetCursorNameW(SQLHSTMT StatementHandle, SQLWCHAR* CursorName, + SQLSMALLINT NameLength) const override + { + return ODBCFunc(ODBC3SQLFunctionId::SetCursorNameW, StatementHandle, CursorName, NameLength); + } + SQLRETURN Execute(SQLHSTMT StatementHandle) const override { return ODBCFunc(ODBC3SQLFunctionId::Execute, StatementHandle); @@ -424,6 +494,12 @@ public: return ODBCFunc(ODBC3SQLFunctionId::ExecDirect, StatementHandle, StatementText, TextLength); } + SQLRETURN ExecDirectW(SQLHSTMT StatementHandle, SQLWCHAR* StatementText, + SQLINTEGER TextLength) const override + { + return ODBCFunc(ODBC3SQLFunctionId::ExecDirectW, StatementHandle, StatementText, TextLength); + } + SQLRETURN DescribeParam(SQLHSTMT StatementHandle, SQLUSMALLINT ParameterNumber, SQLSMALLINT* DataTypePtr, SQLULEN* ParameterSizePtr, SQLSMALLINT* DecimalDigitsPtr, SQLSMALLINT* NullablePtr) const override @@ -468,6 +544,16 @@ public: NumericAttributePtr); } + SQLRETURN ColAttributeW(SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, + SQLUSMALLINT FieldIdentifier, SQLPOINTER CharacterAttributePtr, + SQLSMALLINT BufferLength, SQLSMALLINT* StringLengthPtr, + SQLLEN* NumericAttributePtr) const override + { + return ODBCFunc(ODBC3SQLFunctionId::ColAttributeW, StatementHandle, ColumnNumber, + FieldIdentifier, CharacterAttributePtr, BufferLength, StringLengthPtr, + NumericAttributePtr); + } + SQLRETURN BindCol(SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLPOINTER TargetValuePtr, SQLLEN BufferLength, SQLLEN* StrLen_or_IndPtr) const override @@ -521,6 +607,14 @@ public: NativeErrorPtr, MessageText, BufferLength, TextLengthPtr); } + SQLRETURN GetDiagRecW(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMALLINT RecNumber, + SQLWCHAR* Sqlstate, SQLINTEGER* NativeErrorPtr, SQLWCHAR* MessageText, + SQLSMALLINT BufferLength, SQLSMALLINT* TextLengthPtr) const override + { + return ODBCFunc(ODBC3SQLFunctionId::GetDiagRecW, HandleType, Handle, RecNumber, Sqlstate, + NativeErrorPtr, MessageText, BufferLength, TextLengthPtr); + } + SQLRETURN ColumnPrivileges(SQLHSTMT StatementHandle, SQLCHAR* CatalogName, SQLSMALLINT NameLength1, SQLCHAR* SchemaName, SQLSMALLINT NameLength2, SQLCHAR* TableName, SQLSMALLINT NameLength3, @@ -531,6 +625,16 @@ public: NameLength4); } + SQLRETURN ColumnPrivilegesW(SQLHSTMT StatementHandle, SQLWCHAR* CatalogName, + SQLSMALLINT NameLength1, SQLWCHAR* SchemaName, + SQLSMALLINT NameLength2, SQLWCHAR* TableName, SQLSMALLINT NameLength3, + SQLWCHAR* ColumnName, SQLSMALLINT NameLength4) const override + { + return ODBCFunc(ODBC3SQLFunctionId::ColumnPrivilegesW, StatementHandle, CatalogName, + NameLength1, SchemaName, NameLength2, TableName, NameLength3, ColumnName, + NameLength4); + } + SQLRETURN Columns(SQLHSTMT StatementHandle, SQLCHAR* CatalogName, SQLSMALLINT NameLength1, SQLCHAR* SchemaName, SQLSMALLINT NameLength2, SQLCHAR* TableName, SQLSMALLINT NameLength3, SQLCHAR* ColumnName, @@ -540,6 +644,15 @@ public: SchemaName, NameLength2, TableName, NameLength3, ColumnName, NameLength4); } + SQLRETURN ColumnsW(SQLHSTMT StatementHandle, SQLWCHAR* CatalogName, SQLSMALLINT NameLength1, + SQLWCHAR* SchemaName, SQLSMALLINT NameLength2, SQLWCHAR* TableName, + SQLSMALLINT NameLength3, SQLWCHAR* ColumnName, + SQLSMALLINT NameLength4) const override + { + return ODBCFunc(ODBC3SQLFunctionId::ColumnsW, StatementHandle, CatalogName, NameLength1, + SchemaName, NameLength2, TableName, NameLength3, ColumnName, NameLength4); + } + SQLRETURN ForeignKeys(SQLHSTMT StatementHandle, SQLCHAR* PKCatalogName, SQLSMALLINT NameLength1, SQLCHAR* PKSchemaName, SQLSMALLINT NameLength2, SQLCHAR* PKTableName, SQLSMALLINT NameLength3, SQLCHAR* FKCatalogName, SQLSMALLINT NameLength4, @@ -552,6 +665,18 @@ public: NameLength6); } + SQLRETURN ForeignKeysW(SQLHSTMT StatementHandle, SQLWCHAR* PKCatalogName, SQLSMALLINT NameLength1, + SQLWCHAR* PKSchemaName, SQLSMALLINT NameLength2, SQLWCHAR* PKTableName, + SQLSMALLINT NameLength3, SQLWCHAR* FKCatalogName, SQLSMALLINT NameLength4, + SQLWCHAR* FKSchemaName, SQLSMALLINT NameLength5, SQLWCHAR* FKTableName, + SQLSMALLINT NameLength6) const override + { + return ODBCFunc(ODBC3SQLFunctionId::ForeignKeysW, StatementHandle, PKCatalogName, + NameLength1, PKSchemaName, NameLength2, PKTableName, NameLength3, + FKCatalogName, NameLength4, FKSchemaName, NameLength5, FKTableName, + NameLength6); + } + SQLRETURN PrimaryKeys(SQLHSTMT StatementHandle, SQLCHAR* CatalogName, SQLSMALLINT NameLength1, SQLCHAR* SchemaName, SQLSMALLINT NameLength2, SQLCHAR* TableName, SQLSMALLINT NameLength3) const override @@ -560,6 +685,14 @@ public: SchemaName, NameLength2, TableName, NameLength3); } + SQLRETURN PrimaryKeysW(SQLHSTMT StatementHandle, SQLWCHAR* CatalogName, SQLSMALLINT NameLength1, + SQLWCHAR* SchemaName, SQLSMALLINT NameLength2, SQLWCHAR* TableName, + SQLSMALLINT NameLength3) const override + { + return ODBCFunc(ODBC3SQLFunctionId::PrimaryKeysW, StatementHandle, CatalogName, NameLength1, + SchemaName, NameLength2, TableName, NameLength3); + } + SQLRETURN ProcedureColumns(SQLHSTMT StatementHandle, SQLCHAR* CatalogName, SQLSMALLINT NameLength1, SQLCHAR* SchemaName, SQLSMALLINT NameLength2, SQLCHAR* ProcName, SQLSMALLINT NameLength3, @@ -570,6 +703,16 @@ public: NameLength4); } + SQLRETURN ProcedureColumnsW(SQLHSTMT StatementHandle, SQLWCHAR* CatalogName, + SQLSMALLINT NameLength1, SQLWCHAR* SchemaName, + SQLSMALLINT NameLength2, SQLWCHAR* ProcName, SQLSMALLINT NameLength3, + SQLWCHAR* ColumnName, SQLSMALLINT NameLength4) const override + { + return ODBCFunc(ODBC3SQLFunctionId::ProcedureColumnsW, StatementHandle, CatalogName, + NameLength1, SchemaName, NameLength2, ProcName, NameLength3, ColumnName, + NameLength4); + } + SQLRETURN Procedures(SQLHSTMT StatementHandle, SQLCHAR* CatalogName, SQLSMALLINT NameLength1, SQLCHAR* SchemaName, SQLSMALLINT NameLength2, SQLCHAR* ProcName, SQLSMALLINT NameLength3) const override @@ -578,6 +721,14 @@ public: SchemaName, NameLength2, ProcName, NameLength3); } + SQLRETURN ProceduresW(SQLHSTMT StatementHandle, SQLWCHAR* CatalogName, SQLSMALLINT NameLength1, + SQLWCHAR* SchemaName, SQLSMALLINT NameLength2, SQLWCHAR* ProcName, + SQLSMALLINT NameLength3) const override + { + return ODBCFunc(ODBC3SQLFunctionId::ProceduresW, StatementHandle, CatalogName, NameLength1, + SchemaName, NameLength2, ProcName, NameLength3); + } + SQLRETURN SpecialColumns(SQLHSTMT StatementHandle, SQLUSMALLINT IdentifierType, SQLCHAR* CatalogName, SQLSMALLINT NameLength1, SQLCHAR* SchemaName, SQLSMALLINT NameLength2, SQLCHAR* TableName, SQLSMALLINT NameLength3, @@ -588,6 +739,16 @@ public: Scope, Nullable); } + SQLRETURN SpecialColumnsW(SQLHSTMT StatementHandle, SQLUSMALLINT IdentifierType, + SQLWCHAR* CatalogName, SQLSMALLINT NameLength1, SQLWCHAR* SchemaName, + SQLSMALLINT NameLength2, SQLWCHAR* TableName, SQLSMALLINT NameLength3, + SQLUSMALLINT Scope, SQLUSMALLINT Nullable) const override + { + return ODBCFunc(ODBC3SQLFunctionId::SpecialColumnsW, StatementHandle, IdentifierType, + CatalogName, NameLength1, SchemaName, NameLength2, TableName, NameLength3, + Scope, Nullable); + } + SQLRETURN Statistics(SQLHSTMT StatementHandle, SQLCHAR* CatalogName, SQLSMALLINT NameLength1, SQLCHAR* SchemaName, SQLSMALLINT NameLength2, SQLCHAR* TableName, SQLSMALLINT NameLength3, SQLUSMALLINT Unique, @@ -597,6 +758,15 @@ public: SchemaName, NameLength2, TableName, NameLength3, Unique, Reserved); } + SQLRETURN StatisticsW(SQLHSTMT StatementHandle, SQLWCHAR* CatalogName, SQLSMALLINT NameLength1, + SQLWCHAR* SchemaName, SQLSMALLINT NameLength2, SQLWCHAR* TableName, + SQLSMALLINT NameLength3, SQLUSMALLINT Unique, + SQLUSMALLINT Reserved) const override + { + return ODBCFunc(ODBC3SQLFunctionId::StatisticsW, StatementHandle, CatalogName, NameLength1, + SchemaName, NameLength2, TableName, NameLength3, Unique, Reserved); + } + SQLRETURN TablePrivileges(SQLHSTMT StatementHandle, SQLCHAR* CatalogName, SQLSMALLINT NameLength1, SQLCHAR* SchemaName, SQLSMALLINT NameLength2, SQLCHAR* TableName, SQLSMALLINT NameLength3) const override @@ -605,6 +775,14 @@ public: NameLength1, SchemaName, NameLength2, TableName, NameLength3); } + SQLRETURN TablePrivilegesW(SQLHSTMT StatementHandle, SQLWCHAR* CatalogName, + SQLSMALLINT NameLength1, SQLWCHAR* SchemaName, SQLSMALLINT NameLength2, + SQLWCHAR* TableName, SQLSMALLINT NameLength3) const override + { + return ODBCFunc(ODBC3SQLFunctionId::TablePrivilegesW, StatementHandle, CatalogName, + NameLength1, SchemaName, NameLength2, TableName, NameLength3); + } + SQLRETURN Tables(SQLHSTMT StatementHandle, SQLCHAR* CatalogName, SQLSMALLINT NameLength1, SQLCHAR* SchemaName, SQLSMALLINT NameLength2, SQLCHAR* TableName, SQLSMALLINT NameLength3, SQLCHAR* TableType, @@ -614,6 +792,15 @@ public: SchemaName, NameLength2, TableName, NameLength3, TableType, NameLength4); } + SQLRETURN TablesW(SQLHSTMT StatementHandle, SQLWCHAR* CatalogName, SQLSMALLINT NameLength1, + SQLWCHAR* SchemaName, SQLSMALLINT NameLength2, SQLWCHAR* TableName, + SQLSMALLINT NameLength3, SQLWCHAR* TableType, + SQLSMALLINT NameLength4) const override + { + return ODBCFunc(ODBC3SQLFunctionId::TablesW, StatementHandle, CatalogName, NameLength1, + SchemaName, NameLength2, TableName, NameLength3, TableType, NameLength4); + } + SQLRETURN FreeStmt(SQLHSTMT StatementHandle, SQLUSMALLINT Option) const override { return ODBCFunc(ODBC3SQLFunctionId::FreeStmt, StatementHandle, Option); @@ -652,6 +839,13 @@ public: BufferLength, NameLength2); } + SQLRETURN GetCursorNameW(SQLHSTMT StatementHandle, SQLWCHAR* CursorName, SQLSMALLINT BufferLength, + SQLSMALLINT* NameLength2) const override + { + return ODBCFunc(ODBC3SQLFunctionId::GetCursorNameW, StatementHandle, CursorName, + BufferLength, NameLength2); + } + SQLRETURN NativeSql(SQLHDBC ConnectionHandle, SQLCHAR* InStatementText, SQLINTEGER TextLength1, SQLCHAR* OutStatementText, SQLINTEGER BufferLength, SQLINTEGER* TextLength2Ptr) const override @@ -660,6 +854,14 @@ public: TextLength1, OutStatementText, BufferLength, TextLength2Ptr); } + SQLRETURN NativeSqlW(SQLHDBC ConnectionHandle, SQLWCHAR* InStatementText, SQLINTEGER TextLength1, + SQLWCHAR* OutStatementText, SQLINTEGER BufferLength, + SQLINTEGER* TextLength2Ptr) const override + { + return ODBCFunc(ODBC3SQLFunctionId::NativeSqlW, ConnectionHandle, InStatementText, + TextLength1, OutStatementText, BufferLength, TextLength2Ptr); + } + protected: virtual SQLHANDLE EnvironmentHandle() override; diff --git a/connectivity/source/drivers/odbc/OPreparedStatement.cxx b/connectivity/source/drivers/odbc/OPreparedStatement.cxx index 1537ede5f6fe..c73f210ddd9e 100644 --- a/connectivity/source/drivers/odbc/OPreparedStatement.cxx +++ b/connectivity/source/drivers/odbc/OPreparedStatement.cxx @@ -47,14 +47,6 @@ using namespace com::sun::star::util; IMPLEMENT_SERVICE_INFO(OPreparedStatement,u"com.sun.star.sdbcx.OPreparedStatement"_ustr,u"com.sun.star.sdbc.PreparedStatement"_ustr); -namespace -{ - // for now, never use wchar, - // but most of code is prepared to handle it - // in case we make this configurable - const bool bUseWChar = false; -} - OPreparedStatement::OPreparedStatement( OConnection* _pConnection,const OUString& sql) :OStatement_BASE2(_pConnection) ,numParams(0) @@ -314,36 +306,21 @@ void OPreparedStatement::setParameter(const sal_Int32 parameterIndex, const sal_ * * Our internal OUString storage is always UTF-16, so no conversion to do here. */ - static_assert(sizeof (SQLWCHAR) == 2 || sizeof (SQLWCHAR) == 4, "must be 2 or 4"); - if (sizeof (SQLWCHAR) == 2) - { - nCharLen = _sData.getLength(); - nByteLen = 2 * nCharLen; - pData = allocBindBuf(parameterIndex, nByteLen); - memcpy(pData, _sData.getStr(), nByteLen); - } - else - { - pData = allocBindBuf(parameterIndex, _sData.getLength() * 4); - sal_uInt32* pCursor = static_cast<sal_uInt32*>(pData); - nCharLen = 0; - for (sal_Int32 i = 0; i != _sData.getLength();) - { - *pCursor++ = _sData.iterateCodePoints(&i); - nCharLen += 1; - } - nByteLen = 4 * nCharLen; - } + SQLWChars data(_sData); + nCharLen = data.cch(); + nByteLen = data.cb(); + pData = allocBindBuf(parameterIndex, nByteLen); + memcpy(pData, data.get(), nByteLen); } else { assert(getOwnConnection()->getTextEncoding() != RTL_TEXTENCODING_UCS2 && getOwnConnection()->getTextEncoding() != RTL_TEXTENCODING_UCS4); - OString sOData( - OUStringToOString(_sData, getOwnConnection()->getTextEncoding())); - nCharLen = nByteLen = sOData.getLength(); + SQLChars data(_sData, getOwnConnection()->getTextEncoding()); + nCharLen = data.cch(); + nByteLen = data.cb(); pData = allocBindBuf(parameterIndex, nByteLen); - memcpy(pData, sOData.getStr(), nByteLen); + memcpy(pData, data.get(), nByteLen); } setParameter( parameterIndex, _nType, nCharLen, _nScale, pData, nByteLen, nByteLen ); @@ -367,7 +344,7 @@ void OPreparedStatement::setParameter(const sal_Int32 parameterIndex, const sal_ void OPreparedStatement::setParameter(const sal_Int32 parameterIndex, const sal_Int32 _nType, const SQLULEN _nColumnSize, const sal_Int32 _nScale, const void* const _pData, const SQLULEN _nDataLen, const SQLLEN _nDataAllocLen) { SQLSMALLINT fCType, fSqlType; - OTools::getBindTypes(bUseWChar, m_pConnection->useOldDateFormat(), OTools::jdbcTypeToOdbc(_nType), fCType, fSqlType); + OTools::getBindTypes(m_pConnection->useOldDateFormat(), OTools::jdbcTypeToOdbc(_nType), fCType, fSqlType); SQLLEN& rDataLen = boundParams[parameterIndex-1].getBindLengthBuffer(); rDataLen = _nDataLen; @@ -507,8 +484,7 @@ void SAL_CALL OPreparedStatement::setNull( sal_Int32 parameterIndex, const sal_I SQLSMALLINT fCType; SQLSMALLINT fSqlType; - OTools::getBindTypes( bUseWChar, - m_pConnection->useOldDateFormat(), + OTools::getBindTypes( m_pConnection->useOldDateFormat(), OTools::jdbcTypeToOdbc(_nType), fCType, fSqlType); @@ -819,7 +795,7 @@ void OPreparedStatement::setStream( *lenBuf = SQL_LEN_DATA_AT_EXEC (length); SQLSMALLINT fCType, fSqlType; - OTools::getBindTypes(bUseWChar, m_pConnection->useOldDateFormat(), OTools::jdbcTypeToOdbc(_nType), fCType, fSqlType); + OTools::getBindTypes(m_pConnection->useOldDateFormat(), OTools::jdbcTypeToOdbc(_nType), fCType, fSqlType); OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); @@ -882,8 +858,17 @@ void OPreparedStatement::prepareStatement() if(!isPrepared()) { OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); - OString aSql(OUStringToOString(m_sSqlStatement,getOwnConnection()->getTextEncoding())); - SQLRETURN nReturn = functions().Prepare(m_aStatementHandle, reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(aSql.getStr())), aSql.getLength()); + SQLRETURN nReturn; + if (bUseWChar && functions().has(ODBC3SQLFunctionId::PrepareW)) + { + SQLWChars aSql(m_sSqlStatement); + nReturn = functions().PrepareW(m_aStatementHandle, aSql.get(), aSql.cch()); + } + else + { + SQLChars aSql(m_sSqlStatement, getOwnConnection()->getTextEncoding()); + nReturn = functions().Prepare(m_aStatementHandle, aSql.get(), aSql.cch()); + } OTools::ThrowException(m_pConnection.get(),nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this); m_bPrepared = true; initBoundParam(); diff --git a/connectivity/source/drivers/odbc/OResultSet.cxx b/connectivity/source/drivers/odbc/OResultSet.cxx index 696df003254e..ca669491165e 100644 --- a/connectivity/source/drivers/odbc/OResultSet.cxx +++ b/connectivity/source/drivers/odbc/OResultSet.cxx @@ -31,6 +31,7 @@ #include <cppuhelper/typeprovider.hxx> #include <cppuhelper/supportsservice.hxx> #include <comphelper/types.hxx> +#include <comphelper/scopeguard.hxx> #include <connectivity/dbtools.hxx> #include <connectivity/dbexception.hxx> #include <o3tl/safeint.hxx> @@ -55,11 +56,77 @@ static_assert(ODBC_SQL_NOT_DEFINED != SQL_UB_ON, "ODBC_SQL_NOT_DEFINED must be u static_assert(ODBC_SQL_NOT_DEFINED != SQL_UB_FIXED, "ODBC_SQL_NOT_DEFINED must be unique"); static_assert(ODBC_SQL_NOT_DEFINED != SQL_UB_VARIABLE, "ODBC_SQL_NOT_DEFINED must be unique"); +class connectivity::odbc::BindData +{ +public: + virtual void* data() = 0; + virtual SQLLEN len() const = 0; + + virtual ~BindData() {} +}; + namespace { - const SQLLEN nMaxBookmarkLen = 20; -} +const SQLLEN nMaxBookmarkLen = 20; + +template <typename T> class SimpleBindData : public connectivity::odbc::BindData +{ +public: + SimpleBindData(const void* p) + : value(*static_cast<const T*>(p)) + { + } + void* data() override { return &value; } + SQLLEN len() const override { return sizeof(T); } +private: + T value; +}; + +template <class CHARS_t> class CharsBindData : public connectivity::odbc::BindData +{ +public: + template <typename... Args> + CharsBindData(const void* p, Args... args) + : value(*static_cast<const OUString*>(p), args...) + { + } + template <class S> requires std::is_class_v<S> + CharsBindData(const S& val) + : value(val) + { + } + void* data() override { return value.get(); } + SQLLEN len() const override { return value.cch(); } + +private: + CHARS_t value; +}; + +class NullBindData : public connectivity::odbc::BindData +{ +public: + void* data() override { return &value; } + SQLLEN len() const override { return SQL_NULL_DATA; } + +private: + char value[2] = {}; +}; + +class BinaryBindData : public connectivity::odbc::BindData +{ +public: + BinaryBindData(const void* p) + : value(*static_cast<const css::uno::Sequence<sal_Int8>*>(p)) + { + } + void* data() override { return const_cast<sal_Int8*>(value.getConstArray()); } + SQLLEN len() const override { return value.getLength(); } + +private: + css::uno::Sequence<sal_Int8> value; // ref-counted CoW +}; +} // IMPLEMENT_SERVICE_INFO(OResultSet,"com.sun.star.sdbcx.OResultSet","com.sun.star.sdbc.ResultSet"); OUString SAL_CALL OResultSet::getImplementationName( ) @@ -180,135 +247,17 @@ void OResultSet::disposing() m_xMetaData.clear(); } +// See OResultSet::updateValue SQLRETURN OResultSet::unbind(bool _bUnbindHandle) { SQLRETURN nRet = 0; if ( _bUnbindHandle ) nRet = functions().FreeStmt(m_aStatementHandle,SQL_UNBIND); - if ( !m_aBindVector.empty() ) - { - for(auto& [rPtrAddr, rType] : m_aBindVector) - { - switch (rType) - { - case DataType::CHAR: - case DataType::VARCHAR: - delete static_cast< OString* >(reinterpret_cast< void * >(rPtrAddr)); - break; - case DataType::BIGINT: - delete static_cast< sal_Int64* >(reinterpret_cast< void * >(rPtrAddr)); - break; - case DataType::DECIMAL: - case DataType::NUMERIC: - delete static_cast< OString* >(reinterpret_cast< void * >(rPtrAddr)); - break; - case DataType::REAL: - case DataType::DOUBLE: - delete static_cast< double* >(reinterpret_cast< void * >(rPtrAddr)); - break; - case DataType::LONGVARCHAR: - case DataType::CLOB: - delete [] static_cast< char* >(reinterpret_cast< void * >(rPtrAddr)); - break; - case DataType::LONGVARBINARY: - case DataType::BLOB: - delete [] static_cast< char* >(reinterpret_cast< void * >(rPtrAddr)); - break; - case DataType::DATE: - delete static_cast< DATE_STRUCT* >(reinterpret_cast< void * >(rPtrAddr)); - break; - case DataType::TIME: - delete static_cast< TIME_STRUCT* >(reinterpret_cast< void * >(rPtrAddr)); - break; - case DataType::TIMESTAMP: - delete static_cast< TIMESTAMP_STRUCT* >(reinterpret_cast< void * >(rPtrAddr)); - break; - case DataType::BIT: - case DataType::TINYINT: - delete static_cast< sal_Int8* >(reinterpret_cast< void * >(rPtrAddr)); - break; - case DataType::SMALLINT: - delete static_cast< sal_Int16* >(reinterpret_cast< void * >(rPtrAddr)); - break; - case DataType::INTEGER: - delete static_cast< sal_Int32* >(reinterpret_cast< void * >(rPtrAddr)); - break; - case DataType::FLOAT: - delete static_cast< float* >(reinterpret_cast< void * >(rPtrAddr)); - break; - case DataType::BINARY: - case DataType::VARBINARY: - delete static_cast< sal_Int8* >(reinterpret_cast< void * >(rPtrAddr)); - break; - } - } - m_aBindVector.clear(); - } + m_aBindVector.clear(); return nRet; } -TVoidPtr OResultSet::allocBindColumn(sal_Int32 _nType,sal_Int32 _nColumnIndex) -{ - TVoidPtr aPair; - switch (_nType) - { - case DataType::CHAR: - case DataType::VARCHAR: - aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new OString()),_nType); - break; - case DataType::BIGINT: - aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int64(0)),_nType); - break; - case DataType::DECIMAL: - case DataType::NUMERIC: - aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new OString()),_nType); - break; - case DataType::REAL: - case DataType::DOUBLE: - aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new double(0.0)),_nType); - break; - case DataType::LONGVARCHAR: - case DataType::CLOB: - aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new char[2]),_nType); // only for finding - break; - case DataType::LONGVARBINARY: - case DataType::BLOB: - aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new char[2]),_nType); // only for finding - break; - case DataType::DATE: - aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new DATE_STRUCT),_nType); - break; - case DataType::TIME: - aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new TIME_STRUCT),_nType); - break; - case DataType::TIMESTAMP: - aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new TIMESTAMP_STRUCT),_nType); - break; - case DataType::BIT: - case DataType::TINYINT: - aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int8(0)),_nType); - break; - case DataType::SMALLINT: - aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int16(0)),_nType); - break; - case DataType::INTEGER: - aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int32(0)),_nType); - break; - case DataType::FLOAT: - aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new float(0)),_nType); - break; - case DataType::BINARY: - case DataType::VARBINARY: - aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int8[m_aRow[_nColumnIndex].getSequence().getLength()]),_nType); - break; - default: - SAL_WARN( "connectivity.odbc", "Unknown type"); - aPair = TVoidPtr(0,_nType); - } - return aPair; -} - void OResultSet::allocBuffer() { Reference< XResultSetMetaData > xMeta = getMetaData(); @@ -852,18 +801,9 @@ void SAL_CALL OResultSet::insertRow( ) fillNeededData( nRet ); } aBookmark.realloc(nRealLen); - try - { - OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this); - } - catch(const SQLException&) - { - nRet = unbind(); - throw; - } - - nRet = unbind(); + SQLRETURN nRet2 = unbind(); OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this); + OTools::ThrowException(m_pStatement->getOwnConnection(),nRet2,m_aStatementHandle,SQL_HANDLE_STMT,*this); if ( bPositionByBookmark ) { @@ -996,30 +936,115 @@ void OResultSet::updateValue(sal_Int32 columnIndex, SQLSMALLINT _nType, void con ::osl::MutexGuard aGuard( m_aMutex ); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - m_aBindVector.push_back(allocBindColumn(OTools::MapOdbcType2Jdbc(_nType),columnIndex)); - void* pData = reinterpret_cast<void*>(m_aBindVector.rbegin()->first); - OSL_ENSURE(pData != nullptr,"Data for update is NULL!"); - OTools::bindValue( m_pStatement->getOwnConnection(), - m_aStatementHandle, - columnIndex, - _nType, - 0, - _pValue, - pData, - &m_aLengthVector[columnIndex], - **this, - m_nTextEncoding, - m_pStatement->getOwnConnection()->useOldDateFormat()); + SQLSMALLINT fCType, dummy; + OTools::getBindTypes(m_pStatement->getOwnConnection()->useOldDateFormat(), _nType, fCType, + dummy); + + SQLLEN* const pLen = &m_aLengthVector[columnIndex]; + *pLen = 0; + std::unique_ptr<BindData> bindData; + void* pData = nullptr; + + if (columnIndex != 0 && !_pValue) + { + bindData = std::make_unique<NullBindData>(); + } + else + { + assert(_pValue); + + switch (_nType) + { + case SQL_CHAR: + case SQL_VARCHAR: + case SQL_WCHAR: + case SQL_WVARCHAR: + if (fCType == SQL_C_CHAR) + bindData = std::make_unique<CharsBindData<SQLChars>>(_pValue, m_nTextEncoding); + else + bindData = std::make_unique<CharsBindData<SQLWChars>>(_pValue); + break; + case SQL_DECIMAL: + case SQL_NUMERIC: + if (fCType == SQL_C_CHAR) + bindData = std::make_unique<CharsBindData<SQLChars>>( + OString::number(*static_cast<const double*>(_pValue))); + else + bindData = std::make_unique<CharsBindData<SQLWChars>>( + OUString::number(*static_cast<const double*>(_pValue))); + break; + case SQL_BIT: + case SQL_TINYINT: + bindData = std::make_unique<SimpleBindData<sal_Int8>>(_pValue); + break; + case SQL_SMALLINT: + bindData = std::make_unique<SimpleBindData<sal_Int16>>(_pValue); + break; + case SQL_INTEGER: + bindData = std::make_unique<SimpleBindData<sal_Int32>>(_pValue); + break; + case SQL_BIGINT: + bindData = std::make_unique<SimpleBindData<sal_Int64>>(_pValue); + break; + case SQL_FLOAT: + bindData = std::make_unique<SimpleBindData<float>>(_pValue); + break; + case SQL_REAL: + case SQL_DOUBLE: + bindData = std::make_unique<SimpleBindData<double>>(_pValue); + break; + case SQL_BINARY: + case SQL_VARBINARY: + bindData = std::make_unique<BinaryBindData>(_pValue); + break; + case SQL_LONGVARBINARY: + { + /* see https://msdn.microsoft.com/en-us/library/ms716238%28v=vs.85%29.aspx + * for an explanation of that apparently weird cast */ + pData = reinterpret_cast<void*>(static_cast<sal_uIntPtr>(columnIndex)); + sal_Int32 nLen + = static_cast<const css::uno::Sequence<sal_Int8>*>(_pValue)->getLength(); + *pLen = SQL_LEN_DATA_AT_EXEC(nLen); + } + break; + case SQL_LONGVARCHAR: + case SQL_WLONGVARCHAR: + { + /* see https://msdn.microsoft.com/en-us/library/ms716238%28v=vs.85%29.aspx + * for an explanation of that apparently weird cast */ + pData = reinterpret_cast<void*>(static_cast<sal_uIntPtr>(columnIndex)); + sal_Int32 nLen = static_cast<const OUString*>(_pValue)->getLength(); + *pLen = SQL_LEN_DATA_AT_EXEC(nLen); + } + break; + case SQL_DATE: + bindData = std::make_unique<SimpleBindData<DATE_STRUCT>>(_pValue); + break; + case SQL_TIME: + bindData = std::make_unique<SimpleBindData<TIME_STRUCT>>(_pValue); + break; + case SQL_TIMESTAMP: + bindData = std::make_unique<SimpleBindData<TIMESTAMP_STRUCT>>(_pValue); + break; + } + } + + if (bindData) + { + pData = bindData->data(); + *pLen = bindData->len(); + m_aBindVector.push_back(std::move(bindData)); + } + + SQLRETURN nRetcode + = functions().BindCol(m_aStatementHandle, columnIndex, fCType, pData, 0, pLen); + OTools::ThrowException(m_pStatement->getOwnConnection(), nRetcode, m_aStatementHandle, + SQL_HANDLE_STMT, **this); } void SAL_CALL OResultSet::updateNull( sal_Int32 columnIndex ) { - ::osl::MutexGuard aGuard( m_aMutex ); - checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - - m_aBindVector.push_back(allocBindColumn(DataType::CHAR,columnIndex)); - void* pData = reinterpret_cast<void*>(m_aBindVector.rbegin()->first); - OTools::bindValue(m_pStatement->getOwnConnection(),m_aStatementHandle,columnIndex,SQL_CHAR,0,nullptr,pData,&m_aLengthVector[columnIndex],**this,m_nTextEncoding,m_pStatement->getOwnConnection()->useOldDateFormat()); + updateValue(columnIndex, SQL_CHAR, nullptr); } @@ -1320,10 +1345,19 @@ sal_Int32 OResultSet::getFetchSize() const OUString OResultSet::getCursorName() const { - SQLCHAR pName[258]; SQLSMALLINT nRealLen = 0; - functions().GetCursorName(m_aStatementHandle,pName,256,&nRealLen); - return OUString::createFromAscii(reinterpret_cast<char*>(pName)); + if (bUseWChar && functions().has(ODBC3SQLFunctionId::GetCursorNameW)) + { + SQLWCHAR pName[258]{}; + functions().GetCursorNameW(m_aStatementHandle, pName, 256, &nRealLen); + return toUString(pName, nRealLen); + } + else + { + SQLCHAR pName[258]{}; + functions().GetCursorName(m_aStatementHandle, pName, 256, &nRealLen); + return toUString(pName); + } } bool OResultSet::isBookmarkable() const @@ -1793,16 +1827,15 @@ void OResultSet::fillNeededData(SQLRETURN _nRet) break; case SQL_WLONGVARCHAR: { - OUString const & sRet = m_aRow[nColumnIndex].getString(); - functions().PutData (m_aStatementHandle, static_cast<SQLPOINTER>(const_cast<sal_Unicode *>(sRet.getStr())), sizeof(sal_Unicode)*sRet.getLength()); + SQLWChars data(m_aRow[nColumnIndex].getString()); + functions().PutData(m_aStatementHandle, data.get(), data.cb()); break; } case DataType::LONGVARCHAR: case DataType::CLOB: { - OUString sRet = m_aRow[nColumnIndex].getString(); - OString aString(OUStringToOString(sRet,m_nTextEncoding)); - functions().PutData (m_aStatementHandle, static_cast<SQLPOINTER>(const_cast<char *>(aString.getStr())), aString.getLength()); + SQLChars data(m_aRow[nColumnIndex].getString(), m_nTextEncoding); + functions().PutData(m_aStatementHandle, data.get(), data.cb()); break; } default: diff --git a/connectivity/source/drivers/odbc/OResultSetMetaData.cxx b/connectivity/source/drivers/odbc/OResultSetMetaData.cxx index 8448e7bd6ee9..260c2111fbfc 100644 --- a/connectivity/source/drivers/odbc/OResultSetMetaData.cxx +++ b/connectivity/source/drivers/odbc/OResultSetMetaData.cxx @@ -35,40 +35,77 @@ OUString OResultSetMetaData::getCharColAttrib(sal_Int32 _column,sal_Int32 ident) if(_column <static_cast<sal_Int32>(m_vMapping.size())) // use mapping column = m_vMapping[_column]; - SQLSMALLINT BUFFER_LEN = 128; - std::unique_ptr<char[]> pName(new char[BUFFER_LEN+1]); - SQLSMALLINT nRealLen=0; - SQLRETURN nRet = functions().ColAttribute(m_aStatementHandle, - static_cast<SQLUSMALLINT>(column), - static_cast<SQLUSMALLINT>(ident), - static_cast<SQLPOINTER>(pName.get()), - BUFFER_LEN, - &nRealLen, - nullptr - ); OUString sValue; - if ( nRet == SQL_SUCCESS ) + SQLSMALLINT cbRealLen = 0; + if (bUseWChar && functions().has(ODBC3SQLFunctionId::ColAttributeW)) { - if ( nRealLen < 0 ) - nRealLen = BUFFER_LEN; - sValue = OUString(pName.get(),nRealLen,m_pConnection->getTextEncoding()); + // SQLColAttributeW gets/returns count of bytes, not characters + SQLSMALLINT cbBufferLen = 128 * sizeof(SQLWCHAR); + auto pName = std::make_unique<SQLWCHAR[]>(cbBufferLen / sizeof(SQLWCHAR) + 1); + SQLRETURN nRet = functions().ColAttributeW(m_aStatementHandle, + column, + ident, + pName.get(), + cbBufferLen, + &cbRealLen, + nullptr); + OTools::ThrowException(m_pConnection, nRet, m_aStatementHandle, SQL_HANDLE_STMT, *this); + if (nRet == SQL_SUCCESS) + { + if (cbRealLen < 0) + cbRealLen = cbBufferLen; + sValue = toUString(pName.get(), cbRealLen / sizeof(SQLWCHAR)); + } + if (cbRealLen > cbBufferLen) + { + cbBufferLen = (cbRealLen + 1) & ~1; // Make sure it's even + pName = std::make_unique<SQLWCHAR[]>(cbBufferLen / sizeof(SQLWCHAR) + 1); + nRet = functions().ColAttributeW(m_aStatementHandle, + column, + ident, + pName.get(), + cbBufferLen, + &cbRealLen, + nullptr); + OTools::ThrowException(m_pConnection, nRet, m_aStatementHandle, SQL_HANDLE_STMT, *this); + if (nRet == SQL_SUCCESS && cbRealLen > 0) + sValue = toUString(pName.get(), cbRealLen / sizeof(SQLWCHAR)); + } } - pName.reset(); - OTools::ThrowException(m_pConnection,nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this); - if(nRealLen > BUFFER_LEN) + else { - pName.reset(new char[nRealLen+1]); - nRet = functions().ColAttribute(m_aStatementHandle, - static_cast<SQLUSMALLINT>(column), - static_cast<SQLUSMALLINT>(ident), - static_cast<SQLPOINTER>(pName.get()), - nRealLen, - &nRealLen, - nullptr - ); - if ( nRet == SQL_SUCCESS && nRealLen > 0) - sValue = OUString(pName.get(),nRealLen,m_pConnection->getTextEncoding()); + SQLSMALLINT BUFFER_LEN = 128; + auto pName = std::make_unique<SQLCHAR[]>(BUFFER_LEN + 1); + SQLRETURN nRet = functions().ColAttribute(m_aStatementHandle, + static_cast<SQLUSMALLINT>(column), + static_cast<SQLUSMALLINT>(ident), + static_cast<SQLPOINTER>(pName.get()), + BUFFER_LEN, + &cbRealLen, + nullptr + ); + if ( nRet == SQL_SUCCESS ) + { + if ( cbRealLen < 0 ) + cbRealLen = BUFFER_LEN; + sValue = toUString(pName.get(), cbRealLen, m_pConnection->getTextEncoding()); + } OTools::ThrowException(m_pConnection,nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this); + if(cbRealLen > BUFFER_LEN) + { + pName = std::make_unique<SQLCHAR[]>(cbRealLen + 1); + nRet = functions().ColAttribute(m_aStatementHandle, + static_cast<SQLUSMALLINT>(column), + static_cast<SQLUSMALLINT>(ident), + static_cast<SQLPOINTER>(pName.get()), + cbRealLen, + &cbRealLen, + nullptr + ); + if ( nRet == SQL_SUCCESS && cbRealLen > 0) + sValue = toUString(pName.get(), cbRealLen, m_pConnection->getTextEncoding()); + OTools::ThrowException(m_pConnection,nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this); + } } return sValue; @@ -143,11 +180,10 @@ sal_Int32 SAL_CALL OResultSetMetaData::getColumnType( sal_Int32 column ) catch(SQLException& ) // in this case we have an odbc 2.0 driver { m_bUseODBC2Types = true; - nType = OTools::MapOdbcType2Jdbc(getNumColAttrib(column,SQL_DESC_CONCISE_TYPE )); } } - else - nType = OTools::MapOdbcType2Jdbc(getNumColAttrib(column,SQL_DESC_CONCISE_TYPE )); + if (m_bUseODBC2Types) + nType = OTools::MapOdbcType2Jdbc(getNumColAttrib(column, SQL_DESC_CONCISE_TYPE)); aFind = m_aColumnTypes.emplace(column,nType).first; } @@ -230,30 +266,38 @@ sal_Bool SAL_CALL OResultSetMetaData::isSigned( sal_Int32 column ) sal_Int32 SAL_CALL OResultSetMetaData::getPrecision( sal_Int32 column ) { sal_Int32 nType = 0; - try - { - nType = getNumColAttrib(column,SQL_DESC_PRECISION); - } - catch(const SQLException& ) // in this case we have an odbc 2.0 driver + if (!m_bUseODBC2Types) { - m_bUseODBC2Types = true; - nType = getNumColAttrib(column,SQL_COLUMN_PRECISION ); + try + { + nType = getNumColAttrib(column, SQL_DESC_PRECISION); + } + catch (const SQLException&) // in this case we have an odbc 2.0 driver + { + m_bUseODBC2Types = true; + } } + if (m_bUseODBC2Types) + nType = getNumColAttrib(column, SQL_COLUMN_PRECISION); return nType; } sal_Int32 SAL_CALL OResultSetMetaData::getScale( sal_Int32 column ) { sal_Int32 nType = 0; -e ... etc. - the rest is truncated