@@ -1238,8 +1238,110 @@ SQLRETURN SQLDescribeCol(SQLHSTMT stmt, SQLUSMALLINT column_number, SQLWCHAR* co
12381238 << " , decimal_digits_ptr: "
12391239 << static_cast <const void *>(decimal_digits_ptr)
12401240 << " , nullable_ptr: " << static_cast <const void *>(nullable_ptr);
1241- // GH-47724 TODO: Implement SQLDescribeCol
1242- return SQL_INVALID_HANDLE;
1241+
1242+ using ODBC::ODBCDescriptor;
1243+ using ODBC::ODBCStatement;
1244+
1245+ return ODBCStatement::ExecuteWithDiagnostics (stmt, SQL_ERROR, [=]() {
1246+ ODBCStatement* statement = reinterpret_cast <ODBCStatement*>(stmt);
1247+ ODBCDescriptor* ird = statement->GetIRD ();
1248+ SQLINTEGER output_length_int;
1249+ SQLSMALLINT sql_type;
1250+
1251+ // Column SQL Type
1252+ ird->GetField (column_number, SQL_DESC_CONCISE_TYPE, &sql_type, sizeof (SQLSMALLINT),
1253+ nullptr );
1254+ if (data_type_ptr) {
1255+ *data_type_ptr = sql_type;
1256+ }
1257+
1258+ // Column Name
1259+ if (column_name || name_length_ptr) {
1260+ ird->GetField (column_number, SQL_DESC_NAME, column_name, buffer_length,
1261+ &output_length_int);
1262+ if (name_length_ptr) {
1263+ // returned length should be in characters
1264+ *name_length_ptr =
1265+ static_cast <SQLSMALLINT>(output_length_int / GetSqlWCharSize ());
1266+ }
1267+ }
1268+
1269+ // Column Size
1270+ if (column_size_ptr) {
1271+ switch (sql_type) {
1272+ // All numeric types
1273+ case SQL_DECIMAL:
1274+ case SQL_NUMERIC:
1275+ case SQL_TINYINT:
1276+ case SQL_SMALLINT:
1277+ case SQL_INTEGER:
1278+ case SQL_BIGINT:
1279+ case SQL_REAL:
1280+ case SQL_FLOAT:
1281+ case SQL_DOUBLE: {
1282+ ird->GetField (column_number, SQL_DESC_PRECISION, column_size_ptr,
1283+ sizeof (SQLULEN), nullptr );
1284+ break ;
1285+ }
1286+
1287+ default : {
1288+ ird->GetField (column_number, SQL_DESC_LENGTH, column_size_ptr, sizeof (SQLULEN),
1289+ nullptr );
1290+ }
1291+ }
1292+ }
1293+
1294+ // Column Decimal Digits
1295+ if (decimal_digits_ptr) {
1296+ switch (sql_type) {
1297+ // All exact numeric types
1298+ case SQL_TINYINT:
1299+ case SQL_SMALLINT:
1300+ case SQL_INTEGER:
1301+ case SQL_BIGINT:
1302+ case SQL_DECIMAL:
1303+ case SQL_NUMERIC: {
1304+ ird->GetField (column_number, SQL_DESC_SCALE, decimal_digits_ptr,
1305+ sizeof (SQLULEN), nullptr );
1306+ break ;
1307+ }
1308+
1309+ // All datetime types (ODBC 2)
1310+ case SQL_DATE:
1311+ case SQL_TIME:
1312+ case SQL_TIMESTAMP:
1313+ // All datetime types (ODBC 3)
1314+ case SQL_TYPE_DATE:
1315+ case SQL_TYPE_TIME:
1316+ case SQL_TYPE_TIMESTAMP:
1317+ // All interval types with a seconds component
1318+ case SQL_INTERVAL_SECOND:
1319+ case SQL_INTERVAL_MINUTE_TO_SECOND:
1320+ case SQL_INTERVAL_HOUR_TO_SECOND:
1321+ case SQL_INTERVAL_DAY_TO_SECOND: {
1322+ ird->GetField (column_number, SQL_DESC_PRECISION, decimal_digits_ptr,
1323+ sizeof (SQLULEN), nullptr );
1324+ break ;
1325+ }
1326+
1327+ default : {
1328+ // All character and binary types
1329+ // SQL_BIT
1330+ // All approximate numeric types
1331+ // All interval types with no seconds component
1332+ *decimal_digits_ptr = static_cast <SQLSMALLINT>(0 );
1333+ }
1334+ }
1335+ }
1336+
1337+ // Column Nullable
1338+ if (nullable_ptr) {
1339+ ird->GetField (column_number, SQL_DESC_NULLABLE, nullable_ptr, sizeof (SQLSMALLINT),
1340+ nullptr );
1341+ }
1342+
1343+ return SQL_SUCCESS;
1344+ });
12431345}
12441346
12451347} // namespace arrow::flight::sql::odbc
0 commit comments