diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_api.cc b/cpp/src/arrow/flight/sql/odbc/odbc_api.cc index 82a167b3c16c..f89b1b974810 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc_api.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbc_api.cc @@ -752,6 +752,21 @@ SQLRETURN SQLSetConnectAttr(SQLHDBC conn, SQLINTEGER attr, SQLPOINTER valuePtr, }); } +// Load properties from the given DSN. The properties loaded do _not_ overwrite existing +// entries in the properties. +void loadPropertiesFromDSN(const std::string& dsn, + Connection::ConnPropertyMap& properties) { + 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))); + } + } +} + SQLRETURN SQLDriverConnect(SQLHDBC conn, SQLHWND windowHandle, SQLWCHAR* inConnectionString, SQLSMALLINT inConnectionStringLen, @@ -782,8 +797,11 @@ SQLRETURN SQLDriverConnect(SQLHDBC conn, SQLHWND windowHandle, std::string connection_string = ODBC::SqlWcharToString(inConnectionString, inConnectionStringLen); Connection::ConnPropertyMap properties; - std::string dsn = - ODBCConnection::getPropertiesFromConnString(connection_string, properties); + std::string dsn = ODBCConnection::getDsnIfExists(connection_string); + if (!dsn.empty()) { + loadPropertiesFromDSN(dsn, properties); + } + ODBCConnection::getPropertiesFromConnString(connection_string, properties); std::vector missing_properties; diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/odbc_impl/odbc_connection.h b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/odbc_impl/odbc_connection.h index 0e9498bcb8a0..f78a70d136a3 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/odbc_impl/odbc_connection.h +++ b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/odbc_impl/odbc_connection.h @@ -84,8 +84,12 @@ class ODBCConnection : public ODBCHandle { inline bool IsOdbc2Connection() const { return m_is2xConnection; } - /// @return the DSN or empty string if Driver was used. - static std::string getPropertiesFromConnString( + /// @return the DSN or an empty string if the DSN is not found or is found after the + /// driver + static std::string getDsnIfExists(const std::string& connStr); + + /// Read properties from connection string, but does not read values from DSN + static void getPropertiesFromConnString( const std::string& connStr, driver::odbcabstraction::Connection::ConnPropertyMap& properties); 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 337951ede3ac..6aecbc7fd195 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 @@ -54,22 +54,6 @@ namespace { // built statically. const boost::xpressive::sregex CONNECTION_STR_REGEX( boost::xpressive::sregex::compile("([^=;]+)=({.+}|[^;]+|[^;])")); - -// Load properties from the given DSN. The properties loaded do _not_ overwrite existing -// entries in the properties. -void loadPropertiesFromDSN(const std::string& dsn, - Connection::ConnPropertyMap& properties) { - 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))); - } - } -} - } // namespace // Public @@ -696,37 +680,42 @@ void ODBCConnection::dropDescriptor(ODBCDescriptor* desc) { // Public Static // =================================================================================== -std::string ODBCConnection::getPropertiesFromConnString( +std::string ODBCConnection::getDsnIfExists(const std::string& connStr) { + const int groups[] = {1, 2}; // CONNECTION_STR_REGEX has two groups. key: 1, value: 2 + boost::xpressive::sregex_token_iterator regex_iter(connStr.begin(), connStr.end(), + CONNECTION_STR_REGEX, groups), + end; + + // First key in connection string should be either dsn or driver + auto it = regex_iter; + std::string key = *regex_iter; + std::string value = *++regex_iter; + + // Strip wrapping curly braces. + if (value.size() >= 2 && value[0] == '{' && value[value.size() - 1] == '}') { + value = value.substr(1, value.size() - 2); + } + + if (boost::iequals(key, "DSN")) { + return value; + } else if (boost::iequals(key, "Driver")) { + return std::string(""); + } else { + throw DriverException( + "Connection string is faulty. The first key should be DSN or Driver.", "HY000"); + } +} + +void ODBCConnection::getPropertiesFromConnString( const std::string& connStr, Connection::ConnPropertyMap& properties) { const int groups[] = {1, 2}; // CONNECTION_STR_REGEX has two groups. key: 1, value: 2 - boost::xpressive::sregex_token_iterator regexIter(connStr.begin(), connStr.end(), - CONNECTION_STR_REGEX, groups), + boost::xpressive::sregex_token_iterator regex_iter(connStr.begin(), connStr.end(), + CONNECTION_STR_REGEX, groups), end; - bool isDsnFirst = false; - bool isDriverFirst = false; - std::string dsn; - for (auto it = regexIter; end != regexIter; ++regexIter) { - std::string key = *regexIter; - std::string value = *++regexIter; - - // If the DSN shows up before driver key, load settings from the DSN. - // Only load values from the DSN once regardless of how many times the DSN - // key shows up. - if (boost::iequals(key, "DSN")) { - if (!isDriverFirst) { - if (!isDsnFirst) { - isDsnFirst = true; - loadPropertiesFromDSN(value, properties); - dsn.swap(value); - } - } - continue; - } else if (boost::iequals(key, "Driver")) { - if (!isDsnFirst) { - isDriverFirst = true; - } - } + for (auto it = regex_iter; end != regex_iter; ++regex_iter) { + std::string key = *regex_iter; + std::string value = *++regex_iter; // Strip wrapping curly braces. if (value.size() >= 2 && value[0] == '{' && value[value.size() - 1] == '}') { @@ -737,5 +726,4 @@ std::string ODBCConnection::getPropertiesFromConnString( // including over entries in the DSN. properties[key] = std::move(value); } - return dsn; }