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

Reply via email to