This is an automated email from the ASF dual-hosted git repository.
lidavidm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new 7363d521fc GH-47706: [C++][FlightRPC] ODBC SQLFreeStmt implementation
(#48033)
7363d521fc is described below
commit 7363d521fcfd833e05454fea8d4a736dce3fd0e9
Author: Alina (Xi) Li <[email protected]>
AuthorDate: Sun Nov 30 00:05:41 2025 -0800
GH-47706: [C++][FlightRPC] ODBC SQLFreeStmt implementation (#48033)
### Rationale for this change
Support statement deallocation
### What changes are included in this PR?
- Implement SQLFreeStmt
- Add tests
### Are these changes tested?
Tested locally on MSVC CI
### Are there any user-facing changes?
N/A
* GitHub Issue: #47706
Authored-by: Alina (Xi) Li <[email protected]>
Signed-off-by: David Li <[email protected]>
---
cpp/src/arrow/flight/sql/odbc/odbc_api.cc | 41 ++++++++++++++++++++--
.../arrow/flight/sql/odbc/tests/connection_test.cc | 40 +++++++++++++++++++++
2 files changed, 79 insertions(+), 2 deletions(-)
diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_api.cc
b/cpp/src/arrow/flight/sql/odbc/odbc_api.cc
index fc50e4a816..eca49f3209 100644
--- a/cpp/src/arrow/flight/sql/odbc/odbc_api.cc
+++ b/cpp/src/arrow/flight/sql/odbc/odbc_api.cc
@@ -219,8 +219,45 @@ SQLRETURN SQLFreeHandle(SQLSMALLINT type, SQLHANDLE
handle) {
SQLRETURN SQLFreeStmt(SQLHSTMT handle, SQLUSMALLINT option) {
ARROW_LOG(DEBUG) << "SQLFreeStmt called with handle: " << handle
<< ", option: " << option;
- // GH-47706 TODO: Implement SQLFreeStmt
- return SQL_INVALID_HANDLE;
+
+ switch (option) {
+ case SQL_CLOSE: {
+ using ODBC::ODBCStatement;
+
+ return ODBCStatement::ExecuteWithDiagnostics(handle, SQL_ERROR, [=]() {
+ ODBCStatement* statement = reinterpret_cast<ODBCStatement*>(handle);
+
+ // Close cursor with suppressErrors set to true
+ statement->CloseCursor(true);
+
+ return SQL_SUCCESS;
+ });
+ }
+
+ case SQL_DROP: {
+ return SQLFreeHandle(SQL_HANDLE_STMT, handle);
+ }
+
+ case SQL_UNBIND: {
+ // GH-47716 TODO: Add tests for SQLBindCol unbinding
+ using ODBC::ODBCDescriptor;
+ using ODBC::ODBCStatement;
+ return ODBCStatement::ExecuteWithDiagnostics(handle, SQL_ERROR, [=]() {
+ ODBCStatement* statement = reinterpret_cast<ODBCStatement*>(handle);
+ ODBCDescriptor* ard = statement->GetARD();
+ // Unbind columns
+ ard->SetHeaderField(SQL_DESC_COUNT, (void*)0, 0);
+ return SQL_SUCCESS;
+ });
+ }
+
+ // SQLBindParameter is not supported
+ case SQL_RESET_PARAMS: {
+ return SQL_SUCCESS;
+ }
+ }
+
+ return SQL_ERROR;
}
inline bool IsValidStringFieldArgs(SQLPOINTER diag_info_ptr, SQLSMALLINT
buffer_length,
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 531250b69b..33fb48078c 100644
--- a/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc
+++ b/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc
@@ -468,4 +468,44 @@ TYPED_TEST(ConnectionHandleTest,
TestSQLDisconnectWithoutConnection) {
TYPED_TEST(ConnectionTest, TestConnect) {
// Verifies connect and disconnect works on its own
}
+
+TYPED_TEST(ConnectionTest, TestSQLAllocFreeStmt) {
+ SQLHSTMT statement;
+
+ // Allocate a statement using alloc statement
+ ASSERT_EQ(SQL_SUCCESS, SQLAllocStmt(this->conn, &statement));
+
+ // Close statement handle
+ ASSERT_EQ(SQL_SUCCESS, SQLFreeStmt(statement, SQL_CLOSE));
+
+ // Free statement handle
+ ASSERT_EQ(SQL_SUCCESS, SQLFreeStmt(statement, SQL_DROP));
+}
+
+TYPED_TEST(ConnectionHandleTest, TestCloseConnectionWithOpenStatement) {
+ SQLHSTMT statement;
+
+ // Connect string
+ std::string connect_str = this->GetConnectionString();
+ ASSERT_OK_AND_ASSIGN(std::wstring wconnect_str,
+ arrow::util::UTF8ToWideString(connect_str));
+ std::vector<SQLWCHAR> connect_str0(wconnect_str.begin(), wconnect_str.end());
+
+ SQLWCHAR out_str[kOdbcBufferSize] = L"";
+ SQLSMALLINT out_str_len;
+
+ // Connecting to ODBC server.
+ ASSERT_EQ(SQL_SUCCESS,
+ SQLDriverConnect(this->conn, NULL, &connect_str0[0],
+ static_cast<SQLSMALLINT>(connect_str0.size()),
out_str,
+ kOdbcBufferSize, &out_str_len,
SQL_DRIVER_NOPROMPT))
+ << GetOdbcErrorMessage(SQL_HANDLE_DBC, this->conn);
+
+ // Allocate a statement using alloc statement
+ ASSERT_EQ(SQL_SUCCESS, SQLAllocStmt(this->conn, &statement));
+
+ // Disconnect from ODBC without closing the statement first
+ ASSERT_EQ(SQL_SUCCESS, SQLDisconnect(this->conn));
+}
+
} // namespace arrow::flight::sql::odbc