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 029477564799..337951ede3ac 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 @@ -20,6 +20,7 @@ #include "arrow/result.h" #include "arrow/util/utf8.h" +#include "arrow/flight/sql/odbc/flight_sql/include/flight_sql/config/configuration.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" @@ -58,44 +59,10 @@ const boost::xpressive::sregex CONNECTION_STR_REGEX( // entries in the properties. void loadPropertiesFromDSN(const std::string& dsn, Connection::ConnPropertyMap& properties) { - const size_t BUFFER_SIZE = 1024 * 10; - std::vector outputBuffer; - outputBuffer.resize(BUFFER_SIZE, '\0'); - SQLSetConfigMode(ODBC_BOTH_DSN); - - 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; - size_t pos = 0; - while (pos < BUFFER_SIZE) { - std::wstring wKey(&outputBuffer[pos]); - if (wKey.empty()) { - break; - } - size_t len = wKey.size(); - - // Skip over Driver or DSN keys. - if (!boost::iequals(wKey, L"DSN") && !boost::iequals(wKey, L"Driver")) { - keys.emplace_back(std::move(wKey)); - } - pos += len + 1; - } - - for (auto& wKey : keys) { - outputBuffer.clear(); - outputBuffer.resize(BUFFER_SIZE, '\0'); - SQLGetPrivateProfileString(wDsn.c_str(), wKey.data(), L"", &outputBuffer[0], - BUFFER_SIZE, L"odbc.ini"); - - 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(""); + driver::flight_sql::config::Configuration config; + config.LoadDsn(dsn); + Connection::ConnPropertyMap dsnProperties = config.GetProperties(); + for (auto& [key, value] : dsnProperties) { 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/connection_test.cc b/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc index 471a2fffd80d..81c4abe70cfe 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc +++ b/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc @@ -361,6 +361,79 @@ TYPED_TEST(FlightSQLODBCTestBase, TestSQLDriverConnect) { EXPECT_EQ(ret, SQL_SUCCESS); } +TYPED_TEST(FlightSQLODBCTestBase, TestSQLDriverConnectDsn) { + // ODBC Environment + SQLHENV env; + SQLHDBC conn; + + // Allocate an environment handle + SQLRETURN ret = SQLAllocEnv(&env); + + EXPECT_EQ(ret, SQL_SUCCESS); + + ret = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); + + EXPECT_EQ(ret, SQL_SUCCESS); + + // Allocate a connection using alloc handle + ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &conn); + + EXPECT_EQ(ret, SQL_SUCCESS); + + // Connect string + std::string connect_str = this->getConnectionString(); + + // Write connection string content into a DSN, + // must succeed before continuing + ASSERT_TRUE(writeDSN(connect_str)); + + std::string dsn(TEST_DSN); + ASSERT_OK_AND_ASSIGN(std::wstring wdsn, arrow::util::UTF8ToWideString(dsn)); + + // Update connection string to use DSN to connect + connect_str = std::string("DSN=") + std::string(TEST_DSN) + + std::string(";driver={Apache Arrow Flight SQL ODBC Driver};"); + ASSERT_OK_AND_ASSIGN(std::wstring wconnect_str, + arrow::util::UTF8ToWideString(connect_str)); + std::vector connect_str0(wconnect_str.begin(), wconnect_str.end()); + + SQLWCHAR outstr[ODBC_BUFFER_SIZE] = L""; + SQLSMALLINT outstrlen; + + // Connecting to ODBC server. + ret = SQLDriverConnect(conn, NULL, &connect_str0[0], + static_cast(connect_str0.size()), outstr, + ODBC_BUFFER_SIZE, &outstrlen, SQL_DRIVER_NOPROMPT); + + if (ret != SQL_SUCCESS) { + std::cerr << GetOdbcErrorMessage(SQL_HANDLE_DBC, conn) << std::endl; + } + + EXPECT_EQ(ret, SQL_SUCCESS); + + // Remove DSN + EXPECT_TRUE(UnregisterDsn(wdsn)); + + // Disconnect from ODBC + ret = SQLDisconnect(conn); + + if (ret != SQL_SUCCESS) { + std::cerr << GetOdbcErrorMessage(SQL_HANDLE_DBC, conn) << std::endl; + } + + EXPECT_EQ(ret, SQL_SUCCESS); + + // Free connection handle + ret = SQLFreeHandle(SQL_HANDLE_DBC, conn); + + EXPECT_EQ(ret, SQL_SUCCESS); + + // Free environment handle + ret = SQLFreeHandle(SQL_HANDLE_ENV, env); + + EXPECT_EQ(ret, SQL_SUCCESS); +} + TEST_F(FlightSQLODBCRemoteTestBase, TestSQLDriverConnectInvalidUid) { // ODBC Environment SQLHENV env;