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

Reply via email to