Skip to content

Commit 45719f4

Browse files
authored
Unicode support for DSN ODBC APIs
* Let compiler append `W` to ODBC APIs where applicable.
1 parent 2a41071 commit 45719f4

24 files changed

+383
-329
lines changed

cpp/src/arrow/flight/sql/odbc/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ else()
3232
set(ODBCINST odbcinst)
3333
endif()
3434

35+
add_definitions(-DUNICODE=1)
36+
3537
add_subdirectory(flight_sql)
3638
add_subdirectory(odbcabstraction)
3739
add_subdirectory(tests)

cpp/src/arrow/flight/sql/odbc/entry_points.cc

Lines changed: 77 additions & 78 deletions
Large diffs are not rendered by default.

cpp/src/arrow/flight/sql/odbc/flight_sql/config/configuration.cc

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
#include "arrow/flight/sql/odbc/flight_sql/include/flight_sql/config/configuration.h"
1919
#include "arrow/flight/sql/odbc/flight_sql/flight_sql_connection.h"
20+
#include "arrow/result.h"
21+
#include "arrow/util/utf8.h"
2022

2123
#include <odbcinst.h>
2224
#include <boost/range/adaptor/map.hpp>
@@ -27,7 +29,6 @@
2729
namespace driver {
2830
namespace flight_sql {
2931
namespace config {
30-
3132
static const char DEFAULT_DSN[] = "Apache Arrow Flight SQL";
3233
static const char DEFAULT_ENABLE_ENCRYPTION[] = TRUE_STR;
3334
static const char DEFAULT_USE_CERT_STORE[] = TRUE_STR;
@@ -36,19 +37,27 @@ static const char DEFAULT_DISABLE_CERT_VERIFICATION[] = FALSE_STR;
3637
namespace {
3738
std::string ReadDsnString(const std::string& dsn, const std::string_view& key,
3839
const std::string& dflt = "") {
40+
std::wstring wDsn = arrow::util::UTF8ToWideString(dsn).ValueOr(L"");
41+
std::wstring wKey = arrow::util::UTF8ToWideString(key).ValueOr(L"");
42+
std::wstring wDflt = arrow::util::UTF8ToWideString(dflt).ValueOr(L"");
43+
3944
#define BUFFER_SIZE (1024)
40-
std::vector<char> buf(BUFFER_SIZE);
41-
int ret = SQLGetPrivateProfileString(dsn.c_str(), key.data(), dflt.c_str(), buf.data(),
42-
static_cast<int>(buf.size()), "ODBC.INI");
45+
std::vector<wchar_t> buf(BUFFER_SIZE);
46+
int ret =
47+
SQLGetPrivateProfileString(wDsn.c_str(), wKey.c_str(), wDflt.c_str(), buf.data(),
48+
static_cast<int>(buf.size()), L"ODBC.INI");
4349

4450
if (ret > BUFFER_SIZE) {
4551
// If there wasn't enough space, try again with the right size buffer.
4652
buf.resize(ret + 1);
47-
ret = SQLGetPrivateProfileString(dsn.c_str(), key.data(), dflt.c_str(), buf.data(),
48-
static_cast<int>(buf.size()), "ODBC.INI");
53+
ret =
54+
SQLGetPrivateProfileString(wDsn.c_str(), wKey.c_str(), wDflt.c_str(), buf.data(),
55+
static_cast<int>(buf.size()), L"ODBC.INI");
4956
}
5057

51-
return std::string(buf.data(), ret);
58+
std::wstring wResult = std::wstring(buf.data(), ret);
59+
std::string result = arrow::util::WideStringToUTF8(wResult).ValueOr("");
60+
return result;
5261
}
5362

5463
void RemoveAllKnownKeys(std::vector<std::string>& keys) {
@@ -65,28 +74,32 @@ void RemoveAllKnownKeys(std::vector<std::string>& keys) {
6574
}
6675

6776
std::vector<std::string> ReadAllKeys(const std::string& dsn) {
68-
std::vector<char> buf(BUFFER_SIZE);
77+
std::wstring wDsn = arrow::util::UTF8ToWideString(dsn).ValueOr(L"");
78+
79+
std::vector<wchar_t> buf(BUFFER_SIZE);
6980

70-
int ret = SQLGetPrivateProfileString(dsn.c_str(), NULL, "", buf.data(),
71-
static_cast<int>(buf.size()), "ODBC.INI");
81+
int ret = SQLGetPrivateProfileString(wDsn.c_str(), NULL, L"", buf.data(),
82+
static_cast<int>(buf.size()), L"ODBC.INI");
7283

7384
if (ret > BUFFER_SIZE) {
7485
// If there wasn't enough space, try again with the right size buffer.
7586
buf.resize(ret + 1);
76-
ret = SQLGetPrivateProfileString(dsn.c_str(), NULL, "", buf.data(),
77-
static_cast<int>(buf.size()), "ODBC.INI");
87+
ret = SQLGetPrivateProfileString(wDsn.c_str(), NULL, L"", buf.data(),
88+
static_cast<int>(buf.size()), L"ODBC.INI");
7889
}
7990

8091
// When you pass NULL to SQLGetPrivateProfileString it gives back a \0 delimited list of
8192
// all the keys. The below loop simply tokenizes all the keys and places them into a
8293
// vector.
8394
std::vector<std::string> keys;
84-
char* begin = buf.data();
95+
wchar_t* begin = buf.data();
8596
while (begin && *begin != '\0') {
86-
char* cur;
97+
wchar_t* cur;
8798
for (cur = begin; *cur != '\0'; ++cur) {
8899
}
89-
keys.emplace_back(begin, cur);
100+
101+
std::string key = arrow::util::WideStringToUTF8(std::wstring(begin, cur)).ValueOr("");
102+
keys.emplace_back(key);
90103
begin = ++cur;
91104
}
92105
return keys;
@@ -150,6 +163,11 @@ const std::string& Configuration::Get(const std::string_view& key) const {
150163
return itr->second;
151164
}
152165

166+
void Configuration::Set(const std::string_view& key, const std::wstring& wValue) {
167+
std::string value = arrow::util::WideStringToUTF8(wValue).ValueOr("");
168+
Set(key, value);
169+
}
170+
153171
void Configuration::Set(const std::string_view& key, const std::string& value) {
154172
const std::string copy = boost::trim_copy(value);
155173
if (!copy.empty()) {

cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_connection.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ namespace {
8383

8484
#if _WIN32 || _WIN64
8585
constexpr auto SYSTEM_TRUST_STORE_DEFAULT = true;
86-
constexpr auto STORES = {"CA", "MY", "ROOT", "SPC"};
86+
constexpr auto STORES = {L"CA", L"MY", L"ROOT", L"SPC"};
8787

8888
inline std::string GetCerts() {
8989
std::string certs;

cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/config/configuration.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class Configuration {
5252
void Clear();
5353
bool IsSet(const std::string_view& key) const;
5454
const std::string& Get(const std::string_view& key) const;
55+
void Set(const std::string_view& key, const std::wstring& wValue);
5556
void Set(const std::string_view& key, const std::string& value);
5657
void Emplace(const std::string_view& key, std::string&& value);
5758
/**

cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/ui/add_property_window.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class AddPropertyWindow : public CustomWindow {
7070
*
7171
* @return true if the dialog was OK'd, false otherwise.
7272
*/
73-
bool GetProperty(std::string& key, std::string& value);
73+
bool GetProperty(std::wstring& key, std::wstring& value);
7474

7575
private:
7676
/**
@@ -97,9 +97,9 @@ class AddPropertyWindow : public CustomWindow {
9797

9898
std::unique_ptr<Window> valueEdit;
9999

100-
std::string key;
100+
std::wstring key;
101101

102-
std::string value;
102+
std::wstring value;
103103

104104
/** Window width. */
105105
int width;

cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/ui/custom_window.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class CustomWindow : public Window {
6565
* @param className Window class name.
6666
* @param title Window title.
6767
*/
68-
CustomWindow(Window* parent, const char* className, const char* title);
68+
CustomWindow(Window* parent, const wchar_t* className, const wchar_t* title);
6969

7070
/**
7171
* Destructor.

cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/ui/window.h

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class Window {
4444
* @param className Window class name.
4545
* @param title Window title.
4646
*/
47-
Window(Window* parent, const char* className, const char* title);
47+
Window(Window* parent, const wchar_t* className, const wchar_t* title);
4848

4949
/**
5050
* Constructor for the existing window.
@@ -102,7 +102,7 @@ class Window {
102102
* @return Auto pointer containing new window.
103103
*/
104104
std::unique_ptr<Window> CreateGroupBox(int posX, int posY, int sizeX, int sizeY,
105-
const char* title, int id);
105+
const wchar_t* title, int id);
106106

107107
/**
108108
* Create child label window.
@@ -116,7 +116,7 @@ class Window {
116116
* @return Auto pointer containing new window.
117117
*/
118118
std::unique_ptr<Window> CreateLabel(int posX, int posY, int sizeX, int sizeY,
119-
const char* title, int id);
119+
const wchar_t* title, int id);
120120

121121
/**
122122
* Create child Edit window.
@@ -131,7 +131,7 @@ class Window {
131131
* @return Auto pointer containing new window.
132132
*/
133133
std::unique_ptr<Window> CreateEdit(int posX, int posY, int sizeX, int sizeY,
134-
const char* title, int id, int style = 0);
134+
const wchar_t* title, int id, int style = 0);
135135

136136
/**
137137
* Create child button window.
@@ -146,7 +146,7 @@ class Window {
146146
* @return Auto pointer containing new window.
147147
*/
148148
std::unique_ptr<Window> CreateButton(int posX, int posY, int sizeX, int sizeY,
149-
const char* title, int id, int style = 0);
149+
const wchar_t* title, int id, int style = 0);
150150

151151
/**
152152
* Create child CheckBox window.
@@ -161,7 +161,7 @@ class Window {
161161
* @return Auto pointer containing new window.
162162
*/
163163
std::unique_ptr<Window> CreateCheckBox(int posX, int posY, int sizeX, int sizeY,
164-
const char* title, int id, bool state);
164+
const wchar_t* title, int id, bool state);
165165

166166
/**
167167
* Create child ComboBox window.
@@ -175,7 +175,7 @@ class Window {
175175
* @return Auto pointer containing new window.
176176
*/
177177
std::unique_ptr<Window> CreateComboBox(int posX, int posY, int sizeX, int sizeY,
178-
const char* title, int id);
178+
const wchar_t* title, int id);
179179

180180
/**
181181
* Show window.
@@ -201,15 +201,15 @@ class Window {
201201

202202
void SetVisible(bool isVisible);
203203

204-
void ListAddColumn(const std::string& name, int index, int width);
204+
void ListAddColumn(const std::wstring& name, int index, int width);
205205

206-
void ListAddItem(const std::vector<std::string>& items);
206+
void ListAddItem(const std::vector<std::wstring>& items);
207207

208208
void ListDeleteSelectedItem();
209209

210-
std::vector<std::vector<std::string> > ListGetAll();
210+
std::vector<std::vector<std::wstring> > ListGetAll();
211211

212-
void AddTab(const std::string& name, int index);
212+
void AddTab(const std::wstring& name, int index);
213213

214214
bool IsTextEmpty() const;
215215

@@ -218,14 +218,14 @@ class Window {
218218
*
219219
* @param text Text.
220220
*/
221-
void GetText(std::string& text) const;
221+
void GetText(std::wstring& text) const;
222222

223223
/**
224224
* Set window text.
225225
*
226226
* @param text Text.
227227
*/
228-
void SetText(const std::string& text) const;
228+
void SetText(const std::wstring& text) const;
229229

230230
/**
231231
* Get CheckBox state.
@@ -246,7 +246,7 @@ class Window {
246246
*
247247
* @param str String.
248248
*/
249-
void AddString(const std::string& str);
249+
void AddString(const std::wstring& str);
250250

251251
/**
252252
* Set current ComboBox selection.
@@ -285,10 +285,10 @@ class Window {
285285
void SetHandle(HWND value) { handle = value; }
286286

287287
/** Window class name. */
288-
std::string className;
288+
std::wstring className;
289289

290290
/** Window title. */
291-
std::string title;
291+
std::wstring title;
292292

293293
/** Window handle. */
294294
HWND handle;

cpp/src/arrow/flight/sql/odbc/flight_sql/system_dsn.cc

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
#include "arrow/flight/sql/odbc/flight_sql/flight_sql_connection.h"
2121
#include "arrow/flight/sql/odbc/flight_sql/include/flight_sql/config/configuration.h"
22+
#include "arrow/result.h"
23+
#include "arrow/util/utf8.h"
2224

2325
#include <odbcinst.h>
2426
#include <sstream>
@@ -29,14 +31,14 @@ using driver::flight_sql::config::Configuration;
2931
void PostLastInstallerError() {
3032
#define BUFFER_SIZE (1024)
3133
DWORD code;
32-
char msg[BUFFER_SIZE];
34+
wchar_t msg[BUFFER_SIZE];
3335
SQLInstallerError(1, &code, msg, BUFFER_SIZE, NULL);
3436

35-
std::stringstream buf;
36-
buf << "Message: \"" << msg << "\", Code: " << code;
37-
std::string errorMsg = buf.str();
37+
std::wstringstream buf;
38+
buf << L"Message: \"" << msg << L"\", Code: " << code;
39+
std::wstring errorMsg = buf.str();
3840

39-
MessageBox(NULL, errorMsg.c_str(), "Error!", MB_ICONEXCLAMATION | MB_OK);
41+
MessageBox(NULL, errorMsg.c_str(), L"Error!", MB_ICONEXCLAMATION | MB_OK);
4042
SQLPostInstallerError(code, errorMsg.c_str());
4143
}
4244

@@ -46,7 +48,7 @@ void PostLastInstallerError() {
4648
* @param dsn DSN name.
4749
* @return True on success and false on fail.
4850
*/
49-
bool UnregisterDsn(const std::string& dsn) {
51+
bool UnregisterDsn(const std::wstring& dsn) {
5052
if (SQLRemoveDSNFromIni(dsn.c_str())) {
5153
return true;
5254
}
@@ -62,10 +64,11 @@ bool UnregisterDsn(const std::string& dsn) {
6264
* @param driver Driver.
6365
* @return True on success and false on fail.
6466
*/
65-
bool RegisterDsn(const Configuration& config, LPCSTR driver) {
67+
bool RegisterDsn(const Configuration& config, LPCWSTR driver) {
6668
const std::string& dsn = config.Get(FlightSqlConnection::DSN);
69+
std::wstring wDsn = arrow::util::UTF8ToWideString(dsn).ValueOr(L"");
6770

68-
if (!SQLWriteDSNToIni(dsn.c_str(), driver)) {
71+
if (!SQLWriteDSNToIni(wDsn.c_str(), driver)) {
6972
PostLastInstallerError();
7073
return false;
7174
}
@@ -78,8 +81,10 @@ bool RegisterDsn(const Configuration& config, LPCSTR driver) {
7881
continue;
7982
}
8083

81-
if (!SQLWritePrivateProfileString(dsn.c_str(), key.data(), it->second.c_str(),
82-
"ODBC.INI")) {
84+
std::wstring wKey = arrow::util::UTF8ToWideString(key).ValueOr(L"");
85+
std::wstring wValue = arrow::util::UTF8ToWideString(it->second).ValueOr(L"");
86+
if (!SQLWritePrivateProfileString(wDsn.c_str(), wKey.c_str(), wValue.c_str(),
87+
L"ODBC.INI")) {
8388
PostLastInstallerError();
8489
return false;
8590
}

cpp/src/arrow/flight/sql/odbc/flight_sql/system_dsn.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,12 @@ bool DisplayConnectionWindow(void* windowParent, Configuration& config,
5454
* @param driver Driver.
5555
* @return True on success and false on fail.
5656
*/
57-
bool RegisterDsn(const Configuration& config, LPCSTR driver);
57+
bool RegisterDsn(const Configuration& config, LPCWSTR driver);
5858

5959
/**
6060
* Unregister specified DSN.
6161
*
6262
* @param dsn DSN name.
6363
* @return True on success and false on fail.
6464
*/
65-
bool UnregisterDsn(const std::string& dsn);
65+
bool UnregisterDsn(const std::wstring& dsn);

cpp/src/arrow/flight/sql/odbc/flight_sql/system_trust_store.cc

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18+
#include "arrow/result.h"
19+
#include "arrow/util/utf8.h"
20+
1821
#include "arrow/flight/sql/odbc/flight_sql/system_trust_store.h"
1922

2023
#if defined _WIN32 || defined _WIN64
@@ -32,18 +35,20 @@ std::string SystemTrustStore::GetNext() const {
3235
CryptBinaryToString(p_context_->pbCertEncoded, p_context_->cbCertEncoded,
3336
CRYPT_STRING_BASE64HEADER, nullptr, &size);
3437

35-
std::string cert;
36-
cert.resize(size);
38+
std::wstring wCert;
39+
wCert.resize(size);
3740
CryptBinaryToString(p_context_->pbCertEncoded, p_context_->cbCertEncoded,
38-
CRYPT_STRING_BASE64HEADER, &cert[0], &size);
39-
cert.resize(size);
41+
CRYPT_STRING_BASE64HEADER, &wCert[0], &size);
42+
wCert.resize(size);
43+
44+
std::string cert = arrow::util::WideStringToUTF8(wCert).ValueOr("");
4045

4146
return cert;
4247
}
4348

4449
bool SystemTrustStore::SystemHasStore() { return h_store_ != nullptr; }
4550

46-
SystemTrustStore::SystemTrustStore(const char* store)
51+
SystemTrustStore::SystemTrustStore(const wchar_t* store)
4752
: stores_(store), h_store_(CertOpenSystemStore(NULL, store)), p_context_(nullptr) {}
4853

4954
SystemTrustStore::~SystemTrustStore() {

0 commit comments

Comments
 (0)