Skip to content
Merged
Changes from 2 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
4516e4c
Implement SQLGetStmtAttr and SQLSetStmtAttr
rscales Jul 3, 2025
12a059f
Reformat files
rscales Jul 4, 2025
04962f3
Add initial version of statement attr tests
rscales Jul 8, 2025
a5735bf
Change order to have log as first line in method
rscales Jul 8, 2025
6f3e58a
Fix outstanding issues from test cases
rscales Jul 8, 2025
22469a0
Revert back to use void return for ODBCStatement GetStmtAttr and SetS…
rscales Jul 9, 2025
e5cdd2b
Fix formatting issues
rscales Jul 9, 2025
bbbdedf
Fix additional test case issues
rscales Jul 9, 2025
570fa28
Fix issue with expected returned value for SQL_ATTR_ROW_NUMBER test
rscales Jul 9, 2025
87800d5
Revert to use null SQLPOINTER for SQL_ATTR_FETCH_BOOKMARK_PTR default…
rscales Jul 9, 2025
403a53b
Update tests that require use of SQLPOINTER data
rscales Jul 11, 2025
44c331c
Fix copy and paste error for SQL_ATTR_PARAM_STATUS_PTR test case
rscales Jul 11, 2025
413723e
Merge branch 'apache-odbc' into sql-get-stmt-attr
rscales Jul 11, 2025
6cdff25
Update to address comments from review
rscales Jul 11, 2025
b192397
Merge branch 'sql-get-stmt-attr' of https://github.com/Bit-Quill/arro…
rscales Jul 11, 2025
17f2e16
Add SQLPOINTER static casts where missing
rscales Jul 11, 2025
599ffec
Empty commit to force running workflows
rscales Jul 11, 2025
61af11d
Empty commit to force running workflows
rscales Jul 11, 2025
db63cdb
Reformat entry points file due to line added by merge
rscales Jul 11, 2025
dfbf53b
Add missing this reference for statement instance
rscales Jul 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 121 additions & 23 deletions cpp/src/arrow/flight/sql/odbc/tests/statement_attr_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,42 @@ namespace arrow::flight::sql::odbc {

// Helper Functions

// Validate unsigned length SQLULEN return value
// Validate SQLULEN return value
void validateGetStmtAttr(SQLHSTMT statement, SQLINTEGER attribute,
SQLULEN expected_value) {
SQLULEN value = 0;
SQLINTEGER stringLengthPtr;
SQLINTEGER stringLength = 0;

SQLRETURN ret = SQLGetStmtAttr(statement, attribute, &value, 0, &stringLengthPtr);
SQLRETURN ret =
SQLGetStmtAttr(statement, attribute, &value, sizeof(value), &stringLength);

EXPECT_EQ(ret, SQL_SUCCESS);

EXPECT_EQ(value, expected_value);
}

// Validate SQLLEN return value
void validateGetStmtAttr(SQLHSTMT statement, SQLINTEGER attribute,
SQLLEN expected_value) {
SQLLEN value = 0;
SQLINTEGER stringLength = 0;

SQLRETURN ret =
SQLGetStmtAttr(statement, attribute, &value, sizeof(value), &stringLength);

EXPECT_EQ(ret, SQL_SUCCESS);

EXPECT_EQ(value, expected_value);
}

// Validate SQLPOINTER return value
void validateGetStmtAttr(SQLHSTMT statement, SQLINTEGER attribute,
SQLPOINTER expected_value) {
SQLPOINTER value = nullptr;
SQLINTEGER stringLength = 0;

SQLRETURN ret =
SQLGetStmtAttr(statement, attribute, &value, sizeof(value), &stringLength);

EXPECT_EQ(ret, SQL_SUCCESS);

Expand Down Expand Up @@ -72,7 +101,7 @@ void validateGetStmtAttrErrorCode(SQLHSTMT statement, SQLINTEGER attribute,
VerifyOdbcErrorState(SQL_HANDLE_STMT, statement, error_code);
}

// Validate unsigned length SQLULEN return value
// Validate return value for call to SQLSetStmtAttr with SQLULEN
void validateSetStmtAttr(SQLHSTMT statement, SQLINTEGER attribute, SQLULEN new_value) {
SQLINTEGER stringLengthPtr = sizeof(SQLULEN);

Expand All @@ -82,6 +111,23 @@ void validateSetStmtAttr(SQLHSTMT statement, SQLINTEGER attribute, SQLULEN new_v
EXPECT_EQ(ret, SQL_SUCCESS);
}

// Validate return value for call to SQLSetStmtAttr with SQLLEN
void validateSetStmtAttr(SQLHSTMT statement, SQLINTEGER attribute, SQLLEN new_value) {
SQLINTEGER stringLengthPtr = sizeof(SQLLEN);

SQLRETURN ret = SQLSetStmtAttr(
statement, attribute, reinterpret_cast<SQLPOINTER>(new_value), stringLengthPtr);

EXPECT_EQ(ret, SQL_SUCCESS);
}

// Validate return value for call to SQLSetStmtAttr with SQLPOINTER
void validateSetStmtAttr(SQLHSTMT statement, SQLINTEGER attribute, SQLPOINTER value) {
SQLRETURN ret = SQLSetStmtAttr(statement, attribute, value, 0);

EXPECT_EQ(ret, SQL_SUCCESS);
}

// Validate error return value and code
void validateSetStmtAttrErrorCode(SQLHSTMT statement, SQLINTEGER attribute,
SQLULEN new_value, std::string_view error_code) {
Expand Down Expand Up @@ -274,7 +320,7 @@ TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetStmtAttrParamBindOffsetPtr) {
this->connect();

validateGetStmtAttr(this->stmt, SQL_ATTR_PARAM_BIND_OFFSET_PTR,
static_cast<SQLULEN>(0));
static_cast<SQLPOINTER>(nullptr));

this->disconnect();
}
Comment thread
rscales marked this conversation as resolved.
Expand All @@ -291,23 +337,26 @@ TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetStmtAttrParamBindType) {
TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetStmtAttrParamOperationPtr) {
this->connect();

validateGetStmtAttr(this->stmt, SQL_ATTR_PARAM_OPERATION_PTR, static_cast<SQLULEN>(0));
validateGetStmtAttr(this->stmt, SQL_ATTR_PARAM_OPERATION_PTR,
static_cast<SQLPOINTER>(nullptr));

this->disconnect();
}

TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetStmtAttrParamStatusPtr) {
this->connect();

validateGetStmtAttr(this->stmt, SQL_ATTR_PARAM_STATUS_PTR, static_cast<SQLULEN>(0));
validateGetStmtAttr(this->stmt, SQL_ATTR_PARAM_STATUS_PTR,
static_cast<SQLPOINTER>(nullptr));

this->disconnect();
}

TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetStmtAttrParamsProcessedPtr) {
this->connect();

validateGetStmtAttr(this->stmt, SQL_ATTR_PARAMS_PROCESSED_PTR, static_cast<SQLULEN>(0));
validateGetStmtAttr(this->stmt, SQL_ATTR_PARAMS_PROCESSED_PTR,
static_cast<SQLPOINTER>(nullptr));

this->disconnect();
}
Expand Down Expand Up @@ -348,7 +397,8 @@ TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetStmtAttrRowArraySize) {
TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetStmtAttrRowBindOffsetPtr) {
this->connect();

validateGetStmtAttr(this->stmt, SQL_ATTR_ROW_BIND_OFFSET_PTR, static_cast<SQLULEN>(0));
validateGetStmtAttr(this->stmt, SQL_ATTR_ROW_BIND_OFFSET_PTR,
static_cast<SQLPOINTER>(nullptr));

this->disconnect();
}
Expand Down Expand Up @@ -384,23 +434,26 @@ TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetStmtAttrRowNumber) {
TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetStmtAttrRowOperationPtr) {
this->connect();

validateGetStmtAttr(this->stmt, SQL_ATTR_ROW_OPERATION_PTR, static_cast<SQLULEN>(0));
validateGetStmtAttr(this->stmt, SQL_ATTR_ROW_OPERATION_PTR,
static_cast<SQLPOINTER>(nullptr));

this->disconnect();
}

TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetStmtAttrRowStatusPtr) {
this->connect();

validateGetStmtAttr(this->stmt, SQL_ATTR_ROW_STATUS_PTR, static_cast<SQLULEN>(0));
validateGetStmtAttr(this->stmt, SQL_ATTR_ROW_STATUS_PTR,
static_cast<SQLPOINTER>(nullptr));

this->disconnect();
}

TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetStmtAttrRowsFetchedPtr) {
this->connect();

validateGetStmtAttr(this->stmt, SQL_ATTR_ROWS_FETCHED_PTR, static_cast<SQLULEN>(0));
validateGetStmtAttr(this->stmt, SQL_ATTR_ROWS_FETCHED_PTR,
static_cast<SQLPOINTER>(nullptr));

this->disconnect();
}
Expand Down Expand Up @@ -589,11 +642,9 @@ TYPED_TEST(FlightSQLODBCTestBase, TestSQLSetStmtAttrIMPRowDesc) {
}

TYPED_TEST(FlightSQLODBCTestBase, TestSQLSetStmtAttrKeysetSizeUnsupported) {
GTEST_SKIP();
this->connect();

// Optional feature not implemented
validateSetStmtAttrErrorCode(this->stmt, SQL_ATTR_KEYSET_SIZE, 0, error_state_HYC00);
validateSetStmtAttr(this->stmt, SQL_ATTR_KEYSET_SIZE, static_cast<SQLULEN>(0));

this->disconnect();
}
Expand Down Expand Up @@ -635,8 +686,13 @@ TYPED_TEST(FlightSQLODBCTestBase, TestSQLSetStmtAttrNoscan) {
TYPED_TEST(FlightSQLODBCTestBase, TestSQLSetStmtAttrParamBindOffsetPtr) {
this->connect();

SQLULEN offset = 1000;

validateSetStmtAttr(this->stmt, SQL_ATTR_PARAM_BIND_OFFSET_PTR,
static_cast<SQLULEN>(1));
static_cast<SQLPOINTER>(&offset));

validateGetStmtAttr(this->stmt, SQL_ATTR_PARAM_BIND_OFFSET_PTR,
static_cast<SQLPOINTER>(&offset));

this->disconnect();
}
Expand All @@ -653,23 +709,40 @@ TYPED_TEST(FlightSQLODBCTestBase, TestSQLSetStmtAttrParamBindType) {
TYPED_TEST(FlightSQLODBCTestBase, TestSQLSetStmtAttrParamOperationPtr) {
this->connect();

validateSetStmtAttr(this->stmt, SQL_ATTR_PARAM_OPERATION_PTR, static_cast<SQLULEN>(0));
constexpr SQLULEN param_set_size = 4;
SQLUSMALLINT param_operations[param_set_size] = {SQL_PARAM_PROCEED, SQL_PARAM_IGNORE,
SQL_PARAM_PROCEED, SQL_PARAM_IGNORE};

validateSetStmtAttr(this->stmt, SQL_ATTR_PARAM_OPERATION_PTR, param_operations);

validateGetStmtAttr(this->stmt, SQL_ATTR_PARAM_OPERATION_PTR, param_operations);
Comment thread
rscales marked this conversation as resolved.
Outdated

this->disconnect();
}

TYPED_TEST(FlightSQLODBCTestBase, TestSQLSetStmtAttrParamStatusPtr) {
this->connect();

validateSetStmtAttr(this->stmt, SQL_ATTR_PARAM_STATUS_PTR, static_cast<SQLULEN>(0));
// Driver does not support parameters, so just check array can be saved/retrieved
constexpr SQLULEN param_status_size = 4;
SQLUSMALLINT param_status[param_status_size] = {SQL_PARAM_PROCEED, SQL_PARAM_IGNORE,
SQL_PARAM_PROCEED, SQL_PARAM_IGNORE};

validateSetStmtAttr(this->stmt, SQL_ATTR_PARAM_STATUS_PTR, param_status);

validateGetStmtAttr(this->stmt, SQL_ATTR_PARAM_STATUS_PTR, param_status);
Comment thread
rscales marked this conversation as resolved.
Outdated

this->disconnect();
}

TYPED_TEST(FlightSQLODBCTestBase, TestSQLSetStmtAttrParamsProcessedPtr) {
this->connect();

validateSetStmtAttr(this->stmt, SQL_ATTR_PARAMS_PROCESSED_PTR, static_cast<SQLULEN>(0));
SQLULEN processed_count = 0;

validateSetStmtAttr(stmt, SQL_ATTR_PARAMS_PROCESSED_PTR, &processed_count);

validateGetStmtAttr(stmt, SQL_ATTR_PARAMS_PROCESSED_PTR, &processed_count);
Comment thread
rscales marked this conversation as resolved.
Outdated

this->disconnect();
}
Expand Down Expand Up @@ -710,7 +783,13 @@ TYPED_TEST(FlightSQLODBCTestBase, TestSQLSetStmtAttrRowArraySize) {
TYPED_TEST(FlightSQLODBCTestBase, TestSQLSetStmtAttrRowBindOffsetPtr) {
this->connect();

validateSetStmtAttr(this->stmt, SQL_ATTR_ROW_BIND_OFFSET_PTR, static_cast<SQLULEN>(0));
SQLULEN offset = 1000;

validateSetStmtAttr(this->stmt, SQL_ATTR_ROW_BIND_OFFSET_PTR,
static_cast<SQLPOINTER>(&offset));

validateGetStmtAttr(this->stmt, SQL_ATTR_ROW_BIND_OFFSET_PTR,
static_cast<SQLPOINTER>(&offset));

this->disconnect();
}
Expand All @@ -736,23 +815,42 @@ TYPED_TEST(FlightSQLODBCTestBase, TestSQLSetStmtAttrRowNumber) {
TYPED_TEST(FlightSQLODBCTestBase, TestSQLSetStmtAttrRowOperationPtr) {
this->connect();

validateSetStmtAttr(this->stmt, SQL_ATTR_ROW_OPERATION_PTR, static_cast<SQLULEN>(0));
constexpr SQLULEN param_set_size = 4;
SQLUSMALLINT row_operations[param_set_size] = {SQL_ROW_PROCEED, SQL_ROW_IGNORE,
SQL_ROW_PROCEED, SQL_ROW_IGNORE};

validateSetStmtAttr(this->stmt, SQL_ATTR_ROW_OPERATION_PTR, row_operations);

validateGetStmtAttr(this->stmt, SQL_ATTR_ROW_OPERATION_PTR, row_operations);
Comment thread
rscales marked this conversation as resolved.
Outdated

this->disconnect();
}

TYPED_TEST(FlightSQLODBCTestBase, TestSQLSetStmtAttrRowStatusPtr) {
this->connect();

validateSetStmtAttr(this->stmt, SQL_ATTR_ROW_STATUS_PTR, static_cast<SQLULEN>(0));
constexpr SQLULEN row_status_size = 4;
SQLUSMALLINT values[4] = {0, 0, 0, 0};

validateSetStmtAttr(this->stmt, SQL_ATTR_ROW_STATUS_PTR,
static_cast<SQLPOINTER>(&values));

validateGetStmtAttr(this->stmt, SQL_ATTR_ROW_STATUS_PTR,
static_cast<SQLPOINTER>(&values));
Comment thread
rscales marked this conversation as resolved.
Outdated

this->disconnect();
}

TYPED_TEST(FlightSQLODBCTestBase, TestSQLSetStmtAttrRowsFetchedPtr) {
this->connect();

validateSetStmtAttr(this->stmt, SQL_ATTR_ROWS_FETCHED_PTR, static_cast<SQLULEN>(0));
SQLULEN rows_fetched = 1;

validateSetStmtAttr(this->stmt, SQL_ATTR_ROWS_FETCHED_PTR,
static_cast<SQLPOINTER>(&rows_fetched));

validateGetStmtAttr(this->stmt, SQL_ATTR_ROWS_FETCHED_PTR,
static_cast<SQLPOINTER>(&rows_fetched));

this->disconnect();
}
Expand Down