Skip to content

feat: add spatial type support (geography, geometry, hierarchyid)

8bcb847
Select commit
Loading
Failed to load commit list.
Closed

FEAT: Add spatial type support (geography, geometry, hierarchyid) #422

feat: add spatial type support (geography, geometry, hierarchyid)
8bcb847
Select commit
Loading
Failed to load commit list.
Azure Pipelines / MSSQL-Python-PR-Validation failed Feb 7, 2026 in 28m 49s

Build #pr-validation-pipeline had test failures

Details

Tests

  • Failed: 102 (0.41%)
  • Passed: 23,987 (96.78%)
  • Other: 697 (2.81%)
  • Total: 24,786

Annotations

Check failure on line 1967 in Build log

See this annotation in the file changed.

@azure-pipelines azure-pipelines / MSSQL-Python-PR-Validation

Build log #L1967

Bash exited with code '1'.

Check failure on line 1974 in Build log

See this annotation in the file changed.

@azure-pipelines azure-pipelines / MSSQL-Python-PR-Validation

Build log #L1974

Cmd.exe exited with code '1'.

Check failure on line 2015 in Build log

See this annotation in the file changed.

@azure-pipelines azure-pipelines / MSSQL-Python-PR-Validation

Build log #L2015

Bash exited with code '1'.

Check failure on line 1966 in Build log

See this annotation in the file changed.

@azure-pipelines azure-pipelines / MSSQL-Python-PR-Validation

Build log #L1966

Bash exited with code '1'.

Check failure on line 1 in test_geography_output_converter

See this annotation in the file changed.

@azure-pipelines azure-pipelines / MSSQL-Python-PR-Validation

test_geography_output_converter

assert 0 > 0
 +  where 0 = len([])
Raw output
cursor = <mssql_python.cursor.Cursor object at 0x7f906447bed0>
db_connection = <mssql_python.connection.Connection object at 0x7f9060d7d550>

    def test_geography_output_converter(cursor, db_connection):
        """Test output converter registration for geography (SQL_SS_UDT)."""
        try:
            cursor.execute(
                "CREATE TABLE #pytest_geography_converter (id INT PRIMARY KEY IDENTITY(1,1), geo_col GEOGRAPHY NULL);"
            )
            db_connection.commit()
    
            cursor.execute(
                "INSERT INTO #pytest_geography_converter (geo_col) VALUES (geography::STGeomFromText(?, 4326));",
                POINT_WKT,
            )
            db_connection.commit()
    
            converted = []
    
            def geography_converter(value):
                if value is None:
                    return None
                converted.append(True)
                return value
    
            db_connection.add_output_converter(ConstantsDDBC.SQL_SS_UDT.value, geography_converter)
    
            try:
                row = cursor.execute("SELECT geo_col FROM #pytest_geography_converter;").fetchone()
>               assert len(converted) > 0
E               assert 0 > 0
E                +  where 0 = len([])

tests/test_017_spatial_types.py:411: AssertionError

Check failure on line 1 in test_geography_description_metadata

See this annotation in the file changed.

@azure-pipelines azure-pipelines / MSSQL-Python-PR-Validation

test_geography_description_metadata

TypeError: int() argument must be a string, a bytes-like object or a real number, not 'type'
Raw output
cursor = <mssql_python.cursor.Cursor object at 0x7f906447bed0>
db_connection = <mssql_python.connection.Connection object at 0x7f9060d7d550>

    def test_geography_description_metadata(cursor, db_connection):
        """Test cursor.description for geography columns reports SQL_SS_UDT."""
        try:
            cursor.execute(
                "CREATE TABLE #pytest_geography_desc (id INT PRIMARY KEY, geo_col GEOGRAPHY NULL);"
            )
            db_connection.commit()
    
            cursor.execute("SELECT id, geo_col FROM #pytest_geography_desc;")
            desc = cursor.description
    
            assert len(desc) == 2
            assert desc[0][0] == "id"
            assert desc[1][0] == "geo_col"
>           assert int(desc[1][1]) == ConstantsDDBC.SQL_SS_UDT.value
                   ^^^^^^^^^^^^^^^
E           TypeError: int() argument must be a string, a bytes-like object or a real number, not 'type'

tests/test_017_spatial_types.py:435: TypeError

Check failure on line 1 in test_geography_binary_parameter_round_trip

See this annotation in the file changed.

@azure-pipelines azure-pipelines / MSSQL-Python-PR-Validation

test_geography_binary_parameter_round_trip

mssql_python.exceptions.ProgrammingError: Driver Error: Syntax error or access violation; DDBC Error: [Microsoft][SQL Server]A .NET Framework error occurred during execution of user-defined routine or aggregate "geography": 
System.FormatException: 24201: Latitude values must be between -90 and 90 degrees.
System.FormatException: 
   at Microsoft.SqlServer.Types.GeographyValidator.ValidatePoint(Double x, Double y, Nullable`1 z, Nullable`1 m)
   at Microsoft.SqlServer.Types.Validator.BeginFigure(Double x, Double y, Nullable`1 z, Nullable`1 m)
   at Microsoft.SqlServer.Typ#x00䊶翽#x00㈧攒羐ӳ᥺#x0042000#x00䊶#x01#x00풘㺗#x00#x00ऀ•#x00#x00멨¥#x00#x00䊶#x01#x00䊶翽#x00䊶翽#x00#x00#x00#x00#x00#x00#x00#x00#x00䊶翽#x00䊶翽#x00尴攙羐#x00䊶翽#x00䊶翽#x00䊶翽#x01鈀㻄#x00#x00䊶翽#x00#xFFFF#xFFFF#x00#x00䊶翽#x00攙羐#x00䊶翽#x00䬘㷿#x00#x00䊶翽#x00䊶翽#x00풠㺗#x00#x00풐㺗#x00#x00䊶翽#x00䃸¨#x00#x00䊶翽#x00침攘羐#x00䊶翽#x00䬘㷿#x00#x00䊶翽#x00䊶翽#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00翽#x00儠攻羐#x00䊶翽#x00因攗羐#x00䊶翽#x00#x00#x00#x00#x00#xFFFF㺠#x00#x00麀㷧#x00#x00†攥羐#x00풠㺗#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00풠㺗#x00#x00풐㺗#x00#x00#x03攕羐#x00#x00#x00#x00#x00谠㷂#x00#x00䊶翽#x00�攔羐#x00˰㺠#x00#x00谠㷂#x00#x00䊶翽#x00퉂攓羐#x00#x00#x00#x00#x00儠攻羐#x00䊶翽#x00䃸¨#x00#x00ް㺓#x00#x00#x05#x00#x00#x00#x06#x00#x00#x00攔羐#x00䊶翽#x00#x00#x00#x00#x00#x00#x00翽#x00�攓羐#x00䊶翽#x00蝨㸈#x00Ѐ䬘㷿#x00#x00䬘㷿#x00#x00#x00#x00#x00#x00儠攻羐#x00䊶翽#x00壈攗羐#x00˰㺠#x00#x00䊶翽#x00䊶翽#x00帥攓羐#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00�㣓茥椢䊶翽#x00#x00#x00#x00#x00⟀慱羐#x00Ố敒羐#x00#x00#x00#x00#x00#x00#x00羐#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00굀斃羐#x00#x00#x00#x00#x00䊶翽#x00#x01#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00㾀翽#x00#x00#x00#x00#x00#x00#x00#x00#x00䫠㷿#x00#x00雰㺔#x00#x00霈㺔#x00#x00霈㺔#x00#x00˰㺠#x00#x00#x00#x00羐#x00˰㺠#x00#x00#x03#x00羐#x00˸㺠#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00뫨¥#x00#x00#x00#x00#x00#x00䃸¨#x00#x00榰朅羐#x00䊶翽#x00儀敘羐#x00䊶翽#x00䃸¨#x00#x00䊶翽#x00#x00#x00#x00#x00扏T#x00#x00寀昁羐#x00멨¥#x00#x00#x00#x00#x00#x00#x03#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00䃸¨#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x01#x00#x00#x00뫨¥#x00#x00#x03#x00#x00#x00#x00#x00#x00#x00犐斐羐#x00#x00#x00#x00#x00屈T#x00#x00#x08#x000#x00#x00#x00#x00#x00䊶翽#x00楐朅羐#x00䊶翽#x00#x00#x00#x00#x00 #x00#x00#x00퇀教羐#x00ീ敍羐#x00#x10#x00#x00#x00䊶翽#x00䃸¨#x00#x00얀敖羐#x00#x00#x00#x00#x00﬐昐羐#x00犐斐羐#x00掽羐#x00ࠅV#x00#x00ꌐ㸈#x00#x00퇀教羐#x00詐摥羐#x00ť#x00#x00#x00鸀懞羐#x00䃸¨#x00#x00犐斐羐#x00#x00#x00#x00#x00犐斐羐#x00䄵斒羐#x00賀㸈#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00ť#x00#x00#x00ť#x00#x00#x00㴐斒羐#x00䃸¨#x00
Raw output
cursor = <mssql_python.cursor.Cursor object at 0x7f906447bed0>
db_connection = <mssql_python.connection.Connection object at 0x7f9060d7d550>

    def test_geography_binary_parameter_round_trip(cursor, db_connection):
        """Test binary round-trip: fetch as bytes, reinsert via STGeomFromWKB, compare WKT."""
        try:
            cursor.execute(
                "CREATE TABLE #pytest_geography_binary (id INT PRIMARY KEY IDENTITY(1,1), geo_col GEOGRAPHY NULL);"
            )
            db_connection.commit()
    
            cursor.execute(
                "INSERT INTO #pytest_geography_binary (geo_col) VALUES (geography::STGeomFromText(?, 4326));",
                POINT_WKT,
            )
            db_connection.commit()
    
            row = cursor.execute("SELECT geo_col FROM #pytest_geography_binary;").fetchone()
            original_binary = row[0]
            assert isinstance(original_binary, bytes)
    
            # Reinsert the binary via STGeomFromWKB
>           cursor.execute(
                "INSERT INTO #pytest_geography_binary (geo_col) VALUES (geography::STGeomFromWKB(?, 4326));",
                original_binary,
            )

tests/test_017_spatial_types.py:494: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
mssql_python/cursor.py:1349: in execute
    check_error(ddbc_sql_const.SQL_HANDLE_STMT.value, self.hstmt, ret)
mssql_python/helpers.py:38: in check_error
    raise_exception(error_info.sqlState, error_info.ddbcErrorMsg)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

sqlstate = '42000'
ddbc_error = '[Microsoft][ODBC Driver 18 for SQL Server][SQL Server]A .NET Framework error occurred during execution of user-define...犐斐羐\x00\x00\x00\x00\x00犐斐羐\x00䄵斒羐\x00賀㸈\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ť\x00\x00\x00ť\x00\x00\x00㴐斒羐\x00䃸¨\x00'

    def raise_exception(sqlstate: str, ddbc_error: str) -> None:
        """
        Raise a custom exception based on the given SQLSTATE code.
        This function raises a custom exception based on the provided SQLSTATE code.
        If the code is not found in the mapping, a generic DatabaseError is raised.
    
        Args:
            sqlstate (str): The SQLSTATE code to map to a custom exception.
            ddbc_error (str): The DDBC error message.
    
        Raises:
            DatabaseError: If the SQLSTATE code is not found in the mapping.
        """
        exception_class = sqlstate_to_exception(sqlstate, ddbc_error)
        if exception_class:
            logger.error(f"Raising exception: {exception_class}")
>           raise exception_class
E           mssql_python.exceptions.ProgrammingError: Driver Error: Syntax error or access violation; DDBC Error: [Microsoft][SQL Server]A .NET Framework error occurred during execution of user-defined routine or aggregate "geography": 
E           System.FormatException: 24201: Latitude values must be between -90 and 90 degrees.
E           System.FormatException: 
E              at Microsoft.SqlServer.Types.GeographyValidator.ValidatePoint(Double x, Double y, Nullable`1 z, Nullable`1 m)
E              at Microsoft.SqlServer.Types.Validator.BeginFigure(Double x, Double y, Nullable`1 z, Nullable`1 m)
E              at Microsoft.SqlServer.Typ#x00䊶翽#x00㈧攒羐ӳ᥺#x0042000#x00䊶#x01#x00풘㺗#x00#x00ऀ•#x00#x00멨¥#x00#x00䊶#x01#x00䊶翽#x00䊶翽#x00#x00#x00#x00#x00#x00#x00#x00#x00䊶翽#x00䊶翽#x00尴攙羐#x00䊶翽#x00䊶翽#x00䊶翽#x01鈀㻄#x00#x00䊶翽#x00#xFFFF#xFFFF#x00#x00䊶翽#x00攙羐#x00䊶翽#x00䬘㷿#x00#x00䊶翽#x00䊶翽#x00풠㺗#x00#x00풐㺗#x00#x00䊶翽#x00䃸¨#x00#x00䊶翽#x00침攘羐#x00䊶翽#x00䬘㷿#x00#x00䊶翽#x00䊶翽#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00翽#x00儠攻羐#x00䊶翽#x00因攗羐#x00䊶翽#x00#x00#x00#x00#x00#xFFFF㺠#x00#x00麀㷧#x00#x00†攥羐#x00풠㺗#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00#x00풠㺗#x00#x00풐㺗#x00#x00#x03攕羐#x00#x00#x00#x00#x00谠㷂#x00#x00䊶翽#x00�攔羐#x00˰㺠#x00#x00谠㷂#x00#x00䊶翽#x00퉂攓羐#x00#x00#x00#x00#x00儠攻羐#x00䊶翽#x00䃸¨#x00#x00ް㺓#x00#x00#x05#x00#x00#x00#x06

Check failure on line 1 in test_geometry_description_metadata

See this annotation in the file changed.

@azure-pipelines azure-pipelines / MSSQL-Python-PR-Validation

test_geometry_description_metadata

TypeError: int() argument must be a string, a bytes-like object or a real number, not 'type'
Raw output
cursor = <mssql_python.cursor.Cursor object at 0x7f906447bed0>
db_connection = <mssql_python.connection.Connection object at 0x7f9060d7d550>

    def test_geometry_description_metadata(cursor, db_connection):
        """Test cursor.description for geometry columns reports SQL_SS_UDT."""
        try:
            cursor.execute(
                "CREATE TABLE #pytest_geometry_desc (id INT PRIMARY KEY, geom_col GEOMETRY NULL);"
            )
            db_connection.commit()
    
            cursor.execute("SELECT id, geom_col FROM #pytest_geometry_desc;")
            desc = cursor.description
    
            assert len(desc) == 2
            assert desc[0][0] == "id"
            assert desc[1][0] == "geom_col"
>           assert int(desc[1][1]) == ConstantsDDBC.SQL_SS_UDT.value
                   ^^^^^^^^^^^^^^^
E           TypeError: int() argument must be a string, a bytes-like object or a real number, not 'type'

tests/test_017_spatial_types.py:701: TypeError