This is an automated email from the ASF dual-hosted git repository.

lidavidm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new 0c694e7833 GH-47722: [C++][FlightRPC] ODBC Data Type Information 
(#48051)
0c694e7833 is described below

commit 0c694e78331687e838c74d0d0aa73af350bdb66a
Author: Alina (Xi) Li <[email protected]>
AuthorDate: Mon Dec 29 17:19:57 2025 -0800

    GH-47722: [C++][FlightRPC] ODBC Data Type Information (#48051)
    
    ### Rationale for this change
    Implement ODBC to return information about data types supported by the data 
source
    
    ### What changes are included in this PR?
    - SQLGetTypeInfo & Tests
    ### Are these changes tested?
    Tested locally on MSVC
    
    ### Are there any user-facing changes?
    N/A
    * GitHub Issue: #47722
    
    Authored-by: Alina (Xi) Li <[email protected]>
    Signed-off-by: David Li <[email protected]>
---
 cpp/src/arrow/flight/sql/odbc/odbc_api.cc          |   56 +-
 .../flight_sql_statement_get_type_info.cc          |    9 +-
 cpp/src/arrow/flight/sql/odbc/odbc_impl/util.cc    |    8 +
 cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt |    1 +
 .../arrow/flight/sql/odbc/tests/type_info_test.cc  | 1672 ++++++++++++++++++++
 5 files changed, 1741 insertions(+), 5 deletions(-)

diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_api.cc 
b/cpp/src/arrow/flight/sql/odbc/odbc_api.cc
index 6ce248a4fa..4eec8dcbf2 100644
--- a/cpp/src/arrow/flight/sql/odbc/odbc_api.cc
+++ b/cpp/src/arrow/flight/sql/odbc/odbc_api.cc
@@ -1388,8 +1388,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<ODBCStatement*>(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 e94378b7e0..3fd1494c0a 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<std::shared_ptr<RecordBatch>> 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<std::shared_ptr<RecordBatch>> 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<std::shared_ptr<RecordBatch>> 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<SqlDataType>(reader.GetSqlDataType()),
-                               metadata_settings_.use_wide_char);
+                               metadata_settings_.use_wide_char));
     data.sql_datetime_sub =
         util::GetSqlDateTimeSubCode(static_cast<SqlDataType>(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 f06f00845a..fa0a35274a 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;
 }
@@ -147,6 +150,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;
   }
@@ -748,10 +754,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 f4e90420a7..5485ef9b4d 100644
--- a/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt
+++ b/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt
@@ -43,6 +43,7 @@ add_arrow_test(flight_sql_odbc_test
                statement_attr_test.cc
                statement_test.cc
                tables_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 0000000000..ce05f8a70b
--- /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 <sql.h>
+#include <sqltypes.h>
+#include <sqlucode.h>
+
+#include <gtest/gtest.h>
+
+namespace arrow::flight::sql::odbc {
+
+using std::optional;
+
+template <typename T>
+class TypeInfoTest : public T {};
+
+class TypeInfoMockTest : public FlightSQLODBCMockTestBase {};
+using TestTypes = ::testing::Types<TypeInfoMockTest, 
FlightSQLODBCRemoteTestBase>;
+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<std::wstring>& expected_literal_prefix,
+    const optional<std::wstring>& expected_literal_suffix,
+    const optional<std::wstring>& 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

Reply via email to