@@ -994,8 +994,110 @@ SQLRETURN SQLDescribeCol(SQLHSTMT stmt, SQLUSMALLINT column_number, SQLWCHAR* co
994994 << " , decimal_digits_ptr: "
995995 << static_cast <const void *>(decimal_digits_ptr)
996996 << " , nullable_ptr: " << static_cast <const void *>(nullable_ptr);
997- // GH-47724 TODO: Implement SQLDescribeCol
998- return SQL_INVALID_HANDLE;
997+
998+ using ODBC::ODBCDescriptor;
999+ using ODBC::ODBCStatement;
1000+
1001+ return ODBCStatement::ExecuteWithDiagnostics (stmt, SQL_ERROR, [=]() {
1002+ ODBCStatement* statement = reinterpret_cast <ODBCStatement*>(stmt);
1003+ ODBCDescriptor* ird = statement->GetIRD ();
1004+ SQLINTEGER output_length_int;
1005+ SQLSMALLINT sql_type;
1006+
1007+ // Column SQL Type
1008+ ird->GetField (column_number, SQL_DESC_CONCISE_TYPE, &sql_type, sizeof (SQLSMALLINT),
1009+ nullptr );
1010+ if (data_type_ptr) {
1011+ *data_type_ptr = sql_type;
1012+ }
1013+
1014+ // Column Name
1015+ if (column_name || name_length_ptr) {
1016+ ird->GetField (column_number, SQL_DESC_NAME, column_name, buffer_length,
1017+ &output_length_int);
1018+ if (name_length_ptr) {
1019+ // returned length should be in characters
1020+ *name_length_ptr =
1021+ static_cast <SQLSMALLINT>(output_length_int / GetSqlWCharSize ());
1022+ }
1023+ }
1024+
1025+ // Column Size
1026+ if (column_size_ptr) {
1027+ switch (sql_type) {
1028+ // All numeric types
1029+ case SQL_DECIMAL:
1030+ case SQL_NUMERIC:
1031+ case SQL_TINYINT:
1032+ case SQL_SMALLINT:
1033+ case SQL_INTEGER:
1034+ case SQL_BIGINT:
1035+ case SQL_REAL:
1036+ case SQL_FLOAT:
1037+ case SQL_DOUBLE: {
1038+ ird->GetField (column_number, SQL_DESC_PRECISION, column_size_ptr,
1039+ sizeof (SQLULEN), nullptr );
1040+ break ;
1041+ }
1042+
1043+ default : {
1044+ ird->GetField (column_number, SQL_DESC_LENGTH, column_size_ptr, sizeof (SQLULEN),
1045+ nullptr );
1046+ }
1047+ }
1048+ }
1049+
1050+ // Column Decimal Digits
1051+ if (decimal_digits_ptr) {
1052+ switch (sql_type) {
1053+ // All exact numeric types
1054+ case SQL_TINYINT:
1055+ case SQL_SMALLINT:
1056+ case SQL_INTEGER:
1057+ case SQL_BIGINT:
1058+ case SQL_DECIMAL:
1059+ case SQL_NUMERIC: {
1060+ ird->GetField (column_number, SQL_DESC_SCALE, decimal_digits_ptr,
1061+ sizeof (SQLULEN), nullptr );
1062+ break ;
1063+ }
1064+
1065+ // All datetime types (ODBC2)
1066+ case SQL_DATE:
1067+ case SQL_TIME:
1068+ case SQL_TIMESTAMP:
1069+ // All datetime types (ODBC3)
1070+ case SQL_TYPE_DATE:
1071+ case SQL_TYPE_TIME:
1072+ case SQL_TYPE_TIMESTAMP:
1073+ // All interval types with a seconds component
1074+ case SQL_INTERVAL_SECOND:
1075+ case SQL_INTERVAL_MINUTE_TO_SECOND:
1076+ case SQL_INTERVAL_HOUR_TO_SECOND:
1077+ case SQL_INTERVAL_DAY_TO_SECOND: {
1078+ ird->GetField (column_number, SQL_DESC_PRECISION, decimal_digits_ptr,
1079+ sizeof (SQLULEN), nullptr );
1080+ break ;
1081+ }
1082+
1083+ default : {
1084+ // All character and binary types
1085+ // SQL_BIT
1086+ // All approximate numeric types
1087+ // All interval types with no seconds component
1088+ *decimal_digits_ptr = static_cast <SQLSMALLINT>(0 );
1089+ }
1090+ }
1091+ }
1092+
1093+ // Column Nullable
1094+ if (nullable_ptr) {
1095+ ird->GetField (column_number, SQL_DESC_NULLABLE, nullable_ptr, sizeof (SQLSMALLINT),
1096+ nullptr );
1097+ }
1098+
1099+ return SQL_SUCCESS;
1100+ });
9991101}
10001102
10011103} // namespace arrow::flight::sql::odbc
0 commit comments