Skip to content

Commit 430d4b1

Browse files
GH-47710: [C++][FlightRPC] Statement attribute Support in ODBC (#47773)
### Rationale for this change Support for getting and setting statement attributes in ODBC is added. ### What changes are included in this PR? - Implementation of `SQLGetStmtAttr` and `SQLSetStmtAttr` to get and set statement attributes. - Tests ### Are these changes tested? Tested on local MSVC ### Are there any user-facing changes? No * GitHub Issue: #47710 Lead-authored-by: Alina (Xi) Li <[email protected]> Co-authored-by: alinalibq <[email protected]> Co-authored-by: justing-bq <[email protected]> Signed-off-by: David Li <[email protected]>
1 parent fa41b26 commit 430d4b1

File tree

5 files changed

+703
-9
lines changed

5 files changed

+703
-9
lines changed

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

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -923,17 +923,38 @@ SQLRETURN SQLGetStmtAttr(SQLHSTMT stmt, SQLINTEGER attribute, SQLPOINTER value_p
923923
<< ", attribute: " << attribute << ", value_ptr: " << value_ptr
924924
<< ", buffer_length: " << buffer_length << ", string_length_ptr: "
925925
<< static_cast<const void*>(string_length_ptr);
926-
// GH-47710 TODO: Implement SQLGetStmtAttr
927-
return SQL_INVALID_HANDLE;
926+
927+
using ODBC::ODBCStatement;
928+
929+
return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() {
930+
ODBCStatement* statement = reinterpret_cast<ODBCStatement*>(stmt);
931+
932+
bool is_unicode = true;
933+
934+
statement->GetStmtAttr(attribute, value_ptr, buffer_length, string_length_ptr,
935+
is_unicode);
936+
937+
return SQL_SUCCESS;
938+
});
928939
}
929940

930941
SQLRETURN SQLSetStmtAttr(SQLHSTMT stmt, SQLINTEGER attribute, SQLPOINTER value_ptr,
931942
SQLINTEGER string_length) {
932943
ARROW_LOG(DEBUG) << "SQLSetStmtAttrW called with stmt: " << stmt
933944
<< ", attribute: " << attribute << ", value_ptr: " << value_ptr
934945
<< ", string_length: " << string_length;
935-
// GH-47710 TODO: Implement SQLSetStmtAttr
936-
return SQL_INVALID_HANDLE;
946+
947+
using ODBC::ODBCStatement;
948+
949+
return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() {
950+
ODBCStatement* statement = reinterpret_cast<ODBCStatement*>(stmt);
951+
952+
bool is_unicode = true;
953+
954+
statement->SetStmtAttr(attribute, value_ptr, string_length, is_unicode);
955+
956+
return SQL_SUCCESS;
957+
});
937958
}
938959

939960
SQLRETURN SQLExecDirect(SQLHSTMT stmt, SQLWCHAR* query_text, SQLINTEGER text_length) {

cpp/src/arrow/flight/sql/odbc/odbc_impl/odbc_statement.cc

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,14 @@ void ODBCStatement::GetStmtAttr(SQLINTEGER statement_attribute, SQLPOINTER outpu
375375
return;
376376
case SQL_ATTR_PARAM_BIND_TYPE:
377377
current_apd_->GetHeaderField(SQL_DESC_BIND_TYPE, output, buffer_size, str_len_ptr);
378+
if (output) {
379+
// Convert SQLINTEGER output to SQLULEN, since SQL_DESC_BIND_TYPE is SQLINTEGER
380+
// and SQL_ATTR_PARAM_BIND_TYPE is SQLULEN
381+
SQLINTEGER* output_int_ptr = reinterpret_cast<SQLINTEGER*>(output);
382+
SQLINTEGER output_int = *output_int_ptr;
383+
SQLULEN* typed_output = reinterpret_cast<SQLULEN*>(output);
384+
*typed_output = static_cast<SQLULEN>(output_int);
385+
}
378386
return;
379387
case SQL_ATTR_PARAM_OPERATION_PTR:
380388
current_apd_->GetHeaderField(SQL_DESC_ARRAY_STATUS_PTR, output, buffer_size,
@@ -398,6 +406,14 @@ void ODBCStatement::GetStmtAttr(SQLINTEGER statement_attribute, SQLPOINTER outpu
398406
return;
399407
case SQL_ATTR_ROW_BIND_TYPE:
400408
current_ard_->GetHeaderField(SQL_DESC_BIND_TYPE, output, buffer_size, str_len_ptr);
409+
if (output) {
410+
// Convert SQLINTEGER output to SQLULEN, since SQL_DESC_BIND_TYPE is SQLINTEGER
411+
// and SQL_ATTR_ROW_BIND_TYPE is SQLULEN
412+
SQLINTEGER* output_int_ptr = reinterpret_cast<SQLINTEGER*>(output);
413+
SQLINTEGER output_int = *output_int_ptr;
414+
SQLULEN* typed_output = reinterpret_cast<SQLULEN*>(output);
415+
*typed_output = static_cast<SQLULEN>(output_int);
416+
}
401417
return;
402418
case SQL_ATTR_ROW_OPERATION_PTR:
403419
current_ard_->GetHeaderField(SQL_DESC_ARRAY_STATUS_PTR, output, buffer_size,
@@ -627,7 +643,7 @@ void ODBCStatement::SetStmtAttr(SQLINTEGER statement_attribute, SQLPOINTER value
627643
CheckIfAttributeIsSetToOnlyValidValue(value, static_cast<SQLULEN>(SQL_UB_OFF));
628644
return;
629645
case SQL_ATTR_RETRIEVE_DATA:
630-
CheckIfAttributeIsSetToOnlyValidValue(value, static_cast<SQLULEN>(SQL_TRUE));
646+
CheckIfAttributeIsSetToOnlyValidValue(value, static_cast<SQLULEN>(SQL_RD_ON));
631647
return;
632648
case SQL_ROWSET_SIZE:
633649
SetAttribute(value, rowset_size_);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ add_arrow_test(flight_sql_odbc_test
3434
SOURCES
3535
odbc_test_suite.cc
3636
odbc_test_suite.h
37+
statement_attr_test.cc
3738
connection_test.cc
3839
# Enable Protobuf cleanup after test execution
3940
# GH-46889: move protobuf_test_util to a more common location

cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.cc

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,11 @@ void ODBCRemoteTestBase::ConnectWithString(std::string connect_str) {
6161
kOdbcBufferSize, &out_str_len, SQL_DRIVER_NOPROMPT))
6262
<< GetOdbcErrorMessage(SQL_HANDLE_DBC, conn);
6363

64-
// GH-47710: TODO Allocate a statement using alloc handle
65-
// ASSERT_EQ(SQL_SUCCESS, SQLAllocHandle(SQL_HANDLE_STMT, conn, &stmt));
64+
ASSERT_EQ(SQL_SUCCESS, SQLAllocHandle(SQL_HANDLE_STMT, conn, &stmt));
6665
}
6766

6867
void ODBCRemoteTestBase::Disconnect() {
69-
// GH-47710: TODO Close statement
70-
// EXPECT_EQ(SQL_SUCCESS, SQLFreeHandle(SQL_HANDLE_STMT, stmt));
68+
EXPECT_EQ(SQL_SUCCESS, SQLFreeHandle(SQL_HANDLE_STMT, stmt));
7169

7270
// Disconnect from ODBC
7371
EXPECT_EQ(SQL_SUCCESS, SQLDisconnect(conn))

0 commit comments

Comments
 (0)