diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/get_info_cache.cc b/cpp/src/arrow/flight/sql/odbc/flight_sql/get_info_cache.cc index d18322badbe3..cf10c658dbf4 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/get_info_cache.cc +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/get_info_cache.cc @@ -1173,6 +1173,7 @@ void GetInfoCache::LoadDefaultsForMissingEntries() { SetDefaultIfMissing(info_, SQL_CONVERT_DECIMAL, static_cast(0)); SetDefaultIfMissing(info_, SQL_CONVERT_DOUBLE, static_cast(0)); SetDefaultIfMissing(info_, SQL_CONVERT_FLOAT, static_cast(0)); + SetDefaultIfMissing(info_, SQL_CONVERT_FUNCTIONS, static_cast(0)); SetDefaultIfMissing(info_, SQL_CONVERT_GUID, static_cast(0)); SetDefaultIfMissing(info_, SQL_CONVERT_INTEGER, static_cast(0)); SetDefaultIfMissing(info_, SQL_CONVERT_INTERVAL_YEAR_MONTH, static_cast(0)); @@ -1251,6 +1252,7 @@ void GetInfoCache::LoadDefaultsForMissingEntries() { SetDefaultIfMissing(info_, SQL_MAX_COLUMNS_IN_ORDER_BY, static_cast(0)); SetDefaultIfMissing(info_, SQL_MAX_COLUMNS_IN_SELECT, static_cast(0)); SetDefaultIfMissing(info_, SQL_MAX_COLUMNS_IN_TABLE, static_cast(0)); + SetDefaultIfMissing(info_, SQL_MAX_CONCURRENT_ACTIVITIES, static_cast(0)); SetDefaultIfMissing(info_, SQL_MAX_CURSOR_NAME_LEN, static_cast(0)); SetDefaultIfMissing(info_, SQL_MAX_DRIVER_CONNECTIONS, static_cast(0)); SetDefaultIfMissing(info_, SQL_MAX_IDENTIFIER_LEN, static_cast(65535)); @@ -1270,6 +1272,7 @@ void GetInfoCache::LoadDefaultsForMissingEntries() { SetDefaultIfMissing(info_, SQL_OJ_CAPABILITIES, static_cast(SQL_OJ_LEFT | SQL_OJ_RIGHT | SQL_OJ_FULL)); SetDefaultIfMissing(info_, SQL_ORDER_BY_COLUMNS_IN_SELECT, "Y"); + SetDefaultIfMissing(info_, SQL_OUTER_JOINS, "N"); SetDefaultIfMissing(info_, SQL_PROCEDURE_TERM, ""); SetDefaultIfMissing(info_, SQL_PROCEDURES, "N"); SetDefaultIfMissing(info_, SQL_QUOTED_IDENTIFIER_CASE, @@ -1278,6 +1281,7 @@ void GetInfoCache::LoadDefaultsForMissingEntries() { SetDefaultIfMissing(info_, SQL_SCHEMA_USAGE, static_cast(SQL_SU_DML_STATEMENTS)); SetDefaultIfMissing(info_, SQL_SEARCH_PATTERN_ESCAPE, "\\"); + SetDefaultIfMissing(info_, SQL_SPECIAL_CHARACTERS, ""); SetDefaultIfMissing( info_, SQL_SERVER_NAME, "Arrow Flight SQL Server"); // This might actually need to be the hostname. @@ -1332,6 +1336,16 @@ void GetInfoCache::LoadDefaultsForMissingEntries() { SQL_FN_TSI_FRAC_SECOND | SQL_FN_TSI_SECOND | SQL_FN_TSI_MINUTE | SQL_FN_TSI_HOUR | SQL_FN_TSI_DAY | SQL_FN_TSI_WEEK | SQL_FN_TSI_MONTH | SQL_FN_TSI_QUARTER | SQL_FN_TSI_YEAR)); + SetDefaultIfMissing( + info_, SQL_TIMEDATE_FUNCTIONS, + static_cast( + SQL_FN_TD_CURRENT_DATE | SQL_FN_TD_CURRENT_TIME | SQL_FN_TD_CURRENT_TIMESTAMP | + SQL_FN_TD_CURDATE | SQL_FN_TD_CURTIME | SQL_FN_TD_DAYNAME | + SQL_FN_TD_DAYOFMONTH | SQL_FN_TD_DAYOFWEEK | SQL_FN_TD_DAYOFYEAR | + SQL_FN_TD_EXTRACT | SQL_FN_TD_HOUR | SQL_FN_TD_MINUTE | SQL_FN_TD_MONTH | + SQL_FN_TD_MONTHNAME | SQL_FN_TD_NOW | SQL_FN_TD_QUARTER | SQL_FN_TD_SECOND | + SQL_FN_TD_TIMESTAMPADD | SQL_FN_TD_TIMESTAMPDIFF | SQL_FN_TD_WEEK | + SQL_FN_TD_YEAR)); SetDefaultIfMissing(info_, SQL_UNION, static_cast(SQL_U_UNION | SQL_U_UNION_ALL)); SetDefaultIfMissing(info_, SQL_XOPEN_CLI_YEAR, "1995"); diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_api.cc b/cpp/src/arrow/flight/sql/odbc/odbc_api.cc index 4053375b430c..3faf56bf290c 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc_api.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbc_api.cc @@ -847,27 +847,26 @@ SQLRETURN SQLDisconnect(SQLHDBC conn) { } SQLRETURN SQLGetInfo(SQLHDBC conn, SQLUSMALLINT infoType, SQLPOINTER infoValuePtr, - SQLSMALLINT bufLen, SQLSMALLINT* length) { - // TODO: complete implementation of SQLGetInfoW and write tests + SQLSMALLINT bufLen, SQLSMALLINT* stringLengthPtr) { using ODBC::ODBCConnection; LOG_DEBUG( - "SQLGetInfoW called with conn: {}, infoType: {}, infoValuePtr: {}, bufLen: {}, " - "length: {}", - conn, infoType, infoValuePtr, bufLen, fmt::ptr(length)); + "SQLGetInfo called with conn: {}, infoType: {}, infoValuePtr: {}, bufLen: {}, " + "stringLengthPtr: {}", + conn, infoType, infoValuePtr, bufLen, fmt::ptr(stringLengthPtr)); return ODBCConnection::ExecuteWithDiagnostics(conn, SQL_ERROR, [=]() { ODBCConnection* connection = reinterpret_cast(conn); - // Partially stubbed implementation of SQLGetInfoW - if (infoType == SQL_DRIVER_ODBC_VER) { - std::string_view ver("03.80"); + // Set character type to be Unicode by default + const bool isUnicode = true; - return ODBC::GetStringAttribute(true, ver, true, infoValuePtr, bufLen, length, - connection->GetDiagnostics()); + if (!infoValuePtr && !stringLengthPtr) { + return static_cast SQL_ERROR; } - return static_cast(SQL_ERROR); + return connection->GetInfo(infoType, infoValuePtr, bufLen, stringLengthPtr, + isUnicode); }); } diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/odbc_impl/odbc_connection.h b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/odbc_impl/odbc_connection.h index 92946e5a0a59..0e9498bcb8a0 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/odbc_impl/odbc_connection.h +++ b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/odbc_impl/odbc_connection.h @@ -60,8 +60,8 @@ class ODBCConnection : public ODBCHandle { const driver::odbcabstraction::Connection::ConnPropertyMap& properties, std::vector& missing_properties); - void GetInfo(SQLUSMALLINT infoType, SQLPOINTER value, SQLSMALLINT bufferLength, - SQLSMALLINT* outputLength, bool isUnicode); + SQLRETURN GetInfo(SQLUSMALLINT infoType, SQLPOINTER value, SQLSMALLINT bufferLength, + SQLSMALLINT* outputLength, bool isUnicode); void SetConnectAttr(SQLINTEGER attribute, SQLPOINTER value, SQLINTEGER stringLength, bool isUnicode); SQLRETURN GetConnectAttr(SQLINTEGER attribute, SQLPOINTER value, diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/odbc_impl/odbc_connection.cc b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/odbc_impl/odbc_connection.cc index c98674094070..1f3d365397a7 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/odbc_impl/odbc_connection.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/odbc_impl/odbc_connection.cc @@ -136,152 +136,144 @@ void ODBCConnection::connect(std::string dsn, m_attributeTrackingStatement = std::make_shared(*this, spiStatement); } -void ODBCConnection::GetInfo(SQLUSMALLINT infoType, SQLPOINTER value, - SQLSMALLINT bufferLength, SQLSMALLINT* outputLength, - bool isUnicode) { +SQLRETURN ODBCConnection::GetInfo(SQLUSMALLINT infoType, SQLPOINTER value, + SQLSMALLINT bufferLength, SQLSMALLINT* outputLength, + bool isUnicode) { switch (infoType) { case SQL_ACTIVE_ENVIRONMENTS: GetAttribute(static_cast(0), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; #ifdef SQL_ASYNC_DBC_FUNCTIONS case SQL_ASYNC_DBC_FUNCTIONS: GetAttribute(static_cast(SQL_ASYNC_DBC_NOT_CAPABLE), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; #endif case SQL_ASYNC_MODE: GetAttribute(static_cast(SQL_AM_NONE), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; #ifdef SQL_ASYNC_NOTIFICATION case SQL_ASYNC_NOTIFICATION: GetAttribute(static_cast(SQL_ASYNC_NOTIFICATION_NOT_CAPABLE), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; #endif case SQL_BATCH_ROW_COUNT: GetAttribute(static_cast(0), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_BATCH_SUPPORT: GetAttribute(static_cast(0), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_DATA_SOURCE_NAME: - GetStringAttribute(isUnicode, m_dsn, true, value, bufferLength, outputLength, - GetDiagnostics()); - break; + return GetStringAttribute(isUnicode, m_dsn, true, value, bufferLength, outputLength, + GetDiagnostics()); case SQL_DRIVER_ODBC_VER: - GetStringAttribute(isUnicode, "03.80", true, value, bufferLength, outputLength, - GetDiagnostics()); - break; + return GetStringAttribute(isUnicode, "03.80", true, value, bufferLength, outputLength, + GetDiagnostics()); case SQL_DYNAMIC_CURSOR_ATTRIBUTES1: GetAttribute(static_cast(0), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_DYNAMIC_CURSOR_ATTRIBUTES2: GetAttribute(static_cast(0), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1: GetAttribute(static_cast(SQL_CA1_NEXT), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2: GetAttribute(static_cast(SQL_CA2_READ_ONLY_CONCURRENCY), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_FILE_USAGE: GetAttribute(static_cast(SQL_FILE_NOT_SUPPORTED), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_KEYSET_CURSOR_ATTRIBUTES1: GetAttribute(static_cast(0), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_KEYSET_CURSOR_ATTRIBUTES2: GetAttribute(static_cast(0), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_MAX_ASYNC_CONCURRENT_STATEMENTS: GetAttribute(static_cast(0), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_ODBC_INTERFACE_CONFORMANCE: GetAttribute(static_cast(SQL_OIC_CORE), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; // case SQL_ODBC_STANDARD_CLI_CONFORMANCE: - mentioned in SQLGetInfo spec with no // description and there is no constant for this. case SQL_PARAM_ARRAY_ROW_COUNTS: GetAttribute(static_cast(SQL_PARC_NO_BATCH), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_PARAM_ARRAY_SELECTS: GetAttribute(static_cast(SQL_PAS_NO_SELECT), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_ROW_UPDATES: - GetStringAttribute(isUnicode, "N", true, value, bufferLength, outputLength, - GetDiagnostics()); - break; + return GetStringAttribute(isUnicode, "N", true, value, bufferLength, outputLength, + GetDiagnostics()); case SQL_SCROLL_OPTIONS: GetAttribute(static_cast(SQL_SO_FORWARD_ONLY), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_STATIC_CURSOR_ATTRIBUTES1: GetAttribute(static_cast(0), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_STATIC_CURSOR_ATTRIBUTES2: GetAttribute(static_cast(0), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_BOOKMARK_PERSISTENCE: GetAttribute(static_cast(0), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_DESCRIBE_PARAMETER: - GetStringAttribute(isUnicode, "N", true, value, bufferLength, outputLength, - GetDiagnostics()); - break; + return GetStringAttribute(isUnicode, "N", true, value, bufferLength, outputLength, + GetDiagnostics()); case SQL_MULT_RESULT_SETS: - GetStringAttribute(isUnicode, "N", true, value, bufferLength, outputLength, - GetDiagnostics()); - break; + return GetStringAttribute(isUnicode, "N", true, value, bufferLength, outputLength, + GetDiagnostics()); case SQL_MULTIPLE_ACTIVE_TXN: - GetStringAttribute(isUnicode, "N", true, value, bufferLength, outputLength, - GetDiagnostics()); - break; + return GetStringAttribute(isUnicode, "N", true, value, bufferLength, outputLength, + GetDiagnostics()); case SQL_NEED_LONG_DATA_LEN: - GetStringAttribute(isUnicode, "N", true, value, bufferLength, outputLength, - GetDiagnostics()); - break; + return GetStringAttribute(isUnicode, "N", true, value, bufferLength, outputLength, + GetDiagnostics()); case SQL_TXN_CAPABLE: GetAttribute(static_cast(SQL_TC_NONE), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_TXN_ISOLATION_OPTION: GetAttribute(static_cast(0), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_TABLE_TERM: - GetStringAttribute(isUnicode, "table", true, value, bufferLength, outputLength, - GetDiagnostics()); - break; + return GetStringAttribute(isUnicode, "table", true, value, bufferLength, outputLength, + GetDiagnostics()); // Deprecated ODBC 2.x fields required for backwards compatibility. case SQL_ODBC_API_CONFORMANCE: GetAttribute(static_cast(SQL_OAC_LEVEL1), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_FETCH_DIRECTION: GetAttribute(static_cast(SQL_FETCH_NEXT), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_LOCK_TYPES: GetAttribute(static_cast(0), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_POS_OPERATIONS: GetAttribute(static_cast(0), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_POSITIONED_STATEMENTS: GetAttribute(static_cast(0), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_SCROLL_CONCURRENCY: GetAttribute(static_cast(0), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; case SQL_STATIC_SENSITIVITY: GetAttribute(static_cast(0), value, bufferLength, outputLength); - break; + return SQL_SUCCESS; // Driver-level string properties. case SQL_USER_NAME: @@ -316,9 +308,8 @@ void ODBCConnection::GetInfo(SQLUSMALLINT infoType, SQLPOINTER value, case SQL_XOPEN_CLI_YEAR: { const auto& info = m_spiConnection->GetInfo(infoType); const std::string& infoValue = boost::get(info); - GetStringAttribute(isUnicode, infoValue, true, value, bufferLength, outputLength, - GetDiagnostics()); - break; + return GetStringAttribute(isUnicode, infoValue, true, value, bufferLength, outputLength, + GetDiagnostics()); } // Driver-level 32-bit integer properties. @@ -408,7 +399,7 @@ void ODBCConnection::GetInfo(SQLUSMALLINT infoType, SQLPOINTER value, const auto& info = m_spiConnection->GetInfo(infoType); uint32_t infoValue = boost::get(info); GetAttribute(infoValue, value, bufferLength, outputLength); - break; + return SQL_SUCCESS; } // Driver-level 16-bit integer properties. @@ -443,7 +434,7 @@ void ODBCConnection::GetInfo(SQLUSMALLINT infoType, SQLPOINTER value, const auto& info = m_spiConnection->GetInfo(infoType); uint16_t infoValue = boost::get(info); GetAttribute(infoValue, value, bufferLength, outputLength); - break; + return SQL_SUCCESS; } // Special case - SQL_DATABASE_NAME is an alias for SQL_ATTR_CURRENT_CATALOG. @@ -453,13 +444,14 @@ void ODBCConnection::GetInfo(SQLUSMALLINT infoType, SQLPOINTER value, throw DriverException("Optional feature not supported.", "HYC00"); } const std::string& infoValue = boost::get(*attr); - GetStringAttribute(isUnicode, infoValue, true, value, bufferLength, outputLength, - GetDiagnostics()); - break; + return GetStringAttribute(isUnicode, infoValue, true, value, bufferLength, outputLength, + GetDiagnostics()); } default: - throw DriverException("Unknown SQLGetInfo type: " + std::to_string(infoType)); + throw DriverException("Unknown SQLGetInfo type: " + std::to_string(infoType), "HY096"); } + + return SQL_ERROR; } void ODBCConnection::SetConnectAttr(SQLINTEGER attribute, SQLPOINTER value, diff --git a/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt b/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt index 7dcd11935cc4..1a3da7fad317 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt +++ b/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt @@ -32,6 +32,7 @@ set(ARROW_FLIGHT_SQL_MOCK_SERVER_SRCS add_arrow_test(flight_sql_odbc_test SOURCES connection_attr_test.cc + connection_info_test.cc statement_test.cc # Connection test needs to be put last to resolve segfault issue connection_test.cc 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 new file mode 100644 index 000000000000..b8734a8f8b26 --- /dev/null +++ b/cpp/src/arrow/flight/sql/odbc/tests/connection_info_test.cc @@ -0,0 +1,1481 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +#include "arrow/flight/sql/odbc/tests/odbc_test_suite.h" + +#ifdef _WIN32 +# include +#endif + +#include +#include +#include + +#include "gtest/gtest.h" + +namespace arrow::flight::sql::odbc { + +// Helper Functions + +// Validate unsigned short SQLUSMALLINT return value +void validate(SQLHDBC connection, SQLUSMALLINT infoType, SQLUSMALLINT expected_value) { + SQLUSMALLINT info_value; + SQLSMALLINT message_length; + + SQLRETURN ret = SQLGetInfo(connection, infoType, &info_value, 0, &message_length); + + EXPECT_EQ(ret, SQL_SUCCESS); + + EXPECT_EQ(info_value, expected_value); +} + +// Validate unsigned long SQLUINTEGER return value +void validate(SQLHDBC connection, SQLUSMALLINT infoType, SQLUINTEGER expected_value) { + SQLUINTEGER info_value; + SQLSMALLINT message_length; + + SQLRETURN ret = SQLGetInfo(connection, infoType, &info_value, 0, &message_length); + + EXPECT_EQ(ret, SQL_SUCCESS); + + EXPECT_EQ(info_value, expected_value); +} + +// Validate unsigned length SQLULEN return value +void validate(SQLHDBC connection, SQLUSMALLINT infoType, SQLULEN expected_value) { + SQLULEN info_value; + SQLSMALLINT message_length; + + SQLRETURN ret = SQLGetInfo(connection, infoType, &info_value, 0, &message_length); + + EXPECT_EQ(ret, SQL_SUCCESS); + + EXPECT_EQ(info_value, expected_value); +} + +// Validate wchar string SQLWCHAR return value +void validate(SQLHDBC connection, SQLUSMALLINT infoType, SQLWCHAR* expected_value) { + SQLWCHAR info_value[ODBC_BUFFER_SIZE] = L""; + SQLSMALLINT message_length; + + SQLRETURN ret = + SQLGetInfo(connection, infoType, info_value, ODBC_BUFFER_SIZE, &message_length); + + EXPECT_EQ(ret, SQL_SUCCESS); + + EXPECT_EQ(*info_value, *expected_value); +} + +// Validate unsigned long SQLUINTEGER return value is greater than +void validateGreaterThan(SQLHDBC connection, SQLUSMALLINT infoType, + SQLUINTEGER compared_value) { + SQLUINTEGER info_value; + SQLSMALLINT message_length; + + SQLRETURN ret = SQLGetInfo(connection, infoType, &info_value, 0, &message_length); + + EXPECT_EQ(ret, SQL_SUCCESS); + + EXPECT_GT(info_value, compared_value); +} + +// Validate unsigned length SQLULEN return value is greater than +void validateGreaterThan(SQLHDBC connection, SQLUSMALLINT infoType, + SQLULEN compared_value) { + SQLULEN info_value; + SQLSMALLINT message_length; + + SQLRETURN ret = SQLGetInfo(connection, infoType, &info_value, 0, &message_length); + + EXPECT_EQ(ret, SQL_SUCCESS); + + EXPECT_GT(info_value, compared_value); +} + +// Validate wchar string SQLWCHAR return value is not empty +void validateNotEmptySQLWCHAR(SQLHDBC connection, SQLUSMALLINT infoType, + bool allowTruncation) { + SQLWCHAR info_value[ODBC_BUFFER_SIZE] = L""; + SQLSMALLINT message_length; + + SQLRETURN ret = + SQLGetInfo(connection, infoType, info_value, ODBC_BUFFER_SIZE, &message_length); + + if (allowTruncation && ret == SQL_SUCCESS_WITH_INFO) { + EXPECT_EQ(ret, SQL_SUCCESS_WITH_INFO); + } else { + EXPECT_EQ(ret, SQL_SUCCESS); + } + + EXPECT_GT(wcslen(info_value), 0); +} + +// Driver Information + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_ACTIVE_ENVIRONMENTS) { + this->connect(); + + validate(this->conn, SQL_ACTIVE_ENVIRONMENTS, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_ASYNC_DBC_FUNCTIONS) { + this->connect(); + +#ifdef SQL_ASYNC_DBC_FUNCTIONS + validate(this->conn, SQL_ASYNC_DBC_FUNCTIONS, + static_cast(SQL_ASYNC_DBC_NOT_CAPABLE)); +#endif + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_ASYNC_MODE) { + this->connect(); + + validate(this->conn, SQL_ASYNC_MODE, static_cast(SQL_AM_NONE)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_ASYNC_NOTIFICATION) { + this->connect(); + +#ifdef SQL_ASYNC_NOTIFICATION + validate(this->conn, SQL_ASYNC_NOTIFICATION, + static_cast(SQL_ASYNC_NOTIFICATION_NOT_CAPABLE)); +#endif + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_BATCH_ROW_COUNT) { + this->connect(); + + validate(this->conn, SQL_BATCH_ROW_COUNT, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_BATCH_SUPPORT) { + this->connect(); + + validate(this->conn, SQL_BATCH_SUPPORT, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DATA_SOURCE_NAME) { + this->connect(); + + validate(this->conn, SQL_DATA_SOURCE_NAME, L""); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DRIVER_AWARE_POOLING_SUPPORTED) { + // A driver does not need to implement SQL_DRIVER_AWARE_POOLING_SUPPORTED and the + // Driver Manager will not honor to the driver's return value. + this->connect(); + + validate(this->conn, SQL_DRIVER_AWARE_POOLING_SUPPORTED, + static_cast(SQL_DRIVER_AWARE_POOLING_NOT_CAPABLE)); + + this->disconnect(); +} + +// These information types are implemented by the Driver Manager alone. +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DRIVER_HDBC) { + this->connect(); + + // Value returned from driver manager is the connection address + validateGreaterThan(this->conn, SQL_DRIVER_HDBC, static_cast(0)); + + this->disconnect(); +} + +// These information types are implemented by the Driver Manager alone. +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DRIVER_HDESC) { + // TODO This is failing due to no descriptor being created + GTEST_SKIP(); + this->connect(); + + validate(this->conn, SQL_DRIVER_HDESC, static_cast(0)); + + this->disconnect(); +} + +// These information types are implemented by the Driver Manager alone. +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DRIVER_HENV) { + this->connect(); + + // Value returned from driver manager is the env address + validateGreaterThan(this->conn, SQL_DRIVER_HENV, static_cast(0)); + + this->disconnect(); +} + +// These information types are implemented by the Driver Manager alone. +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DRIVER_HLIB) { + this->connect(); + + validateGreaterThan(this->conn, SQL_DRIVER_HLIB, static_cast(0)); + + this->disconnect(); +} + +// These information types are implemented by the Driver Manager alone. +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DRIVER_HSTMT) { + // TODO This is failing due to no statement being created + // This should run after SQLGetStmtAttr is implemented + GTEST_SKIP(); + this->connect(); + + validate(this->conn, SQL_DRIVER_HSTMT, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DRIVER_NAME) { + this->connect(); + + validate(this->conn, SQL_DRIVER_NAME, L"Arrow Flight ODBC Driver"); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DRIVER_ODBC_VER) { + this->connect(); + + validate(this->conn, SQL_DRIVER_ODBC_VER, L"03.80"); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DRIVER_VER) { + this->connect(); + + validate(this->conn, SQL_DRIVER_VER, L"00.09.0000.0"); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DYNAMIC_CURSOR_ATTRIBUTES1) { + this->connect(); + + validate(this->conn, SQL_DYNAMIC_CURSOR_ATTRIBUTES1, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DYNAMIC_CURSOR_ATTRIBUTES2) { + this->connect(); + + validate(this->conn, SQL_DYNAMIC_CURSOR_ATTRIBUTES2, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1) { + this->connect(); + + validate(this->conn, SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1, + static_cast(SQL_CA1_NEXT)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2) { + this->connect(); + + validate(this->conn, SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2, + static_cast(SQL_CA2_READ_ONLY_CONCURRENCY)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_FILE_USAGE) { + this->connect(); + + validate(this->conn, SQL_FILE_USAGE, static_cast(SQL_FILE_NOT_SUPPORTED)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_GETDATA_EXTENSIONS) { + this->connect(); + + validate(this->conn, SQL_GETDATA_EXTENSIONS, + static_cast(SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_INFO_SCHEMA_VIEWS) { + this->connect(); + + validate(this->conn, SQL_INFO_SCHEMA_VIEWS, + static_cast(SQL_ISV_TABLES | SQL_ISV_COLUMNS | SQL_ISV_VIEWS)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_KEYSET_CURSOR_ATTRIBUTES1) { + this->connect(); + + validate(this->conn, SQL_KEYSET_CURSOR_ATTRIBUTES1, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_KEYSET_CURSOR_ATTRIBUTES2) { + this->connect(); + + validate(this->conn, SQL_KEYSET_CURSOR_ATTRIBUTES2, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_MAX_ASYNC_CONCURRENT_STATEMENTS) { + this->connect(); + + validate(this->conn, SQL_MAX_ASYNC_CONCURRENT_STATEMENTS, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_MAX_CONCURRENT_ACTIVITIES) { + this->connect(); + + validate(this->conn, SQL_MAX_CONCURRENT_ACTIVITIES, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_MAX_DRIVER_CONNECTIONS) { + this->connect(); + + validate(this->conn, SQL_MAX_DRIVER_CONNECTIONS, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_ODBC_INTERFACE_CONFORMANCE) { + this->connect(); + + validate(this->conn, SQL_ODBC_INTERFACE_CONFORMANCE, + static_cast(SQL_OIC_CORE)); + + this->disconnect(); +} + +// case SQL_ODBC_STANDARD_CLI_CONFORMANCE: - mentioned in SQLGetInfo spec with no +// description and there is no constant for this. +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_ODBC_STANDARD_CLI_CONFORMANCE) { + // Type commented out in odbc_connection.cc + GTEST_SKIP(); + this->connect(); + + // Type does not exist in sql.h + // validate(this->conn, SQL_ODBC_STANDARD_CLI_CONFORMANCE, + // static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_ODBC_VER) { + // This is implemented only in the Driver Manager. + this->connect(); + + validate(this->conn, SQL_ODBC_VER, L"03.80.0000"); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_PARAM_ARRAY_ROW_COUNTS) { + this->connect(); + + validate(this->conn, SQL_PARAM_ARRAY_ROW_COUNTS, + static_cast(SQL_PARC_NO_BATCH)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_PARAM_ARRAY_SELECTS) { + this->connect(); + + validate(this->conn, SQL_PARAM_ARRAY_SELECTS, + static_cast(SQL_PAS_NO_SELECT)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_ROW_UPDATES) { + this->connect(); + + validate(this->conn, SQL_ROW_UPDATES, L"N"); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_SEARCH_PATTERN_ESCAPE) { + this->connect(); + + validate(this->conn, SQL_SEARCH_PATTERN_ESCAPE, L"\\"); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_SERVER_NAME) { + this->connect(); + + validateNotEmptySQLWCHAR(this->conn, SQL_SERVER_NAME, false); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_STATIC_CURSOR_ATTRIBUTES1) { + this->connect(); + + validate(this->conn, SQL_STATIC_CURSOR_ATTRIBUTES1, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_STATIC_CURSOR_ATTRIBUTES2) { + this->connect(); + + validate(this->conn, SQL_STATIC_CURSOR_ATTRIBUTES2, static_cast(0)); + + this->disconnect(); +} + +// DBMS Product Information + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DATABASE_NAME) { + this->connect(); + + validate(this->conn, SQL_DATABASE_NAME, L""); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DBMS_NAME) { + this->connect(); + + validateNotEmptySQLWCHAR(this->conn, SQL_DBMS_NAME, false); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DBMS_VER) { + this->connect(); + + validateNotEmptySQLWCHAR(this->conn, SQL_DBMS_VER, false); + + this->disconnect(); +} + +// Data Source Information + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_ACCESSIBLE_PROCEDURES) { + this->connect(); + + validate(conn, SQL_ACCESSIBLE_PROCEDURES, L"N"); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_ACCESSIBLE_TABLES) { + this->connect(); + + validate(conn, SQL_ACCESSIBLE_TABLES, L"Y"); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_BOOKMARK_PERSISTENCE) { + this->connect(); + + validate(conn, SQL_BOOKMARK_PERSISTENCE, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CATALOG_TERM) { + this->connect(); + + validate(conn, SQL_CATALOG_TERM, L""); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_COLLATION_SEQ) { + this->connect(); + + validate(conn, SQL_COLLATION_SEQ, L""); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CONCAT_NULL_BEHAVIOR) { + this->connect(); + + validate(conn, SQL_CONCAT_NULL_BEHAVIOR, static_cast(SQL_CB_NULL)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CURSOR_COMMIT_BEHAVIOR) { + this->connect(); + + validate(conn, SQL_CURSOR_COMMIT_BEHAVIOR, static_cast(SQL_CB_CLOSE)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CURSOR_ROLLBACK_BEHAVIOR) { + this->connect(); + + validate(conn, SQL_CURSOR_ROLLBACK_BEHAVIOR, static_cast(SQL_CB_CLOSE)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CURSOR_SENSITIVITY) { + this->connect(); + + validate(conn, SQL_CURSOR_SENSITIVITY, static_cast(SQL_UNSPECIFIED)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DATA_SOURCE_READ_ONLY) { + this->connect(); + + validate(conn, SQL_DATA_SOURCE_READ_ONLY, L"N"); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DEFAULT_TXN_ISOLATION) { + this->connect(); + + validate(conn, SQL_DEFAULT_TXN_ISOLATION, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DESCRIBE_PARAMETER) { + this->connect(); + + validate(conn, SQL_DESCRIBE_PARAMETER, L"N"); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_MULT_RESULT_SETS) { + this->connect(); + + validate(conn, SQL_MULT_RESULT_SETS, L"N"); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_MULTIPLE_ACTIVE_TXN) { + this->connect(); + + validate(conn, SQL_MULTIPLE_ACTIVE_TXN, L"N"); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_NEED_LONG_DATA_LEN) { + this->connect(); + + validate(conn, SQL_NEED_LONG_DATA_LEN, L"N"); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_NULL_COLLATION) { + this->connect(); + + validate(conn, SQL_NULL_COLLATION, static_cast(SQL_NC_START)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_PROCEDURE_TERM) { + this->connect(); + + validate(conn, SQL_PROCEDURE_TERM, L""); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_SCHEMA_TERM) { + this->connect(); + + validate(conn, SQL_SCHEMA_TERM, L"schema"); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_SCROLL_OPTIONS) { + this->connect(); + + validate(conn, SQL_SCROLL_OPTIONS, static_cast(SQL_SO_FORWARD_ONLY)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_TABLE_TERM) { + this->connect(); + + validate(conn, SQL_TABLE_TERM, L"table"); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_TXN_CAPABLE) { + this->connect(); + + validate(conn, SQL_TXN_CAPABLE, static_cast(SQL_TC_NONE)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_TXN_ISOLATION_OPTION) { + this->connect(); + + validate(conn, SQL_TXN_ISOLATION_OPTION, static_cast(0)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_USER_NAME) { + this->connect(); + + validate(conn, SQL_USER_NAME, L""); + + this->disconnect(); +} + +// Supported SQL + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_AGGREGATE_FUNCTIONS) { + this->connect(); + + validate( + conn, SQL_AGGREGATE_FUNCTIONS, + static_cast(SQL_AF_ALL | SQL_AF_AVG | SQL_AF_COUNT | SQL_AF_DISTINCT | + SQL_AF_MAX | SQL_AF_MIN | SQL_AF_SUM)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_ALTER_DOMAIN) { + this->connect(); + + validate(conn, SQL_ALTER_DOMAIN, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_ALTER_SCHEMA) { + // Type commented out in odbc_connection.cc + GTEST_SKIP(); + this->connect(); + + // Type does not exist in sql.h + // validate(conn, SQL_ALTER_SCHEMA, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_ALTER_TABLE) { + this->connect(); + + validate(conn, SQL_ALTER_TABLE, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_ANSI_SQL_DATETIME_LITERALS) { + // Type commented out in odbc_connection.cc + GTEST_SKIP(); + this->connect(); + + // Type does not exist in sql.h + // validate(conn, SQL_ANSI_SQL_DATETIME_LITERALS, L""); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CATALOG_LOCATION) { + this->connect(); + + validate(conn, SQL_CATALOG_LOCATION, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CATALOG_NAME) { + this->connect(); + + validate(conn, SQL_CATALOG_NAME, L"N"); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CATALOG_NAME_SEPARATOR) { + this->connect(); + + validate(conn, SQL_CATALOG_NAME_SEPARATOR, L""); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_CATALOG_USAGE) { + this->connect(); + + validate(conn, SQL_CATALOG_USAGE, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_COLUMN_ALIAS) { + this->connect(); + + validate(conn, SQL_COLUMN_ALIAS, L"Y"); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_CORRELATION_NAME) { + this->connect(); + + validate(conn, SQL_CORRELATION_NAME, static_cast(SQL_CN_NONE)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CREATE_ASSERTION) { + this->connect(); + + validate(conn, SQL_CREATE_ASSERTION, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CREATE_CHARACTER_SET) { + this->connect(); + + validate(conn, SQL_CREATE_CHARACTER_SET, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CREATE_COLLATION) { + this->connect(); + + validate(conn, SQL_CREATE_COLLATION, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CREATE_DOMAIN) { + this->connect(); + + validate(conn, SQL_CREATE_DOMAIN, static_cast(0)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_CREATE_SCHEMA) { + this->connect(); + + validate(conn, SQL_CREATE_SCHEMA, static_cast(1)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_CREATE_TABLE) { + this->connect(); + + validate(conn, SQL_CREATE_TABLE, static_cast(1)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CREATE_TRANSLATION) { + this->connect(); + + validate(conn, SQL_CREATE_TRANSLATION, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DDL_INDEX) { + this->connect(); + + validate(conn, SQL_DDL_INDEX, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DROP_ASSERTION) { + this->connect(); + + validate(conn, SQL_DROP_ASSERTION, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DROP_CHARACTER_SET) { + this->connect(); + + validate(conn, SQL_DROP_CHARACTER_SET, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DROP_COLLATION) { + this->connect(); + + validate(conn, SQL_DROP_COLLATION, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DROP_DOMAIN) { + this->connect(); + + validate(conn, SQL_DROP_DOMAIN, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DROP_SCHEMA) { + this->connect(); + + validate(conn, SQL_DROP_SCHEMA, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DROP_TABLE) { + this->connect(); + + validate(conn, SQL_DROP_TABLE, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DROP_TRANSLATION) { + this->connect(); + + validate(conn, SQL_DROP_TRANSLATION, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_DROP_VIEW) { + this->connect(); + + validate(conn, SQL_DROP_VIEW, static_cast(0)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_EXPRESSIONS_IN_ORDERBY) { + this->connect(); + + validate(conn, SQL_EXPRESSIONS_IN_ORDERBY, L"N"); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_GROUP_BY) { + this->connect(); + + validate(conn, SQL_GROUP_BY, + static_cast(SQL_GB_GROUP_BY_CONTAINS_SELECT)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_IDENTIFIER_CASE) { + this->connect(); + + validate(conn, SQL_IDENTIFIER_CASE, static_cast(SQL_IC_MIXED)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_IDENTIFIER_QUOTE_CHAR) { + this->connect(); + + validate(conn, SQL_IDENTIFIER_QUOTE_CHAR, L"\""); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_INDEX_KEYWORDS) { + this->connect(); + + validate(conn, SQL_INDEX_KEYWORDS, static_cast(SQL_IK_NONE)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_INSERT_STATEMENT) { + this->connect(); + + validate(conn, SQL_INSERT_STATEMENT, + static_cast(SQL_IS_INSERT_LITERALS | SQL_IS_INSERT_SEARCHED | + SQL_IS_SELECT_INTO)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_INTEGRITY) { + this->connect(); + + validate(conn, SQL_INTEGRITY, L"N"); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_KEYWORDS) { + this->connect(); + + validateNotEmptySQLWCHAR(conn, SQL_KEYWORDS, true); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_LIKE_ESCAPE_CLAUSE) { + this->connect(); + + validate(conn, SQL_LIKE_ESCAPE_CLAUSE, L"Y"); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_NON_NULLABLE_COLUMNS) { + this->connect(); + + validate(conn, SQL_NON_NULLABLE_COLUMNS, static_cast(SQL_NNC_NULL)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_OJ_CAPABILITIES) { + this->connect(); + + validate(this->conn, SQL_OJ_CAPABILITIES, + static_cast(SQL_OJ_LEFT | SQL_OJ_RIGHT | SQL_OJ_FULL)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_ORDER_BY_COLUMNS_IN_SELECT) { + this->connect(); + + validate(conn, SQL_ORDER_BY_COLUMNS_IN_SELECT, L"Y"); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_OUTER_JOINS) { + this->connect(); + + validate(conn, SQL_OUTER_JOINS, L"N"); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_PROCEDURES) { + this->connect(); + + validate(conn, SQL_PROCEDURES, L"N"); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_QUOTED_IDENTIFIER_CASE) { + this->connect(); + + validate(conn, SQL_QUOTED_IDENTIFIER_CASE, static_cast(SQL_IC_MIXED)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_SCHEMA_USAGE) { + this->connect(); + + validate(conn, SQL_SCHEMA_USAGE, static_cast(SQL_SU_DML_STATEMENTS)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_SPECIAL_CHARACTERS) { + this->connect(); + + validate(conn, SQL_SPECIAL_CHARACTERS, L""); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_SQL_CONFORMANCE) { + this->connect(); + + validate(conn, SQL_SQL_CONFORMANCE, static_cast(SQL_SC_SQL92_ENTRY)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_SUBQUERIES) { + this->connect(); + + validate(conn, SQL_SUBQUERIES, + static_cast(SQL_SQ_CORRELATED_SUBQUERIES | SQL_SQ_COMPARISON | + SQL_SQ_EXISTS | SQL_SQ_IN | SQL_SQ_QUANTIFIED)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_UNION) { + this->connect(); + + validate(conn, SQL_UNION, static_cast(SQL_U_UNION | SQL_U_UNION_ALL)); + + this->disconnect(); +} + +// SQL Limits + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_MAX_BINARY_LITERAL_LEN) { + this->connect(); + + validate(conn, SQL_MAX_BINARY_LITERAL_LEN, static_cast(0)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_MAX_CATALOG_NAME_LEN) { + this->connect(); + + validate(conn, SQL_MAX_CATALOG_NAME_LEN, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_MAX_CHAR_LITERAL_LEN) { + this->connect(); + + validate(conn, SQL_MAX_CHAR_LITERAL_LEN, static_cast(0)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_MAX_COLUMN_NAME_LEN) { + this->connect(); + + validate(conn, SQL_MAX_COLUMN_NAME_LEN, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_MAX_COLUMNS_IN_GROUP_BY) { + this->connect(); + + validate(conn, SQL_MAX_COLUMNS_IN_GROUP_BY, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_MAX_COLUMNS_IN_INDEX) { + this->connect(); + + validate(conn, SQL_MAX_COLUMNS_IN_INDEX, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_MAX_COLUMNS_IN_ORDER_BY) { + this->connect(); + + validate(conn, SQL_MAX_COLUMNS_IN_ORDER_BY, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_MAX_COLUMNS_IN_SELECT) { + this->connect(); + + validate(conn, SQL_MAX_COLUMNS_IN_SELECT, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_MAX_COLUMNS_IN_TABLE) { + this->connect(); + + validate(conn, SQL_MAX_COLUMNS_IN_TABLE, static_cast(0)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_MAX_CURSOR_NAME_LEN) { + this->connect(); + + validate(conn, SQL_MAX_CURSOR_NAME_LEN, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_MAX_IDENTIFIER_LEN) { + this->connect(); + + validate(conn, SQL_MAX_IDENTIFIER_LEN, static_cast(65535)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_MAX_INDEX_SIZE) { + this->connect(); + + validate(conn, SQL_MAX_INDEX_SIZE, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_MAX_PROCEDURE_NAME_LEN) { + this->connect(); + + validate(conn, SQL_MAX_PROCEDURE_NAME_LEN, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_MAX_ROW_SIZE) { + this->connect(); + + validate(conn, SQL_MAX_ROW_SIZE, L""); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_MAX_ROW_SIZE_INCLUDES_LONG) { + this->connect(); + + validate(conn, SQL_MAX_ROW_SIZE_INCLUDES_LONG, L"N"); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_MAX_SCHEMA_NAME_LEN) { + this->connect(); + + validate(conn, SQL_MAX_SCHEMA_NAME_LEN, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_MAX_STATEMENT_LEN) { + this->connect(); + + validate(conn, SQL_MAX_STATEMENT_LEN, static_cast(0)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_MAX_TABLE_NAME_LEN) { + this->connect(); + + validate(conn, SQL_MAX_TABLE_NAME_LEN, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_MAX_TABLES_IN_SELECT) { + this->connect(); + + validate(conn, SQL_MAX_TABLES_IN_SELECT, static_cast(0)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_MAX_USER_NAME_LEN) { + this->connect(); + + validate(conn, SQL_MAX_USER_NAME_LEN, static_cast(0)); + + this->disconnect(); +} + +// Scalar Function Information + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_CONVERT_FUNCTIONS) { + this->connect(); + + validate(conn, SQL_CONVERT_FUNCTIONS, static_cast(0)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_NUMERIC_FUNCTIONS) { + this->connect(); + + validate(conn, SQL_NUMERIC_FUNCTIONS, static_cast(4058942)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_STRING_FUNCTIONS) { + this->connect(); + + validate(conn, SQL_STRING_FUNCTIONS, + static_cast(SQL_FN_STR_LTRIM | SQL_FN_STR_LENGTH | + SQL_FN_STR_REPLACE | SQL_FN_STR_RTRIM)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_SYSTEM_FUNCTIONS) { + this->connect(); + + validate(conn, SQL_SYSTEM_FUNCTIONS, + static_cast(SQL_FN_SYS_IFNULL | SQL_FN_SYS_USERNAME)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_TIMEDATE_ADD_INTERVALS) { + this->connect(); + + validate(conn, SQL_TIMEDATE_ADD_INTERVALS, + static_cast(SQL_FN_TSI_FRAC_SECOND | SQL_FN_TSI_SECOND | + SQL_FN_TSI_MINUTE | SQL_FN_TSI_HOUR | SQL_FN_TSI_DAY | + SQL_FN_TSI_WEEK | SQL_FN_TSI_MONTH | + SQL_FN_TSI_QUARTER | SQL_FN_TSI_YEAR)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_TIMEDATE_DIFF_INTERVALS) { + this->connect(); + + validate(conn, SQL_TIMEDATE_DIFF_INTERVALS, + static_cast(SQL_FN_TSI_FRAC_SECOND | SQL_FN_TSI_SECOND | + SQL_FN_TSI_MINUTE | SQL_FN_TSI_HOUR | SQL_FN_TSI_DAY | + SQL_FN_TSI_WEEK | SQL_FN_TSI_MONTH | + SQL_FN_TSI_QUARTER | SQL_FN_TSI_YEAR)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_TIMEDATE_FUNCTIONS) { + this->connect(); + + validate(conn, SQL_TIMEDATE_FUNCTIONS, + static_cast( + SQL_FN_TD_CURRENT_DATE | SQL_FN_TD_CURRENT_TIME | + SQL_FN_TD_CURRENT_TIMESTAMP | SQL_FN_TD_CURDATE | SQL_FN_TD_CURTIME | + SQL_FN_TD_DAYNAME | SQL_FN_TD_DAYOFMONTH | SQL_FN_TD_DAYOFWEEK | + SQL_FN_TD_DAYOFYEAR | SQL_FN_TD_EXTRACT | SQL_FN_TD_HOUR | + SQL_FN_TD_MINUTE | SQL_FN_TD_MONTH | SQL_FN_TD_MONTHNAME | SQL_FN_TD_NOW | + SQL_FN_TD_QUARTER | SQL_FN_TD_SECOND | SQL_FN_TD_TIMESTAMPADD | + SQL_FN_TD_TIMESTAMPDIFF | SQL_FN_TD_WEEK | SQL_FN_TD_YEAR)); + + this->disconnect(); +} + +// Conversion Information + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_CONVERT_BIGINT) { + this->connect(); + + validate(conn, SQL_CONVERT_BIGINT, static_cast(8)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_CONVERT_BINARY) { + this->connect(); + + validate(conn, SQL_CONVERT_BINARY, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CONVERT_BIT) { + this->connect(); + + validate(conn, SQL_CONVERT_BIT, static_cast(0)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_CONVERT_CHAR) { + this->connect(); + + validate(conn, SQL_CONVERT_CHAR, static_cast(0)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_CONVERT_DATE) { + this->connect(); + + validate(conn, SQL_CONVERT_DATE, static_cast(0)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_CONVERT_DECIMAL) { + this->connect(); + + validate(conn, SQL_CONVERT_DECIMAL, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CONVERT_DOUBLE) { + this->connect(); + + validate(conn, SQL_CONVERT_DOUBLE, static_cast(0)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_CONVERT_FLOAT) { + this->connect(); + + validate(conn, SQL_CONVERT_FLOAT, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CONVERT_INTEGER) { + this->connect(); + + validate(conn, SQL_CONVERT_INTEGER, static_cast(0)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_CONVERT_INTERVAL_DAY_TIME) { + this->connect(); + + validate(conn, SQL_CONVERT_INTERVAL_DAY_TIME, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CONVERT_INTERVAL_YEAR_MONTH) { + this->connect(); + + validate(conn, SQL_CONVERT_INTERVAL_YEAR_MONTH, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CONVERT_LONGVARBINARY) { + this->connect(); + + validate(conn, SQL_CONVERT_LONGVARBINARY, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CONVERT_LONGVARCHAR) { + this->connect(); + + validate(conn, SQL_CONVERT_LONGVARCHAR, static_cast(0)); + + this->disconnect(); +} + +TEST_F(FlightSQLODBCMockTestBase, Test_SQL_CONVERT_NUMERIC) { + this->connect(); + + validate(conn, SQL_CONVERT_NUMERIC, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CONVERT_REAL) { + this->connect(); + + validate(conn, SQL_CONVERT_REAL, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CONVERT_SMALLINT) { + this->connect(); + + validate(conn, SQL_CONVERT_SMALLINT, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CONVERT_TIME) { + this->connect(); + + validate(conn, SQL_CONVERT_TIME, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CONVERT_TIMESTAMP) { + this->connect(); + + validate(conn, SQL_CONVERT_TIMESTAMP, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CONVERT_TINYINT) { + this->connect(); + + validate(conn, SQL_CONVERT_TINYINT, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CONVERT_VARBINARY) { + this->connect(); + + validate(conn, SQL_CONVERT_VARBINARY, static_cast(0)); + + this->disconnect(); +} + +TYPED_TEST(FlightSQLODBCTestBase, Test_SQL_CONVERT_VARCHAR) { + this->connect(); + + validate(conn, SQL_CONVERT_VARCHAR, static_cast(0)); + + this->disconnect(); +} + +} // namespace arrow::flight::sql::odbc