From a68f3d69bd0484b56e87a9cbf93f9c82333f70a2 Mon Sep 17 00:00:00 2001 From: justing-bq <62349012+justing-bq@users.noreply.github.com> Date: Wed, 11 Feb 2026 15:43:05 -0800 Subject: [PATCH] Fix Mac Tests --- .../sqlite_tables_schema_batch_reader.cc | 54 +++++++++++-------- .../flight/sql/odbc/odbc_impl/CMakeLists.txt | 6 +-- .../sql/odbc/odbc_impl/odbc_statement.cc | 4 +- .../flight/sql/odbc/odbc_impl/system_dsn.cc | 14 ++--- .../flight/sql/odbc/odbc_impl/system_dsn.h | 5 +- .../sql/odbc/odbc_impl/win_system_dsn.cc | 2 +- .../flight/sql/odbc/tests/columns_test.cc | 41 ++++++++++++-- .../sql/odbc/tests/connection_attr_test.cc | 16 ++++++ .../sql/odbc/tests/connection_info_test.cc | 10 ++-- .../flight/sql/odbc/tests/connection_test.cc | 3 -- .../flight/sql/odbc/tests/errors_test.cc | 3 ++ .../sql/odbc/tests/get_functions_test.cc | 4 ++ .../flight/sql/odbc/tests/odbc_test_suite.cc | 4 -- .../flight/sql/odbc/tests/odbc_test_suite.h | 6 +++ .../sql/odbc/tests/statement_attr_test.cc | 39 ++++++++++---- .../flight/sql/odbc/tests/statement_test.cc | 40 ++++++++++++-- .../flight/sql/odbc/tests/type_info_test.cc | 18 +++++-- 17 files changed, 200 insertions(+), 69 deletions(-) diff --git a/cpp/src/arrow/flight/sql/example/sqlite_tables_schema_batch_reader.cc b/cpp/src/arrow/flight/sql/example/sqlite_tables_schema_batch_reader.cc index 85332e6c4df..674377f6b58 100644 --- a/cpp/src/arrow/flight/sql/example/sqlite_tables_schema_batch_reader.cc +++ b/cpp/src/arrow/flight/sql/example/sqlite_tables_schema_batch_reader.cc @@ -65,33 +65,43 @@ Status SqliteTablesWithSchemaBatchReader::ReadNext(std::shared_ptr* auto* string_array = reinterpret_cast(table_name_array.get()); - std::vector> column_fields; + std::map>> table_columns_map; for (int i = 0; i < table_name_array->length(); i++) { const std::string& table_name = string_array->GetString(i); + table_columns_map[table_name]; + } - while (sqlite3_step(schema_statement->GetSqlite3Stmt()) == SQLITE_ROW) { - std::string sqlite_table_name = std::string(reinterpret_cast( - sqlite3_column_text(schema_statement->GetSqlite3Stmt(), 0))); - if (sqlite_table_name == table_name) { - const char* column_name = reinterpret_cast( - sqlite3_column_text(schema_statement->GetSqlite3Stmt(), 1)); - const char* column_type = reinterpret_cast( - sqlite3_column_text(schema_statement->GetSqlite3Stmt(), 2)); - int nullable = sqlite3_column_int(schema_statement->GetSqlite3Stmt(), 3); - - const ColumnMetadata& column_metadata = GetColumnMetadata( - GetSqlTypeFromTypeName(column_type), sqlite_table_name.c_str()); - std::shared_ptr arrow_type; - auto status = GetArrowType(column_type).Value(&arrow_type); - if (!status.ok()) { - return Status::NotImplemented("Unknown SQLite type '", column_type, - "' for column '", column_name, "' in table '", - table_name, "': ", status); - } - column_fields.push_back(arrow::field(column_name, arrow_type, nullable == 0, - column_metadata.metadata_map())); + while (sqlite3_step(schema_statement->GetSqlite3Stmt()) == SQLITE_ROW) { + std::string table_name = std::string(reinterpret_cast( + sqlite3_column_text(schema_statement->GetSqlite3Stmt(), 0))); + + if (table_columns_map.contains(table_name)) { + const char* column_name = reinterpret_cast( + sqlite3_column_text(schema_statement->GetSqlite3Stmt(), 1)); + const char* column_type = reinterpret_cast( + sqlite3_column_text(schema_statement->GetSqlite3Stmt(), 2)); + int nullable = sqlite3_column_int(schema_statement->GetSqlite3Stmt(), 3); + + const ColumnMetadata& column_metadata = + GetColumnMetadata(GetSqlTypeFromTypeName(column_type), table_name.c_str()); + + std::shared_ptr arrow_type; + auto status = GetArrowType(column_type).Value(&arrow_type); + if (!status.ok()) { + return Status::NotImplemented("Unknown SQLite type '", column_type, + "' for column '", column_name, "' in table '", + table_name, "': ", status); } + table_columns_map[table_name].push_back(arrow::field( + column_name, arrow_type, nullable == 0, column_metadata.metadata_map())); } + } + + std::vector> column_fields; + for (int i = 0; i < table_name_array->length(); i++) { + const std::string& table_name = string_array->GetString(i); + column_fields = table_columns_map[table_name]; + ARROW_ASSIGN_OR_RAISE(std::shared_ptr schema_buffer, ipc::SerializeSchema(*arrow::schema(column_fields))); diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_impl/CMakeLists.txt b/cpp/src/arrow/flight/sql/odbc/odbc_impl/CMakeLists.txt index e58558258df..12251f0740e 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc_impl/CMakeLists.txt +++ b/cpp/src/arrow/flight/sql/odbc/odbc_impl/CMakeLists.txt @@ -104,6 +104,8 @@ add_library(arrow_odbc_spi_impl spi/result_set.h spi/result_set_metadata.h spi/statement.h + system_dsn.cc + system_dsn.h system_trust_store.cc system_trust_store.h types.h @@ -125,9 +127,7 @@ if(WIN32) ui/dsn_configuration_window.h ui/window.cc ui/window.h - win_system_dsn.cc - system_dsn.cc - system_dsn.h) + win_system_dsn.cc) endif() if(APPLE) diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_impl/odbc_statement.cc b/cpp/src/arrow/flight/sql/odbc/odbc_impl/odbc_statement.cc index c77e97934ae..a19797e80f3 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc_impl/odbc_statement.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbc_impl/odbc_statement.cc @@ -554,7 +554,7 @@ void ODBCStatement::SetStmtAttr(SQLINTEGER statement_attribute, SQLPOINTER value switch (statement_attribute) { case SQL_ATTR_APP_PARAM_DESC: { ODBCDescriptor* desc = static_cast(value); - if (current_apd_ != desc) { + if (desc && current_apd_ != desc) { if (current_apd_ != built_in_apd_.get()) { current_apd_->DetachFromStatement(this, true); } @@ -567,7 +567,7 @@ void ODBCStatement::SetStmtAttr(SQLINTEGER statement_attribute, SQLPOINTER value } case SQL_ATTR_APP_ROW_DESC: { ODBCDescriptor* desc = static_cast(value); - if (current_ard_ != desc) { + if (desc && current_ard_ != desc) { if (current_ard_ != built_in_ard_.get()) { current_ard_->DetachFromStatement(this, false); } diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_impl/system_dsn.cc b/cpp/src/arrow/flight/sql/odbc/odbc_impl/system_dsn.cc index 468f05e4cf4..902b370ba18 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc_impl/system_dsn.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbc_impl/system_dsn.cc @@ -17,23 +17,19 @@ #include "arrow/flight/sql/odbc/odbc_impl/system_dsn.h" -#include "arrow/flight/sql/odbc/odbc_impl/config/configuration.h" -#include "arrow/flight/sql/odbc/odbc_impl/flight_sql_connection.h" -#include "arrow/flight/sql/odbc/odbc_impl/ui/dsn_configuration_window.h" -#include "arrow/flight/sql/odbc/odbc_impl/ui/window.h" -#include "arrow/flight/sql/odbc/odbc_impl/util.h" #include "arrow/result.h" #include "arrow/util/utf8.h" -#include #include namespace arrow::flight::sql::odbc { using config::Configuration; -void PostError(DWORD error_code, LPCWSTR error_msg) { +void PostError(DWORD error_code, LPWSTR error_msg) { +#if defined _WIN32 MessageBox(NULL, error_msg, L"Error!", MB_ICONEXCLAMATION | MB_OK); +#endif // _WIN32 SQLPostInstallerError(error_code, error_msg); } @@ -42,7 +38,7 @@ void PostArrowUtilError(arrow::Status error_status) { std::wstring werror_msg = arrow::util::UTF8ToWideString(error_msg).ValueOr( L"Error during utf8 to wide string conversion"); - PostError(ODBC_ERROR_GENERAL_ERR, werror_msg.c_str()); + PostError(ODBC_ERROR_GENERAL_ERR, (LPWSTR)werror_msg.c_str()); } void PostLastInstallerError() { @@ -55,7 +51,7 @@ void PostLastInstallerError() { buf << L"Message: \"" << msg << L"\", Code: " << code; std::wstring error_msg = buf.str(); - PostError(code, error_msg.c_str()); + PostError(code, (LPWSTR)error_msg.c_str()); } /** diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_impl/system_dsn.h b/cpp/src/arrow/flight/sql/odbc/odbc_impl/system_dsn.h index f1fee84fbd4..59c8cc9601f 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc_impl/system_dsn.h +++ b/cpp/src/arrow/flight/sql/odbc/odbc_impl/system_dsn.h @@ -19,8 +19,11 @@ #include "arrow/flight/sql/odbc/odbc_impl/platform.h" #include "arrow/flight/sql/odbc/odbc_impl/config/configuration.h" +#include "arrow/flight/sql/odbc/odbc_impl/flight_sql_connection.h" #include "arrow/status.h" +#include + namespace arrow::flight::sql::odbc { #if defined _WIN32 @@ -64,7 +67,7 @@ bool RegisterDsn(const config::Configuration& config, LPCWSTR driver); */ bool UnregisterDsn(const std::wstring& dsn); -void PostError(DWORD error_code, LPCWSTR error_msg); +void PostError(DWORD error_code, LPWSTR error_msg); void PostArrowUtilError(arrow::Status error_status); } // namespace arrow::flight::sql::odbc diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_impl/win_system_dsn.cc b/cpp/src/arrow/flight/sql/odbc/odbc_impl/win_system_dsn.cc index 2ea9a2451c2..3140b9ade42 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc_impl/win_system_dsn.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbc_impl/win_system_dsn.cc @@ -144,7 +144,7 @@ BOOL INSTAPI ConfigDSNW(HWND hwnd_parent, WORD req, LPCWSTR wdriver, std::wstring werror_msg = arrow::util::UTF8ToWideString(error_msg).ValueOr(L"Error during DSN load"); - PostError(err.GetNativeError(), werror_msg.c_str()); + PostError(err.GetNativeError(), (LPWSTR)werror_msg.c_str()); return FALSE; } diff --git a/cpp/src/arrow/flight/sql/odbc/tests/columns_test.cc b/cpp/src/arrow/flight/sql/odbc/tests/columns_test.cc index f9936a83467..b383bf51e7d 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/columns_test.cc +++ b/cpp/src/arrow/flight/sql/odbc/tests/columns_test.cc @@ -24,6 +24,8 @@ #include +// Many tests are disabled for MacOS due to iODBC limitations. + namespace arrow::flight::sql::odbc { template @@ -237,6 +239,7 @@ void CheckSQLColAttribute(SQLHSTMT stmt, SQLUSMALLINT idx, EXPECT_EQ(expected_unsigned_column, unsigned_col); } +#ifndef __APPLE__ void CheckSQLColAttributes(SQLHSTMT stmt, SQLUSMALLINT idx, const std::wstring& expected_column_name, SQLLEN expected_data_type, SQLLEN expected_display_size, @@ -306,6 +309,7 @@ void CheckSQLColAttributes(SQLHSTMT stmt, SQLUSMALLINT idx, EXPECT_EQ(expected_searchable, searchable); EXPECT_EQ(expected_unsigned_column, unsigned_col); } +#endif // __APPLE__ void GetSQLColAttributeString(SQLHSTMT stmt, const std::wstring& wsql, SQLUSMALLINT idx, SQLUSMALLINT field_identifier, std::wstring& value) { @@ -364,6 +368,7 @@ void GetSQLColAttributeNumeric(SQLHSTMT stmt, const std::wstring& wsql, SQLUSMAL SQLColAttribute(stmt, idx, field_identifier, 0, 0, nullptr, value)); } +#ifndef __APPLE__ void GetSQLColAttributesNumeric(SQLHSTMT stmt, const std::wstring& wsql, SQLUSMALLINT idx, SQLUSMALLINT field_identifier, SQLLEN* value) { // Execute query and check SQLColAttribute numeric attribute @@ -377,7 +382,7 @@ void GetSQLColAttributesNumeric(SQLHSTMT stmt, const std::wstring& wsql, SQLUSMA ASSERT_EQ(SQL_SUCCESS, SQLColAttributes(stmt, idx, field_identifier, 0, 0, nullptr, value)); } - +#endif // __APPLE__ } // namespace TYPED_TEST(ColumnsTest, SQLColumnsTestInputData) { @@ -1387,7 +1392,9 @@ TEST_F(ColumnsMockTest, TestSQLColAttributeAllTypes) { SQL_FALSE); // expected_unsigned_column } -TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesAllTypesODBCVer2) { +// iODBC does not support SQLColAttributes for ODBC 3.0 attributes. +#ifndef __APPLE__ +TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesAllTypes) { // Tests ODBC 2.0 API SQLColAttributes this->CreateTableAllDataType(); @@ -1446,6 +1453,7 @@ TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesAllTypesODBCVer2) { SQL_PRED_NONE, // expected_searchable SQL_FALSE); // expected_unsigned_column } +#endif // __APPLE__ TEST_F(ColumnsRemoteTest, TestSQLColAttributeAllTypes) { // Test assumes there is a table $scratch.ODBCTest in remote server @@ -1612,7 +1620,9 @@ TEST_F(ColumnsRemoteTest, TestSQLColAttributeAllTypes) { SQL_TRUE); // expected_unsigned_column } -TEST_F(ColumnsOdbcV2RemoteTest, TestSQLColAttributeAllTypesODBCVer2) { +// iODBC does not support SQLColAttribute in ODBC 2.0 mode. +#ifndef __APPLE__ +TEST_F(ColumnsOdbcV2RemoteTest, TestSQLColAttributeAllTypes) { // Test assumes there is a table $scratch.ODBCTest in remote server std::wstring wsql = L"SELECT * from $scratch.ODBCTest;"; std::vector sql0(wsql.begin(), wsql.end()); @@ -1776,7 +1786,8 @@ TEST_F(ColumnsOdbcV2RemoteTest, TestSQLColAttributeAllTypesODBCVer2) { SQL_TRUE); // expected_unsigned_column } -TEST_F(ColumnsOdbcV2RemoteTest, TestSQLColAttributesAllTypesODBCVer2) { +// iODBC does not support SQLColAttributes for ODBC 3.0 attributes. +TEST_F(ColumnsOdbcV2RemoteTest, TestSQLColAttributesAllTypes) { // Tests ODBC 2.0 API SQLColAttributes // Test assumes there is a table $scratch.ODBCTest in remote server std::wstring wsql = L"SELECT * from $scratch.ODBCTest;"; @@ -1895,6 +1906,7 @@ TEST_F(ColumnsOdbcV2RemoteTest, TestSQLColAttributesAllTypesODBCVer2) { SQL_SEARCHABLE, // expected_searchable SQL_TRUE); // expected_unsigned_column } +#endif // __APPLE__ TYPED_TEST(ColumnsTest, TestSQLColAttributeCaseSensitive) { // Arrow limitation: returns SQL_FALSE for case sensitive column @@ -1910,6 +1922,8 @@ TYPED_TEST(ColumnsTest, TestSQLColAttributeCaseSensitive) { ASSERT_EQ(SQL_FALSE, value); } +// iODBC does not support SQLColAttributes for ODBC 3.0 attributes. +#ifndef __APPLE__ TYPED_TEST(ColumnsOdbcV2Test, TestSQLColAttributesCaseSensitive) { // Arrow limitation: returns SQL_FALSE for case sensitive column // Tests ODBC 2.0 API SQLColAttributes @@ -1924,6 +1938,7 @@ TYPED_TEST(ColumnsOdbcV2Test, TestSQLColAttributesCaseSensitive) { GetSQLColAttributesNumeric(this->stmt, wsql, 28, SQL_COLUMN_CASE_SENSITIVE, &value); ASSERT_EQ(SQL_FALSE, value); } +#endif // __APPLE__ TEST_F(ColumnsMockTest, TestSQLColAttributeUniqueValue) { // Mock server limitation: returns false for auto-increment column @@ -1935,6 +1950,8 @@ TEST_F(ColumnsMockTest, TestSQLColAttributeUniqueValue) { ASSERT_EQ(SQL_FALSE, value); } +// iODBC does not support SQLColAttributes for ODBC 3.0 attributes. +#ifndef __APPLE__ TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesAutoIncrement) { // Tests ODBC 2.0 API SQLColAttributes // Mock server limitation: returns false for auto-increment column @@ -1945,6 +1962,7 @@ TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesAutoIncrement) { GetSQLColAttributeNumeric(this->stmt, wsql, 1, SQL_COLUMN_AUTO_INCREMENT, &value); ASSERT_EQ(SQL_FALSE, value); } +#endif // __APPLE__ TEST_F(ColumnsMockTest, TestSQLColAttributeBaseTableName) { this->CreateTableAllDataType(); @@ -1955,6 +1973,8 @@ TEST_F(ColumnsMockTest, TestSQLColAttributeBaseTableName) { ASSERT_EQ(std::wstring(L"AllTypesTable"), value); } +// iODBC does not support SQLColAttributes for ODBC 3.0 attributes. +#ifndef __APPLE__ TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesTableName) { // Tests ODBC 2.0 API SQLColAttributes this->CreateTableAllDataType(); @@ -1964,6 +1984,7 @@ TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesTableName) { GetSQLColAttributesString(this->stmt, wsql, 1, SQL_COLUMN_TABLE_NAME, value); ASSERT_EQ(std::wstring(L"AllTypesTable"), value); } +#endif // __APPLE__ TEST_F(ColumnsMockTest, TestSQLColAttributeCatalogName) { // Mock server limitattion: mock doesn't return catalog for result metadata, @@ -1985,6 +2006,8 @@ TEST_F(ColumnsRemoteTest, TestSQLColAttributeCatalogName) { ASSERT_EQ(std::wstring(L""), value); } +// iODBC does not support SQLColAttribute in ODBC 2.0 mode. +#ifndef __APPLE__ TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesQualifierName) { // Mock server limitattion: mock doesn't return catalog for result metadata, // and the defautl catalog should be 'main' @@ -2005,6 +2028,7 @@ TEST_F(ColumnsOdbcV2RemoteTest, TestSQLColAttributesQualifierName) { GetSQLColAttributeString(this->stmt, wsql, 1, SQL_COLUMN_QUALIFIER_NAME, value); ASSERT_EQ(std::wstring(L""), value); } +#endif // __APPLE__ TYPED_TEST(ColumnsTest, TestSQLColAttributeCount) { std::wstring wsql = this->GetQueryAllDataTypes(); @@ -2050,6 +2074,8 @@ TEST_F(ColumnsRemoteTest, TestSQLColAttributeSchemaName) { ASSERT_EQ(std::wstring(L""), value); } +// iODBC does not support SQLColAttributes for ODBC 3.0 attributes. +#ifndef __APPLE__ TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesOwnerName) { // Tests ODBC 2.0 API SQLColAttributes this->CreateTableAllDataType(); @@ -2071,6 +2097,7 @@ TEST_F(ColumnsOdbcV2RemoteTest, TestSQLColAttributesOwnerName) { GetSQLColAttributesString(this->stmt, wsql, 1, SQL_COLUMN_OWNER_NAME, value); ASSERT_EQ(std::wstring(L""), value); } +#endif // __APPLE__ TEST_F(ColumnsMockTest, TestSQLColAttributeTableName) { this->CreateTableAllDataType(); @@ -2119,6 +2146,8 @@ TEST_F(ColumnsRemoteTest, TestSQLColAttributeTypeName) { ASSERT_EQ(std::wstring(L"TIMESTAMP"), value); } +// iODBC does not support SQLColAttributes for ODBC 3.0 attributes. +#ifndef __APPLE__ TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesTypeName) { // Tests ODBC 2.0 API SQLColAttributes this->CreateTableAllDataType(); @@ -2159,6 +2188,7 @@ TEST_F(ColumnsOdbcV2RemoteTest, TestSQLColAttributesTypeName) { GetSQLColAttributesString(this->stmt, L"", 9, SQL_COLUMN_TYPE_NAME, value); ASSERT_EQ(std::wstring(L"TIMESTAMP"), value); } +#endif // __APPLE__ TYPED_TEST(ColumnsTest, TestSQLColAttributeUnnamed) { std::wstring wsql = this->GetQueryAllDataTypes(); @@ -2175,6 +2205,8 @@ TYPED_TEST(ColumnsTest, TestSQLColAttributeUpdatable) { ASSERT_EQ(SQL_ATTR_READWRITE_UNKNOWN, value); } +// iODBC does not support SQLColAttributes for ODBC 3.0 attributes. +#ifndef __APPLE__ TYPED_TEST(ColumnsOdbcV2Test, TestSQLColAttributesUpdatable) { // Tests ODBC 2.0 API SQLColAttributes std::wstring wsql = this->GetQueryAllDataTypes(); @@ -2183,6 +2215,7 @@ TYPED_TEST(ColumnsOdbcV2Test, TestSQLColAttributesUpdatable) { GetSQLColAttributesNumeric(this->stmt, wsql, 1, SQL_COLUMN_UPDATABLE, &value); ASSERT_EQ(SQL_ATTR_READWRITE_UNKNOWN, value); } +#endif // __APPLE__ TEST_F(ColumnsMockTest, SQLDescribeColValidateInput) { this->CreateTestTables(); diff --git a/cpp/src/arrow/flight/sql/odbc/tests/connection_attr_test.cc b/cpp/src/arrow/flight/sql/odbc/tests/connection_attr_test.cc index 413bc43c0ad..6797b7bd2c6 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/connection_attr_test.cc +++ b/cpp/src/arrow/flight/sql/odbc/tests/connection_attr_test.cc @@ -104,12 +104,15 @@ TYPED_TEST(ConnectionAttributeTest, TestSQLSetConnectAttrQuietModeReadOnly) { VerifyOdbcErrorState(SQL_HANDLE_DBC, this->conn, kErrorStateHY092); } +// iODBC needs to be compiled with tracing enabled to handle SQL_ATTR_TRACE +#ifndef __APPLE__ TYPED_TEST(ConnectionAttributeTest, TestSQLSetConnectAttrTraceDMOnly) { // Verify DM-only attribute is settable via Driver Manager ASSERT_EQ(SQL_SUCCESS, SQLSetConnectAttr(this->conn, SQL_ATTR_TRACE, reinterpret_cast(SQL_OPT_TRACE_OFF), 0)); } +#endif // __APPLE__ TYPED_TEST(ConnectionAttributeTest, TestSQLSetConnectAttrTracefileDMOnly) { // Verify DM-only attribute is handled by Driver Manager @@ -120,14 +123,22 @@ TYPED_TEST(ConnectionAttributeTest, TestSQLSetConnectAttrTracefileDMOnly) { std::vector trace_file0(trace_file.begin(), trace_file.end()); ASSERT_EQ(SQL_ERROR, SQLSetConnectAttr(this->conn, SQL_ATTR_TRACEFILE, &trace_file0[0], static_cast(trace_file0.size()))); +#ifdef __APPLE__ + VerifyOdbcErrorState(SQL_HANDLE_DBC, this->conn, kErrorStateHYC00); +#else VerifyOdbcErrorState(SQL_HANDLE_DBC, this->conn, kErrorStateHY000); +#endif // __APPLE__ } TYPED_TEST(ConnectionAttributeTest, TestSQLSetConnectAttrTranslateLabDMOnly) { // Verify DM-only attribute is handled by Driver Manager ASSERT_EQ(SQL_ERROR, SQLSetConnectAttr(this->conn, SQL_ATTR_TRANSLATE_LIB, 0, 0)); // Checks for invalid argument return error +#ifdef __APPLE__ + VerifyOdbcErrorState(SQL_HANDLE_DBC, this->conn, kErrorStateHYC00); +#else VerifyOdbcErrorState(SQL_HANDLE_DBC, this->conn, kErrorStateHY024); +#endif // __APPLE__ } TYPED_TEST(ConnectionAttributeTest, TestSQLSetConnectAttrTranslateOptionUnsupported) { @@ -152,6 +163,8 @@ TYPED_TEST(ConnectionAttributeTest, TestSQLGetConnectAttrDbcInfoTokenSetOnly) { } #endif +// iODBC does not treat SQL_ATTR_ODBC_CURSORS as DM-only +#ifndef __APPLE__ TYPED_TEST(ConnectionAttributeTest, TestSQLGetConnectAttrOdbcCursorsDMOnly) { // Verify that DM-only attribute is handled by driver manager SQLULEN cursor_attr; @@ -160,6 +173,7 @@ 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; @@ -168,6 +182,7 @@ TYPED_TEST(ConnectionAttributeTest, TestSQLGetConnectAttrTraceDMOnly) { 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]; @@ -181,6 +196,7 @@ TYPED_TEST(ConnectionAttributeTest, TestSQLGetConnectAttrTraceFileDMOnly) { ODBC::SqlWcharToString(out_str, static_cast(out_str_len)); EXPECT_FALSE(out_connection_string.empty()); } +#endif // __APPLE__ TYPED_TEST(ConnectionAttributeTest, TestSQLGetConnectAttrTranslateLibUnsupported) { SQLWCHAR out_str[kOdbcBufferSize]; diff --git a/cpp/src/arrow/flight/sql/odbc/tests/connection_info_test.cc b/cpp/src/arrow/flight/sql/odbc/tests/connection_info_test.cc index c9ee212224a..09cffefaa31 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/connection_info_test.cc +++ b/cpp/src/arrow/flight/sql/odbc/tests/connection_info_test.cc @@ -73,7 +73,7 @@ TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoTruncation) { SQLSMALLINT message_length; ASSERT_EQ(SQL_SUCCESS_WITH_INFO, - SQLGetInfo(this->conn, SQL_KEYWORDS, value, info_len, &message_length)); + SQLGetInfo(this->conn, SQL_INTEGRITY, value, info_len, &message_length)); // Verify string truncation is reported VerifyOdbcErrorState(SQL_HANDLE_DBC, this->conn, kErrorState01004); @@ -319,7 +319,11 @@ TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoOdbcVer) { SQLWCHAR value[kOdbcBufferSize] = L""; GetInfo(this->conn, SQL_ODBC_VER, value); +#ifdef __APPLE__ + EXPECT_STREQ(static_cast(L"03.52.0000"), value); +#else EXPECT_STREQ(static_cast(L"03.80.0000"), value); +#endif // __APPLE__ } TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoParamArrayRowCounts) { @@ -786,8 +790,8 @@ TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoIntegrity) { } TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoKeywords) { - // Keyword strings can require 5000 buffer length - static constexpr int info_len = kOdbcBufferSize * 5; + // Keyword strings can require 10000 buffer length + static constexpr int info_len = kOdbcBufferSize * 10; SQLWCHAR value[info_len] = L""; GetInfo(this->conn, SQL_KEYWORDS, value, info_len); diff --git a/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc b/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc index 3ca4a50ef76..57f6c9349bf 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc +++ b/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc @@ -248,7 +248,6 @@ TYPED_TEST(ConnectionHandleTest, TestSQLDriverConnect) { << GetOdbcErrorMessage(SQL_HANDLE_DBC, this->conn); } -#if defined _WIN32 TYPED_TEST(ConnectionHandleTest, TestSQLDriverConnectDsn) { // Connect string std::string connect_str = this->GetConnectionString(); @@ -432,8 +431,6 @@ TEST_F(ConnectionRemoteTest, TestSQLConnectDSNPrecedence) { << GetOdbcErrorMessage(SQL_HANDLE_DBC, conn); } -#endif // _WIN32 - TEST_F(ConnectionRemoteTest, TestSQLDriverConnectInvalidUid) { // Invalid connect string std::string connect_str = GetInvalidConnectionString(); diff --git a/cpp/src/arrow/flight/sql/odbc/tests/errors_test.cc b/cpp/src/arrow/flight/sql/odbc/tests/errors_test.cc index 34a32738455..3f10c661c20 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/errors_test.cc +++ b/cpp/src/arrow/flight/sql/odbc/tests/errors_test.cc @@ -156,6 +156,8 @@ TYPED_TEST(ErrorsHandleTest, DISABLED_TestSQLGetDiagFieldWForConnectFailureNTS) EXPECT_GT(message_text_length, 100); } +// iODBC does not support application allocated descriptors. +#ifndef __APPLE__ TYPED_TEST(ErrorsTest, TestSQLGetDiagFieldWForDescriptorFailureFromDriverManager) { SQLHDESC descriptor; @@ -252,6 +254,7 @@ TYPED_TEST(ErrorsTest, TestSQLGetDiagRecForDescriptorFailureFromDriverManager) { // Free descriptor handle EXPECT_EQ(SQL_SUCCESS, SQLFreeHandle(SQL_HANDLE_DESC, descriptor)); } +#endif // __APPLE__ TYPED_TEST(ErrorsHandleTest, TestSQLGetDiagRecForConnectFailure) { // Invalid connect string diff --git a/cpp/src/arrow/flight/sql/odbc/tests/get_functions_test.cc b/cpp/src/arrow/flight/sql/odbc/tests/get_functions_test.cc index 35d7f2f935d..4b399e76436 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/get_functions_test.cc +++ b/cpp/src/arrow/flight/sql/odbc/tests/get_functions_test.cc @@ -26,6 +26,9 @@ namespace arrow::flight::sql::odbc { +// MacOS driver manager iODBC does not support SQLGetFunctions for ODBC 3.x or 2.x driver +#ifndef __APPLE__ + template class GetFunctionsTest : public T {}; @@ -216,5 +219,6 @@ TYPED_TEST(GetFunctionsOdbcV2Test, TestSQLGetFunctionsUnsupportedSingleAPIODBCVe api_exists = -1; } } +#endif // __APPLE__ } // namespace arrow::flight::sql::odbc diff --git a/cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.cc b/cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.cc index 470a68b3beb..d35713581cd 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.cc +++ b/cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.cc @@ -463,9 +463,6 @@ std::string GetOdbcErrorMessage(SQLSMALLINT handle_type, SQLHANDLE handle) { return res; } -// GH-47822 TODO: once RegisterDsn is implemented in Mac and Linux, the following can be -// re-enabled. -#if defined _WIN32 bool WriteDSN(std::string connection_str) { Connection::ConnPropertyMap properties; @@ -490,7 +487,6 @@ bool WriteDSN(Connection::ConnPropertyMap properties) { std::wstring w_driver = arrow::util::UTF8ToWideString(driver).ValueOr(L""); return RegisterDsn(config, w_driver.c_str()); } -#endif std::wstring GetStringColumnW(SQLHSTMT stmt, int col_id) { SQLWCHAR buf[1024]; diff --git a/cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.h b/cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.h index 3115cd62754..27c33bfa01e 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.h +++ b/cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.h @@ -206,7 +206,13 @@ class FlightSQLOdbcEnvConnHandleMockTestBase : public FlightSQLODBCMockTestBase }; /** ODBC read buffer size. */ +#ifdef __APPLE__ +// iODBC driver manager may crash with smaller buffer sizes +// so we use a larger buffer on MacOS +static constexpr int kOdbcBufferSize = 2048; +#else static constexpr int kOdbcBufferSize = 1024; +#endif // __APPLE__ /// Compare ConnPropertyMap, key value is case-insensitive bool CompareConnPropertyMap(Connection::ConnPropertyMap map1, diff --git a/cpp/src/arrow/flight/sql/odbc/tests/statement_attr_test.cc b/cpp/src/arrow/flight/sql/odbc/tests/statement_attr_test.cc index 0a4e99d33a6..aa72734c395 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/statement_attr_test.cc +++ b/cpp/src/arrow/flight/sql/odbc/tests/statement_attr_test.cc @@ -104,14 +104,18 @@ void ValidateSetStmtAttr(SQLHSTMT statement, SQLINTEGER attribute, SQLPOINTER va // Validate error return value and code void ValidateSetStmtAttrErrorCode(SQLHSTMT statement, SQLINTEGER attribute, - SQLULEN new_value, std::string_view error_code) { + SQLULEN new_value, SQLRETURN expected_rc, + std::string_view error_code) { SQLINTEGER string_length_ptr = sizeof(SQLULEN); - ASSERT_EQ(SQL_ERROR, + ASSERT_EQ(expected_rc, SQLSetStmtAttr(statement, attribute, reinterpret_cast(new_value), - string_length_ptr)); + string_length_ptr)) + << GetOdbcErrorMessage(SQL_HANDLE_STMT, statement); - VerifyOdbcErrorState(SQL_HANDLE_STMT, statement, error_code); + if (expected_rc == SQL_ERROR) { + VerifyOdbcErrorState(SQL_HANDLE_STMT, statement, error_code); + } } } // namespace @@ -418,21 +422,21 @@ TYPED_TEST(StatementAttributeTest, TestSQLSetStmtAttrAppRowDesc) { TYPED_TEST(StatementAttributeTest, TestSQLSetStmtAttrAsyncEnableUnsupported) { // Optional feature not implemented ValidateSetStmtAttrErrorCode(this->stmt, SQL_ATTR_ASYNC_ENABLE, SQL_ASYNC_ENABLE_OFF, - kErrorStateHYC00); + SQL_ERROR, kErrorStateHYC00); } #endif #ifdef SQL_ATTR_ASYNC_STMT_EVENT TYPED_TEST(StatementAttributeTest, TestSQLSetStmtAttrAsyncStmtEventUnsupported) { // Driver does not support asynchronous notification - ValidateSetStmtAttrErrorCode(this->stmt, SQL_ATTR_ASYNC_STMT_EVENT, 0, + ValidateSetStmtAttrErrorCode(this->stmt, SQL_ATTR_ASYNC_STMT_EVENT, 0, SQL_ERROR, kErrorStateHY118); } #endif #ifdef SQL_ATTR_ASYNC_STMT_PCALLBACK TYPED_TEST(StatementAttributeTest, TestSQLSetStmtAttrAsyncStmtPCCallbackUnsupported) { - ValidateSetStmtAttrErrorCode(this->stmt, SQL_ATTR_ASYNC_STMT_PCALLBACK, 0, + ValidateSetStmtAttrErrorCode(this->stmt, SQL_ATTR_ASYNC_STMT_PCALLBACK, 0, SQL_ERROR, kErrorStateHYC00); } #endif @@ -440,7 +444,7 @@ TYPED_TEST(StatementAttributeTest, TestSQLSetStmtAttrAsyncStmtPCCallbackUnsuppor #ifdef SQL_ATTR_ASYNC_STMT_PCONTEXT TYPED_TEST(StatementAttributeTest, TestSQLSetStmtAttrAsyncStmtPCContextUnsupported) { // Optional feature not implemented - ValidateSetStmtAttrErrorCode(this->stmt, SQL_ATTR_ASYNC_STMT_PCONTEXT, 0, + ValidateSetStmtAttrErrorCode(this->stmt, SQL_ATTR_ASYNC_STMT_PCONTEXT, 0, SQL_ERROR, kErrorStateHYC00); } #endif @@ -477,12 +481,25 @@ TYPED_TEST(StatementAttributeTest, TestSQLSetStmtAttrFetchBookmarkPointer) { TYPED_TEST(StatementAttributeTest, TestSQLSetStmtAttrIMPParamDesc) { // Invalid use of an automatically allocated descriptor handle ValidateSetStmtAttrErrorCode(this->stmt, SQL_ATTR_IMP_PARAM_DESC, - static_cast(0), kErrorStateHY017); + static_cast(0), +#ifdef __APPLE__ + // iODBC on MacOS returns SQL_INVALID_HANDLE for this case + SQL_INVALID_HANDLE, +#else + SQL_ERROR, +#endif + kErrorStateHY017); } TYPED_TEST(StatementAttributeTest, TestSQLSetStmtAttrIMPRowDesc) { // Invalid use of an automatically allocated descriptor handle ValidateSetStmtAttrErrorCode(this->stmt, SQL_ATTR_IMP_ROW_DESC, static_cast(0), +#ifdef __APPLE__ + // iODBC on MacOS returns SQL_INVALID_HANDLE for this case + SQL_INVALID_HANDLE, +#else + SQL_ERROR, +#endif kErrorStateHY017); } @@ -497,7 +514,7 @@ TYPED_TEST(StatementAttributeTest, TestSQLSetStmtAttrMaxLength) { TYPED_TEST(StatementAttributeTest, TestSQLSetStmtAttrMaxRows) { // Cannot set read-only attribute ValidateSetStmtAttrErrorCode(this->stmt, SQL_ATTR_MAX_ROWS, static_cast(0), - kErrorStateHY092); + SQL_ERROR, kErrorStateHY092); } TYPED_TEST(StatementAttributeTest, TestSQLSetStmtAttrMetadataID) { @@ -602,7 +619,7 @@ TYPED_TEST(StatementAttributeTest, TestSQLSetStmtAttrRowBindType) { TYPED_TEST(StatementAttributeTest, TestSQLSetStmtAttrRowNumber) { // Cannot set read-only attribute ValidateSetStmtAttrErrorCode(this->stmt, SQL_ATTR_ROW_NUMBER, static_cast(0), - kErrorStateHY092); + SQL_ERROR, kErrorStateHY092); } TYPED_TEST(StatementAttributeTest, TestSQLSetStmtAttrRowOperationPtr) { diff --git a/cpp/src/arrow/flight/sql/odbc/tests/statement_test.cc b/cpp/src/arrow/flight/sql/odbc/tests/statement_test.cc index 1a38bd0e242..5e8abf485c6 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/statement_test.cc +++ b/cpp/src/arrow/flight/sql/odbc/tests/statement_test.cc @@ -54,9 +54,15 @@ TYPED_TEST(StatementTest, TestSQLExecDirectSimpleQuery) { ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +#ifdef __APPLE__ + // With iODBC we expect SQL_SUCCESS and the buffer unchanged in this situation. + ASSERT_EQ(SQL_SUCCESS, SQLGetData(this->stmt, 1, SQL_C_LONG, &val, 0, nullptr)); + EXPECT_EQ(1, val); +#else ASSERT_EQ(SQL_ERROR, SQLGetData(this->stmt, 1, SQL_C_LONG, &val, 0, nullptr)); // Invalid cursor state VerifyOdbcErrorState(SQL_HANDLE_STMT, this->stmt, kErrorState24000); +#endif // __APPLE__ } TYPED_TEST(StatementTest, TestSQLExecDirectInvalidQuery) { @@ -89,9 +95,15 @@ TYPED_TEST(StatementTest, TestSQLExecuteSimpleQuery) { ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +#ifdef __APPLE__ + // With iODBC we expect SQL_SUCCESS and the buffer unchanged in this situation. + ASSERT_EQ(SQL_SUCCESS, SQLGetData(this->stmt, 1, SQL_C_LONG, &val, 0, nullptr)); + EXPECT_EQ(1, val); +#else ASSERT_EQ(SQL_ERROR, SQLGetData(this->stmt, 1, SQL_C_LONG, &val, 0, nullptr)); // Invalid cursor state VerifyOdbcErrorState(SQL_HANDLE_STMT, this->stmt, kErrorState24000); +#endif // __APPLE__ } TYPED_TEST(StatementTest, TestSQLPrepareInvalidQuery) { @@ -805,10 +817,15 @@ TYPED_TEST(StatementTest, TestSQLExecDirectRowFetching) { // Verify result set has no more data beyond row 3 ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +#ifdef __APPLE__ + // With iODBC we expect SQL_SUCCESS and the buffer unchanged in this situation. + ASSERT_EQ(SQL_SUCCESS, SQLGetData(this->stmt, 1, SQL_C_LONG, &val, 0, nullptr)); + EXPECT_EQ(3, val); +#else ASSERT_EQ(SQL_ERROR, SQLGetData(this->stmt, 1, SQL_C_LONG, &val, 0, &ind)); - // Invalid cursor state VerifyOdbcErrorState(SQL_HANDLE_STMT, this->stmt, kErrorState24000); +#endif // __APPLE__ } TYPED_TEST(StatementTest, TestSQLFetchScrollRowFetching) { @@ -864,9 +881,15 @@ TYPED_TEST(StatementTest, TestSQLFetchScrollRowFetching) { // Verify result set has no more data beyond row 3 ASSERT_EQ(SQL_NO_DATA, SQLFetchScroll(this->stmt, SQL_FETCH_NEXT, 0)); +#ifdef __APPLE__ + // With iODBC we expect SQL_SUCCESS and the buffer unchanged in this situation. + ASSERT_EQ(SQL_SUCCESS, SQLGetData(this->stmt, 1, SQL_C_LONG, &val, 0, nullptr)); + EXPECT_EQ(3, val); +#else ASSERT_EQ(SQL_ERROR, SQLGetData(this->stmt, 1, SQL_C_LONG, &val, 0, &ind)); // Invalid cursor state VerifyOdbcErrorState(SQL_HANDLE_STMT, this->stmt, kErrorState24000); +#endif // __APPLE__ } TYPED_TEST(StatementTest, TestSQLFetchScrollUnsupportedOrientation) { @@ -900,9 +923,12 @@ TYPED_TEST(StatementTest, TestSQLFetchScrollUnsupportedOrientation) { VerifyOdbcErrorState(SQL_HANDLE_STMT, this->stmt, kErrorStateHYC00); ASSERT_EQ(SQL_ERROR, SQLFetchScroll(this->stmt, SQL_FETCH_BOOKMARK, fetch_offset)); - - // DM returns state HY106 for SQL_FETCH_BOOKMARK +#ifdef __APPLE__ + VerifyOdbcErrorState(SQL_HANDLE_STMT, this->stmt, kErrorStateHYC00); +#else + // Windows DM returns state HY106 for SQL_FETCH_BOOKMARK VerifyOdbcErrorState(SQL_HANDLE_STMT, this->stmt, kErrorStateHY106); +#endif // __APPLE__ } TYPED_TEST(StatementTest, TestSQLExecDirectVarcharTruncation) { @@ -1170,6 +1196,9 @@ TEST_F(StatementRemoteTest, TestSQLExecDirectNullQueryNullIndicator) { VerifyOdbcErrorState(SQL_HANDLE_STMT, this->stmt, kErrorState22002); } +// MacOS Driver Manager iODBC returns SQL_ERROR when invalid buffer length is provided to +// SQLGetData +#ifndef __APPLE__ TYPED_TEST(StatementTest, TestSQLExecDirectIgnoreInvalidBufLen) { // Verify the driver ignores invalid buffer length for fixed data types @@ -1367,6 +1396,7 @@ TYPED_TEST(StatementTest, TestSQLExecDirectIgnoreInvalidBufLen) { EXPECT_EQ(59, timestamp_var.second); EXPECT_EQ(0, timestamp_var.fraction); } +#endif // __APPLE__ TYPED_TEST(StatementTest, TestSQLBindColDataQuery) { // Numeric Types @@ -2149,7 +2179,11 @@ TYPED_TEST(StatementTest, SQLNumResultColsFunctionSequenceErrorOnNoQuery) { SQLSMALLINT expected_value = 0; ASSERT_EQ(SQL_ERROR, SQLNumResultCols(this->stmt, &column_count)); +#ifdef __APPLE__ + VerifyOdbcErrorState(SQL_HANDLE_STMT, this->stmt, kErrorStateS1010); +#else VerifyOdbcErrorState(SQL_HANDLE_STMT, this->stmt, kErrorStateHY010); +#endif // __APPLE__ EXPECT_EQ(expected_value, column_count); } diff --git a/cpp/src/arrow/flight/sql/odbc/tests/type_info_test.cc b/cpp/src/arrow/flight/sql/odbc/tests/type_info_test.cc index 0adaf51c71f..d8cb5162061 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/type_info_test.cc +++ b/cpp/src/arrow/flight/sql/odbc/tests/type_info_test.cc @@ -1655,12 +1655,16 @@ TEST_F(TypeInfoOdbcV2MockTest, TestSQLGetTypeInfoDateODBCVer2) { ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); } -TEST_F(TypeInfoOdbcV2MockTest, TestSQLGetTypeInfoSQLTypeDateODBCVer2) { +TEST_F(TypeInfoOdbcV2MockTest, TestSQLGetTypeInfoSQLTypeDate) { +#ifdef __APPLE__ + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_TYPE_DATE)); +#else // Pass ODBC Ver 3 data type ASSERT_EQ(SQL_ERROR, SQLGetTypeInfo(this->stmt, SQL_TYPE_DATE)); // Driver manager returns SQL data type out of range error state VerifyOdbcErrorState(SQL_HANDLE_STMT, this->stmt, kErrorStateS1004); +#endif // __APPLE__ } TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoSQLTypeTime) { @@ -1763,12 +1767,16 @@ TEST_F(TypeInfoOdbcV2MockTest, TestSQLGetTypeInfoTimeODBCVer2) { ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); } -TEST_F(TypeInfoOdbcV2MockTest, TestSQLGetTypeInfoSQLTypeTimeODBCVer2) { +TEST_F(TypeInfoOdbcV2MockTest, TestSQLGetTypeInfoSQLTypeTime) { +#ifdef __APPLE__ + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_TYPE_DATE)); +#else // Pass ODBC Ver 3 data type ASSERT_EQ(SQL_ERROR, SQLGetTypeInfo(this->stmt, SQL_TYPE_TIME)); // Driver manager returns SQL data type out of range error state VerifyOdbcErrorState(SQL_HANDLE_STMT, this->stmt, kErrorStateS1004); +#endif // __APPLE__ } TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoSQLTypeTimestamp) { @@ -1871,12 +1879,16 @@ TEST_F(TypeInfoOdbcV2MockTest, TestSQLGetTypeInfoSQLTimestampODBCVer2) { ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); } -TEST_F(TypeInfoOdbcV2MockTest, TestSQLGetTypeInfoSQLTypeTimestampODBCVer2) { +TEST_F(TypeInfoOdbcV2MockTest, TestSQLGetTypeInfoSQLTypeTimestamp) { +#ifdef __APPLE__ + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_TYPE_TIMESTAMP)); +#else // Pass ODBC Ver 3 data type ASSERT_EQ(SQL_ERROR, SQLGetTypeInfo(this->stmt, SQL_TYPE_TIMESTAMP)); // Driver manager returns SQL data type out of range error state VerifyOdbcErrorState(SQL_HANDLE_STMT, this->stmt, kErrorStateS1004); +#endif // __APPLE__ } TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoInvalidDataType) {