Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
65 changes: 35 additions & 30 deletions cpp/src/arrow/flight/sql/odbc/odbc_impl/get_info_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "arrow/flight/sql/odbc/odbc_impl/exceptions.h"
#include "arrow/scalar.h"
#include "arrow/type_fwd.h"
#include "arrow/util/checked_cast.h"

#include "arrow/flight/sql/odbc/odbc_impl/flight_sql_stream_chunk_buffer.h"
#include "arrow/flight/sql/odbc/odbc_impl/scalar_function_reporter.h"
Expand Down Expand Up @@ -76,6 +77,9 @@
#define ARROW_CONVERT_VARCHAR 19

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

using arrow::internal::checked_cast;

namespace {
// Return the corresponding field in SQLGetInfo's SQL_CONVERT_* field
// types for the given Arrow SqlConvert enum value.
Expand Down Expand Up @@ -190,7 +194,7 @@ inline int64_t ScalarToInt64(UnionScalar* scalar) {
}

inline std::string ScalarToBoolString(UnionScalar* scalar) {
return reinterpret_cast<BooleanScalar*>(scalar->child_value().get())->value ? "Y" : "N";
return checked_cast<BooleanScalar*>(scalar->child_value().get())->value ? "Y" : "N";
}

inline void SetDefaultIfMissing(std::unordered_map<uint16_t, Connection::Info>& cache,
Expand Down Expand Up @@ -395,25 +399,21 @@ bool GetInfoCache::LoadInfoFromServer() {
// Unused by ODBC.
break;
case SqlInfoOptions::SQL_DDL_SCHEMA: {
// GH-49500 TODO: use scalar bool to determine `SQL_CREATE_SCHEMA` and
// `SQL_DROP_SCHEMA` values

// Note: this is a bitmask and we can't describe cascade or restrict
// flags.
info_[SQL_DROP_SCHEMA] = static_cast<uint32_t>(SQL_DS_DROP_SCHEMA);

// Note: this is a bitmask and we can't describe authorization or
// collation
info_[SQL_CREATE_SCHEMA] = static_cast<uint32_t>(SQL_CS_CREATE_SCHEMA);
bool supported =
checked_cast<BooleanScalar*>(scalar->child_value().get())->value;
info_[SQL_DROP_SCHEMA] =
static_cast<uint32_t>(supported ? SQL_DS_DROP_SCHEMA : 0);
info_[SQL_CREATE_SCHEMA] =
static_cast<uint32_t>(supported ? SQL_CS_CREATE_SCHEMA : 0);
break;
}
case SqlInfoOptions::SQL_DDL_TABLE: {
// GH-49500 TODO: use scalar bool to determine `SQL_CREATE_TABLE` and
// `SQL_DROP_TABLE` values

// This is a bitmask and we cannot describe all clauses.
info_[SQL_CREATE_TABLE] = static_cast<uint32_t>(SQL_CT_CREATE_TABLE);
info_[SQL_DROP_TABLE] = static_cast<uint32_t>(SQL_DT_DROP_TABLE);
bool supported =
checked_cast<BooleanScalar*>(scalar->child_value().get())->value;
info_[SQL_CREATE_TABLE] =
static_cast<uint32_t>(supported ? SQL_CT_CREATE_TABLE : 0);
info_[SQL_DROP_TABLE] =
static_cast<uint32_t>(supported ? SQL_DT_DROP_TABLE : 0);
break;
}
case SqlInfoOptions::SQL_ALL_TABLES_ARE_SELECTABLE: {
Expand All @@ -426,7 +426,7 @@ bool GetInfoCache::LoadInfoFromServer() {
}
case SqlInfoOptions::SQL_NULL_PLUS_NULL_IS_NULL: {
info_[SQL_CONCAT_NULL_BEHAVIOR] = static_cast<uint16_t>(
reinterpret_cast<BooleanScalar*>(scalar->child_value().get())->value
checked_cast<BooleanScalar*>(scalar->child_value().get())->value
? SQL_CB_NULL
: SQL_CB_NON_NULL);
break;
Expand All @@ -436,15 +436,15 @@ bool GetInfoCache::LoadInfoFromServer() {
// SQL_SUPPORTS_DIFFERENT_TABLE_CORRELATION_NAMES since we need both
// properties to determine the value for SQL_CORRELATION_NAME.
supports_correlation_name =
reinterpret_cast<BooleanScalar*>(scalar->child_value().get())->value;
checked_cast<BooleanScalar*>(scalar->child_value().get())->value;
break;
}
case SqlInfoOptions::SQL_SUPPORTS_DIFFERENT_TABLE_CORRELATION_NAMES: {
// Simply cache SQL_SUPPORTS_TABLE_CORRELATION_NAMES and
// SQL_SUPPORTS_DIFFERENT_TABLE_CORRELATION_NAMES since we need both
// properties to determine the value for SQL_CORRELATION_NAME.
requires_different_correlation_name =
reinterpret_cast<BooleanScalar*>(scalar->child_value().get())->value;
checked_cast<BooleanScalar*>(scalar->child_value().get())->value;
break;
}
case SqlInfoOptions::SQL_SUPPORTS_EXPRESSIONS_IN_ORDER_BY: {
Expand All @@ -454,7 +454,7 @@ bool GetInfoCache::LoadInfoFromServer() {
case SqlInfoOptions::SQL_SUPPORTS_ORDER_BY_UNRELATED: {
// Note: this is the negation of the Flight SQL property.
info_[SQL_ORDER_BY_COLUMNS_IN_SELECT] =
reinterpret_cast<BooleanScalar*>(scalar->child_value().get())->value
checked_cast<BooleanScalar*>(scalar->child_value().get())->value
? "N"
: "Y";
break;
Expand All @@ -465,7 +465,7 @@ bool GetInfoCache::LoadInfoFromServer() {
}
case SqlInfoOptions::SQL_SUPPORTS_NON_NULLABLE_COLUMNS: {
info_[SQL_NON_NULLABLE_COLUMNS] = static_cast<uint16_t>(
reinterpret_cast<BooleanScalar*>(scalar->child_value().get())->value
checked_cast<BooleanScalar*>(scalar->child_value().get())->value
? SQL_NNC_NON_NULL
: SQL_NNC_NULL);
break;
Expand All @@ -475,10 +475,15 @@ bool GetInfoCache::LoadInfoFromServer() {
break;
}
case SqlInfoOptions::SQL_CATALOG_AT_START: {
info_[SQL_CATALOG_LOCATION] = static_cast<uint16_t>(
reinterpret_cast<BooleanScalar*>(scalar->child_value().get())->value
? SQL_CL_START
: SQL_CL_END);
// Only use this as a fallback if ARROW_SQL_CATALOG_TERM has not already
// set SQL_CATALOG_LOCATION (to avoid conflicting writes depending on
// response key ordering).
SetDefaultIfMissing(
info_, SQL_CATALOG_LOCATION,
static_cast<uint16_t>(
checked_cast<BooleanScalar*>(scalar->child_value().get())->value
? SQL_CL_START
: SQL_CL_END));
break;
}
case SqlInfoOptions::SQL_SELECT_FOR_UPDATE_SUPPORTED:
Expand All @@ -494,22 +499,22 @@ bool GetInfoCache::LoadInfoFromServer() {
}
case SqlInfoOptions::SQL_TRANSACTIONS_SUPPORTED: {
transactions_supported =
reinterpret_cast<BooleanScalar*>(scalar->child_value().get())->value;
Comment on lines 496 to -497
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please fix the CI build failures from checked_cast in this file:
https://github.com/apache/arrow/actions/runs/26406439067/job/77730895486?pr=50021#step:7:4419

/Users/runner/work/arrow/arrow/cpp/src/arrow/flight/sql/odbc/odbc_impl/get_info_cache.cc:499:19: error: use of undeclared identifier 'checked_cast'; did you mean 'internal::checked_cast'?
  499 |                   checked_cast<BooleanScalar*>(scalar->child_value().get())->value;
      |                   ^~~~~~~~~~~~
      |                   internal::checked_cast
/Users/runner/work/arrow/arrow/cpp/src/arrow/util/checked_cast.h:28:19: note: 'internal::checked_cast' declared here

checked_cast<BooleanScalar*>(scalar->child_value().get())->value;
break;
}
case SqlInfoOptions::SQL_DATA_DEFINITION_CAUSES_TRANSACTION_COMMIT: {
transaction_ddl_commit =
reinterpret_cast<BooleanScalar*>(scalar->child_value().get())->value;
checked_cast<BooleanScalar*>(scalar->child_value().get())->value;
break;
}
case SqlInfoOptions::SQL_DATA_DEFINITIONS_IN_TRANSACTIONS_IGNORED: {
transaction_ddl_ignore =
reinterpret_cast<BooleanScalar*>(scalar->child_value().get())->value;
checked_cast<BooleanScalar*>(scalar->child_value().get())->value;
break;
}
case SqlInfoOptions::SQL_BATCH_UPDATES_SUPPORTED: {
info_[SQL_BATCH_SUPPORT] = static_cast<uint32_t>(
reinterpret_cast<BooleanScalar*>(scalar->child_value().get())->value
checked_cast<BooleanScalar*>(scalar->child_value().get())->value
? SQL_BS_ROW_COUNT_EXPLICIT
: 0);
break;
Expand Down
31 changes: 5 additions & 26 deletions cpp/src/arrow/flight/sql/odbc/tests/connection_info_test.cc
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It seems there's some failing tests - some more test cases need updating?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@vanshaj2023 To ensure maximum coverage, please build and run the ODBC tests locally against a Dremio docker instance with documentation here:

## Steps to Run the ODBC tests
After ODBC has been registered, you can run the ODBC tests. It is recommended to run the ODBC tests locally first.

Original file line number Diff line number Diff line change
Expand Up @@ -616,18 +616,11 @@ TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoAlterTable) {
EXPECT_EQ(static_cast<SQLUINTEGER>(0), value);
}

TYPED_TEST(ConnectionInfoHandleTest, TestSQLGetInfoCatalogLocation) {
// GH-49482 TODO: resolve inconsitent return value for SQL_CATALOG_LOCATION and change
// test type to `ConnectionInfoTest`
this->ConnectWithString(this->GetConnectionString(), this->conn);

TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoCatalogLocation) {
SQLUSMALLINT value;
GetInfo(this->conn, SQL_CATALOG_LOCATION, &value);

EXPECT_EQ(static_cast<SQLUSMALLINT>(0), value);

EXPECT_EQ(SQL_SUCCESS, SQLDisconnect(this->conn))
<< GetOdbcErrorMessage(SQL_HANDLE_DBC, this->conn);
}

TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoCatalogName) {
Expand Down Expand Up @@ -752,32 +745,18 @@ TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoDropDomain) {
EXPECT_EQ(static_cast<SQLUINTEGER>(0), value);
}

TYPED_TEST(ConnectionInfoHandleTest, TestSQLGetInfoDropSchema) {
// GH-49482 TODO: resolve inconsitent return value for SQL_DROP_SCHEMA and change test
// type to `ConnectionInfoTest`
this->ConnectWithString(this->GetConnectionString(), this->conn);

TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoDropSchema) {
SQLUINTEGER value;
GetInfo(this->conn, SQL_DROP_SCHEMA, &value);

EXPECT_EQ(static_cast<SQLUINTEGER>(0), value);

EXPECT_EQ(SQL_SUCCESS, SQLDisconnect(this->conn))
<< GetOdbcErrorMessage(SQL_HANDLE_DBC, this->conn);
EXPECT_EQ(static_cast<SQLUINTEGER>(SQL_DS_DROP_SCHEMA), value);
}

TYPED_TEST(ConnectionInfoHandleTest, TestSQLGetInfoDropTable) {
// GH-49482 TODO: resolve inconsitent return value for SQL_DROP_TABLE and change test
// type to `ConnectionInfoTest`
this->ConnectWithString(this->GetConnectionString(), this->conn);

TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoDropTable) {
SQLUINTEGER value;
GetInfo(this->conn, SQL_DROP_TABLE, &value);

EXPECT_EQ(static_cast<SQLUINTEGER>(0), value);

EXPECT_EQ(SQL_SUCCESS, SQLDisconnect(this->conn))
<< GetOdbcErrorMessage(SQL_HANDLE_DBC, this->conn);
EXPECT_EQ(static_cast<SQLUINTEGER>(SQL_DT_DROP_TABLE), value);
}

TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoDropTranslation) {
Expand Down