@@ -1330,8 +1330,110 @@ SQLRETURN SQLDescribeCol(SQLHSTMT stmt, SQLUSMALLINT column_number, SQLWCHAR* co
13301330 << " , decimal_digits_ptr: "
13311331 << static_cast <const void *>(decimal_digits_ptr)
13321332 << " , nullable_ptr: " << static_cast <const void *>(nullable_ptr);
1333- // GH-47724 TODO: Implement SQLDescribeCol
1334- return SQL_INVALID_HANDLE;
1333+
1334+ using ODBC::ODBCDescriptor;
1335+ using ODBC::ODBCStatement;
1336+
1337+ return ODBCStatement::ExecuteWithDiagnostics (stmt, SQL_ERROR, [=]() {
1338+ ODBCStatement* statement = reinterpret_cast <ODBCStatement*>(stmt);
1339+ ODBCDescriptor* ird = statement->GetIRD ();
1340+ SQLINTEGER output_length_int;
1341+ SQLSMALLINT sql_type;
1342+
1343+ // Column SQL Type
1344+ ird->GetField (column_number, SQL_DESC_CONCISE_TYPE, &sql_type, sizeof (SQLSMALLINT),
1345+ nullptr );
1346+ if (data_type_ptr) {
1347+ *data_type_ptr = sql_type;
1348+ }
1349+
1350+ // Column Name
1351+ if (column_name || name_length_ptr) {
1352+ ird->GetField (column_number, SQL_DESC_NAME, column_name, buffer_length,
1353+ &output_length_int);
1354+ if (name_length_ptr) {
1355+ // returned length should be in characters
1356+ *name_length_ptr =
1357+ static_cast <SQLSMALLINT>(output_length_int / GetSqlWCharSize ());
1358+ }
1359+ }
1360+
1361+ // Column Size
1362+ if (column_size_ptr) {
1363+ switch (sql_type) {
1364+ // All numeric types
1365+ case SQL_DECIMAL:
1366+ case SQL_NUMERIC:
1367+ case SQL_TINYINT:
1368+ case SQL_SMALLINT:
1369+ case SQL_INTEGER:
1370+ case SQL_BIGINT:
1371+ case SQL_REAL:
1372+ case SQL_FLOAT:
1373+ case SQL_DOUBLE: {
1374+ ird->GetField (column_number, SQL_DESC_PRECISION, column_size_ptr,
1375+ sizeof (SQLULEN), nullptr );
1376+ break ;
1377+ }
1378+
1379+ default : {
1380+ ird->GetField (column_number, SQL_DESC_LENGTH, column_size_ptr, sizeof (SQLULEN),
1381+ nullptr );
1382+ }
1383+ }
1384+ }
1385+
1386+ // Column Decimal Digits
1387+ if (decimal_digits_ptr) {
1388+ switch (sql_type) {
1389+ // All exact numeric types
1390+ case SQL_TINYINT:
1391+ case SQL_SMALLINT:
1392+ case SQL_INTEGER:
1393+ case SQL_BIGINT:
1394+ case SQL_DECIMAL:
1395+ case SQL_NUMERIC: {
1396+ ird->GetField (column_number, SQL_DESC_SCALE, decimal_digits_ptr,
1397+ sizeof (SQLULEN), nullptr );
1398+ break ;
1399+ }
1400+
1401+ // All datetime types (ODBC 2)
1402+ case SQL_DATE:
1403+ case SQL_TIME:
1404+ case SQL_TIMESTAMP:
1405+ // All datetime types (ODBC 3)
1406+ case SQL_TYPE_DATE:
1407+ case SQL_TYPE_TIME:
1408+ case SQL_TYPE_TIMESTAMP:
1409+ // All interval types with a seconds component
1410+ case SQL_INTERVAL_SECOND:
1411+ case SQL_INTERVAL_MINUTE_TO_SECOND:
1412+ case SQL_INTERVAL_HOUR_TO_SECOND:
1413+ case SQL_INTERVAL_DAY_TO_SECOND: {
1414+ ird->GetField (column_number, SQL_DESC_PRECISION, decimal_digits_ptr,
1415+ sizeof (SQLULEN), nullptr );
1416+ break ;
1417+ }
1418+
1419+ default : {
1420+ // All character and binary types
1421+ // SQL_BIT
1422+ // All approximate numeric types
1423+ // All interval types with no seconds component
1424+ *decimal_digits_ptr = static_cast <SQLSMALLINT>(0 );
1425+ }
1426+ }
1427+ }
1428+
1429+ // Column Nullable
1430+ if (nullable_ptr) {
1431+ ird->GetField (column_number, SQL_DESC_NULLABLE, nullable_ptr, sizeof (SQLSMALLINT),
1432+ nullptr );
1433+ }
1434+
1435+ return SQL_SUCCESS;
1436+ });
13351437}
13361438
13371439} // namespace arrow::flight::sql::odbc
0 commit comments