Skip to content

Commit 2a3c5db

Browse files
authored
apacheGH-47713: [C++][FlightRPC] ODBC return number of result columns (apache#48036)
### Rationale for this change Implement ODBC to return the number of result columns ### What changes are included in this PR? - SQLNumResultCols implementation & tests ### Are these changes tested? Tested locally on MSVC ### Are there any user-facing changes? N/A * GitHub Issue: apache#47713 Authored-by: Alina (Xi) Li <[email protected]> Signed-off-by: David Li <[email protected]>
1 parent 2571c2c commit 2a3c5db

File tree

4 files changed

+64
-2
lines changed

4 files changed

+64
-2
lines changed

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,8 +1147,13 @@ SQLRETURN SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT* column_count_ptr) {
11471147
ARROW_LOG(DEBUG) << "SQLNumResultCols called with stmt: " << stmt
11481148
<< ", column_count_ptr: "
11491149
<< static_cast<const void*>(column_count_ptr);
1150-
// GH-47713 TODO: Implement SQLNumResultCols
1151-
return SQL_INVALID_HANDLE;
1150+
1151+
using ODBC::ODBCStatement;
1152+
return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() {
1153+
ODBCStatement* statement = reinterpret_cast<ODBCStatement*>(stmt);
1154+
statement->GetColumnCount(column_count_ptr);
1155+
return SQL_SUCCESS;
1156+
});
11521157
}
11531158

11541159
SQLRETURN SQLRowCount(SQLHSTMT stmt, SQLLEN* row_count_ptr) {

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,16 @@ SQLRETURN ODBCStatement::GetData(SQLSMALLINT record_number, SQLSMALLINT c_type,
761761
data_ptr, buffer_length, indicator_ptr);
762762
}
763763

764+
void ODBCStatement::GetColumnCount(SQLSMALLINT* column_count_ptr) {
765+
if (!column_count_ptr) {
766+
// column count pointer is not valid, do nothing as ODBC spec does not mention this as
767+
// an error
768+
return;
769+
}
770+
size_t column_count = ird_->GetRecords().size();
771+
*column_count_ptr = static_cast<SQLSMALLINT>(column_count);
772+
}
773+
764774
void ODBCStatement::GetRowCount(SQLLEN* row_count_ptr) {
765775
if (!row_count_ptr) {
766776
// row count pointer is not valid, do nothing as ODBC spec does not mention this as an

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ class ODBCStatement : public ODBCHandle<ODBCStatement> {
7878
SQLRETURN GetData(SQLSMALLINT record_number, SQLSMALLINT c_type, SQLPOINTER data_ptr,
7979
SQLLEN buffer_length, SQLLEN* indicator_ptr);
8080

81+
/// \brief Return number of columns from data set
82+
void GetColumnCount(SQLSMALLINT* column_count_ptr);
83+
8184
/// \brief Return number of rows affected by an UPDATE, INSERT, or DELETE statement\
8285
///
8386
/// -1 is returned as driver only supports SELECT statement

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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,50 @@ TYPED_TEST(StatementTest, TestSQLNativeSqlReturnsErrorOnBadInputs) {
12811281
VerifyOdbcErrorState(SQL_HANDLE_DBC, this->conn, kErrorStateHY090);
12821282
}
12831283

1284+
TYPED_TEST(StatementTest, SQLNumResultColsReturnsColumnsOnSelect) {
1285+
SQLSMALLINT column_count = 0;
1286+
SQLSMALLINT expected_value = 3;
1287+
SQLWCHAR sql_query[] = L"SELECT 1 AS col1, 'One' AS col2, 3 AS col3";
1288+
SQLINTEGER query_length = static_cast<SQLINTEGER>(wcslen(sql_query));
1289+
1290+
ASSERT_EQ(SQL_SUCCESS, SQLExecDirect(this->stmt, sql_query, query_length));
1291+
1292+
ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt));
1293+
1294+
CheckIntColumn(this->stmt, 1, 1);
1295+
CheckStringColumnW(this->stmt, 2, L"One");
1296+
CheckIntColumn(this->stmt, 3, 3);
1297+
1298+
ASSERT_EQ(SQL_SUCCESS, SQLNumResultCols(this->stmt, &column_count));
1299+
1300+
EXPECT_EQ(expected_value, column_count);
1301+
}
1302+
1303+
TYPED_TEST(StatementTest, SQLNumResultColsReturnsSuccessOnNullptr) {
1304+
SQLWCHAR sql_query[] = L"SELECT 1 AS col1, 'One' AS col2, 3 AS col3";
1305+
SQLINTEGER query_length = static_cast<SQLINTEGER>(wcslen(sql_query));
1306+
1307+
ASSERT_EQ(SQL_SUCCESS, SQLExecDirect(this->stmt, sql_query, query_length));
1308+
1309+
ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt));
1310+
1311+
CheckIntColumn(this->stmt, 1, 1);
1312+
CheckStringColumnW(this->stmt, 2, L"One");
1313+
CheckIntColumn(this->stmt, 3, 3);
1314+
1315+
ASSERT_EQ(SQL_SUCCESS, SQLNumResultCols(this->stmt, nullptr));
1316+
}
1317+
1318+
TYPED_TEST(StatementTest, SQLNumResultColsFunctionSequenceErrorOnNoQuery) {
1319+
SQLSMALLINT column_count = 0;
1320+
SQLSMALLINT expected_value = 0;
1321+
1322+
ASSERT_EQ(SQL_ERROR, SQLNumResultCols(this->stmt, &column_count));
1323+
VerifyOdbcErrorState(SQL_HANDLE_STMT, this->stmt, kErrorStateHY010);
1324+
1325+
EXPECT_EQ(expected_value, column_count);
1326+
}
1327+
12841328
TYPED_TEST(StatementTest, SQLRowCountReturnsNegativeOneOnSelect) {
12851329
SQLLEN row_count = 0;
12861330
SQLLEN expected_value = -1;

0 commit comments

Comments
 (0)