@@ -1367,4 +1367,118 @@ SQLRETURN SQLNativeSql(SQLHDBC connectionHandle, SQLWCHAR* inStatementText,
13671367 });
13681368}
13691369
1370+ SQLRETURN SQLDescribeCol (SQLHSTMT stmt, SQLUSMALLINT columnNumber, SQLWCHAR* columnName,
1371+ SQLSMALLINT bufferLength, SQLSMALLINT* nameLengthPtr,
1372+ SQLSMALLINT* dataTypePtr, SQLULEN* columnSizePtr,
1373+ SQLSMALLINT* decimalDigitsPtr, SQLSMALLINT* nullablePtr) {
1374+ LOG_DEBUG (
1375+ " SQLDescribeColW called with stmt: {}, columnNumber: {}, "
1376+ " columnName: {}, bufferLength: {}, nameLengthPtr: {}, dataTypePtr: {}, "
1377+ " columnSizePtr: {}, decimalDigitsPtr: {}, nullablePtr: {}" ,
1378+ stmt, columnNumber, fmt::ptr (columnName), bufferLength, fmt::ptr (nameLengthPtr),
1379+ fmt::ptr (dataTypePtr), fmt::ptr (columnSizePtr), fmt::ptr (decimalDigitsPtr),
1380+ fmt::ptr (nullablePtr));
1381+ using ODBC::ODBCDescriptor;
1382+ using ODBC::ODBCStatement;
1383+
1384+ return ODBCStatement::ExecuteWithDiagnostics (stmt, SQL_ERROR, [=]() {
1385+ ODBCStatement* statement = reinterpret_cast <ODBCStatement*>(stmt);
1386+ ODBCDescriptor* ird = statement->GetIRD ();
1387+ SQLINTEGER outputLengthInt;
1388+ SQLSMALLINT sqlType;
1389+
1390+ // Column SQL Type
1391+ ird->GetField (columnNumber, SQL_DESC_CONCISE_TYPE, &sqlType, sizeof (SQLSMALLINT),
1392+ nullptr );
1393+ if (dataTypePtr) {
1394+ *dataTypePtr = sqlType;
1395+ }
1396+
1397+ // Column Name
1398+ if (columnName || nameLengthPtr) {
1399+ ird->GetField (columnNumber, SQL_DESC_NAME, columnName, bufferLength,
1400+ &outputLengthInt);
1401+ if (nameLengthPtr) {
1402+ *nameLengthPtr = static_cast <SQLSMALLINT>(outputLengthInt);
1403+ }
1404+ }
1405+
1406+ // Column Size
1407+ if (columnSizePtr) {
1408+ switch (sqlType) {
1409+ // All numeric types
1410+ case SQL_DECIMAL:
1411+ case SQL_NUMERIC:
1412+ case SQL_TINYINT:
1413+ case SQL_SMALLINT:
1414+ case SQL_INTEGER:
1415+ case SQL_BIGINT:
1416+ case SQL_REAL:
1417+ case SQL_FLOAT:
1418+ case SQL_DOUBLE: {
1419+ ird->GetField (columnNumber, SQL_DESC_PRECISION, columnSizePtr, sizeof (SQLULEN),
1420+ nullptr );
1421+ break ;
1422+ }
1423+
1424+ default : {
1425+ ird->GetField (columnNumber, SQL_DESC_LENGTH, columnSizePtr, sizeof (SQLULEN),
1426+ nullptr );
1427+ }
1428+ }
1429+ }
1430+
1431+ // Column Decimal Digits
1432+ if (decimalDigitsPtr) {
1433+ switch (sqlType) {
1434+ // All exact numeric types
1435+ case SQL_TINYINT:
1436+ case SQL_SMALLINT:
1437+ case SQL_INTEGER:
1438+ case SQL_BIGINT:
1439+ case SQL_DECIMAL:
1440+ case SQL_NUMERIC: {
1441+ ird->GetField (columnNumber, SQL_DESC_SCALE, decimalDigitsPtr, sizeof (SQLULEN),
1442+ nullptr );
1443+ break ;
1444+ }
1445+
1446+ // All datetime types (ODBC2)
1447+ case SQL_DATE:
1448+ case SQL_TIME:
1449+ case SQL_TIMESTAMP:
1450+ // All datetime types (ODBC3)
1451+ case SQL_TYPE_DATE:
1452+ case SQL_TYPE_TIME:
1453+ case SQL_TYPE_TIMESTAMP:
1454+ // All interval types with a seconds component
1455+ case SQL_INTERVAL_SECOND:
1456+ case SQL_INTERVAL_MINUTE_TO_SECOND:
1457+ case SQL_INTERVAL_HOUR_TO_SECOND:
1458+ case SQL_INTERVAL_DAY_TO_SECOND: {
1459+ ird->GetField (columnNumber, SQL_DESC_PRECISION, decimalDigitsPtr,
1460+ sizeof (SQLULEN), nullptr );
1461+ break ;
1462+ }
1463+
1464+ default : {
1465+ // All character and binary types
1466+ // SQL_BIT
1467+ // All approximate numeric types
1468+ // All interval types with no seconds component
1469+ *decimalDigitsPtr = static_cast <SQLSMALLINT>(0 );
1470+ }
1471+ }
1472+ }
1473+
1474+ // Column Nullable
1475+ if (nullablePtr) {
1476+ ird->GetField (columnNumber, SQL_DESC_NULLABLE, nullablePtr, sizeof (SQLSMALLINT),
1477+ nullptr );
1478+ }
1479+
1480+ return SQL_SUCCESS;
1481+ });
1482+ }
1483+
13701484} // namespace arrow
0 commit comments