diff --git a/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt b/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt index 449db0fedf43..2017fa512bf5 100644 --- a/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt +++ b/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt @@ -32,6 +32,8 @@ else() set(ODBCINST odbcinst) endif() +add_definitions(-DUNICODE=1) + add_subdirectory(flight_sql) add_subdirectory(odbcabstraction) add_subdirectory(tests) diff --git a/cpp/src/arrow/flight/sql/odbc/entry_points.cc b/cpp/src/arrow/flight/sql/odbc/entry_points.cc index ef6aa2e5fd00..b397631992f5 100644 --- a/cpp/src/arrow/flight/sql/odbc/entry_points.cc +++ b/cpp/src/arrow/flight/sql/odbc/entry_points.cc @@ -61,20 +61,20 @@ SQLRETURN SQL_API SQLFreeStmt(SQLHSTMT stmt, SQLUSMALLINT option) { return arrow::SQLFreeStmt(stmt, option); } -SQLRETURN SQL_API SQLGetDiagFieldW(SQLSMALLINT handleType, SQLHANDLE handle, - SQLSMALLINT recNumber, SQLSMALLINT diagIdentifier, - SQLPOINTER diagInfoPtr, SQLSMALLINT bufferLength, - SQLSMALLINT* stringLengthPtr) { - return arrow::SQLGetDiagFieldW(handleType, handle, recNumber, diagIdentifier, - diagInfoPtr, bufferLength, stringLengthPtr); +SQLRETURN SQL_API SQLGetDiagField(SQLSMALLINT handleType, SQLHANDLE handle, + SQLSMALLINT recNumber, SQLSMALLINT diagIdentifier, + SQLPOINTER diagInfoPtr, SQLSMALLINT bufferLength, + SQLSMALLINT* stringLengthPtr) { + return arrow::SQLGetDiagField(handleType, handle, recNumber, diagIdentifier, + diagInfoPtr, bufferLength, stringLengthPtr); } -SQLRETURN SQL_API SQLGetDiagRecW(SQLSMALLINT handleType, SQLHANDLE handle, - SQLSMALLINT recNumber, SQLWCHAR* sqlState, - SQLINTEGER* nativeErrorPtr, SQLWCHAR* messageText, - SQLSMALLINT bufferLength, SQLSMALLINT* textLengthPtr) { - return arrow::SQLGetDiagRecW(handleType, handle, recNumber, sqlState, nativeErrorPtr, - messageText, bufferLength, textLengthPtr); +SQLRETURN SQL_API SQLGetDiagRec(SQLSMALLINT handleType, SQLHANDLE handle, + SQLSMALLINT recNumber, SQLWCHAR* sqlState, + SQLINTEGER* nativeErrorPtr, SQLWCHAR* messageText, + SQLSMALLINT bufferLength, SQLSMALLINT* textLengthPtr) { + return arrow::SQLGetDiagRec(handleType, handle, recNumber, sqlState, nativeErrorPtr, + messageText, bufferLength, textLengthPtr); } SQLRETURN SQL_API SQLGetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER valuePtr, @@ -87,36 +87,35 @@ SQLRETURN SQL_API SQLSetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER valuePt return arrow::SQLSetEnvAttr(env, attr, valuePtr, strLen); } -SQLRETURN SQL_API SQLSetConnectAttrW(SQLHDBC conn, SQLINTEGER attr, SQLPOINTER value, - SQLINTEGER valueLen) { +SQLRETURN SQL_API SQLSetConnectAttr(SQLHDBC conn, SQLINTEGER attr, SQLPOINTER value, + SQLINTEGER valueLen) { LOG_DEBUG("SQLSetConnectAttrW called with conn: {}, attr: {}, value: {}, valueLen: {}", conn, attr, value, valueLen); return SQL_ERROR; } -SQLRETURN SQL_API SQLGetInfoW(SQLHDBC conn, SQLUSMALLINT infoType, - SQLPOINTER infoValuePtr, SQLSMALLINT bufLen, - SQLSMALLINT* length) { - return arrow::SQLGetInfoW(conn, infoType, infoValuePtr, bufLen, length); +SQLRETURN SQL_API SQLGetInfo(SQLHDBC conn, SQLUSMALLINT infoType, SQLPOINTER infoValuePtr, + SQLSMALLINT bufLen, SQLSMALLINT* length) { + return arrow::SQLGetInfo(conn, infoType, infoValuePtr, bufLen, length); } -SQLRETURN SQL_API SQLDriverConnectW(SQLHDBC conn, SQLHWND windowHandle, - SQLWCHAR* inConnectionString, - SQLSMALLINT inConnectionStringLen, - SQLWCHAR* outConnectionString, - SQLSMALLINT outConnectionStringBufferLen, - SQLSMALLINT* outConnectionStringLen, - SQLUSMALLINT driverCompletion) { - return arrow::SQLDriverConnectW( +SQLRETURN SQL_API SQLDriverConnect(SQLHDBC conn, SQLHWND windowHandle, + SQLWCHAR* inConnectionString, + SQLSMALLINT inConnectionStringLen, + SQLWCHAR* outConnectionString, + SQLSMALLINT outConnectionStringBufferLen, + SQLSMALLINT* outConnectionStringLen, + SQLUSMALLINT driverCompletion) { + return arrow::SQLDriverConnect( conn, windowHandle, inConnectionString, inConnectionStringLen, outConnectionString, outConnectionStringBufferLen, outConnectionStringLen, driverCompletion); } -SQLRETURN SQL_API SQLConnectW(SQLHDBC conn, SQLWCHAR* dsnName, SQLSMALLINT dsnNameLen, - SQLWCHAR* userName, SQLSMALLINT userNameLen, - SQLWCHAR* password, SQLSMALLINT passwordLen) { - return arrow::SQLConnectW(conn, dsnName, dsnNameLen, userName, userNameLen, password, - passwordLen); +SQLRETURN SQL_API SQLConnect(SQLHDBC conn, SQLWCHAR* dsnName, SQLSMALLINT dsnNameLen, + SQLWCHAR* userName, SQLSMALLINT userNameLen, + SQLWCHAR* password, SQLSMALLINT passwordLen) { + return arrow::SQLConnect(conn, dsnName, dsnNameLen, userName, userNameLen, password, + passwordLen); } SQLRETURN SQL_API SQLDisconnect(SQLHDBC conn) { return arrow::SQLDisconnect(conn); } @@ -142,11 +141,11 @@ SQLRETURN SQL_API SQLCloseCursor(SQLHSTMT statementHandle) { return SQL_ERROR; } -SQLRETURN SQL_API SQLColAttributeW(SQLHSTMT statementHandle, SQLUSMALLINT columnNumber, - SQLUSMALLINT fieldIdentifier, - SQLPOINTER characterAttributePtr, - SQLSMALLINT bufferLength, SQLSMALLINT* stringLengthPtr, - SQLLEN* numericAttributePtr) { +SQLRETURN SQL_API SQLColAttribute(SQLHSTMT statementHandle, SQLUSMALLINT columnNumber, + SQLUSMALLINT fieldIdentifier, + SQLPOINTER characterAttributePtr, + SQLSMALLINT bufferLength, SQLSMALLINT* stringLengthPtr, + SQLLEN* numericAttributePtr) { LOG_DEBUG( "SQLColAttributeW called with statementHandle: {}, columnNumber: {}, " "fieldIdentifier: {}, characterAttributePtr: {}, bufferLength: {}, " @@ -156,11 +155,11 @@ SQLRETURN SQL_API SQLColAttributeW(SQLHSTMT statementHandle, SQLUSMALLINT column return SQL_ERROR; } -SQLRETURN SQL_API SQLColumnsW(SQLHSTMT statementHandle, SQLWCHAR* catalogName, - SQLSMALLINT catalogNameLength, SQLWCHAR* schemaName, - SQLSMALLINT schemaNameLength, SQLWCHAR* tableName, - SQLSMALLINT tableNameLength, SQLWCHAR* columnName, - SQLSMALLINT columnNameLength) { +SQLRETURN SQL_API SQLColumns(SQLHSTMT statementHandle, SQLWCHAR* catalogName, + SQLSMALLINT catalogNameLength, SQLWCHAR* schemaName, + SQLSMALLINT schemaNameLength, SQLWCHAR* tableName, + SQLSMALLINT tableNameLength, SQLWCHAR* columnName, + SQLSMALLINT columnNameLength) { LOG_DEBUG( "SQLColumnsW called with statementHandle: {}, catalogName: {}, catalogNameLength: " "{}, " @@ -173,10 +172,10 @@ SQLRETURN SQL_API SQLColumnsW(SQLHSTMT statementHandle, SQLWCHAR* catalogName, return SQL_ERROR; } -SQLRETURN SQL_API SQLErrorW(SQLHENV handleType, SQLHDBC handle, SQLHSTMT hstmt, - SQLWCHAR FAR* szSqlState, SQLINTEGER FAR* pfNativeError, - SQLWCHAR FAR* szErrorMsg, SQLSMALLINT cbErrorMsgMax, - SQLSMALLINT FAR* pcbErrorMsg) { +SQLRETURN SQL_API SQLError(SQLHENV handleType, SQLHDBC handle, SQLHSTMT hstmt, + SQLWCHAR FAR* szSqlState, SQLINTEGER FAR* pfNativeError, + SQLWCHAR FAR* szErrorMsg, SQLSMALLINT cbErrorMsgMax, + SQLSMALLINT FAR* pcbErrorMsg) { LOG_DEBUG( "SQLErrorW called with handleType: {}, handle: {}, hstmt: {}, szSqlState: {}, " "pfNativeError: {}, szErrorMsg: {}, cbErrorMsgMax: {}, pcbErrorMsg: {}", @@ -185,8 +184,8 @@ SQLRETURN SQL_API SQLErrorW(SQLHENV handleType, SQLHDBC handle, SQLHSTMT hstmt, return SQL_ERROR; } -SQLRETURN SQL_API SQLExecDirectW(SQLHSTMT statementHandle, SQLWCHAR* statementText, - SQLINTEGER textLength) { +SQLRETURN SQL_API SQLExecDirect(SQLHSTMT statementHandle, SQLWCHAR* statementText, + SQLINTEGER textLength) { LOG_DEBUG( "SQLExecDirectW called with statementHandle: {}, statementText: {}, textLength: {}", statementHandle, fmt::ptr(statementText), textLength); @@ -203,13 +202,13 @@ SQLRETURN SQL_API SQLFetch(SQLHSTMT statementHandle) { return SQL_ERROR; } -SQLRETURN SQL_API SQLForeignKeysW(SQLHSTMT statementHandle, SQLWCHAR* pKCatalogName, - SQLSMALLINT pKCatalogNameLength, SQLWCHAR* pKSchemaName, - SQLSMALLINT pKSchemaNameLength, SQLWCHAR* pKTableName, - SQLSMALLINT pKTableNameLength, SQLWCHAR* fKCatalogName, - SQLSMALLINT fKCatalogNameLength, SQLWCHAR* fKSchemaName, - SQLSMALLINT fKSchemaNameLength, SQLWCHAR* fKTableName, - SQLSMALLINT fKTableNameLength) { +SQLRETURN SQL_API SQLForeignKeys(SQLHSTMT statementHandle, SQLWCHAR* pKCatalogName, + SQLSMALLINT pKCatalogNameLength, SQLWCHAR* pKSchemaName, + SQLSMALLINT pKSchemaNameLength, SQLWCHAR* pKTableName, + SQLSMALLINT pKTableNameLength, SQLWCHAR* fKCatalogName, + SQLSMALLINT fKCatalogNameLength, SQLWCHAR* fKSchemaName, + SQLSMALLINT fKSchemaNameLength, SQLWCHAR* fKTableName, + SQLSMALLINT fKTableNameLength) { LOG_DEBUG( "SQLForeignKeysW called with statementHandle: {}, pKCatalogName: {}, " "pKCatalogNameLength: " @@ -226,9 +225,9 @@ SQLRETURN SQL_API SQLForeignKeysW(SQLHSTMT statementHandle, SQLWCHAR* pKCatalogN return SQL_ERROR; } -SQLRETURN SQL_API SQLGetConnectAttrW(SQLHDBC connectionHandle, SQLINTEGER attribute, - SQLPOINTER valuePtr, SQLINTEGER bufferLength, - SQLINTEGER* stringLengthPtr) { +SQLRETURN SQL_API SQLGetConnectAttr(SQLHDBC connectionHandle, SQLINTEGER attribute, + SQLPOINTER valuePtr, SQLINTEGER bufferLength, + SQLINTEGER* stringLengthPtr) { LOG_DEBUG( "SQLGetConnectAttrW called with connectionHandle: {}, attribute: {}, valuePtr: {}, " "bufferLength: {}, stringLengthPtr: {}", @@ -247,9 +246,9 @@ SQLRETURN SQL_API SQLGetData(SQLHSTMT statementHandle, SQLUSMALLINT col_or_Param return SQL_ERROR; } -SQLRETURN SQL_API SQLGetStmtAttrW(SQLHSTMT statementHandle, SQLINTEGER attribute, - SQLPOINTER valuePtr, SQLINTEGER bufferLength, - SQLINTEGER* stringLengthPtr) { +SQLRETURN SQL_API SQLGetStmtAttr(SQLHSTMT statementHandle, SQLINTEGER attribute, + SQLPOINTER valuePtr, SQLINTEGER bufferLength, + SQLINTEGER* stringLengthPtr) { LOG_DEBUG( "SQLGetStmtAttrW called with statementHandle: {}, attribute: {}, valuePtr: {}, " "bufferLength: {}, stringLengthPtr: {}", @@ -257,7 +256,7 @@ SQLRETURN SQL_API SQLGetStmtAttrW(SQLHSTMT statementHandle, SQLINTEGER attribute return SQL_ERROR; } -SQLRETURN SQL_API SQLGetTypeInfoW(SQLHSTMT statementHandle, SQLSMALLINT dataType) { +SQLRETURN SQL_API SQLGetTypeInfo(SQLHSTMT statementHandle, SQLSMALLINT dataType) { LOG_DEBUG("SQLGetTypeInfoW called with statementHandle: {} dataType: {}", statementHandle, dataType); return SQL_ERROR; @@ -268,10 +267,10 @@ SQLRETURN SQL_API SQLMoreResults(SQLHSTMT statementHandle) { return SQL_ERROR; } -SQLRETURN SQL_API SQLNativeSqlW(SQLHDBC connectionHandle, SQLWCHAR* inStatementText, - SQLINTEGER inStatementTextLength, - SQLWCHAR* outStatementText, SQLINTEGER bufferLength, - SQLINTEGER* outStatementTextLength) { +SQLRETURN SQL_API SQLNativeSql(SQLHDBC connectionHandle, SQLWCHAR* inStatementText, + SQLINTEGER inStatementTextLength, + SQLWCHAR* outStatementText, SQLINTEGER bufferLength, + SQLINTEGER* outStatementTextLength) { LOG_DEBUG( "SQLNativeSqlW called with connectionHandle: {}, inStatementText: {}, " "inStatementTextLength: " @@ -288,18 +287,18 @@ SQLRETURN SQL_API SQLNumResultCols(SQLHSTMT statementHandle, return SQL_ERROR; } -SQLRETURN SQL_API SQLPrepareW(SQLHSTMT statementHandle, SQLWCHAR* statementText, - SQLINTEGER textLength) { +SQLRETURN SQL_API SQLPrepare(SQLHSTMT statementHandle, SQLWCHAR* statementText, + SQLINTEGER textLength) { LOG_DEBUG( "SQLPrepareW called with statementHandle: {}, statementText: {}, textLength: {}", statementHandle, fmt::ptr(statementText), textLength); return SQL_ERROR; } -SQLRETURN SQL_API SQLPrimaryKeysW(SQLHSTMT statementHandle, SQLWCHAR* catalogName, - SQLSMALLINT catalogNameLength, SQLWCHAR* schemaName, - SQLSMALLINT schemaNameLength, SQLWCHAR* tableName, - SQLSMALLINT tableNameLength) { +SQLRETURN SQL_API SQLPrimaryKeys(SQLHSTMT statementHandle, SQLWCHAR* catalogName, + SQLSMALLINT catalogNameLength, SQLWCHAR* schemaName, + SQLSMALLINT schemaNameLength, SQLWCHAR* tableName, + SQLSMALLINT tableNameLength) { LOG_DEBUG( "SQLPrimaryKeysW called with statementHandle: {}, catalogName: {}, " "catalogNameLength: " @@ -309,8 +308,8 @@ SQLRETURN SQL_API SQLPrimaryKeysW(SQLHSTMT statementHandle, SQLWCHAR* catalogNam return SQL_ERROR; } -SQLRETURN SQL_API SQLSetStmtAttrW(SQLHSTMT statementHandle, SQLINTEGER attribute, - SQLPOINTER valuePtr, SQLINTEGER stringLength) { +SQLRETURN SQL_API SQLSetStmtAttr(SQLHSTMT statementHandle, SQLINTEGER attribute, + SQLPOINTER valuePtr, SQLINTEGER stringLength) { LOG_DEBUG( "SQLSetStmtAttrW called with statementHandle: {}, attribute: {}, valuePtr: {}, " "stringLength: {}", @@ -318,11 +317,11 @@ SQLRETURN SQL_API SQLSetStmtAttrW(SQLHSTMT statementHandle, SQLINTEGER attribute return SQL_ERROR; } -SQLRETURN SQL_API SQLTablesW(SQLHSTMT statementHandle, SQLWCHAR* catalogName, - SQLSMALLINT catalogNameLength, SQLWCHAR* schemaName, - SQLSMALLINT schemaNameLength, SQLWCHAR* tableName, - SQLSMALLINT tableNameLength, SQLWCHAR* tableType, - SQLSMALLINT tableTypeLength) { +SQLRETURN SQL_API SQLTables(SQLHSTMT statementHandle, SQLWCHAR* catalogName, + SQLSMALLINT catalogNameLength, SQLWCHAR* schemaName, + SQLSMALLINT schemaNameLength, SQLWCHAR* tableName, + SQLSMALLINT tableNameLength, SQLWCHAR* tableType, + SQLSMALLINT tableTypeLength) { LOG_DEBUG( "SQLTablesW called with statementHandle: {}, catalogName: {}, catalogNameLength: " "{}, " diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/config/configuration.cc b/cpp/src/arrow/flight/sql/odbc/flight_sql/config/configuration.cc index 7cebebe56eb9..db18239c47a1 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/config/configuration.cc +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/config/configuration.cc @@ -17,6 +17,8 @@ #include "arrow/flight/sql/odbc/flight_sql/include/flight_sql/config/configuration.h" #include "arrow/flight/sql/odbc/flight_sql/flight_sql_connection.h" +#include "arrow/result.h" +#include "arrow/util/utf8.h" #include #include @@ -27,7 +29,6 @@ namespace driver { namespace flight_sql { namespace config { - static const char DEFAULT_DSN[] = "Apache Arrow Flight SQL"; static const char DEFAULT_ENABLE_ENCRYPTION[] = TRUE_STR; static const char DEFAULT_USE_CERT_STORE[] = TRUE_STR; @@ -36,19 +37,27 @@ static const char DEFAULT_DISABLE_CERT_VERIFICATION[] = FALSE_STR; namespace { std::string ReadDsnString(const std::string& dsn, const std::string_view& key, const std::string& dflt = "") { + std::wstring wDsn = arrow::util::UTF8ToWideString(dsn).ValueOr(L""); + std::wstring wKey = arrow::util::UTF8ToWideString(key).ValueOr(L""); + std::wstring wDflt = arrow::util::UTF8ToWideString(dflt).ValueOr(L""); + #define BUFFER_SIZE (1024) - std::vector buf(BUFFER_SIZE); - int ret = SQLGetPrivateProfileString(dsn.c_str(), key.data(), dflt.c_str(), buf.data(), - static_cast(buf.size()), "ODBC.INI"); + std::vector buf(BUFFER_SIZE); + int ret = + SQLGetPrivateProfileString(wDsn.c_str(), wKey.c_str(), wDflt.c_str(), buf.data(), + static_cast(buf.size()), L"ODBC.INI"); if (ret > BUFFER_SIZE) { // If there wasn't enough space, try again with the right size buffer. buf.resize(ret + 1); - ret = SQLGetPrivateProfileString(dsn.c_str(), key.data(), dflt.c_str(), buf.data(), - static_cast(buf.size()), "ODBC.INI"); + ret = + SQLGetPrivateProfileString(wDsn.c_str(), wKey.c_str(), wDflt.c_str(), buf.data(), + static_cast(buf.size()), L"ODBC.INI"); } - return std::string(buf.data(), ret); + std::wstring wResult = std::wstring(buf.data(), ret); + std::string result = arrow::util::WideStringToUTF8(wResult).ValueOr(""); + return result; } void RemoveAllKnownKeys(std::vector& keys) { @@ -65,28 +74,32 @@ void RemoveAllKnownKeys(std::vector& keys) { } std::vector ReadAllKeys(const std::string& dsn) { - std::vector buf(BUFFER_SIZE); + std::wstring wDsn = arrow::util::UTF8ToWideString(dsn).ValueOr(L""); + + std::vector buf(BUFFER_SIZE); - int ret = SQLGetPrivateProfileString(dsn.c_str(), NULL, "", buf.data(), - static_cast(buf.size()), "ODBC.INI"); + int ret = SQLGetPrivateProfileString(wDsn.c_str(), NULL, L"", buf.data(), + static_cast(buf.size()), L"ODBC.INI"); if (ret > BUFFER_SIZE) { // If there wasn't enough space, try again with the right size buffer. buf.resize(ret + 1); - ret = SQLGetPrivateProfileString(dsn.c_str(), NULL, "", buf.data(), - static_cast(buf.size()), "ODBC.INI"); + ret = SQLGetPrivateProfileString(wDsn.c_str(), NULL, L"", buf.data(), + static_cast(buf.size()), L"ODBC.INI"); } // When you pass NULL to SQLGetPrivateProfileString it gives back a \0 delimited list of // all the keys. The below loop simply tokenizes all the keys and places them into a // vector. std::vector keys; - char* begin = buf.data(); + wchar_t* begin = buf.data(); while (begin && *begin != '\0') { - char* cur; + wchar_t* cur; for (cur = begin; *cur != '\0'; ++cur) { } - keys.emplace_back(begin, cur); + + std::string key = arrow::util::WideStringToUTF8(std::wstring(begin, cur)).ValueOr(""); + keys.emplace_back(key); begin = ++cur; } return keys; @@ -150,6 +163,11 @@ const std::string& Configuration::Get(const std::string_view& key) const { return itr->second; } +void Configuration::Set(const std::string_view& key, const std::wstring& wValue) { + std::string value = arrow::util::WideStringToUTF8(wValue).ValueOr(""); + Set(key, value); +} + void Configuration::Set(const std::string_view& key, const std::string& value) { const std::string copy = boost::trim_copy(value); if (!copy.empty()) { diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_connection.cc b/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_connection.cc index 422316a9f8bf..6d5d95865ba6 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_connection.cc +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_connection.cc @@ -83,7 +83,7 @@ namespace { #if _WIN32 || _WIN64 constexpr auto SYSTEM_TRUST_STORE_DEFAULT = true; -constexpr auto STORES = {"CA", "MY", "ROOT", "SPC"}; +constexpr auto STORES = {L"CA", L"MY", L"ROOT", L"SPC"}; inline std::string GetCerts() { std::string certs; diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/config/configuration.h b/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/config/configuration.h index 8c4d68655051..c94cc5b78328 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/config/configuration.h +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/config/configuration.h @@ -52,6 +52,7 @@ class Configuration { void Clear(); bool IsSet(const std::string_view& key) const; const std::string& Get(const std::string_view& key) const; + void Set(const std::string_view& key, const std::wstring& wValue); void Set(const std::string_view& key, const std::string& value); void Emplace(const std::string_view& key, std::string&& value); /** diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/ui/add_property_window.h b/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/ui/add_property_window.h index 01d93829a46b..b7a8016447c1 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/ui/add_property_window.h +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/ui/add_property_window.h @@ -70,7 +70,7 @@ class AddPropertyWindow : public CustomWindow { * * @return true if the dialog was OK'd, false otherwise. */ - bool GetProperty(std::string& key, std::string& value); + bool GetProperty(std::wstring& key, std::wstring& value); private: /** @@ -97,9 +97,9 @@ class AddPropertyWindow : public CustomWindow { std::unique_ptr valueEdit; - std::string key; + std::wstring key; - std::string value; + std::wstring value; /** Window width. */ int width; diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/ui/custom_window.h b/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/ui/custom_window.h index 0fc3737ed8bc..649f0ef6547b 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/ui/custom_window.h +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/ui/custom_window.h @@ -65,7 +65,7 @@ class CustomWindow : public Window { * @param className Window class name. * @param title Window title. */ - CustomWindow(Window* parent, const char* className, const char* title); + CustomWindow(Window* parent, const wchar_t* className, const wchar_t* title); /** * Destructor. diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/ui/window.h b/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/ui/window.h index e56ad88dec65..596ff47c577a 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/ui/window.h +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/ui/window.h @@ -44,7 +44,7 @@ class Window { * @param className Window class name. * @param title Window title. */ - Window(Window* parent, const char* className, const char* title); + Window(Window* parent, const wchar_t* className, const wchar_t* title); /** * Constructor for the existing window. @@ -102,7 +102,7 @@ class Window { * @return Auto pointer containing new window. */ std::unique_ptr CreateGroupBox(int posX, int posY, int sizeX, int sizeY, - const char* title, int id); + const wchar_t* title, int id); /** * Create child label window. @@ -116,7 +116,7 @@ class Window { * @return Auto pointer containing new window. */ std::unique_ptr CreateLabel(int posX, int posY, int sizeX, int sizeY, - const char* title, int id); + const wchar_t* title, int id); /** * Create child Edit window. @@ -131,7 +131,7 @@ class Window { * @return Auto pointer containing new window. */ std::unique_ptr CreateEdit(int posX, int posY, int sizeX, int sizeY, - const char* title, int id, int style = 0); + const wchar_t* title, int id, int style = 0); /** * Create child button window. @@ -146,7 +146,7 @@ class Window { * @return Auto pointer containing new window. */ std::unique_ptr CreateButton(int posX, int posY, int sizeX, int sizeY, - const char* title, int id, int style = 0); + const wchar_t* title, int id, int style = 0); /** * Create child CheckBox window. @@ -161,7 +161,7 @@ class Window { * @return Auto pointer containing new window. */ std::unique_ptr CreateCheckBox(int posX, int posY, int sizeX, int sizeY, - const char* title, int id, bool state); + const wchar_t* title, int id, bool state); /** * Create child ComboBox window. @@ -175,7 +175,7 @@ class Window { * @return Auto pointer containing new window. */ std::unique_ptr CreateComboBox(int posX, int posY, int sizeX, int sizeY, - const char* title, int id); + const wchar_t* title, int id); /** * Show window. @@ -201,15 +201,15 @@ class Window { void SetVisible(bool isVisible); - void ListAddColumn(const std::string& name, int index, int width); + void ListAddColumn(const std::wstring& name, int index, int width); - void ListAddItem(const std::vector& items); + void ListAddItem(const std::vector& items); void ListDeleteSelectedItem(); - std::vector > ListGetAll(); + std::vector > ListGetAll(); - void AddTab(const std::string& name, int index); + void AddTab(const std::wstring& name, int index); bool IsTextEmpty() const; @@ -218,14 +218,14 @@ class Window { * * @param text Text. */ - void GetText(std::string& text) const; + void GetText(std::wstring& text) const; /** * Set window text. * * @param text Text. */ - void SetText(const std::string& text) const; + void SetText(const std::wstring& text) const; /** * Get CheckBox state. @@ -246,7 +246,7 @@ class Window { * * @param str String. */ - void AddString(const std::string& str); + void AddString(const std::wstring& str); /** * Set current ComboBox selection. @@ -285,10 +285,10 @@ class Window { void SetHandle(HWND value) { handle = value; } /** Window class name. */ - std::string className; + std::wstring className; /** Window title. */ - std::string title; + std::wstring title; /** Window handle. */ HWND handle; diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/system_dsn.cc b/cpp/src/arrow/flight/sql/odbc/flight_sql/system_dsn.cc index 95b47bdb1e2b..f0006b36c9a4 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/system_dsn.cc +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/system_dsn.cc @@ -19,6 +19,8 @@ #include "arrow/flight/sql/odbc/flight_sql/flight_sql_connection.h" #include "arrow/flight/sql/odbc/flight_sql/include/flight_sql/config/configuration.h" +#include "arrow/result.h" +#include "arrow/util/utf8.h" #include #include @@ -29,14 +31,14 @@ using driver::flight_sql::config::Configuration; void PostLastInstallerError() { #define BUFFER_SIZE (1024) DWORD code; - char msg[BUFFER_SIZE]; + wchar_t msg[BUFFER_SIZE]; SQLInstallerError(1, &code, msg, BUFFER_SIZE, NULL); - std::stringstream buf; - buf << "Message: \"" << msg << "\", Code: " << code; - std::string errorMsg = buf.str(); + std::wstringstream buf; + buf << L"Message: \"" << msg << L"\", Code: " << code; + std::wstring errorMsg = buf.str(); - MessageBox(NULL, errorMsg.c_str(), "Error!", MB_ICONEXCLAMATION | MB_OK); + MessageBox(NULL, errorMsg.c_str(), L"Error!", MB_ICONEXCLAMATION | MB_OK); SQLPostInstallerError(code, errorMsg.c_str()); } @@ -46,7 +48,7 @@ void PostLastInstallerError() { * @param dsn DSN name. * @return True on success and false on fail. */ -bool UnregisterDsn(const std::string& dsn) { +bool UnregisterDsn(const std::wstring& dsn) { if (SQLRemoveDSNFromIni(dsn.c_str())) { return true; } @@ -62,10 +64,11 @@ bool UnregisterDsn(const std::string& dsn) { * @param driver Driver. * @return True on success and false on fail. */ -bool RegisterDsn(const Configuration& config, LPCSTR driver) { +bool RegisterDsn(const Configuration& config, LPCWSTR driver) { const std::string& dsn = config.Get(FlightSqlConnection::DSN); + std::wstring wDsn = arrow::util::UTF8ToWideString(dsn).ValueOr(L""); - if (!SQLWriteDSNToIni(dsn.c_str(), driver)) { + if (!SQLWriteDSNToIni(wDsn.c_str(), driver)) { PostLastInstallerError(); return false; } @@ -78,8 +81,10 @@ bool RegisterDsn(const Configuration& config, LPCSTR driver) { continue; } - if (!SQLWritePrivateProfileString(dsn.c_str(), key.data(), it->second.c_str(), - "ODBC.INI")) { + std::wstring wKey = arrow::util::UTF8ToWideString(key).ValueOr(L""); + std::wstring wValue = arrow::util::UTF8ToWideString(it->second).ValueOr(L""); + if (!SQLWritePrivateProfileString(wDsn.c_str(), wKey.c_str(), wValue.c_str(), + L"ODBC.INI")) { PostLastInstallerError(); return false; } diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/system_dsn.h b/cpp/src/arrow/flight/sql/odbc/flight_sql/system_dsn.h index f3744d3428a7..1ac9b4d9b804 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/system_dsn.h +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/system_dsn.h @@ -54,7 +54,7 @@ bool DisplayConnectionWindow(void* windowParent, Configuration& config, * @param driver Driver. * @return True on success and false on fail. */ -bool RegisterDsn(const Configuration& config, LPCSTR driver); +bool RegisterDsn(const Configuration& config, LPCWSTR driver); /** * Unregister specified DSN. @@ -62,4 +62,4 @@ bool RegisterDsn(const Configuration& config, LPCSTR driver); * @param dsn DSN name. * @return True on success and false on fail. */ -bool UnregisterDsn(const std::string& dsn); +bool UnregisterDsn(const std::wstring& dsn); diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/system_trust_store.cc b/cpp/src/arrow/flight/sql/odbc/flight_sql/system_trust_store.cc index 67db1fc35be6..ebc8fd90adf8 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/system_trust_store.cc +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/system_trust_store.cc @@ -15,6 +15,9 @@ // specific language governing permissions and limitations // under the License. +#include "arrow/result.h" +#include "arrow/util/utf8.h" + #include "arrow/flight/sql/odbc/flight_sql/system_trust_store.h" #if defined _WIN32 || defined _WIN64 @@ -32,18 +35,20 @@ std::string SystemTrustStore::GetNext() const { CryptBinaryToString(p_context_->pbCertEncoded, p_context_->cbCertEncoded, CRYPT_STRING_BASE64HEADER, nullptr, &size); - std::string cert; - cert.resize(size); + std::wstring wCert; + wCert.resize(size); CryptBinaryToString(p_context_->pbCertEncoded, p_context_->cbCertEncoded, - CRYPT_STRING_BASE64HEADER, &cert[0], &size); - cert.resize(size); + CRYPT_STRING_BASE64HEADER, &wCert[0], &size); + wCert.resize(size); + + std::string cert = arrow::util::WideStringToUTF8(wCert).ValueOr(""); return cert; } bool SystemTrustStore::SystemHasStore() { return h_store_ != nullptr; } -SystemTrustStore::SystemTrustStore(const char* store) +SystemTrustStore::SystemTrustStore(const wchar_t* store) : stores_(store), h_store_(CertOpenSystemStore(NULL, store)), p_context_(nullptr) {} SystemTrustStore::~SystemTrustStore() { diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/system_trust_store.h b/cpp/src/arrow/flight/sql/odbc/flight_sql/system_trust_store.h index f8e02fea5262..0ff3adc2f482 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/system_trust_store.h +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/system_trust_store.h @@ -41,12 +41,12 @@ namespace flight_sql { /// https://github.com/apache/drill/blob/master/contrib/native/client/src/clientlib/wincert.ipp. class SystemTrustStore { private: - const char* stores_; + const wchar_t* stores_; HCERTSTORE h_store_; PCCERT_CONTEXT p_context_; public: - explicit SystemTrustStore(const char* store); + explicit SystemTrustStore(const wchar_t* store); ~SystemTrustStore(); diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/ui/add_property_window.cc b/cpp/src/arrow/flight/sql/odbc/flight_sql/ui/add_property_window.cc index 75aa491f781b..15799c1f9a28 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/ui/add_property_window.cc +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/ui/add_property_window.cc @@ -33,7 +33,7 @@ namespace flight_sql { namespace config { AddPropertyWindow::AddPropertyWindow(Window* parent) - : CustomWindow(parent, "AddProperty", "Add Property"), + : CustomWindow(parent, L"AddProperty", L"Add Property"), width(300), height(120), accepted(false), @@ -69,7 +69,7 @@ void AddPropertyWindow::Create() { } } -bool AddPropertyWindow::GetProperty(std::string& key, std::string& value) { +bool AddPropertyWindow::GetProperty(std::wstring& key, std::wstring& value) { if (accepted) { key = this->key; value = this->value; @@ -87,10 +87,10 @@ void AddPropertyWindow::OnCreate() { int cancelPosX = width - MARGIN - BUTTON_WIDTH; int okPosX = cancelPosX - INTERVAL - BUTTON_WIDTH; - okButton = CreateButton(okPosX, groupPosY, BUTTON_WIDTH, BUTTON_HEIGHT, "Ok", + okButton = CreateButton(okPosX, groupPosY, BUTTON_WIDTH, BUTTON_HEIGHT, L"Ok", ChildId::OK_BUTTON, BS_DEFPUSHBUTTON); cancelButton = CreateButton(cancelPosX, groupPosY, BUTTON_WIDTH, BUTTON_HEIGHT, - "Cancel", ChildId::CANCEL_BUTTON); + L"Cancel", ChildId::CANCEL_BUTTON); isInitialized = true; CheckEnableOk(); } @@ -104,15 +104,15 @@ int AddPropertyWindow::CreateEdits(int posX, int posY, int sizeX) { int rowPos = posY; labels.push_back( - CreateLabel(posX, rowPos, LABEL_WIDTH, ROW_HEIGHT, "Key:", ChildId::KEY_LABEL)); - keyEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, "", ChildId::KEY_EDIT); + CreateLabel(posX, rowPos, LABEL_WIDTH, ROW_HEIGHT, L"Key:", ChildId::KEY_LABEL)); + keyEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, L"", ChildId::KEY_EDIT); rowPos += INTERVAL + ROW_HEIGHT; - labels.push_back( - CreateLabel(posX, rowPos, LABEL_WIDTH, ROW_HEIGHT, "Value:", ChildId::VALUE_LABEL)); + labels.push_back(CreateLabel(posX, rowPos, LABEL_WIDTH, ROW_HEIGHT, L"Value:", + ChildId::VALUE_LABEL)); valueEdit = - CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, "", ChildId::VALUE_EDIT); + CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, L"", ChildId::VALUE_EDIT); rowPos += INTERVAL + ROW_HEIGHT; diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/ui/custom_window.cc b/cpp/src/arrow/flight/sql/odbc/flight_sql/ui/custom_window.cc index 8f660a21329c..bde7967c7e99 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/ui/custom_window.cc +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/ui/custom_window.cc @@ -84,7 +84,7 @@ LRESULT CALLBACK CustomWindow::WndProc(HWND hwnd, UINT msg, WPARAM wParam, return DefWindowProc(hwnd, msg, wParam, lParam); } -CustomWindow::CustomWindow(Window* parent, const char* className, const char* title) +CustomWindow::CustomWindow(Window* parent, const wchar_t* className, const wchar_t* title) : Window(parent, className, title) { WNDCLASS wcx; diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/ui/dsn_configuration_window.cc b/cpp/src/arrow/flight/sql/odbc/flight_sql/ui/dsn_configuration_window.cc index e469b6b067f2..58bf9d37b485 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/ui/dsn_configuration_window.cc +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/ui/dsn_configuration_window.cc @@ -15,8 +15,11 @@ // specific language governing permissions and limitations // under the License. -#include "arrow/flight/sql/odbc/flight_sql/include/flight_sql/ui/dsn_configuration_window.h" +#include "arrow/result.h" +#include "arrow/util/utf8.h" + #include "arrow/flight/sql/odbc/flight_sql/flight_sql_connection.h" +#include "arrow/flight/sql/odbc/flight_sql/include/flight_sql/ui/dsn_configuration_window.h" #include #include @@ -55,7 +58,7 @@ namespace config { DsnConfigurationWindow::DsnConfigurationWindow(Window* parent, config::Configuration& config) - : CustomWindow(parent, "FlightConfigureDSN", "Configure Apache Arrow Flight SQL"), + : CustomWindow(parent, L"FlightConfigureDSN", L"Configure Apache Arrow Flight SQL"), width(480), height(375), config(config), @@ -91,11 +94,11 @@ void DsnConfigurationWindow::Create() { throw odbcabstraction::DriverException(buf.str()); } } - +//-AL- fix this file next void DsnConfigurationWindow::OnCreate() { tabControl = CreateTabControl(ChildId::TAB_CONTROL); - tabControl->AddTab("Common", COMMON_TAB); - tabControl->AddTab("Advanced", ADVANCED_TAB); + tabControl->AddTab(L"Common", COMMON_TAB); + tabControl->AddTab(L"Advanced", ADVANCED_TAB); int groupPosY = 3 * MARGIN; int groupSizeY = width - 2 * MARGIN; @@ -118,11 +121,11 @@ void DsnConfigurationWindow::OnCreate() { int buttonPosY = std::max(commonGroupPosY, advancedGroupPosY); testButton = CreateButton(testPosX, buttonPosY, BUTTON_WIDTH + 20, BUTTON_HEIGHT, - "Test Connection", ChildId::TEST_CONNECTION_BUTTON); - okButton = CreateButton(okPosX, buttonPosY, BUTTON_WIDTH, BUTTON_HEIGHT, "Ok", + L"Test Connection", ChildId::TEST_CONNECTION_BUTTON); + okButton = CreateButton(okPosX, buttonPosY, BUTTON_WIDTH, BUTTON_HEIGHT, L"Ok", ChildId::OK_BUTTON); cancelButton = CreateButton(cancelPosX, buttonPosY, BUTTON_WIDTH, BUTTON_HEIGHT, - "Cancel", ChildId::CANCEL_BUTTON); + L"Cancel", ChildId::CANCEL_BUTTON); isInitialized = true; CheckEnableOk(); SelectTab(COMMON_TAB); @@ -138,31 +141,35 @@ int DsnConfigurationWindow::CreateConnectionSettingsGroup(int posX, int posY, in int rowPos = posY + 2 * INTERVAL; - const char* val = config.Get(FlightSqlConnection::DSN).c_str(); + std::string val = config.Get(FlightSqlConnection::DSN); + std::wstring wVal = arrow::util::UTF8ToWideString(val).ValueOr(L""); labels.push_back(CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT, - "Data Source Name:", ChildId::NAME_LABEL)); - nameEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, val, ChildId::NAME_EDIT); + L"Data Source Name:", ChildId::NAME_LABEL)); + nameEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, wVal.c_str(), + ChildId::NAME_EDIT); rowPos += INTERVAL + ROW_HEIGHT; - val = config.Get(FlightSqlConnection::HOST).c_str(); - labels.push_back(CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT, - "Host Name:", ChildId::SERVER_LABEL)); - serverEdit = - CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, val, ChildId::SERVER_EDIT); + val = config.Get(FlightSqlConnection::HOST); + wVal = arrow::util::UTF8ToWideString(val).ValueOr(L""); + labels.push_back(CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT, L"Host Name:", + ChildId::SERVER_LABEL)); + serverEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, wVal.c_str(), + ChildId::SERVER_EDIT); rowPos += INTERVAL + ROW_HEIGHT; - val = config.Get(FlightSqlConnection::PORT).c_str(); - labels.push_back(CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT, - "Port:", ChildId::PORT_LABEL)); - portEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, val, ChildId::PORT_EDIT, - ES_NUMBER); + val = config.Get(FlightSqlConnection::PORT); + wVal = arrow::util::UTF8ToWideString(val).ValueOr(L""); + labels.push_back(CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT, L"Port:", + ChildId::PORT_LABEL)); + portEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, wVal.c_str(), + ChildId::PORT_EDIT, ES_NUMBER); rowPos += INTERVAL + ROW_HEIGHT; connectionSettingsGroupBox = - CreateGroupBox(posX, posY, sizeX, rowPos - posY, "Connection settings", + CreateGroupBox(posX, posY, sizeX, rowPos - posY, L"Connection settings", ChildId::CONNECTION_SETTINGS_GROUP_BOX); return rowPos - posY; @@ -179,36 +186,39 @@ int DsnConfigurationWindow::CreateAuthSettingsGroup(int posX, int posY, int size int rowPos = posY + 2 * INTERVAL; labels.push_back(CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT, - "Authentication Type:", ChildId::AUTH_TYPE_LABEL)); + L"Authentication Type:", ChildId::AUTH_TYPE_LABEL)); authTypeComboBox = CreateComboBox(editPosX, rowPos, editSizeX, ROW_HEIGHT, - "Authentication Type:", ChildId::AUTH_TYPE_COMBOBOX); - authTypeComboBox->AddString("Basic Authentication"); - authTypeComboBox->AddString("Token Authentication"); + L"Authentication Type:", ChildId::AUTH_TYPE_COMBOBOX); + authTypeComboBox->AddString(L"Basic Authentication"); + authTypeComboBox->AddString(L"Token Authentication"); rowPos += INTERVAL + ROW_HEIGHT; - const char* val = config.Get(FlightSqlConnection::UID).c_str(); + std::string val = config.Get(FlightSqlConnection::UID); + std::wstring wVal = arrow::util::UTF8ToWideString(val).ValueOr(L""); - labels.push_back(CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT, - "User:", ChildId::USER_LABEL)); - userEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, val, ChildId::USER_EDIT); + labels.push_back(CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT, L"User:", + ChildId::USER_LABEL)); + userEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, wVal.c_str(), + ChildId::USER_EDIT); rowPos += INTERVAL + ROW_HEIGHT; - val = config.Get(FlightSqlConnection::PWD).c_str(); - labels.push_back(CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT, - "Password:", ChildId::PASSWORD_LABEL)); - passwordEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, val, + val = config.Get(FlightSqlConnection::PWD); + wVal = arrow::util::UTF8ToWideString(val).ValueOr(L""); + labels.push_back(CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT, L"Password:", + ChildId::PASSWORD_LABEL)); + passwordEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, wVal.c_str(), ChildId::USER_EDIT, ES_PASSWORD); rowPos += INTERVAL + ROW_HEIGHT; const auto& token = config.Get(FlightSqlConnection::TOKEN); - val = token.c_str(); + wVal = arrow::util::UTF8ToWideString(token).ValueOr(L""); labels.push_back(CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT, - "Authentication Token:", ChildId::AUTH_TOKEN_LABEL)); - authTokenEdit = - CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, val, ChildId::AUTH_TOKEN_EDIT); + L"Authentication Token:", ChildId::AUTH_TOKEN_LABEL)); + authTokenEdit = CreateEdit(editPosX, rowPos, editSizeX, ROW_HEIGHT, wVal.c_str(), + ChildId::AUTH_TOKEN_EDIT); authTokenEdit->SetEnabled(false); // Ensure the right elements are selected. @@ -218,7 +228,7 @@ int DsnConfigurationWindow::CreateAuthSettingsGroup(int posX, int posY, int size rowPos += INTERVAL + ROW_HEIGHT; authSettingsGroupBox = - CreateGroupBox(posX, posY, sizeX, rowPos - posY, "Authentication settings", + CreateGroupBox(posX, posY, sizeX, rowPos - posY, L"Authentication settings", ChildId::AUTH_SETTINGS_GROUP_BOX); return rowPos - posY; @@ -234,37 +244,38 @@ int DsnConfigurationWindow::CreateEncryptionSettingsGroup(int posX, int posY, in int rowPos = posY + 2 * INTERVAL; - const char* val = config.Get(FlightSqlConnection::USE_ENCRYPTION).c_str(); + std::string val = config.Get(FlightSqlConnection::USE_ENCRYPTION); const bool enableEncryption = driver::odbcabstraction::AsBool(val).value_or(true); labels.push_back(CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT, - "Use Encryption:", ChildId::ENABLE_ENCRYPTION_LABEL)); + L"Use Encryption:", ChildId::ENABLE_ENCRYPTION_LABEL)); enableEncryptionCheckBox = - CreateCheckBox(editPosX, rowPos - 2, editSizeX, ROW_HEIGHT, "", + CreateCheckBox(editPosX, rowPos - 2, editSizeX, ROW_HEIGHT, L"", ChildId::ENABLE_ENCRYPTION_CHECKBOX, enableEncryption); rowPos += INTERVAL + ROW_HEIGHT; - val = config.Get(FlightSqlConnection::TRUSTED_CERTS).c_str(); + val = config.Get(FlightSqlConnection::TRUSTED_CERTS); + std::wstring wVal = arrow::util::UTF8ToWideString(val).ValueOr(L""); labels.push_back(CreateLabel(labelPosX, rowPos, LABEL_WIDTH, ROW_HEIGHT, - "Certificate:", ChildId::CERTIFICATE_LABEL)); + L"Certificate:", ChildId::CERTIFICATE_LABEL)); certificateEdit = CreateEdit(editPosX, rowPos, editSizeX - MARGIN - BUTTON_WIDTH, - ROW_HEIGHT, val, ChildId::CERTIFICATE_EDIT); + ROW_HEIGHT, wVal.c_str(), ChildId::CERTIFICATE_EDIT); certificateBrowseButton = CreateButton(editPosX + editSizeX - BUTTON_WIDTH, rowPos - 2, BUTTON_WIDTH, - BUTTON_HEIGHT, "Browse", ChildId::CERTIFICATE_BROWSE_BUTTON); + BUTTON_HEIGHT, L"Browse", ChildId::CERTIFICATE_BROWSE_BUTTON); rowPos += INTERVAL + ROW_HEIGHT; val = config.Get(FlightSqlConnection::USE_SYSTEM_TRUST_STORE).c_str(); const bool useSystemCertStore = driver::odbcabstraction::AsBool(val).value_or(true); - labels.push_back( - CreateLabel(labelPosX, rowPos, LABEL_WIDTH, 2 * ROW_HEIGHT, - "Use System Certificate Store:", ChildId::USE_SYSTEM_CERT_STORE_LABEL)); + labels.push_back(CreateLabel(labelPosX, rowPos, LABEL_WIDTH, 2 * ROW_HEIGHT, + L"Use System Certificate Store:", + ChildId::USE_SYSTEM_CERT_STORE_LABEL)); useSystemCertStoreCheckBox = - CreateCheckBox(editPosX, rowPos - 2, 20, 2 * ROW_HEIGHT, "", + CreateCheckBox(editPosX, rowPos - 2, 20, 2 * ROW_HEIGHT, L"", ChildId::USE_SYSTEM_CERT_STORE_CHECKBOX, useSystemCertStore); val = config.Get(FlightSqlConnection::DISABLE_CERTIFICATE_VERIFICATION).c_str(); @@ -273,17 +284,17 @@ int DsnConfigurationWindow::CreateEncryptionSettingsGroup(int posX, int posY, in const int rightCheckPosX = rightPosX + (editPosX - labelPosX); const bool disableCertVerification = driver::odbcabstraction::AsBool(val).value_or(false); - labels.push_back(CreateLabel( - rightPosX, rowPos, LABEL_WIDTH, 2 * ROW_HEIGHT, - "Disable Certificate Verification:", ChildId::DISABLE_CERT_VERIFICATION_LABEL)); + labels.push_back(CreateLabel(rightPosX, rowPos, LABEL_WIDTH, 2 * ROW_HEIGHT, + L"Disable Certificate Verification:", + ChildId::DISABLE_CERT_VERIFICATION_LABEL)); disableCertVerificationCheckBox = CreateCheckBox( - rightCheckPosX, rowPos - 2, 20, 2 * ROW_HEIGHT, "", + rightCheckPosX, rowPos - 2, 20, 2 * ROW_HEIGHT, L"", ChildId::DISABLE_CERT_VERIFICATION_CHECKBOX, disableCertVerification); rowPos += INTERVAL + static_cast(1.5 * ROW_HEIGHT); encryptionSettingsGroupBox = - CreateGroupBox(posX, posY, sizeX, rowPos - posY, "Encryption settings", + CreateGroupBox(posX, posY, sizeX, rowPos - posY, L"Encryption settings", ChildId::AUTH_SETTINGS_GROUP_BOX); return rowPos - posY; @@ -301,12 +312,15 @@ int DsnConfigurationWindow::CreatePropertiesGroup(int posX, int posY, int sizeX) propertyList = CreateList(labelPosX, rowPos, listSize, listHeight, ChildId::PROPERTY_LIST); - propertyList->ListAddColumn("Key", 0, columnSize); - propertyList->ListAddColumn("Value", 1, columnSize); + propertyList->ListAddColumn(L"Key", 0, columnSize); + propertyList->ListAddColumn(L"Value", 1, columnSize); const auto keys = config.GetCustomKeys(); for (const auto& key : keys) { - propertyList->ListAddItem({key, config.Get(key)}); + std::wstring wKey = arrow::util::UTF8ToWideString(key).ValueOr(L""); + std::wstring wVal = arrow::util::UTF8ToWideString(config.Get(key)).ValueOr(L""); + + propertyList->ListAddItem({wKey, wVal}); } SendMessage(propertyList->GetHandle(), LVM_SETEXTENDEDLISTVIEWSTYLE, @@ -316,15 +330,15 @@ int DsnConfigurationWindow::CreatePropertiesGroup(int posX, int posY, int sizeX) int deletePosX = width - INTERVAL - MARGIN - BUTTON_WIDTH; int addPosX = deletePosX - INTERVAL - BUTTON_WIDTH; - addButton = CreateButton(addPosX, rowPos, BUTTON_WIDTH, BUTTON_HEIGHT, "Add", + addButton = CreateButton(addPosX, rowPos, BUTTON_WIDTH, BUTTON_HEIGHT, L"Add", ChildId::ADD_BUTTON); - deleteButton = CreateButton(deletePosX, rowPos, BUTTON_WIDTH, BUTTON_HEIGHT, "Delete", + deleteButton = CreateButton(deletePosX, rowPos, BUTTON_WIDTH, BUTTON_HEIGHT, L"Delete", ChildId::DELETE_BUTTON); rowPos += INTERVAL + BUTTON_HEIGHT; propertyGroupBox = CreateGroupBox(posX, posY, sizeX, rowPos - posY, - "Advanced properties", ChildId::PROPERTY_GROUP_BOX); + L"Advanced properties", ChildId::PROPERTY_GROUP_BOX); return rowPos - posY; } @@ -384,7 +398,7 @@ void DsnConfigurationWindow::CheckEnableOk() { void DsnConfigurationWindow::SaveParameters(Configuration& targetConfig) { targetConfig.Clear(); - std::string text; + std::wstring text; nameEdit->GetText(text); targetConfig.Set(FlightSqlConnection::DSN, text); serverEdit->GetText(text); @@ -427,7 +441,9 @@ void DsnConfigurationWindow::SaveParameters(Configuration& targetConfig) { // Get all the list properties. const auto properties = propertyList->ListGetAll(); for (const auto& property : properties) { - targetConfig.Set(property[0], property[1]); + std::string propertyKey = arrow::util::WideStringToUTF8(property[0]).ValueOr(""); + std::string propertyValue = arrow::util::WideStringToUTF8(property[1]).ValueOr(""); + targetConfig.Set(propertyKey, propertyValue); } } @@ -463,10 +479,13 @@ bool DsnConfigurationWindow::OnMessage(UINT msg, WPARAM wParam, LPARAM lParam) { SaveParameters(testConfig); std::string testMessage = TestConnection(testConfig); - MessageBox(NULL, testMessage.c_str(), "Test Connection Success", MB_OK); + std::wstring wTestMessage = + arrow::util::UTF8ToWideString(testMessage).ValueOr(L""); + MessageBox(NULL, wTestMessage.c_str(), L"Test Connection Success", MB_OK); } catch (odbcabstraction::DriverException& err) { - MessageBox(NULL, err.GetMessageText().c_str(), "Error!", - MB_ICONEXCLAMATION | MB_OK); + std::wstring wMessageText = + arrow::util::UTF8ToWideString(err.GetMessageText()).ValueOr(L""); + MessageBox(NULL, wMessageText.c_str(), L"Error!", MB_ICONEXCLAMATION | MB_OK); } break; @@ -477,8 +496,9 @@ bool DsnConfigurationWindow::OnMessage(UINT msg, WPARAM wParam, LPARAM lParam) { accepted = true; PostMessage(GetHandle(), WM_CLOSE, 0, 0); } catch (odbcabstraction::DriverException& err) { - MessageBox(NULL, err.GetMessageText().c_str(), "Error!", - MB_ICONEXCLAMATION | MB_OK); + std::wstring wMessageText = + arrow::util::UTF8ToWideString(err.GetMessageText()).ValueOr(L""); + MessageBox(NULL, wMessageText.c_str(), L"Error!", MB_ICONEXCLAMATION | MB_OK); } break; @@ -520,7 +540,7 @@ bool DsnConfigurationWindow::OnMessage(UINT msg, WPARAM wParam, LPARAM lParam) { case ChildId::CERTIFICATE_BROWSE_BUTTON: { OPENFILENAME openFileName; - char fileName[FILENAME_MAX]; + wchar_t fileName[FILENAME_MAX]; ZeroMemory(&openFileName, sizeof(openFileName)); openFileName.lStructSize = sizeof(openFileName); @@ -529,7 +549,7 @@ bool DsnConfigurationWindow::OnMessage(UINT msg, WPARAM wParam, LPARAM lParam) { openFileName.lpstrFile[0] = '\0'; openFileName.nMaxFile = FILENAME_MAX; // TODO: What type should this be? - openFileName.lpstrFilter = "All\0*.*"; + openFileName.lpstrFilter = L"All\0*.*"; openFileName.nFilterIndex = 1; openFileName.lpstrFileTitle = NULL; openFileName.nMaxFileTitle = 0; @@ -566,8 +586,8 @@ bool DsnConfigurationWindow::OnMessage(UINT msg, WPARAM wParam, LPARAM lParam) { addWindow.Update(); if (ProcessMessages(addWindow) == Result::OK) { - std::string key; - std::string value; + std::wstring key; + std::wstring value; addWindow.GetProperty(key, value); propertyList->ListAddItem({key, value}); } diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/ui/window.cc b/cpp/src/arrow/flight/sql/odbc/flight_sql/ui/window.cc index f88cd8a3f880..2940c95578a8 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/ui/window.cc +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/ui/window.cc @@ -49,7 +49,7 @@ HINSTANCE GetHInstance() { return hInstance; } -Window::Window(Window* parent, const char* className, const char* title) +Window::Window(Window* parent, const wchar_t* className, const wchar_t* title) : className(className), title(title), handle(NULL), parent(parent), created(false) { // No-op. } @@ -88,7 +88,7 @@ void Window::Create(DWORD style, int posX, int posY, int width, int height, int } std::unique_ptr Window::CreateTabControl(int id) { - std::unique_ptr child(new Window(this, WC_TABCONTROL, "")); + std::unique_ptr child(new Window(this, WC_TABCONTROL, L"")); // Get the dimensions of the parent window's client area, and // create a tab control child window of that size. @@ -103,7 +103,7 @@ std::unique_ptr Window::CreateTabControl(int id) { std::unique_ptr Window::CreateList(int posX, int posY, int sizeX, int sizeY, int id) { - std::unique_ptr child(new Window(this, WC_LISTVIEW, "")); + std::unique_ptr child(new Window(this, WC_LISTVIEW, L"")); child->Create( WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_REPORT | LVS_EDITLABELS | WS_TABSTOP, posX, @@ -113,8 +113,8 @@ std::unique_ptr Window::CreateList(int posX, int posY, int sizeX, int si } std::unique_ptr Window::CreateGroupBox(int posX, int posY, int sizeX, int sizeY, - const char* title, int id) { - std::unique_ptr child(new Window(this, "Button", title)); + const wchar_t* title, int id) { + std::unique_ptr child(new Window(this, L"Button", title)); child->Create(WS_CHILD | WS_VISIBLE | BS_GROUPBOX, posX, posY, sizeX, sizeY, id); @@ -122,8 +122,8 @@ std::unique_ptr Window::CreateGroupBox(int posX, int posY, int sizeX, in } std::unique_ptr Window::CreateLabel(int posX, int posY, int sizeX, int sizeY, - const char* title, int id) { - std::unique_ptr child(new Window(this, "Static", title)); + const wchar_t* title, int id) { + std::unique_ptr child(new Window(this, L"Static", title)); child->Create(WS_CHILD | WS_VISIBLE, posX, posY, sizeX, sizeY, id); @@ -131,8 +131,8 @@ std::unique_ptr Window::CreateLabel(int posX, int posY, int sizeX, int s } std::unique_ptr Window::CreateEdit(int posX, int posY, int sizeX, int sizeY, - const char* title, int id, int style) { - std::unique_ptr child(new Window(this, "Edit", title)); + const wchar_t* title, int id, int style) { + std::unique_ptr child(new Window(this, L"Edit", title)); child->Create(WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | WS_TABSTOP | style, posX, posY, sizeX, sizeY, id); @@ -141,8 +141,8 @@ std::unique_ptr Window::CreateEdit(int posX, int posY, int sizeX, int si } std::unique_ptr Window::CreateButton(int posX, int posY, int sizeX, int sizeY, - const char* title, int id, int style) { - std::unique_ptr child(new Window(this, "Button", title)); + const wchar_t* title, int id, int style) { + std::unique_ptr child(new Window(this, L"Button", title)); child->Create(WS_CHILD | WS_VISIBLE | WS_TABSTOP | style, posX, posY, sizeX, sizeY, id); @@ -150,8 +150,8 @@ std::unique_ptr Window::CreateButton(int posX, int posY, int sizeX, int } std::unique_ptr Window::CreateCheckBox(int posX, int posY, int sizeX, int sizeY, - const char* title, int id, bool state) { - std::unique_ptr child(new Window(this, "Button", title)); + const wchar_t* title, int id, bool state) { + std::unique_ptr child(new Window(this, L"Button", title)); child->Create(WS_CHILD | WS_VISIBLE | BS_CHECKBOX | WS_TABSTOP, posX, posY, sizeX, sizeY, id); @@ -162,8 +162,8 @@ std::unique_ptr Window::CreateCheckBox(int posX, int posY, int sizeX, in } std::unique_ptr Window::CreateComboBox(int posX, int posY, int sizeX, int sizeY, - const char* title, int id) { - std::unique_ptr child(new Window(this, "Combobox", title)); + const wchar_t* title, int id) { + std::unique_ptr child(new Window(this, L"Combobox", title)); child->Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_TABSTOP, posX, posY, sizeX, sizeY, id); @@ -194,12 +194,12 @@ bool Window::IsTextEmpty() const { return (len <= 0); } -void Window::ListAddColumn(const std::string& name, int index, int width) { +void Window::ListAddColumn(const std::wstring& name, int index, int width) { LVCOLUMN lvc; lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvc.fmt = LVCFMT_LEFT; lvc.cx = width; - lvc.pszText = const_cast(name.c_str()); + lvc.pszText = const_cast(name.c_str()); lvc.iSubItem = index; if (ListView_InsertColumn(handle, index, &lvc) == -1) { @@ -209,10 +209,10 @@ void Window::ListAddColumn(const std::string& name, int index, int width) { } } -void Window::ListAddItem(const std::vector& items) { +void Window::ListAddItem(const std::vector& items) { LVITEM lvi = {0}; lvi.mask = LVIF_TEXT; - lvi.pszText = const_cast(items[0].c_str()); + lvi.pszText = const_cast(items[0].c_str()); int ret = ListView_InsertItem(handle, &lvi); if (ret < 0) { @@ -223,7 +223,7 @@ void Window::ListAddItem(const std::vector& items) { for (size_t i = 1; i < items.size(); ++i) { ListView_SetItemText(handle, ret, static_cast(i), - const_cast(items[i].c_str())); + const_cast(items[i].c_str())); } } @@ -238,15 +238,15 @@ void Window::ListDeleteSelectedItem() { } } -std::vector > Window::ListGetAll() { +std::vector > Window::ListGetAll() { #define BUF_LEN 1024 - char buf[BUF_LEN]; + wchar_t buf[BUF_LEN]; - std::vector > values; + std::vector > values; const int numColumns = Header_GetItemCount(ListView_GetHeader(handle)); const int numItems = ListView_GetItemCount(handle); for (int i = 0; i < numItems; ++i) { - std::vector row; + std::vector row; for (int j = 0; j < numColumns; ++j) { ListView_GetItemText(handle, i, j, buf, BUF_LEN); row.emplace_back(buf); @@ -257,11 +257,11 @@ std::vector > Window::ListGetAll() { return values; } -void Window::AddTab(const std::string& name, int index) { +void Window::AddTab(const std::wstring& name, int index) { TCITEM tabControlItem; tabControlItem.mask = TCIF_TEXT | TCIF_IMAGE; tabControlItem.iImage = -1; - tabControlItem.pszText = const_cast(name.c_str()); + tabControlItem.pszText = const_cast(name.c_str()); if (TabCtrl_InsertItem(handle, index, &tabControlItem) == -1) { std::stringstream buf; buf << "Can not add tab, error code: " << GetLastError(); @@ -269,7 +269,7 @@ void Window::AddTab(const std::string& name, int index) { } } -void Window::GetText(std::string& text) const { +void Window::GetText(std::wstring& text) const { if (!IsEnabled()) { text.clear(); @@ -292,7 +292,7 @@ void Window::GetText(std::string& text) const { boost::algorithm::trim(text); } -void Window::SetText(const std::string& text) const { +void Window::SetText(const std::wstring& text) const { SNDMSG(handle, WM_SETTEXT, 0, reinterpret_cast(text.c_str())); } @@ -304,7 +304,7 @@ void Window::SetChecked(bool state) { Button_SetCheck(handle, state ? BST_CHECKED : BST_UNCHECKED); } -void Window::AddString(const std::string& str) { +void Window::AddString(const std::wstring& str) { SNDMSG(handle, CB_ADDSTRING, 0, reinterpret_cast(str.c_str())); } diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/win_system_dsn.cc b/cpp/src/arrow/flight/sql/odbc/flight_sql/win_system_dsn.cc index 18b5c399c2cb..2017936dd904 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/win_system_dsn.cc +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/win_system_dsn.cc @@ -22,6 +22,9 @@ #include #include +#include "arrow/result.h" +#include "arrow/util/utf8.h" + #include "arrow/flight/sql/odbc/flight_sql/flight_sql_connection.h" #include "arrow/flight/sql/odbc/flight_sql/include/flight_sql/config/configuration.h" #include "arrow/flight/sql/odbc/flight_sql/include/flight_sql/config/connection_string_parser.h" @@ -44,12 +47,6 @@ using driver::flight_sql::config::Result; using driver::flight_sql::config::Window; using driver::odbcabstraction::DriverException; -BOOL CALLBACK ConfigDriver(HWND hwndParent, WORD fRequest, LPCSTR lpszDriver, - LPCSTR lpszArgs, LPSTR lpszMsg, WORD cbMsgMax, - WORD* pcbMsgOut) { - return false; -} - bool DisplayConnectionWindow(void* windowParent, Configuration& config) { HWND hwndParent = (HWND)windowParent; @@ -69,10 +66,12 @@ bool DisplayConnectionWindow(void* windowParent, Configuration& config) { std::stringstream buf; buf << "SQL State: " << err.GetSqlState() << ", Message: " << err.GetMessageText() << ", Code: " << err.GetNativeError(); - std::string message = buf.str(); - MessageBox(NULL, message.c_str(), "Error!", MB_ICONEXCLAMATION | MB_OK); + std::wstring wMessage = arrow::util::UTF8ToWideString(buf.str()).ValueOr(L""); + MessageBox(NULL, wMessage.c_str(), L"Error!", MB_ICONEXCLAMATION | MB_OK); - SQLPostInstallerError(err.GetNativeError(), err.GetMessageText().c_str()); + std::wstring wMessageText = + arrow::util::UTF8ToWideString(err.GetMessageText()).ValueOr(L""); + SQLPostInstallerError(err.GetNativeError(), wMessageText.c_str()); } return false; @@ -93,15 +92,17 @@ bool DisplayConnectionWindow(void* windowParent, Configuration& config, } } -BOOL INSTAPI ConfigDSN(HWND hwndParent, WORD req, LPCSTR driver, LPCSTR attributes) { +BOOL INSTAPI ConfigDSNW(HWND hwndParent, WORD req, LPCWSTR wDriver, LPCWSTR wAttributes) { Configuration config; ConnectionStringParser parser(config); - parser.ParseConfigAttributes(attributes); + std::string attributes = + arrow::util::WideStringToUTF8(std::wstring(wAttributes)).ValueOr(""); + parser.ParseConfigAttributes(attributes.c_str()); switch (req) { case ODBC_ADD_DSN: { config.LoadDefaults(); - if (!DisplayConnectionWindow(hwndParent, config) || !RegisterDsn(config, driver)) + if (!DisplayConnectionWindow(hwndParent, config) || !RegisterDsn(config, wDriver)) return FALSE; break; @@ -109,13 +110,14 @@ BOOL INSTAPI ConfigDSN(HWND hwndParent, WORD req, LPCSTR driver, LPCSTR attribut case ODBC_CONFIG_DSN: { const std::string& dsn = config.Get(FlightSqlConnection::DSN); - if (!SQLValidDSN(dsn.c_str())) return FALSE; + std::wstring wDsn = arrow::util::UTF8ToWideString(dsn).ValueOr(L""); + if (!SQLValidDSN(wDsn.c_str())) return FALSE; Configuration loaded(config); loaded.LoadDsn(dsn); - if (!DisplayConnectionWindow(hwndParent, loaded) || !UnregisterDsn(dsn.c_str()) || - !RegisterDsn(loaded, driver)) + if (!DisplayConnectionWindow(hwndParent, loaded) || !UnregisterDsn(wDsn.c_str()) || + !RegisterDsn(loaded, wDriver)) return FALSE; break; @@ -123,7 +125,8 @@ BOOL INSTAPI ConfigDSN(HWND hwndParent, WORD req, LPCSTR driver, LPCSTR attribut case ODBC_REMOVE_DSN: { const std::string& dsn = config.Get(FlightSqlConnection::DSN); - if (!SQLValidDSN(dsn.c_str()) || !UnregisterDsn(dsn)) return FALSE; + std::wstring wDsn = arrow::util::UTF8ToWideString(dsn).ValueOr(L""); + if (!SQLValidDSN(wDsn.c_str()) || !UnregisterDsn(wDsn)) return FALSE; break; } diff --git a/cpp/src/arrow/flight/sql/odbc/odbc.def b/cpp/src/arrow/flight/sql/odbc/odbc.def index c90c181d7c17..ed3203afbb41 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc.def +++ b/cpp/src/arrow/flight/sql/odbc/odbc.def @@ -17,7 +17,7 @@ LIBRARY arrow_flight_sql_odbc EXPORTS - ConfigDSN + ConfigDSNW SQLAllocConnect SQLAllocEnv SQLAllocHandle diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_api.cc b/cpp/src/arrow/flight/sql/odbc/odbc_api.cc index 9c734e072a91..cfd8ee645a6f 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc_api.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbc_api.cc @@ -224,10 +224,9 @@ inline bool IsValidStringFieldArgs(SQLPOINTER diagInfoPtr, SQLSMALLINT bufferLen return hasValidBuffer || stringLengthPtr; } -SQLRETURN SQLGetDiagFieldW(SQLSMALLINT handleType, SQLHANDLE handle, - SQLSMALLINT recNumber, SQLSMALLINT diagIdentifier, - SQLPOINTER diagInfoPtr, SQLSMALLINT bufferLength, - SQLSMALLINT* stringLengthPtr) { +SQLRETURN SQLGetDiagField(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT recNumber, + SQLSMALLINT diagIdentifier, SQLPOINTER diagInfoPtr, + SQLSMALLINT bufferLength, SQLSMALLINT* stringLengthPtr) { // TODO: Implement additional fields types // https://github.com/apache/arrow/issues/46573 using driver::odbcabstraction::Diagnostics; @@ -440,10 +439,10 @@ SQLRETURN SQLGetDiagFieldW(SQLSMALLINT handleType, SQLHANDLE handle, return SQL_ERROR; } -SQLRETURN SQLGetDiagRecW(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT recNumber, - SQLWCHAR* sqlState, SQLINTEGER* nativeErrorPtr, - SQLWCHAR* messageText, SQLSMALLINT bufferLength, - SQLSMALLINT* textLengthPtr) { +SQLRETURN SQLGetDiagRec(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT recNumber, + SQLWCHAR* sqlState, SQLINTEGER* nativeErrorPtr, + SQLWCHAR* messageText, SQLSMALLINT bufferLength, + SQLSMALLINT* textLengthPtr) { using driver::odbcabstraction::Diagnostics; using ODBC::ConvertToSqlWChar; using ODBC::GetStringAttribute; @@ -638,17 +637,17 @@ SQLRETURN SQLSetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER valuePtr, }); } -SQLRETURN SQLDriverConnectW(SQLHDBC conn, SQLHWND windowHandle, - SQLWCHAR* inConnectionString, - SQLSMALLINT inConnectionStringLen, - SQLWCHAR* outConnectionString, - SQLSMALLINT outConnectionStringBufferLen, - SQLSMALLINT* outConnectionStringLen, - SQLUSMALLINT driverCompletion) { +SQLRETURN SQLDriverConnect(SQLHDBC conn, SQLHWND windowHandle, + SQLWCHAR* inConnectionString, + SQLSMALLINT inConnectionStringLen, + SQLWCHAR* outConnectionString, + SQLSMALLINT outConnectionStringBufferLen, + SQLSMALLINT* outConnectionStringLen, + SQLUSMALLINT driverCompletion) { // TODO: Implement FILEDSN and SAVEFILE keywords according to the spec // https://github.com/apache/arrow/issues/46449 - // TODO: Copy connection string properly in SQLDriverConnectW according to the + // TODO: Copy connection string properly in SQLDriverConnect according to the // spec https://github.com/apache/arrow/issues/46560 using driver::odbcabstraction::Connection; @@ -673,7 +672,7 @@ SQLRETURN SQLDriverConnectW(SQLHDBC conn, SQLHWND windowHandle, std::vector missing_properties; - // TODO: Implement SQL_DRIVER_COMPLETE_REQUIRED in SQLDriverConnectW according to the + // TODO: Implement SQL_DRIVER_COMPLETE_REQUIRED in SQLDriverConnect according to the // spec https://github.com/apache/arrow/issues/46448 #if defined _WIN32 || defined _WIN64 // Load the DSN window according to driverCompletion @@ -718,9 +717,9 @@ SQLRETURN SQLDriverConnectW(SQLHDBC conn, SQLHWND windowHandle, }); } -SQLRETURN SQLConnectW(SQLHDBC conn, SQLWCHAR* dsnName, SQLSMALLINT dsnNameLen, - SQLWCHAR* userName, SQLSMALLINT userNameLen, SQLWCHAR* password, - SQLSMALLINT passwordLen) { +SQLRETURN SQLConnect(SQLHDBC conn, SQLWCHAR* dsnName, SQLSMALLINT dsnNameLen, + SQLWCHAR* userName, SQLSMALLINT userNameLen, SQLWCHAR* password, + SQLSMALLINT passwordLen) { using driver::flight_sql::FlightSqlConnection; using driver::flight_sql::config::Configuration; using ODBC::ODBCConnection; @@ -772,8 +771,8 @@ SQLRETURN SQLDisconnect(SQLHDBC conn) { }); } -SQLRETURN SQLGetInfoW(SQLHDBC conn, SQLUSMALLINT infoType, SQLPOINTER infoValuePtr, - SQLSMALLINT bufLen, SQLSMALLINT* length) { +SQLRETURN SQLGetInfo(SQLHDBC conn, SQLUSMALLINT infoType, SQLPOINTER infoValuePtr, + SQLSMALLINT bufLen, SQLSMALLINT* length) { // TODO: complete implementation of SQLGetInfoW and write tests using ODBC::ODBCConnection; diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_api.h b/cpp/src/arrow/flight/sql/odbc/odbc_api.h index 9350cead3841..eb2f677a385d 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc_api.h +++ b/cpp/src/arrow/flight/sql/odbc/odbc_api.h @@ -32,29 +32,28 @@ namespace arrow { SQLRETURN SQLAllocHandle(SQLSMALLINT type, SQLHANDLE parent, SQLHANDLE* result); SQLRETURN SQLFreeHandle(SQLSMALLINT type, SQLHANDLE handle); SQLRETURN SQLFreeStmt(SQLHSTMT stmt, SQLUSMALLINT option); -SQLRETURN SQLGetDiagFieldW(SQLSMALLINT handleType, SQLHANDLE handle, - SQLSMALLINT recNumber, SQLSMALLINT diagIdentifier, - SQLPOINTER diagInfoPtr, SQLSMALLINT bufferLength, - SQLSMALLINT* stringLengthPtr); -SQLRETURN SQLGetDiagRecW(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT recNumber, - SQLWCHAR* sqlState, SQLINTEGER* nativeErrorPtr, - SQLWCHAR* messageText, SQLSMALLINT bufferLength, - SQLSMALLINT* textLengthPtr); +SQLRETURN SQLGetDiagField(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT recNumber, + SQLSMALLINT diagIdentifier, SQLPOINTER diagInfoPtr, + SQLSMALLINT bufferLength, SQLSMALLINT* stringLengthPtr); +SQLRETURN SQLGetDiagRec(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT recNumber, + SQLWCHAR* sqlState, SQLINTEGER* nativeErrorPtr, + SQLWCHAR* messageText, SQLSMALLINT bufferLength, + SQLSMALLINT* textLengthPtr); SQLRETURN SQLGetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER valuePtr, SQLINTEGER bufferLen, SQLINTEGER* strLenPtr); SQLRETURN SQLSetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER valuePtr, SQLINTEGER strLen); -SQLRETURN SQLDriverConnectW(SQLHDBC conn, SQLHWND windowHandle, - SQLWCHAR* inConnectionString, - SQLSMALLINT inConnectionStringLen, - SQLWCHAR* outConnectionString, - SQLSMALLINT outConnectionStringBufferLen, - SQLSMALLINT* outConnectionStringLen, - SQLUSMALLINT driverCompletion); -SQLRETURN SQLConnectW(SQLHDBC conn, SQLWCHAR* dsnName, SQLSMALLINT dsnNameLen, - SQLWCHAR* userName, SQLSMALLINT userNameLen, SQLWCHAR* password, - SQLSMALLINT passwordLen); +SQLRETURN SQLDriverConnect(SQLHDBC conn, SQLHWND windowHandle, + SQLWCHAR* inConnectionString, + SQLSMALLINT inConnectionStringLen, + SQLWCHAR* outConnectionString, + SQLSMALLINT outConnectionStringBufferLen, + SQLSMALLINT* outConnectionStringLen, + SQLUSMALLINT driverCompletion); +SQLRETURN SQLConnect(SQLHDBC conn, SQLWCHAR* dsnName, SQLSMALLINT dsnNameLen, + SQLWCHAR* userName, SQLSMALLINT userNameLen, SQLWCHAR* password, + SQLSMALLINT passwordLen); SQLRETURN SQLDisconnect(SQLHDBC conn); -SQLRETURN SQLGetInfoW(SQLHDBC conn, SQLUSMALLINT infoType, SQLPOINTER infoValuePtr, - SQLSMALLINT bufLen, SQLSMALLINT* length); +SQLRETURN SQLGetInfo(SQLHDBC conn, SQLUSMALLINT infoType, SQLPOINTER infoValuePtr, + SQLSMALLINT bufLen, SQLSMALLINT* length); } // namespace arrow diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/odbc_impl/odbc_connection.cc b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/odbc_impl/odbc_connection.cc index f28ee1789b0f..3da4a63c5f5a 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/odbc_impl/odbc_connection.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/odbc_impl/odbc_connection.cc @@ -17,6 +17,9 @@ #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/odbc_impl/odbc_connection.h" +#include "arrow/result.h" +#include "arrow/util/utf8.h" + #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/exceptions.h" #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/odbc_impl/attribute_utils.h" #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/odbc_impl/odbc_descriptor.h" @@ -56,40 +59,44 @@ const boost::xpressive::sregex CONNECTION_STR_REGEX( void loadPropertiesFromDSN(const std::string& dsn, Connection::ConnPropertyMap& properties) { const size_t BUFFER_SIZE = 1024 * 10; - std::vector outputBuffer; + std::vector outputBuffer; outputBuffer.resize(BUFFER_SIZE, '\0'); SQLSetConfigMode(ODBC_BOTH_DSN); - SQLGetPrivateProfileString(dsn.c_str(), NULL, "", &outputBuffer[0], BUFFER_SIZE, - "odbc.ini"); + std::wstring wDsn = arrow::util::UTF8ToWideString(dsn).ValueOr(L""); + + SQLGetPrivateProfileString(wDsn.c_str(), NULL, L"", &outputBuffer[0], BUFFER_SIZE, + L"odbc.ini"); // The output buffer holds the list of keys in a series of NUL-terminated strings. // The series is terminated with an empty string (eg a NUL-terminator terminating the // last key followed by a NUL terminator after). - std::vector keys; + std::vector keys; size_t pos = 0; while (pos < BUFFER_SIZE) { - std::string key(&outputBuffer[pos]); - if (key.empty()) { + std::wstring wKey(&outputBuffer[pos]); + if (wKey.empty()) { break; } - size_t len = key.size(); + size_t len = wKey.size(); // Skip over Driver or DSN keys. - if (!boost::iequals(key, "DSN") && !boost::iequals(key, "Driver")) { - keys.emplace_back(std::move(key)); + if (!boost::iequals(wKey, L"DSN") && !boost::iequals(wKey, L"Driver")) { + keys.emplace_back(std::move(wKey)); } pos += len + 1; } - for (auto& key : keys) { + for (auto& wKey : keys) { outputBuffer.clear(); outputBuffer.resize(BUFFER_SIZE, '\0'); - SQLGetPrivateProfileString(dsn.c_str(), key.data(), "", &outputBuffer[0], BUFFER_SIZE, - "odbc.ini"); + SQLGetPrivateProfileString(wDsn.c_str(), wKey.data(), L"", &outputBuffer[0], + BUFFER_SIZE, L"odbc.ini"); - std::string value = std::string(&outputBuffer[0]); - auto propIter = properties.find(std::string(key)); + std::wstring wValue = std::wstring(&outputBuffer[0]); + std::string value = arrow::util::WideStringToUTF8(wValue).ValueOr(""); + std::string key = arrow::util::WideStringToUTF8(std::wstring(wKey)).ValueOr(""); + auto propIter = properties.find(key); if (propIter == properties.end()) { properties.emplace(std::make_pair(std::move(key), std::move(value))); } diff --git a/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt b/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt index 41e511822755..5f055682dfb7 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt +++ b/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt @@ -19,8 +19,6 @@ add_custom_target(tests) include_directories(${ODBC_INCLUDE_DIRS}) -add_definitions(-DUNICODE=1) - find_package(SQLite3Alt REQUIRED) set(ARROW_FLIGHT_SQL_MOCK_SERVER_SRCS diff --git a/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc b/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc index 176129ba6273..99fce0684c70 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc +++ b/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc @@ -400,10 +400,8 @@ TEST_F(FlightSQLODBCRemoteTestBase, TestSQLDriverConnectInvalidUid) { VerifyOdbcErrorState(SQL_HANDLE_DBC, conn, std::string("28000")); - // TODO: Check that outstr remains empty after SqlWcharToString - // is fixed to handle empty `outstr` - // std::string out_connection_string = ODBC::SqlWcharToString(outstr, outstrlen); - // EXPECT_TRUE(out_connection_string.empty()); + std::string out_connection_string = ODBC::SqlWcharToString(outstr, outstrlen); + EXPECT_TRUE(out_connection_string.empty()); // Free connection handle ret = SQLFreeHandle(SQL_HANDLE_DBC, conn); @@ -463,7 +461,7 @@ TYPED_TEST(FlightSQLODBCTestBase, TestSQLConnect) { EXPECT_TRUE(ret == SQL_SUCCESS); // Remove DSN - EXPECT_TRUE(UnregisterDsn(dsn)); + EXPECT_TRUE(UnregisterDsn(wdsn)); // Disconnect from ODBC ret = SQLDisconnect(conn); @@ -541,7 +539,7 @@ TEST_F(FlightSQLODBCRemoteTestBase, TestSQLConnectInputUidPwd) { EXPECT_TRUE(ret == SQL_SUCCESS); // Remove DSN - EXPECT_TRUE(UnregisterDsn(dsn)); + EXPECT_TRUE(UnregisterDsn(wdsn)); // Disconnect from ODBC ret = SQLDisconnect(conn); @@ -618,7 +616,7 @@ TEST_F(FlightSQLODBCRemoteTestBase, TestSQLConnectInvalidUid) { VerifyOdbcErrorState(SQL_HANDLE_DBC, conn, std::string("28000")); // Remove DSN - EXPECT_TRUE(UnregisterDsn(dsn)); + EXPECT_TRUE(UnregisterDsn(wdsn)); // Free connection handle ret = SQLFreeHandle(SQL_HANDLE_DBC, conn); @@ -681,7 +679,7 @@ TEST_F(FlightSQLODBCRemoteTestBase, TestSQLConnectDSNPrecedence) { EXPECT_TRUE(ret == SQL_SUCCESS); // Remove DSN - EXPECT_TRUE(UnregisterDsn(dsn)); + EXPECT_TRUE(UnregisterDsn(wdsn)); // Disconnect from ODBC ret = SQLDisconnect(conn); diff --git a/cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.cc b/cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.cc index c079c3c175c4..2d2a8f5d305a 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.cc +++ b/cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.cc @@ -262,8 +262,8 @@ bool writeDSN(Connection::ConnPropertyMap properties) { } std::string driver = config.Get(FlightSqlConnection::DRIVER); - - return RegisterDsn(config, driver.c_str()); + std::wstring wDriver = arrow::util::UTF8ToWideString(driver).ValueOr(L""); + return RegisterDsn(config, wDriver.c_str()); } } // namespace integration_tests } // namespace odbc