Skip to content

Commit 0b66236

Browse files
fix: output converter lookup by SQL type code, not Python type
_build_converter_map looked up converters using desc[1] (the mapped Python type, e.g. bytes) but add_output_converter registers by SQL type code (e.g. -151). Added _column_sql_types to Cursor so the converter map tries the raw SQL code first, then falls back to Python type, then WVARCHAR. Also fixes the output converter test to register by SQL_SS_UDT (-151) instead of bytes, and adds docstrings to _get_c_type_for_sql_type and _map_data_type documenting the SQL Server-specific types.
1 parent e7a5a3c commit 0b66236

2 files changed

Lines changed: 22 additions & 6 deletions

File tree

mssql_python/cursor.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -953,9 +953,11 @@ def _initialize_description(self, column_metadata: Optional[Any] = None) -> None
953953
"""Initialize the description attribute from column metadata."""
954954
if not column_metadata:
955955
self.description = None
956+
self._column_sql_types = None
956957
return
957958

958959
description = []
960+
sql_types = []
959961
for _, col in enumerate(column_metadata):
960962
# Get column name - lowercase it if the lowercase flag is set
961963
column_name = col["ColumnName"]
@@ -964,6 +966,8 @@ def _initialize_description(self, column_metadata: Optional[Any] = None) -> None
964966
if get_settings().lowercase:
965967
column_name = column_name.lower()
966968

969+
sql_types.append(col["DataType"])
970+
967971
# Add to description tuple (7 elements as per PEP-249)
968972
description.append(
969973
(
@@ -977,6 +981,7 @@ def _initialize_description(self, column_metadata: Optional[Any] = None) -> None
977981
)
978982
)
979983
self.description = description
984+
self._column_sql_types = sql_types
980985

981986
def _build_converter_map(self):
982987
"""
@@ -992,14 +997,24 @@ def _build_converter_map(self):
992997
return None
993998

994999
converter_map = []
1000+
raw_types = getattr(self, "_column_sql_types", None)
9951001

996-
for desc in self.description:
1002+
for i, desc in enumerate(self.description):
9971003
if desc is None:
9981004
converter_map.append(None)
9991005
continue
1000-
sql_type = desc[1]
1001-
converter = self.connection.get_output_converter(sql_type)
1002-
# If no converter found for the SQL type, try the WVARCHAR converter as a fallback
1006+
1007+
converter = None
1008+
1009+
# First try lookup by raw SQL type code (e.g. -151 for SQL_SS_UDT)
1010+
if raw_types and i < len(raw_types):
1011+
converter = self.connection.get_output_converter(raw_types[i])
1012+
1013+
# Fall back to lookup by Python type from description
1014+
if converter is None:
1015+
converter = self.connection.get_output_converter(desc[1])
1016+
1017+
# Last resort: try the WVARCHAR converter as a catch-all fallback
10031018
if converter is None:
10041019
from mssql_python.constants import ConstantsDDBC
10051020

tests/test_017_spatial_types.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,14 +304,15 @@ def geography_converter(value):
304304
return None
305305
return b"CONVERTED:" + value
306306

307-
db_connection.add_output_converter(bytes, geography_converter)
307+
SQL_SS_UDT = -151
308+
db_connection.add_output_converter(SQL_SS_UDT, geography_converter)
308309

309310
try:
310311
row = cursor.execute("SELECT geo_col FROM #geo_converter;").fetchone()
311312
assert isinstance(row[0], bytes)
312313
assert row[0].startswith(b"CONVERTED:")
313314
finally:
314-
db_connection.remove_output_converter(bytes)
315+
db_connection.remove_output_converter(SQL_SS_UDT)
315316

316317

317318
def test_geography_description_metadata(cursor, db_connection):

0 commit comments

Comments
 (0)