@@ -1295,8 +1295,110 @@ SQLRETURN SQLDescribeCol(SQLHSTMT stmt, SQLUSMALLINT column_number, SQLWCHAR* co
12951295 << " , decimal_digits_ptr: "
12961296 << static_cast <const void *>(decimal_digits_ptr)
12971297 << " , nullable_ptr: " << static_cast <const void *>(nullable_ptr);
1298- // GH-47724 TODO: Implement SQLDescribeCol
1299- return SQL_INVALID_HANDLE;
1298+
1299+ using ODBC::ODBCDescriptor;
1300+ using ODBC::ODBCStatement;
1301+
1302+ return ODBCStatement::ExecuteWithDiagnostics (stmt, SQL_ERROR, [=]() {
1303+ ODBCStatement* statement = reinterpret_cast <ODBCStatement*>(stmt);
1304+ ODBCDescriptor* ird = statement->GetIRD ();
1305+ SQLINTEGER output_length_int;
1306+ SQLSMALLINT sql_type;
1307+
1308+ // Column SQL Type
1309+ ird->GetField (column_number, SQL_DESC_CONCISE_TYPE, &sql_type, sizeof (SQLSMALLINT),
1310+ nullptr );
1311+ if (data_type_ptr) {
1312+ *data_type_ptr = sql_type;
1313+ }
1314+
1315+ // Column Name
1316+ if (column_name || name_length_ptr) {
1317+ ird->GetField (column_number, SQL_DESC_NAME, column_name, buffer_length,
1318+ &output_length_int);
1319+ if (name_length_ptr) {
1320+ // returned length should be in characters
1321+ *name_length_ptr =
1322+ static_cast <SQLSMALLINT>(output_length_int / GetSqlWCharSize ());
1323+ }
1324+ }
1325+
1326+ // Column Size
1327+ if (column_size_ptr) {
1328+ switch (sql_type) {
1329+ // All numeric types
1330+ case SQL_DECIMAL:
1331+ case SQL_NUMERIC:
1332+ case SQL_TINYINT:
1333+ case SQL_SMALLINT:
1334+ case SQL_INTEGER:
1335+ case SQL_BIGINT:
1336+ case SQL_REAL:
1337+ case SQL_FLOAT:
1338+ case SQL_DOUBLE: {
1339+ ird->GetField (column_number, SQL_DESC_PRECISION, column_size_ptr,
1340+ sizeof (SQLULEN), nullptr );
1341+ break ;
1342+ }
1343+
1344+ default : {
1345+ ird->GetField (column_number, SQL_DESC_LENGTH, column_size_ptr, sizeof (SQLULEN),
1346+ nullptr );
1347+ }
1348+ }
1349+ }
1350+
1351+ // Column Decimal Digits
1352+ if (decimal_digits_ptr) {
1353+ switch (sql_type) {
1354+ // All exact numeric types
1355+ case SQL_TINYINT:
1356+ case SQL_SMALLINT:
1357+ case SQL_INTEGER:
1358+ case SQL_BIGINT:
1359+ case SQL_DECIMAL:
1360+ case SQL_NUMERIC: {
1361+ ird->GetField (column_number, SQL_DESC_SCALE, decimal_digits_ptr,
1362+ sizeof (SQLULEN), nullptr );
1363+ break ;
1364+ }
1365+
1366+ // All datetime types (ODBC 2)
1367+ case SQL_DATE:
1368+ case SQL_TIME:
1369+ case SQL_TIMESTAMP:
1370+ // All datetime types (ODBC 3)
1371+ case SQL_TYPE_DATE:
1372+ case SQL_TYPE_TIME:
1373+ case SQL_TYPE_TIMESTAMP:
1374+ // All interval types with a seconds component
1375+ case SQL_INTERVAL_SECOND:
1376+ case SQL_INTERVAL_MINUTE_TO_SECOND:
1377+ case SQL_INTERVAL_HOUR_TO_SECOND:
1378+ case SQL_INTERVAL_DAY_TO_SECOND: {
1379+ ird->GetField (column_number, SQL_DESC_PRECISION, decimal_digits_ptr,
1380+ sizeof (SQLULEN), nullptr );
1381+ break ;
1382+ }
1383+
1384+ default : {
1385+ // All character and binary types
1386+ // SQL_BIT
1387+ // All approximate numeric types
1388+ // All interval types with no seconds component
1389+ *decimal_digits_ptr = static_cast <SQLSMALLINT>(0 );
1390+ }
1391+ }
1392+ }
1393+
1394+ // Column Nullable
1395+ if (nullable_ptr) {
1396+ ird->GetField (column_number, SQL_DESC_NULLABLE, nullable_ptr, sizeof (SQLSMALLINT),
1397+ nullptr );
1398+ }
1399+
1400+ return SQL_SUCCESS;
1401+ });
13001402}
13011403
13021404} // namespace arrow::flight::sql::odbc
0 commit comments