diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_api.cc b/cpp/src/arrow/flight/sql/odbc/odbc_api.cc index 01780f0efe2..008420b574d 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc_api.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbc_api.cc @@ -960,8 +960,60 @@ SQLRETURN SQLGetTypeInfo(SQLHSTMT stmt, SQLSMALLINT data_type) { // appropriate data types in `SEARCHABLE` field ARROW_LOG(DEBUG) << "SQLGetTypeInfoW called with stmt: " << stmt << " data_type: " << data_type; - // GH-47722 TODO: Implement SQLGetTypeInfo - return SQL_INVALID_HANDLE; + + using ODBC::ODBCStatement; + return ODBC::ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { + ODBCStatement* statement = reinterpret_cast(stmt); + + switch (data_type) { + case SQL_ALL_TYPES: + case SQL_CHAR: + case SQL_VARCHAR: + case SQL_LONGVARCHAR: + case SQL_WCHAR: + case SQL_WVARCHAR: + case SQL_WLONGVARCHAR: + case SQL_BIT: + case SQL_BINARY: + case SQL_VARBINARY: + case SQL_LONGVARBINARY: + case SQL_TINYINT: + case SQL_SMALLINT: + case SQL_INTEGER: + case SQL_BIGINT: + case SQL_NUMERIC: + case SQL_DECIMAL: + case SQL_FLOAT: + case SQL_REAL: + case SQL_DOUBLE: + case SQL_GUID: + case SQL_DATE: + case SQL_TYPE_DATE: + case SQL_TIME: + case SQL_TYPE_TIME: + case SQL_TIMESTAMP: + case SQL_TYPE_TIMESTAMP: + case SQL_INTERVAL_DAY: + case SQL_INTERVAL_DAY_TO_HOUR: + case SQL_INTERVAL_DAY_TO_MINUTE: + case SQL_INTERVAL_DAY_TO_SECOND: + case SQL_INTERVAL_HOUR: + case SQL_INTERVAL_HOUR_TO_MINUTE: + case SQL_INTERVAL_HOUR_TO_SECOND: + case SQL_INTERVAL_MINUTE: + case SQL_INTERVAL_MINUTE_TO_SECOND: + case SQL_INTERVAL_SECOND: + case SQL_INTERVAL_YEAR: + case SQL_INTERVAL_YEAR_TO_MONTH: + case SQL_INTERVAL_MONTH: + statement->GetTypeInfo(data_type); + break; + default: + throw DriverException("Invalid SQL data type", "HY004"); + } + + return SQL_SUCCESS; + }); } SQLRETURN SQLNativeSql(SQLHDBC conn, SQLWCHAR* in_statement_text, diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_impl/flight_sql_statement_get_type_info.cc b/cpp/src/arrow/flight/sql/odbc/odbc_impl/flight_sql_statement_get_type_info.cc index e94378b7e04..3fd1494c0a2 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc_impl/flight_sql_statement_get_type_info.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbc_impl/flight_sql_statement_get_type_info.cc @@ -108,7 +108,8 @@ Result> TransformInner( data.literal_suffix = reader.GetLiteralSuffix(); const auto& create_params = reader.GetCreateParams(); - if (create_params) { + if (create_params && !create_params->empty()) { + // GH-48093 TODO: replace boost-algorithm with alternatives data.create_params = boost::algorithm::join(*create_params, ","); } else { data.create_params = nullopt; @@ -116,6 +117,8 @@ Result> TransformInner( data.nullable = reader.GetNullable() ? NULLABILITY_NULLABLE : NULLABILITY_NO_NULLS; data.case_sensitive = reader.GetCaseSensitive(); + // GH-47237 return SEARCHABILITY_LIKE_ONLY and SEARCHABILITY_ALL_EXPECT_LIKE for + // appropriate data types data.searchable = reader.GetSearchable() ? SEARCHABILITY_ALL : SEARCHABILITY_NONE; data.unsigned_attribute = reader.GetUnsignedAttribute(); data.fixed_prec_scale = reader.GetFixedPrecScale(); @@ -123,9 +126,9 @@ Result> TransformInner( data.local_type_name = reader.GetLocalTypeName(); data.minimum_scale = reader.GetMinimumScale(); data.maximum_scale = reader.GetMaximumScale(); - data.sql_data_type = + data.sql_data_type = util::GetNonConciseDataType( EnsureRightSqlCharType(static_cast(reader.GetSqlDataType()), - metadata_settings_.use_wide_char); + metadata_settings_.use_wide_char)); data.sql_datetime_sub = util::GetSqlDateTimeSubCode(static_cast(data.data_type)); data.num_prec_radix = reader.GetNumPrecRadix(); diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_impl/util.cc b/cpp/src/arrow/flight/sql/odbc/odbc_impl/util.cc index df6aff9cfa7..0c284a5ebb9 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc_impl/util.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbc_impl/util.cc @@ -56,6 +56,9 @@ SqlDataType GetDefaultSqlCharType(bool use_wide_char) { SqlDataType GetDefaultSqlVarcharType(bool use_wide_char) { return use_wide_char ? SqlDataType_WVARCHAR : SqlDataType_VARCHAR; } +SqlDataType GetDefaultSqlLongVarcharType(bool use_wide_char) { + return use_wide_char ? SqlDataType_WLONGVARCHAR : SqlDataType_LONGVARCHAR; +} CDataType GetDefaultCCharType(bool use_wide_char) { return use_wide_char ? CDataType_WCHAR : CDataType_CHAR; } @@ -146,6 +149,9 @@ SqlDataType EnsureRightSqlCharType(SqlDataType data_type, bool use_wide_char) { case SqlDataType_VARCHAR: case SqlDataType_WVARCHAR: return GetDefaultSqlVarcharType(use_wide_char); + case SqlDataType_LONGVARCHAR: + case SqlDataType_WLONGVARCHAR: + return GetDefaultSqlLongVarcharType(use_wide_char); default: return data_type; } @@ -747,10 +753,12 @@ bool NeedArrayConversion(Type::type original_type_id, CDataType data_type) { return data_type != CDataType_BINARY; case Type::DECIMAL128: return data_type != CDataType_NUMERIC; + case Type::DURATION: case Type::LIST: case Type::LARGE_LIST: case Type::FIXED_SIZE_LIST: case Type::MAP: + case Type::STRING_VIEW: case Type::STRUCT: return data_type == CDataType_CHAR || data_type == CDataType_WCHAR; default: diff --git a/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt b/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt index 4bc240637e7..faf451eb71b 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt +++ b/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt @@ -35,6 +35,7 @@ add_arrow_test(flight_sql_odbc_test odbc_test_suite.cc odbc_test_suite.h connection_test.cc + type_info_test.cc # Enable Protobuf cleanup after test execution # GH-46889: move protobuf_test_util to a more common location ../../../../engine/substrait/protobuf_test_util.cc 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 new file mode 100644 index 00000000000..ce05f8a70b3 --- /dev/null +++ b/cpp/src/arrow/flight/sql/odbc/tests/type_info_test.cc @@ -0,0 +1,1672 @@ +// 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" + +#include "arrow/flight/sql/odbc/odbc_impl/platform.h" + +#include +#include +#include + +#include + +namespace arrow::flight::sql::odbc { + +using std::optional; + +template +class TypeInfoTest : public T {}; + +class TypeInfoMockTest : public FlightSQLODBCMockTestBase {}; +using TestTypes = ::testing::Types; +TYPED_TEST_SUITE(TypeInfoTest, TestTypes); + +class TypeInfoOdbcV2MockTest : public FlightSQLOdbcV2MockTestBase {}; + +namespace { +// Helper Functions + +void CheckSQLGetTypeInfo( + SQLHSTMT stmt, const std::wstring& expected_type_name, + const SQLSMALLINT& expected_data_type, const SQLINTEGER& expected_column_size, + const optional& expected_literal_prefix, + const optional& expected_literal_suffix, + const optional& expected_create_params, + const SQLSMALLINT& expected_nullable, const SQLSMALLINT& expected_case_sensitive, + const SQLSMALLINT& expected_searchable, const SQLSMALLINT& expected_unsigned_attr, + const SQLSMALLINT& expected_fixed_prec_scale, + const SQLSMALLINT& expected_auto_unique_value, + const std::wstring& expected_local_type_name, const SQLSMALLINT& expected_min_scale, + const SQLSMALLINT& expected_max_scale, const SQLSMALLINT& expected_sql_data_type, + const SQLSMALLINT& expected_sql_datetime_sub, + const SQLINTEGER& expected_num_prec_radix, const SQLINTEGER& expected_interval_prec) { + CheckStringColumnW(stmt, 1, expected_type_name); // type name + CheckSmallIntColumn(stmt, 2, expected_data_type); // data type + CheckIntColumn(stmt, 3, expected_column_size); // column size + + if (expected_literal_prefix) { // literal prefix + CheckStringColumnW(stmt, 4, *expected_literal_prefix); + } else { + CheckNullColumnW(stmt, 4); + } + + if (expected_literal_suffix) { // literal suffix + CheckStringColumnW(stmt, 5, *expected_literal_suffix); + } else { + CheckNullColumnW(stmt, 5); + } + + if (expected_create_params) { // create params + CheckStringColumnW(stmt, 6, *expected_create_params); + } else { + CheckNullColumnW(stmt, 6); + } + + CheckSmallIntColumn(stmt, 7, expected_nullable); // nullable + CheckSmallIntColumn(stmt, 8, expected_case_sensitive); // case sensitive + CheckSmallIntColumn(stmt, 9, expected_searchable); // searchable + CheckSmallIntColumn(stmt, 10, expected_unsigned_attr); // unsigned attr + CheckSmallIntColumn(stmt, 11, expected_fixed_prec_scale); // fixed prec scale + CheckSmallIntColumn(stmt, 12, expected_auto_unique_value); // auto unique value + CheckStringColumnW(stmt, 13, expected_local_type_name); // local type name + CheckSmallIntColumn(stmt, 14, expected_min_scale); // min scale + CheckSmallIntColumn(stmt, 15, expected_max_scale); // max scale + CheckSmallIntColumn(stmt, 16, expected_sql_data_type); // sql data type + CheckSmallIntColumn(stmt, 17, expected_sql_datetime_sub); // sql datetime sub + CheckIntColumn(stmt, 18, expected_num_prec_radix); // num prec radix + CheckIntColumn(stmt, 19, expected_interval_prec); // interval prec +} +} // namespace + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoAllTypes) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_ALL_TYPES)); + + // Check bit data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"bit"), // expected_type_name + SQL_BIT, // expected_data_type + 1, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + NULL, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"bit"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_BIT, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check tinyint data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"tinyint"), // expected_type_name + SQL_TINYINT, // expected_data_type + 3, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"tinyint"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_TINYINT, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check bigint data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"bigint"), // expected_type_name + SQL_BIGINT, // expected_data_type + 19, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"bigint"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_BIGINT, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check longvarbinary data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"longvarbinary"), // expected_type_name + SQL_LONGVARBINARY, // expected_data_type + 65536, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + NULL, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"longvarbinary"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_LONGVARBINARY, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check varbinary data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"varbinary"), // expected_type_name + SQL_VARBINARY, // expected_data_type + 255, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + NULL, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"varbinary"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_VARBINARY, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check text data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + // Driver returns SQL_WLONGVARCHAR since unicode is enabled + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"text"), // expected_type_name + SQL_WLONGVARCHAR, // expected_data_type + 65536, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::wstring(L"length"), // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + NULL, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"text"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_WLONGVARCHAR, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check longvarchar data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"longvarchar"), // expected_type_name + SQL_WLONGVARCHAR, // expected_data_type + 65536, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::wstring(L"length"), // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + NULL, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"longvarchar"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_WLONGVARCHAR, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check char data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + // Driver returns SQL_WCHAR since unicode is enabled + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"char"), // expected_type_name + SQL_WCHAR, // expected_data_type + 255, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::wstring(L"length"), // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + NULL, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"char"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_WCHAR, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check integer data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"integer"), // expected_type_name + SQL_INTEGER, // expected_data_type + 9, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"integer"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_INTEGER, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check smallint data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"smallint"), // expected_type_name + SQL_SMALLINT, // expected_data_type + 5, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"smallint"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_SMALLINT, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check float data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"float"), // expected_type_name + SQL_FLOAT, // expected_data_type + 7, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"float"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_FLOAT, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check double data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"double"), // expected_type_name + SQL_DOUBLE, // expected_data_type + 15, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"double"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DOUBLE, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check numeric data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + // Mock server treats numeric data type as a double type + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"numeric"), // expected_type_name + SQL_DOUBLE, // expected_data_type + 15, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"numeric"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DOUBLE, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check varchar data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + // Driver returns SQL_WVARCHAR since unicode is enabled + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"varchar"), // expected_type_name + SQL_WVARCHAR, // expected_data_type + 255, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::wstring(L"length"), // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"varchar"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_WVARCHAR, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check date data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"date"), // expected_type_name + SQL_TYPE_DATE, // expected_data_type + 10, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"date"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DATETIME, // expected_sql_data_type + SQL_CODE_DATE, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check time data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"time"), // expected_type_name + SQL_TYPE_TIME, // expected_data_type + 8, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"time"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DATETIME, // expected_sql_data_type + SQL_CODE_TIME, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check timestamp data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"timestamp"), // expected_type_name + SQL_TYPE_TIMESTAMP, // expected_data_type + 32, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"timestamp"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DATETIME, // expected_sql_data_type + SQL_CODE_TIMESTAMP, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec +} + +TEST_F(TypeInfoOdbcV2MockTest, TestSQLGetTypeInfoAllTypesODBCVer2) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_ALL_TYPES)); + + // Check bit data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"bit"), // expected_type_name + SQL_BIT, // expected_data_type + 1, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + NULL, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"bit"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_BIT, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check tinyint data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"tinyint"), // expected_type_name + SQL_TINYINT, // expected_data_type + 3, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"tinyint"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_TINYINT, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check bigint data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"bigint"), // expected_type_name + SQL_BIGINT, // expected_data_type + 19, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"bigint"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_BIGINT, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check longvarbinary data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"longvarbinary"), // expected_type_name + SQL_LONGVARBINARY, // expected_data_type + 65536, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + NULL, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"longvarbinary"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_LONGVARBINARY, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check varbinary data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"varbinary"), // expected_type_name + SQL_VARBINARY, // expected_data_type + 255, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + NULL, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"varbinary"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_VARBINARY, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check text data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + // Driver returns SQL_WLONGVARCHAR since unicode is enabled + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"text"), // expected_type_name + SQL_WLONGVARCHAR, // expected_data_type + 65536, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::wstring(L"length"), // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + NULL, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"text"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_WLONGVARCHAR, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check longvarchar data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"longvarchar"), // expected_type_name + SQL_WLONGVARCHAR, // expected_data_type + 65536, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::wstring(L"length"), // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + NULL, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"longvarchar"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_WLONGVARCHAR, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check char data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + // Driver returns SQL_WCHAR since unicode is enabled + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"char"), // expected_type_name + SQL_WCHAR, // expected_data_type + 255, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::wstring(L"length"), // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + NULL, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"char"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_WCHAR, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check integer data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"integer"), // expected_type_name + SQL_INTEGER, // expected_data_type + 9, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"integer"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_INTEGER, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check smallint data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"smallint"), // expected_type_name + SQL_SMALLINT, // expected_data_type + 5, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"smallint"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_SMALLINT, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check float data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"float"), // expected_type_name + SQL_FLOAT, // expected_data_type + 7, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"float"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_FLOAT, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check double data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"double"), // expected_type_name + SQL_DOUBLE, // expected_data_type + 15, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"double"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DOUBLE, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check numeric data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + // Mock server treats numeric data type as a double type + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"numeric"), // expected_type_name + SQL_DOUBLE, // expected_data_type + 15, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"numeric"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DOUBLE, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check varchar data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + // Driver returns SQL_WVARCHAR since unicode is enabled + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"varchar"), // expected_type_name + SQL_WVARCHAR, // expected_data_type + 255, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::wstring(L"length"), // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"varchar"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_WVARCHAR, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check date data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"date"), // expected_type_name + SQL_DATE, // expected_data_type + 10, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"date"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DATETIME, // expected_sql_data_type + NULL, // expected_sql_datetime_sub, driver returns NULL for Ver2 + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check time data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"time"), // expected_type_name + SQL_TIME, // expected_data_type + 8, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"time"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DATETIME, // expected_sql_data_type + NULL, // expected_sql_datetime_sub, driver returns NULL for Ver2 + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check timestamp data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"timestamp"), // expected_type_name + SQL_TIMESTAMP, // expected_data_type + 32, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"timestamp"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DATETIME, // expected_sql_data_type + NULL, // expected_sql_datetime_sub, driver returns NULL for Ver2 + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoBit) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_BIT)); + + // Check bit data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"bit"), // expected_type_name + SQL_BIT, // expected_data_type + 1, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + NULL, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"bit"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_BIT, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoTinyInt) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_TINYINT)); + + // Check tinyint data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"tinyint"), // expected_type_name + SQL_TINYINT, // expected_data_type + 3, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"tinyint"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_TINYINT, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoBigInt) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_BIGINT)); + + // Check bigint data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"bigint"), // expected_type_name + SQL_BIGINT, // expected_data_type + 19, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"bigint"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_BIGINT, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoLongVarbinary) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_LONGVARBINARY)); + + // Check longvarbinary data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"longvarbinary"), // expected_type_name + SQL_LONGVARBINARY, // expected_data_type + 65536, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + NULL, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"longvarbinary"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_LONGVARBINARY, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoVarbinary) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_VARBINARY)); + + // Check varbinary data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"varbinary"), // expected_type_name + SQL_VARBINARY, // expected_data_type + 255, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + NULL, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"varbinary"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_VARBINARY, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoLongVarchar) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_WLONGVARCHAR)); + + // Check text data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + // Driver returns SQL_WLONGVARCHAR since unicode is enabled + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"text"), // expected_type_name + SQL_WLONGVARCHAR, // expected_data_type + 65536, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::wstring(L"length"), // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + NULL, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"text"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_WLONGVARCHAR, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check longvarchar data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"longvarchar"), // expected_type_name + SQL_WLONGVARCHAR, // expected_data_type + 65536, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::wstring(L"length"), // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + NULL, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"longvarchar"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_WLONGVARCHAR, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoChar) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_WCHAR)); + + // Check char data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + // Driver returns SQL_WCHAR since unicode is enabled + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"char"), // expected_type_name + SQL_WCHAR, // expected_data_type + 255, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::wstring(L"length"), // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + NULL, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"char"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_WCHAR, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoInteger) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_INTEGER)); + + // Check integer data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"integer"), // expected_type_name + SQL_INTEGER, // expected_data_type + 9, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"integer"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_INTEGER, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoSmallInt) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_SMALLINT)); + + // Check smallint data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"smallint"), // expected_type_name + SQL_SMALLINT, // expected_data_type + 5, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"smallint"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_SMALLINT, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoFloat) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_FLOAT)); + + // Check float data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"float"), // expected_type_name + SQL_FLOAT, // expected_data_type + 7, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"float"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_FLOAT, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoDouble) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_DOUBLE)); + + // Check double data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"double"), // expected_type_name + SQL_DOUBLE, // expected_data_type + 15, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"double"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DOUBLE, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // Check numeric data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + // Mock server treats numeric data type as a double type + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"numeric"), // expected_type_name + SQL_DOUBLE, // expected_data_type + 15, // expected_column_size + std::nullopt, // expected_literal_prefix + std::nullopt, // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"numeric"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DOUBLE, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoVarchar) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_WVARCHAR)); + + // Check varchar data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + // Driver returns SQL_WVARCHAR since unicode is enabled + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"varchar"), // expected_type_name + SQL_WVARCHAR, // expected_data_type + 255, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::wstring(L"length"), // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"varchar"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_WVARCHAR, // expected_sql_data_type + NULL, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoSQLTypeDate) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_TYPE_DATE)); + + // Check date data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"date"), // expected_type_name + SQL_TYPE_DATE, // expected_data_type + 10, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"date"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DATETIME, // expected_sql_data_type + SQL_CODE_DATE, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoSQLDate) { + // Pass ODBC Ver 2 data type + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_DATE)); + + // Check date data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"date"), // expected_type_name + SQL_TYPE_DATE, // expected_data_type + 10, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"date"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DATETIME, // expected_sql_data_type + SQL_CODE_DATE, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoOdbcV2MockTest, TestSQLGetTypeInfoDateODBCVer2) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_DATE)); + + // Check date data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"date"), // expected_type_name + SQL_DATE, // expected_data_type + 10, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"date"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DATETIME, // expected_sql_data_type + NULL, // expected_sql_datetime_sub, driver returns NULL for Ver2 + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoOdbcV2MockTest, TestSQLGetTypeInfoSQLTypeDateODBCVer2) { + // 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); +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoSQLTypeTime) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_TYPE_TIME)); + + // Check time data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"time"), // expected_type_name + SQL_TYPE_TIME, // expected_data_type + 8, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"time"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DATETIME, // expected_sql_data_type + SQL_CODE_TIME, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoSQLTime) { + // Pass ODBC Ver 2 data type + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_TIME)); + + // Check time data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"time"), // expected_type_name + SQL_TYPE_TIME, // expected_data_type + 8, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"time"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DATETIME, // expected_sql_data_type + SQL_CODE_TIME, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoOdbcV2MockTest, TestSQLGetTypeInfoTimeODBCVer2) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_TIME)); + + // Check time data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"time"), // expected_type_name + SQL_TIME, // expected_data_type + 8, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"time"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DATETIME, // expected_sql_data_type + NULL, // expected_sql_datetime_sub, driver returns NULL for Ver2 + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoOdbcV2MockTest, TestSQLGetTypeInfoSQLTypeTimeODBCVer2) { + // 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); +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoSQLTypeTimestamp) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_TYPE_TIMESTAMP)); + + // Check timestamp data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"timestamp"), // expected_type_name + SQL_TYPE_TIMESTAMP, // expected_data_type + 32, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"timestamp"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DATETIME, // expected_sql_data_type + SQL_CODE_TIMESTAMP, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoSQLTimestamp) { + // Pass ODBC Ver 2 data type + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_TIMESTAMP)); + + // Check timestamp data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"timestamp"), // expected_type_name + SQL_TYPE_TIMESTAMP, // expected_data_type + 32, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"timestamp"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DATETIME, // expected_sql_data_type + SQL_CODE_TIMESTAMP, // expected_sql_datetime_sub + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoOdbcV2MockTest, TestSQLGetTypeInfoSQLTimestampODBCVer2) { + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_TIMESTAMP)); + + // Check timestamp data type + ASSERT_EQ(SQL_SUCCESS, SQLFetch(this->stmt)); + + CheckSQLGetTypeInfo(this->stmt, + std::wstring(L"timestamp"), // expected_type_name + SQL_TIMESTAMP, // expected_data_type + 32, // expected_column_size + std::wstring(L"'"), // expected_literal_prefix + std::wstring(L"'"), // expected_literal_suffix + std::nullopt, // expected_create_params + SQL_NULLABLE, // expected_nullable + SQL_FALSE, // expected_case_sensitive + SQL_SEARCHABLE, // expected_searchable + SQL_FALSE, // expected_unsigned_attr + SQL_FALSE, // expected_fixed_prec_scale + NULL, // expected_auto_unique_value + std::wstring(L"timestamp"), // expected_local_type_name + NULL, // expected_min_scale + NULL, // expected_max_scale + SQL_DATETIME, // expected_sql_data_type + NULL, // expected_sql_datetime_sub, driver returns NULL for Ver2 + NULL, // expected_num_prec_radix + NULL); // expected_interval_prec + + // No more data + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +TEST_F(TypeInfoOdbcV2MockTest, TestSQLGetTypeInfoSQLTypeTimestampODBCVer2) { + // 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); +} + +TEST_F(TypeInfoMockTest, TestSQLGetTypeInfoInvalidDataType) { + SQLSMALLINT invalid_data_type = -114; + ASSERT_EQ(SQL_ERROR, SQLGetTypeInfo(this->stmt, invalid_data_type)); + VerifyOdbcErrorState(SQL_HANDLE_STMT, this->stmt, kErrorStateHY004); +} + +TYPED_TEST(TypeInfoTest, TestSQLGetTypeInfoUnsupportedDataType) { + // Assumes mock and remote server don't support GUID data type + + ASSERT_EQ(SQL_SUCCESS, SQLGetTypeInfo(this->stmt, SQL_GUID)); + + // Result set is empty with valid data type that is unsupported by the server + ASSERT_EQ(SQL_NO_DATA, SQLFetch(this->stmt)); +} + +} // namespace arrow::flight::sql::odbc