Skip to content

Conversation

@dlevy-msft-sql
Copy link
Contributor

Work Item / Issue Reference

GitHub Issue: #352


Summary

Add handling for spatial data types and change cursor.describe to return sql type int per dbapi2 spec

Copilot AI review requested due to automatic review settings December 1, 2025 17:19
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes issue #352 by implementing two main improvements: (1) correcting cursor.description to return SQL type codes (integers) instead of Python type objects, ensuring DB-API 2.0 specification compliance, and (2) adding support for SQL Server spatial data types (geography, geometry, hierarchyid) by handling the SQL_SS_UDT type code (-151).

Key changes:

  • Fixed cursor.description[i][1] to return SQL type integer codes (e.g., 4, -9) instead of Python types (int, str) per DB-API 2.0 spec
  • Added SQL_SS_UDT (-151) support for SQL Server User-Defined Types including spatial data types
  • Updated output converter lookup to use SQL type codes consistently throughout the codebase

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
mssql_python/cursor.py Changed cursor.description to return SQL type codes instead of Python types; added _column_metadata storage; updated _build_converter_map to use SQL type codes; added mappings for UDT, XML, DATETIME2, SMALLDATETIME types
mssql_python/constants.py Added SQL_SS_UDT = -151 constant for SQL Server User-Defined Types
mssql_python/pybind/ddbc_bindings.cpp Added C++ constants for SQL_SS_UDT, SQL_DATETIME2, SQL_SMALLDATETIME; implemented UDT handling in SQLGetData_wrap, FetchBatchData, FetchMany_wrap, and FetchAll_wrap for LOB streaming
tests/test_004_cursor.py Added lob_wvarchar_column to test schema; updated test_cursor_description to expect SQL type codes; added comprehensive geography type test suite (14 new tests); separated LOB and non-LOB fetch tests; fixed output converter test for UTF-16LE encoding
tests/test_003_connection.py Simplified converter integration tests to use SQL type constants directly instead of dynamic type detection

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@dlevy-msft-sql dlevy-msft-sql added bug Something isn't working pr-size: medium Moderate update size labels Dec 1, 2025
@github-actions
Copy link

github-actions bot commented Jan 5, 2026

📊 Code Coverage Report

🔥 Diff Coverage

98%


🎯 Overall Coverage

76%


📈 Total Lines Covered: 5493 out of 7169
📁 Project: mssql-python


Diff Coverage

Diff: main...HEAD, staged and unstaged changes

  • mssql_python/init.py (100%)
  • mssql_python/constants.py (100%)
  • mssql_python/cursor.py (97.4%): Missing lines 128
  • mssql_python/pybind/ddbc_bindings.cpp (100%)

Summary

  • Total: 59 lines
  • Missing: 1 line
  • Coverage: 98%

mssql_python/cursor.py

Lines 124-132



📋 Files Needing Attention

📉 Files with overall lowest coverage (click to expand)
mssql_python.pybind.logger_bridge.hpp: 58.8%
mssql_python.pybind.logger_bridge.cpp: 59.2%
mssql_python.row.py: 66.2%
mssql_python.helpers.py: 67.5%
mssql_python.pybind.ddbc_bindings.cpp: 69.6%
mssql_python.pybind.ddbc_bindings.h: 71.7%
mssql_python.pybind.connection.connection.cpp: 73.6%
mssql_python.ddbc_bindings.py: 79.6%
mssql_python.pybind.connection.connection_pool.cpp: 79.6%
mssql_python.connection.py: 84.1%

🔗 Quick Links

⚙️ Build Summary 📋 Coverage Details

View Azure DevOps Build

Browse Full Coverage Report

@dlevy-msft-sql dlevy-msft-sql added pr-size: small Minimal code update pr-size: medium Moderate update size and removed pr-size: medium Moderate update size labels Jan 16, 2026
(
column_name, # name
self._map_data_type(col["DataType"]), # type_code
col["DataType"], # type_code (SQL type integer) - CHANGED THIS LINE
Copy link
Contributor

@sumitmsft sumitmsft Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the DB-API 2.0 spec states that type_code "must be one of the Type Objects defined in section 'Type Objects'," it does not strictly mandate using SQL type codes over Python types. Returning SQL type codes is consistent with pyodbc's behavior and is permitted, but not strictly required. We can move ahead with this change. However, this is a breaking change.

Please provide a brief migration guide or example to help users transition (e.g., how to map SQL type codes to Python types if needed).

We need to also put this as a breaking change in our Changelog.

For example, user code like this will break silently:

# Before: worked
if cursor.description[0][1] == str:
    print("String column")

# After: fails silently (comparing int to type)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I came at it wrong, thinking it was a bug. Updated to make it a non-breaking change.

This PR addresses Issue microsoft#352 by introducing the SQLTypeCode class, which
provides backwards compatibility with pandas/polars while also supporting
DB-API 2.0 style integer type code comparisons.

## SQLTypeCode Class
- New class in cursor.py that wraps SQL type codes
- Compares equal to BOTH Python types (str, int, float, etc.) AND SQL integers
- Enables: desc[0][1] == str AND desc[0][1] == -9 both returning True
- Properties: type_code (int), python_type (type) per DB-API 2.0 spec
- Exported from mssql_python public API

## Spatial Data Type Support (SQL_SS_UDT)
- Added SQL_SS_UDT (-151) handling in ddbc_bindings.cpp
- Fixes fetchall() for geography, geometry, and hierarchyid columns
- Binds as binary data and processes correctly

## Code Review Feedback Addressed
- Removed unused 'import xml' from cursor.py
- Added self._column_metadata = None in Cursor.close()
- Type stubs updated to match implementation

## Tests Added (36 new tests)
- 18 SQLTypeCode unit tests in test_002_types.py
- 8 geometry live database tests in test_004_cursor.py
- 8 hierarchyid live database tests in test_004_cursor.py
- 2 updated cursor.description compatibility tests

## Documentation
- Updated CHANGELOG.md with usage examples
- Updated type stubs (mssql_python.pyi)
- Wiki update docs prepared in docs/wiki-updates/

Fixes microsoft#352
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 17 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Remove unused 're' import from test_004_cursor.py
- Change bare 'except:' to 'except Exception:' with explanatory comment
- Expand destructor docstring with detailed error handling documentation
- Clarify UTF-16LE encoding comment for output converter test
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 17 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 17 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@dlevy-msft-sql dlevy-msft-sql linked an issue Jan 19, 2026 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working pr-size: medium Moderate update size pr-size: small Minimal code update

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cursor.description returning incorrect values

2 participants