Skip to content

Conversation

@alinaliBQ
Copy link
Contributor

@alinaliBQ alinaliBQ commented Oct 8, 2025

Rationale for this change

ODBC driver needs to set and get environment attributes, such as ODBC driver version.

What changes are included in this PR?

  • Implement SQLGetEnvAttr and SQLSetEnvAttr APIs for retrieving and setting environment attribute values
  • Tests

Are these changes tested?

Tested locally on Windows MSVC.
Will be tested in CI after #47689 is merged

Are there any user-facing changes?

No

@alinaliBQ
Copy link
Contributor Author

@lidavidm @kou Please review this draft ODBC API PR. The testing folder structure will be in a separate PR

namespace arrow::flight::sql::odbc {

TEST(SQLGetEnvAttr, TestSQLGetEnvAttrODBCVersion) {
// ODBC Environment
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, but I don't think these comments add anything

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

Comment on lines +112 to +266
if (!value_ptr && !str_len_ptr) {
throw DriverException("Invalid null pointer for attribute.", "HY000");
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test this case as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a test DISABLED_TestSQLGetEnvAttrNullValuePointer for this case. The test case is disabled because call to SQLGetEnvAttr is handled by the driver manager on Windows. And the Windows driver manager doesn't error out when null pointer is passed, even though it should.

Potentially this can be tested on mac/linux depending on the driver manager on these systems

@github-actions github-actions bot added awaiting changes Awaiting changes and removed awaiting review Awaiting review labels Oct 8, 2025
Comment on lines 19 to 21
#ifdef _WIN32
# include <windows.h>
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/platform.h instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

// Allocate an environment handle
SQLRETURN return_env = SQLAllocEnv(&env);

EXPECT_EQ(SQL_SUCCESS, return_env);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use ASSERT_EQ() not EXPECT_EQ()?
Do we need to proceed this test even when this assertion is failed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed to use ASSERT_EQ

SQLRETURN return_set =
SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, reinterpret_cast<void*>(SQL_OV_ODBC2), 0);

EXPECT_EQ(SQL_SUCCESS, return_set);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is SQL_SUCCESS expected?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we assert set value by SQLGetEnvAttr()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes SQL_SUCCESS is expected since the version is supposed to be supported.

Added check for SQLGetEnvAttr


EXPECT_EQ(SQL_SUCCESS, return_env);

// Attempt to set to unsupported version
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed the comment, thanks good catch

Comment on lines 100 to 255
ARROW_LOG(DEBUG) << "SQLGetEnvAttr called with env: " << env << ", attr: " << attr
<< ", value_ptr: " << value_ptr << ", buffer_length: " << buffer_length
<< ", str_len_ptr: " << static_cast<const void*>(str_len_ptr);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove this debug print now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We generally log the ODBC API calls for debugging so we know which ODBC APIs got passed to the driver, is it ok to keep these logs?

Comment on lines +112 to +266
if (!value_ptr && !str_len_ptr) {
throw DriverException("Invalid null pointer for attribute.", "HY000");
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check this out of this switch?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not in this case. I think attribute needs to be checked first before the pointers, and ODBC needs to error out on attribute value first.
In a case where attribute, value_ptr and str_len_ptr are all invalid, HYC00 (error code for invalid attribute) should be returned first. So we put value_ptr and str_len_ptr check under the switch statement

Copy link
Contributor Author

@alinaliBQ alinaliBQ left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed code review comments

Comment on lines 100 to 255
ARROW_LOG(DEBUG) << "SQLGetEnvAttr called with env: " << env << ", attr: " << attr
<< ", value_ptr: " << value_ptr << ", buffer_length: " << buffer_length
<< ", str_len_ptr: " << static_cast<const void*>(str_len_ptr);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We generally log the ODBC API calls for debugging so we know which ODBC APIs got passed to the driver, is it ok to keep these logs?

Comment on lines +112 to +266
if (!value_ptr && !str_len_ptr) {
throw DriverException("Invalid null pointer for attribute.", "HY000");
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a test DISABLED_TestSQLGetEnvAttrNullValuePointer for this case. The test case is disabled because call to SQLGetEnvAttr is handled by the driver manager on Windows. And the Windows driver manager doesn't error out when null pointer is passed, even though it should.

Potentially this can be tested on mac/linux depending on the driver manager on these systems

Comment on lines +112 to +266
if (!value_ptr && !str_len_ptr) {
throw DriverException("Invalid null pointer for attribute.", "HY000");
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not in this case. I think attribute needs to be checked first before the pointers, and ODBC needs to error out on attribute value first.
In a case where attribute, value_ptr and str_len_ptr are all invalid, HYC00 (error code for invalid attribute) should be returned first. So we put value_ptr and str_len_ptr check under the switch statement

Comment on lines 19 to 21
#ifdef _WIN32
# include <windows.h>
#endif
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

namespace arrow::flight::sql::odbc {

TEST(SQLGetEnvAttr, TestSQLGetEnvAttrODBCVersion) {
// ODBC Environment
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

// Allocate an environment handle
SQLRETURN return_env = SQLAllocEnv(&env);

EXPECT_EQ(SQL_SUCCESS, return_env);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed to use ASSERT_EQ


EXPECT_EQ(SQL_SUCCESS, return_env);

// Attempt to set to unsupported version
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed the comment, thanks good catch

SQLRETURN return_set =
SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, reinterpret_cast<void*>(SQL_OV_ODBC2), 0);

EXPECT_EQ(SQL_SUCCESS, return_set);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes SQL_SUCCESS is expected since the version is supposed to be supported.

Added check for SQLGetEnvAttr

@alinaliBQ alinaliBQ requested review from kou and lidavidm October 20, 2025 23:00
@github-actions github-actions bot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Oct 20, 2025
@alinaliBQ alinaliBQ force-pushed the gh-46098-sql-env-attr branch from 65391da to 1395cff Compare October 22, 2025 18:54
Co-authored-by: rscales <[email protected]>

Add tests for setting and getting environment attributes

Address code review comments

Co-Authored-By: justing-bq <[email protected]>
@alinaliBQ alinaliBQ force-pushed the gh-46098-sql-env-attr branch from 1395cff to c4de836 Compare October 23, 2025 19:28
@alinaliBQ alinaliBQ marked this pull request as ready for review October 23, 2025 19:29
@alinaliBQ
Copy link
Contributor Author

Rebased on top of main branch to resolve merge conflicts. This PR is ready for review

@github-actions github-actions bot added awaiting merge Awaiting merge and removed awaiting change review Awaiting change review labels Oct 24, 2025
@lidavidm lidavidm merged commit 56e3836 into apache:main Oct 24, 2025
46 of 47 checks passed
@lidavidm lidavidm removed the awaiting merge Awaiting merge label Oct 24, 2025
@conbench-apache-arrow
Copy link

After merging your PR, Conbench analyzed the 4 benchmarking runs that have been run so far on merge-commit 56e3836.

There were no benchmark performance regressions. 🎉

The full Conbench report has more details. It also includes information about 11 possible false positives for unstable benchmarks that are known to sometimes produce them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants