Skip to content
Merged
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
1 change: 0 additions & 1 deletion ci/scripts/cpp_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ if ! type minio >/dev/null 2>&1; then
fi
case "$(uname)" in
Linux)
exclude_tests+=("arrow-flight-sql-odbc-test")
n_jobs=$(nproc)
;;
Darwin)
Expand Down
5 changes: 5 additions & 0 deletions cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ set(ARROW_FLIGHT_SQL_ODBC_TEST_SRCS
# GH-46889: move protobuf_test_util to a more common location
../../../../engine/substrait/protobuf_test_util.cc)

# Resolve segmentation fault error on Windows platform due to Arrow Compute Library Initialization
if(WIN32)
list(APPEND ARROW_FLIGHT_SQL_ODBC_TEST_SRCS ../../../../compute/test_env.cc)
endif()

# GH-49651 Link ODBC tests statically on Linux and dynamically on macOS/Windows
if(WIN32 OR APPLE)
set(ARROW_FLIGHT_SQL_ODBC_TEST_LINK_LIBS arrow_flight_sql_odbc_shared
Expand Down
25 changes: 14 additions & 11 deletions cpp/src/arrow/flight/sql/odbc/tests/columns_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ TYPED_TEST_SUITE(ColumnsOdbcV2Test, TestTypesOdbcV2);

namespace {
// Helper functions

// GH-49702: TODO Disabled on Linux due to BlockingQueue issue
#ifndef __linux__
void CheckSQLColumns(
SQLHSTMT stmt, const std::wstring& expected_table,
const std::wstring& expected_column, const SQLINTEGER& expected_data_type,
Expand Down Expand Up @@ -125,6 +128,7 @@ void CheckRemoteSQLColumns(
expected_octet_char_length, expected_ordinal_position,
expected_is_nullable);
}
#endif // __linux__

void CheckSQLColAttribute(SQLHSTMT stmt, SQLUSMALLINT idx,
const std::string& expected_column_name,
Expand Down Expand Up @@ -415,6 +419,8 @@ TYPED_TEST(ColumnsTest, SQLColumnsTestInputData) {
ValidateFetch(stmt, SQL_SUCCESS);
}

// GH-49702: TODO Disabled on Linux due to BlockingQueue issue
#ifndef __linux__
TEST_F(ColumnsMockTest, TestSQLColumnsAllColumns) {
// Check table pattern and column pattern returns all columns

Expand Down Expand Up @@ -1209,6 +1215,7 @@ TEST_F(ColumnsMockTest, TestSQLColumnsTableColumnPattern) {
// There is no more column
EXPECT_EQ(SQL_NO_DATA, SQLFetch(stmt));
}
#endif // __linux__

TEST_F(ColumnsMockTest, TestSQLColumnsInvalidTablePattern) {
ASSIGN_SQLWCHAR_ARR(table_pattern, L"non-existent-table");
Expand All @@ -1224,8 +1231,7 @@ TEST_F(ColumnsMockTest, TestSQLColumnsInvalidTablePattern) {
TYPED_TEST(ColumnsTest, SQLColAttributeTestInputData) {
ASSIGN_SQLWCHAR_ARR_AND_LEN(wsql, L"SELECT 1 as col1;");

ASSERT_EQ(SQL_SUCCESS, SQLExecDirect(stmt, wsql, wsql_len))
<< GetOdbcErrorMessage(SQL_HANDLE_DBC, conn);
ASSERT_EQ(SQL_SUCCESS, SQLExecDirect(stmt, wsql, wsql_len));

ASSERT_EQ(SQL_SUCCESS, SQLFetch(stmt));

Expand Down Expand Up @@ -2560,10 +2566,6 @@ TEST_F(ColumnsMockTest, SQLDescribeColUnicodeTableMetadata) {

ASSIGN_SQLWCHAR_ARR_AND_LEN(sql_query, L"SELECT * from 数据 LIMIT 1;");

ASSIGN_SQLWCHAR_ARR_AND_LEN(expected_column_name, L"资料");
SQLSMALLINT expected_column_data_type = SQL_WVARCHAR;
SQLULEN expected_column_size = 0;

ASSERT_EQ(SQL_SUCCESS, SQLExecDirect(stmt, sql_query, sql_query_len));

ASSERT_EQ(SQL_SUCCESS, SQLFetch(stmt));
Expand All @@ -2572,13 +2574,14 @@ TEST_F(ColumnsMockTest, SQLDescribeColUnicodeTableMetadata) {
SQLDescribeCol(stmt, column_index, column_name, buf_char_len, &name_length,
&column_data_type, &column_size, &decimal_digits, &nullable));

EXPECT_EQ(name_length, expected_column_name_len);
std::wstring expected_column_name_wstr = std::wstring(L"资料");
size_t expected_column_name_len = expected_column_name_wstr.length();

std::wstring returned(column_name, column_name + name_length);
std::wstring expected_col_name_str = ConvertToWString(expected_column_name);
EXPECT_EQ(expected_col_name_str, returned);
EXPECT_EQ(expected_column_data_type, column_data_type);
EXPECT_EQ(expected_column_size, column_size);
EXPECT_EQ(expected_column_name_wstr, returned);
EXPECT_EQ(expected_column_name_len, name_length);
EXPECT_EQ(SQL_WVARCHAR, column_data_type);
EXPECT_EQ(0, column_size);
EXPECT_EQ(0, decimal_digits);
EXPECT_EQ(SQL_NULLABLE, nullable);

Expand Down
72 changes: 51 additions & 21 deletions cpp/src/arrow/flight/sql/odbc/tests/connection_attr_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ using TestTypes =
::testing::Types<FlightSQLODBCMockTestBase, FlightSQLODBCRemoteTestBase>;
TYPED_TEST_SUITE(ConnectionAttributeTest, TestTypes);

template <typename T>
class ConnectionAttributePreConnectTest : public T {};

using TestTypesHandle = ::testing::Types<FlightSQLOdbcEnvConnHandleMockTestBase,
FlightSQLOdbcEnvConnHandleRemoteTestBase>;
TYPED_TEST_SUITE(ConnectionAttributePreConnectTest, TestTypesHandle);

#ifdef SQL_ATTR_ASYNC_DBC_EVENT
TYPED_TEST(ConnectionAttributeTest, TestSQLSetConnectAttrAsyncDbcEventUnsupported) {
ASSERT_EQ(SQL_ERROR, SQLSetConnectAttr(conn, SQL_ATTR_ASYNC_DBC_EVENT, 0, 0));
Expand Down Expand Up @@ -87,15 +94,18 @@ TYPED_TEST(ConnectionAttributeTest, TestSQLSetConnectAttrEnlistInDtcUnsupported)
}

TYPED_TEST(ConnectionAttributeTest, TestSQLSetConnectAttrOdbcCursorsDMOnly) {
this->AllocEnvConnHandles();
SQLHENV test_env = SQL_NULL_HENV;
SQLHDBC test_conn = SQL_NULL_HDBC;
this->AllocEnvConnHandles(test_env, test_conn);

// Verify DM-only attribute is settable via Driver Manager
ASSERT_EQ(SQL_SUCCESS,
SQLSetConnectAttr(conn, SQL_ATTR_ODBC_CURSORS,
SQLSetConnectAttr(test_conn, SQL_ATTR_ODBC_CURSORS,
reinterpret_cast<SQLPOINTER>(SQL_CUR_USE_DRIVER), 0));

std::string connect_str = this->GetConnectionString();
this->ConnectWithString(connect_str);
this->ConnectWithString(connect_str, test_conn);
this->Disconnect(test_env, test_conn);
}

TYPED_TEST(ConnectionAttributeTest, TestSQLSetConnectAttrQuietModeReadOnly) {
Expand All @@ -114,31 +124,33 @@ TYPED_TEST(ConnectionAttributeTest, TestSQLSetConnectAttrTraceDMOnly) {
}
#endif // __APPLE__

TYPED_TEST(ConnectionAttributeTest, TestSQLSetConnectAttrTracefileDMOnly) {
TYPED_TEST(ConnectionAttributePreConnectTest, TestSQLSetConnectAttrTracefileDMOnly) {
// Verify DM-only attribute is handled by Driver Manager

// Use placeholder value as we want the call to fail, or else
// the driver manager will produce a trace file.
std::wstring trace_file = L"invalid/file/path";
std::vector<SQLWCHAR> trace_file0(trace_file.begin(), trace_file.end());

#ifdef _WIN32
ASSERT_EQ(SQL_ERROR, SQLSetConnectAttr(conn, SQL_ATTR_TRACEFILE, &trace_file0[0],
static_cast<SQLINTEGER>(trace_file0.size())));
#ifdef __APPLE__
VerifyOdbcErrorState(SQL_HANDLE_DBC, conn, kErrorStateHYC00);
#else
VerifyOdbcErrorState(SQL_HANDLE_DBC, conn, kErrorStateHY000);
#endif // __APPLE__
#else // Mac & Linux
ASSERT_EQ(SQL_SUCCESS, SQLSetConnectAttr(conn, SQL_ATTR_TRACEFILE, &trace_file0[0],
static_cast<SQLINTEGER>(trace_file0.size())));
#endif
}

TYPED_TEST(ConnectionAttributeTest, TestSQLSetConnectAttrTranslateLabDMOnly) {
// Verify DM-only attribute is handled by Driver Manager
ASSERT_EQ(SQL_ERROR, SQLSetConnectAttr(conn, SQL_ATTR_TRANSLATE_LIB, 0, 0));
// Checks for invalid argument return error
#ifdef __APPLE__
VerifyOdbcErrorState(SQL_HANDLE_DBC, conn, kErrorStateHYC00);
#else
#ifdef _WIN32
VerifyOdbcErrorState(SQL_HANDLE_DBC, conn, kErrorStateHY024);
#endif // __APPLE__
#else // Mac & Linux
VerifyOdbcErrorState(SQL_HANDLE_DBC, conn, kErrorStateHYC00);
#endif
}

TYPED_TEST(ConnectionAttributeTest, TestSQLSetConnectAttrTranslateOptionUnsupported) {
Expand All @@ -162,8 +174,8 @@ TYPED_TEST(ConnectionAttributeTest, TestSQLGetConnectAttrDbcInfoTokenSetOnly) {
}
#endif

// iODBC does not treat SQL_ATTR_ODBC_CURSORS as DM-only
Comment thread
justing-bq marked this conversation as resolved.
#ifndef __APPLE__
// Driver Manager behavior tests for Windows only.
#ifdef _WIN32
TYPED_TEST(ConnectionAttributeTest, TestSQLGetConnectAttrOdbcCursorsDMOnly) {
// Verify that DM-only attribute is handled by driver manager
SQLULEN cursor_attr;
Expand All @@ -172,15 +184,13 @@ TYPED_TEST(ConnectionAttributeTest, TestSQLGetConnectAttrOdbcCursorsDMOnly) {
EXPECT_EQ(SQL_CUR_USE_DRIVER, cursor_attr);
}

// iODBC needs to be compiled with tracing enabled to handle SQL_ATTR_TRACE
TYPED_TEST(ConnectionAttributeTest, TestSQLGetConnectAttrTraceDMOnly) {
// Verify that DM-only attribute is handled by driver manager
SQLUINTEGER trace;
ASSERT_EQ(SQL_SUCCESS, SQLGetConnectAttr(conn, SQL_ATTR_TRACE, &trace, 0, nullptr));
EXPECT_EQ(SQL_OPT_TRACE_OFF, trace);
}

// iODBC needs to be compiled with tracing enabled to handle SQL_ATTR_TRACEFILE
TYPED_TEST(ConnectionAttributeTest, TestSQLGetConnectAttrTraceFileDMOnly) {
// Verify that DM-only attribute is handled by driver manager
SQLWCHAR out_str[kOdbcBufferSize];
Expand All @@ -194,7 +204,7 @@ TYPED_TEST(ConnectionAttributeTest, TestSQLGetConnectAttrTraceFileDMOnly) {
ODBC::SqlWcharToString(out_str, static_cast<SQLSMALLINT>(out_str_len));
EXPECT_FALSE(out_connection_string.empty());
}
#endif // __APPLE__
#endif // _WIN32

TYPED_TEST(ConnectionAttributeTest, TestSQLGetConnectAttrTranslateLibUnsupported) {
SQLWCHAR out_str[kOdbcBufferSize];
Expand All @@ -221,11 +231,16 @@ TYPED_TEST(ConnectionAttributeTest, TestSQLGetConnectAttrTxnIsolationUnsupported
#ifdef SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE
TYPED_TEST(ConnectionAttributeTest,
TestSQLGetConnectAttrAsyncDbcFunctionsEnableUnsupported) {
// Verifies that the Windows driver manager returns HY114 for unsupported functionality
SQLUINTEGER enable;
# ifdef _WIN32
// Verifies that the Windows driver manager returns HY114 for unsupported functionality
ASSERT_EQ(SQL_ERROR,
SQLGetConnectAttr(conn, SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE, &enable, 0, 0));
VerifyOdbcErrorState(SQL_HANDLE_DBC, conn, kErrorStateHY114);
# else // Mac & Linux
ASSERT_EQ(SQL_SUCCESS,
SQLGetConnectAttr(conn, SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE, &enable, 0, 0));
# endif
}
#endif

Expand Down Expand Up @@ -350,14 +365,23 @@ TYPED_TEST(ConnectionAttributeTest, TestSQLSetConnectAttrLoginTimeoutValid) {
EXPECT_EQ(42, timeout);
}

#ifdef __linux__
// On Linux, SQL_ATTR_PACKET_SIZE can only be set before connection
// which is why use a different test fixture for Linux.
TYPED_TEST(ConnectionAttributePreConnectTest, TestSQLSetConnectAttrPacketSizeValid) {
#else // Windows & Mac
TYPED_TEST(ConnectionAttributeTest, TestSQLSetConnectAttrPacketSizeValid) {
// The driver always returns 0. PACKET_SIZE value is unused by the driver.

#endif
// Check default value first
SQLUINTEGER size = -1;
#ifdef __linux__
ASSERT_EQ(SQL_ERROR, SQLGetConnectAttr(conn, SQL_ATTR_PACKET_SIZE, &size, 0, nullptr));
VerifyOdbcErrorState(SQL_HANDLE_DBC, conn, kErrorState08003);
#else // Windows & Mac
ASSERT_EQ(SQL_SUCCESS,
SQLGetConnectAttr(conn, SQL_ATTR_PACKET_SIZE, &size, 0, nullptr));
EXPECT_EQ(0, size);
#endif

ASSERT_EQ(SQL_SUCCESS, SQLSetConnectAttr(conn, SQL_ATTR_PACKET_SIZE,
reinterpret_cast<SQLPOINTER>(0), 0));
Expand All @@ -367,12 +391,18 @@ TYPED_TEST(ConnectionAttributeTest, TestSQLSetConnectAttrPacketSizeValid) {
SQLGetConnectAttr(conn, SQL_ATTR_PACKET_SIZE, &size, 0, nullptr));
EXPECT_EQ(0, size);

// Attempt to set to non-zero value, driver should return warning and not error
// Attempt to set to non-zero value,
#ifdef __linux__
EXPECT_EQ(SQL_SUCCESS, SQLSetConnectAttr(conn, SQL_ATTR_PACKET_SIZE,
reinterpret_cast<SQLPOINTER>(2), 0));
#else // Windows & Mac
// driver should return warning and not error
EXPECT_EQ(SQL_SUCCESS_WITH_INFO, SQLSetConnectAttr(conn, SQL_ATTR_PACKET_SIZE,
reinterpret_cast<SQLPOINTER>(2), 0));

// Verify warning status
VerifyOdbcErrorState(SQL_HANDLE_DBC, conn, kErrorState01S02);
#endif
}

} // namespace arrow::flight::sql::odbc
30 changes: 20 additions & 10 deletions cpp/src/arrow/flight/sql/odbc/tests/connection_info_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoDataSourceName) {
}

#ifdef SQL_DRIVER_AWARE_POOLING_SUPPORTED
// GH-49782: TODO Disabled on Linux until SQL_DRIVER_AWARE_POOLING_SUPPORTED is
// implemented in the driver.
# ifndef __linux__

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Let's add comment

On Linux, unix-odbc doesn't support SQL_DRIVER_AWARE_POOLING_SUPPORTED 

I assume this is the reason we are disabling this test for Linux

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I've looked into this a bit more and discovered that (unlike the Windows and Mac driver managers) unixODBC hands off this attribute to the driver. But our driver does not have any SQLGetInfo logic for SQL_DRIVER_AWARE_POOLING_SUPPORTED.
I will create a ticket for this issue and mention it in a comment here.

TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoDriverAwarePoolingSupported) {
// According to Microsoft documentation, ODBC driver does not need to implement
// SQL_DRIVER_AWARE_POOLING_SUPPORTED and the Driver Manager will ignore the
Expand All @@ -153,7 +156,8 @@ TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoDriverAwarePoolingSupported) {

EXPECT_EQ(static_cast<SQLUINTEGER>(SQL_DRIVER_AWARE_POOLING_NOT_CAPABLE), value);
}
#endif
# endif // __linux__
#endif // SQL_DRIVER_AWARE_POOLING_SUPPORTED

// These information types are implemented by the Driver Manager alone.
TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoDriverHdbc) {
Expand Down Expand Up @@ -329,9 +333,11 @@ TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoOdbcVer) {

std::wstring result = ConvertToWString(value);

#ifdef __APPLE__
#if defined(__APPLE__)
EXPECT_EQ(std::wstring(L"03.52.0000"), result);
#else
#elif defined(__linux__)
EXPECT_EQ(std::wstring(L"03.52"), result);
#else // WINDOWS
EXPECT_EQ(std::wstring(L"03.80.0000"), result);
#endif // __APPLE__
}
Expand Down Expand Up @@ -370,7 +376,8 @@ TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoServerName) {
SQLWCHAR value[kOdbcBufferSize] = {};
GetInfoSQLWCHAR(conn, SQL_SERVER_NAME, value);

EXPECT_GT(wcslen(reinterpret_cast<wchar_t*>(value)), 0);
std::wstring result = ConvertToWString(value);
EXPECT_GT(result.length(), 0);
}

TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoStaticCursorAttributes1) {
Expand Down Expand Up @@ -401,14 +408,16 @@ TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoDbmsName) {
SQLWCHAR value[kOdbcBufferSize] = {};
GetInfoSQLWCHAR(conn, SQL_DBMS_NAME, value);

EXPECT_GT(wcslen(reinterpret_cast<wchar_t*>(value)), 0);
std::wstring result = ConvertToWString(value);
EXPECT_GT(result.length(), 0);
}

TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoDbmsVer) {
SQLWCHAR value[kOdbcBufferSize] = {};
GetInfoSQLWCHAR(conn, SQL_DBMS_VER, value);

EXPECT_GT(wcslen(reinterpret_cast<wchar_t*>(value)), 0);
std::wstring result = ConvertToWString(value);
EXPECT_GT(result.length(), 0);
}

// Data Source Information
Expand Down Expand Up @@ -614,7 +623,7 @@ TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoAlterTable) {
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->ConnectWithString(this->GetConnectionString(), conn);

SQLUSMALLINT value;
GetInfo(conn, SQL_CATALOG_LOCATION, &value);
Expand Down Expand Up @@ -750,7 +759,7 @@ TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoDropDomain) {
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->ConnectWithString(this->GetConnectionString(), conn);

SQLUINTEGER value;
GetInfo(conn, SQL_DROP_SCHEMA, &value);
Expand All @@ -764,7 +773,7 @@ TYPED_TEST(ConnectionInfoHandleTest, TestSQLGetInfoDropSchema) {
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->ConnectWithString(this->GetConnectionString(), conn);

SQLUINTEGER value;
GetInfo(conn, SQL_DROP_TABLE, &value);
Expand Down Expand Up @@ -848,7 +857,8 @@ TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoKeywords) {
SQLWCHAR value[info_len] = {};
GetInfoSQLWCHAR(conn, SQL_KEYWORDS, value, info_len);

EXPECT_GT(wcslen(reinterpret_cast<wchar_t*>(value)), 0);
std::wstring result = ConvertToWString(value, -1, info_len);
EXPECT_GT(result.length(), 0);
}

TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoLikeEscapeClause) {
Expand Down
Loading