From e51c04f09f2638b15620d7940bb09f35d7ce2f95 Mon Sep 17 00:00:00 2001 From: Vikrant Puppala Date: Wed, 12 Aug 2026 06:09:29 +0000 Subject: [PATCH] GH-50852: [C++][FlightRPC][ODBC] Decode wide connection/descriptor string attributes with the wide decoder SetConnectAttr(SQL_ATTR_CURRENT_CATALOG) had its is_unicode decode branches swapped, and SetField(SQL_DESC_NAME) unconditionally used the byte-wise SetAttributeUTF8. In both cases a wide SQLWCHAR buffer was misread, corrupting the stored value. Decode wide buffers with SetAttributeSQLWCHAR, matching the mapping the getters already use (GetStringAttribute / GetAttributeSQLWCHAR). Add a round-trip TYPED_TEST for SQL_ATTR_CURRENT_CATALOG through the wide entry point in connection_attr_test.cc. Co-authored-by: Isaac --- .../sql/odbc/odbc_impl/odbc_connection.cc | 4 ++-- .../sql/odbc/odbc_impl/odbc_descriptor.cc | 2 +- .../sql/odbc/tests/connection_attr_test.cc | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_impl/odbc_connection.cc b/cpp/src/arrow/flight/sql/odbc/odbc_impl/odbc_connection.cc index 142dac53ab6f..e452008b27bb 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc_impl/odbc_connection.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbc_impl/odbc_connection.cc @@ -465,9 +465,9 @@ void ODBCConnection::SetConnectAttr(SQLINTEGER attribute, SQLPOINTER value, case SQL_ATTR_CURRENT_CATALOG: { std::string catalog; if (is_unicode) { - SetAttributeUTF8(value, string_length, catalog); - } else { SetAttributeSQLWCHAR(value, string_length, catalog); + } else { + SetAttributeUTF8(value, string_length, catalog); } if (!spi_connection_->SetAttribute(Connection::CURRENT_CATALOG, catalog)) { throw DriverException("Option value changed.", "01S02"); diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_impl/odbc_descriptor.cc b/cpp/src/arrow/flight/sql/odbc/odbc_impl/odbc_descriptor.cc index 11e4512eb8d1..d58d8b93ba02 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc_impl/odbc_descriptor.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbc_impl/odbc_descriptor.cc @@ -215,7 +215,7 @@ void ODBCDescriptor::SetField(SQLSMALLINT record_number, SQLSMALLINT field_ident has_bindings_changed_ = true; break; case SQL_DESC_NAME: - SetAttributeUTF8(value, buffer_length, record.name); + SetAttributeSQLWCHAR(value, buffer_length, record.name); has_bindings_changed_ = true; break; case SQL_DESC_OCTET_LENGTH: diff --git a/cpp/src/arrow/flight/sql/odbc/tests/connection_attr_test.cc b/cpp/src/arrow/flight/sql/odbc/tests/connection_attr_test.cc index 65aadf1d8f95..63b55def9116 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/connection_attr_test.cc +++ b/cpp/src/arrow/flight/sql/odbc/tests/connection_attr_test.cc @@ -410,4 +410,23 @@ TYPED_TEST(ConnectionAttributeTest, TestSQLSetConnectAttrPacketSizeValid) { #endif } +// A multi-character catalog set through the wide entry point must round-trip +// intact. +TYPED_TEST(ConnectionAttributeTest, TestSQLSetGetConnectAttrCurrentCatalogWide) { + ASSIGN_SQLWCHAR_ARR_AND_LEN(catalog, L"my_catalog"); + + ASSERT_EQ(SQL_SUCCESS, SQLSetConnectAttr(this->conn, SQL_ATTR_CURRENT_CATALOG, catalog, + catalog_len * GetSqlWCharSize())); + + SQLWCHAR out_str[kOdbcBufferSize]; + SQLINTEGER out_str_len; + ASSERT_EQ(SQL_SUCCESS, SQLGetConnectAttr(this->conn, SQL_ATTR_CURRENT_CATALOG, out_str, + kOdbcBufferSize, &out_str_len)); + // SQLGetConnectAttr returns the length in bytes; convert to characters. + out_str_len /= GetSqlWCharSize(); + std::string out_catalog = + ODBC::SqlWcharToString(out_str, static_cast(out_str_len)); + EXPECT_EQ("my_catalog", out_catalog); +} + } // namespace arrow::flight::sql::odbc