GH-50852: [C++][FlightRPC][ODBC] Decode wide connection/descriptor string attributes with the wide decoder - #50853
Open
vikrantpuppala wants to merge 1 commit into
Open
Conversation
|
|
…tor 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
vikrantpuppala
force-pushed
the
GH-wide-attr-decode-fix
branch
from
August 12, 2026 06:22
e57ce97 to
e51c04f
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Corrects wide-string decoding for ODBC catalog and descriptor attributes.
Changes:
- Uses the wide decoder for Unicode catalog and descriptor names.
- Preserves UTF-8 decoding for non-Unicode catalog values.
- Adds catalog round-trip coverage.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
connection_attr_test.cc |
Tests wide catalog round-tripping. |
odbc_descriptor.cc |
Corrects descriptor-name decoding. |
odbc_connection.cc |
Corrects catalog decoder selection. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| break; | ||
| case SQL_DESC_NAME: | ||
| SetAttributeUTF8(value, buffer_length, record.name); | ||
| SetAttributeSQLWCHAR(value, buffer_length, record.name); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rationale for this change
Two string attributes in the ODBC driver are decoded with the byte-wise
decoder even when the value arrives through a wide (Unicode /
*W) entry point,so the wide buffer is misread and corrupted.
ODBCConnection::SetConnectAttr(SQL_ATTR_CURRENT_CATALOG)had its two decodebranches swapped:
is_unicodeselects the buffer width: a unicode (*W) call passes a wideSQLWCHARbuffer that must be decoded withSetAttributeSQLWCHAR; a non-unicodecall passes a byte string decoded with
SetAttributeUTF8. With the branchesswapped, a wide catalog name (e.g. UTF-16
"my_catalog") is reinterpretedbyte-wise and stored with the wide encoding's embedded NULs
(
"m\0y\0_\0c\0a\0t\0a\0l\0o\0g\0"), so catalog scoping operates on a corruptname. This is the inverse of the mapping the getter already uses:
GetStringAttributemapsis_unicode -> GetAttributeSQLWCHAR.ODBCDescriptor::SetField(SQL_DESC_NAME)is the same class of bug: itunconditionally used the byte-wise
SetAttributeUTF8, even though the matchinggetter (
GetField/SQL_DESC_NAME) reads the field back withGetAttributeSQLWCHAR.How this happened (history):
SQL_ATTR_CURRENT_CATALOGbranches were swapped from the start, in theoriginal driver import ([C++][FlightRPC] Accept donation of ODBC driver #46522, GH-46522: [C++][FlightRPC] Add Arrow Flight SQL ODBC driver #40939). Note the getter side was written
against the shared
GetStringAttributehelper (which decides width in oneplace and got it right), while the setter open-coded the branch inline and
inverted the polarity — there is no matching
SetStringAttributehelper.SQL_DESC_NAMEcase was originally consistent (getter andsetter both byte-wise). [C++][FlightRPC][ODBC] SQLColAttribute implementation #47721 (GH-47721: [C++][FlightRPC] Return ODBC Column Attribute from result set #48050) later migrated the descriptor
string getters to the wide
GetAttributeSQLWCHARfor correct Unicode columnattributes, but left the
SQL_DESC_NAMEsetter on the byte-wise decoder,creating the asymmetry.
What changes are included in this PR?
odbc_connection.cc: swap theSQL_ATTR_CURRENT_CATALOGdecode branches so aunicode call uses
SetAttributeSQLWCHARand a non-unicode call usesSetAttributeUTF8, matchingGetStringAttribute.odbc_descriptor.cc: decodeSQL_DESC_NAMEwithSetAttributeSQLWCHARtomatch its getter.
connection_attr_test.cc: addTestSQLSetGetConnectAttrCurrentCatalogWide, aTYPED_TEST(mock + remote fixtures) that sets a multi-character catalogthrough the wide entry point and asserts the full name round-trips back.
Are these changes tested?
Yes. The new test is a set-then-get round-trip through the real driver stack
(
SQLSetConnectAttr/SQLGetConnectAttr), placed next to the other connectionattribute tests, and it distinguishes the fixed and unfixed driver:
out_catalog == "my_catalog"out_catalog == "m\0y\0_\0c\0a\0t\0a\0l\0o\0g\0"ConnectionAttributeTest/0.*(full mock suite)The mock fixture (
FlightSQLODBCMockTestBase) runs against an in-process SQLiteFlight SQL server; the remote variant runs when
ARROW_FLIGHT_SQL_ODBC_CONNisset. Verified locally against the mock fixture.
Are there any user-facing changes?
Yes. A catalog name (and descriptor
SQL_DESC_NAME) set through the wide entrypoint is now decoded correctly instead of being corrupted. Applications that set
a multi-character catalog through
SQLSetConnectAttrWnow scope to the intendedcatalog.
AI usage
Per the AI-generated code guidance:
the diagnosis, the fix, and the test were produced with the assistance of an AI
coding agent and reviewed and verified by me. Correctness was checked by
(1) confirming the getter path (
GetStringAttribute) mapsis_unicodeto thewide decoder, establishing the intended mapping the setters violated, and
(2) running the new round-trip test against both the fixed and unfixed driver to
confirm it distinguishes them (clean name vs. embedded-NUL corruption).
🤖 Drafted by Claude Code (an AI agent) and reviewed & verified by vikrantpuppala.