2828#define SQL_MAX_NUMERIC_LEN 16
2929#define SQL_SS_XML (-152 )
3030#define SQL_SS_VARIANT (-150 )
31- #define SQL_CA_SS_BASE 1200
32- #define SQL_CA_SS_VARIANT_TYPE (SQL_CA_SS_BASE + 15 )
33- #define SQL_CA_SS_VARIANT_SQL_TYPE (SQL_CA_SS_BASE + 16 )
34- #define SQL_CA_SS_VARIANT_SERVER_TYPE (SQL_CA_SS_BASE + 17 )
31+ #define SQL_CA_SS_VARIANT_TYPE (1215 )
3532
3633#define STRINGIFY_FOR_CASE (x ) \
3734 case x: \
@@ -2919,16 +2916,15 @@ SQLSMALLINT MapVariantCTypeToSQLType(SQLLEN variantCType) {
29192916 return SQL_VARCHAR;
29202917 case SQL_C_WCHAR:
29212918 return SQL_WVARCHAR;
2922- // Date/time types - handle both old-style (9, 10, 11) and new-style (91, 92, 93) codes
2923- case 9 : // SQL_C_DATE (old style)
2924- case SQL_C_TYPE_DATE: // 91 (new style)
2919+ case 9 :
2920+ case SQL_C_TYPE_DATE:
29252921 return SQL_TYPE_DATE;
2926- case 10 : // SQL_C_TIME (old style)
2927- case SQL_C_TYPE_TIME: // 92 (new style)
2928- case 16384 : // SQL Server variant TIME type (observed value)
2922+ case 10 :
2923+ case SQL_C_TYPE_TIME:
2924+ case 16384 :
29292925 return SQL_TYPE_TIME;
2930- case 11 : // SQL_C_TIMESTAMP (old style)
2931- case SQL_C_TYPE_TIMESTAMP: // 93 (new style)
2926+ case 11 :
2927+ case SQL_C_TYPE_TIMESTAMP:
29322928 return SQL_TYPE_TIMESTAMP;
29332929 case SQL_C_BINARY:
29342930 return SQL_VARBINARY;
@@ -2941,7 +2937,6 @@ SQLSMALLINT MapVariantCTypeToSQLType(SQLLEN variantCType) {
29412937 case SQL_C_STINYINT:
29422938 return SQL_TINYINT;
29432939 default :
2944- // Unknown type, fallback to WVARCHAR for string conversion
29452940 return SQL_WVARCHAR;
29462941 }
29472942}
@@ -2984,37 +2979,24 @@ SQLRETURN SQLGetData_wrap(SqlHandlePtr StatementHandle, SQLUSMALLINT colCount, p
29842979 continue ;
29852980 }
29862981
2987- printf (" [DEBUG] SQLGetData_wrap: Column %d - dataType=%d, columnSize=%lu\n " , i, dataType,
2988- (unsigned long )columnSize);
2989-
29902982 // Preprocess sql_variant: detect underlying type and handle NULL
2991- // This allows reuse of existing fetch logic instead of duplicating code
29922983 SQLSMALLINT effectiveDataType = dataType;
29932984 if (dataType == SQL_SS_VARIANT) {
2994- // Step 1: Check for NULL using header read
29952985 SQLLEN indicator;
29962986 ret = SQLGetData_ptr (hStmt, i, SQL_C_BINARY, NULL , 0 , &indicator);
29972987 if (indicator == SQL_NULL_DATA) {
29982988 row.append (py::none ());
2999- continue ; // Skip to next column
2989+ continue ;
30002990 }
3001-
3002- // Step 2: Get the variant's underlying C data type
30032991 SQLLEN variantCType = 0 ;
30042992 ret =
30052993 SQLColAttribute_ptr (hStmt, i, SQL_CA_SS_VARIANT_TYPE, NULL , 0 , NULL , &variantCType);
30062994 if (!SQL_SUCCEEDED (ret)) {
30072995 LOG (" SQLGetData: Failed to get sql_variant underlying type for column %d" , i);
30082996 row.append (py::none ());
3009- continue ; // Skip to next column
2997+ continue ;
30102998 }
3011-
3012- printf (" [DEBUG] SQLGetData_wrap: sql_variant column %d has variantCType=%ld\n " , i,
3013- (long )variantCType);
3014-
3015- // Step 3: Map C type to SQL type so existing code can handle it
30162999 effectiveDataType = MapVariantCTypeToSQLType (variantCType);
3017- printf (" [DEBUG] SQLGetData_wrap: Mapped to effectiveDataType=%d\n " , effectiveDataType);
30183000 }
30193001
30203002 switch (effectiveDataType) {
@@ -4129,19 +4111,11 @@ SQLRETURN FetchMany_wrap(SqlHandlePtr StatementHandle, py::list& rows, int fetch
41294111 SQLSMALLINT dataType = colMeta[" DataType" ].cast <SQLSMALLINT>();
41304112 SQLULEN columnSize = colMeta[" ColumnSize" ].cast <SQLULEN>();
41314113
4132- printf (" [DEBUG] FetchMany_wrap: Column %d - dataType=%d, columnSize=%lu\n " , i + 1 , dataType,
4133- (unsigned long )columnSize);
4134-
4135- // Detect LOB columns that need SQLGetData streaming
4136- // sql_variant always uses SQLGetData for native type preservation
4137- if (dataType == SQL_SS_VARIANT) {
4138- lobColumns.push_back (i + 1 ); // 1-based
4139- } else if ((dataType == SQL_WVARCHAR || dataType == SQL_WLONGVARCHAR ||
4140- dataType == SQL_VARCHAR || dataType == SQL_LONGVARCHAR ||
4141- dataType == SQL_VARBINARY || dataType == SQL_LONGVARBINARY ||
4142- dataType == SQL_SS_XML) &&
4143- (columnSize == 0 || columnSize == SQL_NO_TOTAL ||
4144- columnSize > SQL_MAX_LOB_SIZE)) {
4114+ if (dataType == SQL_SS_VARIANT ||
4115+ ((dataType == SQL_WVARCHAR || dataType == SQL_WLONGVARCHAR || dataType == SQL_VARCHAR ||
4116+ dataType == SQL_LONGVARCHAR || dataType == SQL_VARBINARY ||
4117+ dataType == SQL_LONGVARBINARY || dataType == SQL_SS_XML) &&
4118+ (columnSize == 0 || columnSize == SQL_NO_TOTAL || columnSize > SQL_MAX_LOB_SIZE))) {
41454119 lobColumns.push_back (i + 1 ); // 1-based
41464120 }
41474121 }
@@ -4226,8 +4200,6 @@ SQLRETURN FetchAll_wrap(SqlHandlePtr StatementHandle, py::list& rows,
42264200 return ret;
42274201 }
42284202
4229- // Detect LOB columns FIRST (before calculateRowSize)
4230- // This allows sql_variant to skip the binding path entirely
42314203 std::vector<SQLUSMALLINT> lobColumns;
42324204 for (SQLSMALLINT i = 0 ; i < numCols; i++) {
42334205 auto colMeta = columnNames[i].cast <py::dict>();
@@ -4239,14 +4211,11 @@ SQLRETURN FetchAll_wrap(SqlHandlePtr StatementHandle, py::list& rows,
42394211
42404212 // Detect LOB columns that need SQLGetData streaming
42414213 // sql_variant always uses SQLGetData for native type preservation
4242- if (dataType == SQL_SS_VARIANT) {
4243- lobColumns.push_back (i + 1 ); // 1-based
4244- } else if ((dataType == SQL_WVARCHAR || dataType == SQL_WLONGVARCHAR ||
4245- dataType == SQL_VARCHAR || dataType == SQL_LONGVARCHAR ||
4246- dataType == SQL_VARBINARY || dataType == SQL_LONGVARBINARY ||
4247- dataType == SQL_SS_XML) &&
4248- (columnSize == 0 || columnSize == SQL_NO_TOTAL ||
4249- columnSize > SQL_MAX_LOB_SIZE)) {
4214+ if (dataType == SQL_SS_VARIANT ||
4215+ ((dataType == SQL_WVARCHAR || dataType == SQL_WLONGVARCHAR || dataType == SQL_VARCHAR ||
4216+ dataType == SQL_LONGVARCHAR || dataType == SQL_VARBINARY ||
4217+ dataType == SQL_LONGVARBINARY || dataType == SQL_SS_XML) &&
4218+ (columnSize == 0 || columnSize == SQL_NO_TOTAL || columnSize > SQL_MAX_LOB_SIZE))) {
42504219 lobColumns.push_back (i + 1 ); // 1-based
42514220 }
42524221 }
0 commit comments