From 7bacf72aafd418070c64ef4ca352066fb3593666 Mon Sep 17 00:00:00 2001 From: akilude Date: Wed, 6 Mar 2024 14:58:42 +0530 Subject: [PATCH 1/5] Add support for SQL Variant fields sql_variant fields in databases causes the following error "ODBC SQL type -150 is not yet supported. column-index=0 type=-150', 'HY106'" This commit converts these fields into a string and returns --- mssql/base.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mssql/base.py b/mssql/base.py index 033660c2..c2fb7323 100644 --- a/mssql/base.py +++ b/mssql/base.py @@ -81,6 +81,9 @@ def encode_value(v): return '{%s}' % (v.replace('}', '}}'),) return v +def handle_sql_variant_as_string(value): + # SQL variant of type 150 is not supported, convert it to string and return + return value.decode('utf-16le') def handle_datetimeoffset(dto_value): # Decode bytes returned from SQL Server @@ -379,6 +382,10 @@ def get_new_connection(self, conn_params): # Handling values from DATETIMEOFFSET columns # source: https://github.com/mkleehammer/pyodbc/wiki/Using-an-Output-Converter-function conn.add_output_converter(SQL_TIMESTAMP_WITH_TIMEZONE, handle_datetimeoffset) + + # add support for sql_variant fields + conn.add_output_converter(-150, handle_sql_variant_as_string) + conn.timeout = query_timeout if setencoding: for entry in setencoding: From 0e96914d74a0b5f7eb618fbbd4ad563fa69e8e7e Mon Sep 17 00:00:00 2001 From: akilude Date: Wed, 6 Mar 2024 16:46:39 +0530 Subject: [PATCH 2/5] Add SQL_VARIANT const --- mssql/introspection.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mssql/introspection.py b/mssql/introspection.py index 1f217206..e2ec271c 100644 --- a/mssql/introspection.py +++ b/mssql/introspection.py @@ -17,6 +17,7 @@ SQL_BIGAUTOFIELD = -777444 SQL_SMALLAUTOFIELD = -777333 SQL_TIMESTAMP_WITH_TIMEZONE = -155 +SQL_VARIANT = -150 FieldInfo = namedtuple("FieldInfo", BaseFieldInfo._fields + ("comment",)) TableInfo = namedtuple("TableInfo", BaseTableInfo._fields + ("comment",)) From 136210e15291da4c8ac64726bf6f19901a6caa5c Mon Sep 17 00:00:00 2001 From: akilude Date: Wed, 6 Mar 2024 16:47:36 +0530 Subject: [PATCH 3/5] Remove magic number --- mssql/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mssql/base.py b/mssql/base.py index c2fb7323..ab1dd659 100644 --- a/mssql/base.py +++ b/mssql/base.py @@ -37,7 +37,7 @@ from .client import DatabaseClient # noqa from .creation import DatabaseCreation # noqa from .features import DatabaseFeatures # noqa -from .introspection import DatabaseIntrospection, SQL_TIMESTAMP_WITH_TIMEZONE # noqa +from .introspection import DatabaseIntrospection, SQL_TIMESTAMP_WITH_TIMEZONE, SQL_VARIANT # noqa from .operations import DatabaseOperations # noqa from .schema import DatabaseSchemaEditor # noqa @@ -384,7 +384,7 @@ def get_new_connection(self, conn_params): conn.add_output_converter(SQL_TIMESTAMP_WITH_TIMEZONE, handle_datetimeoffset) # add support for sql_variant fields - conn.add_output_converter(-150, handle_sql_variant_as_string) + conn.add_output_converter(SQL_VARIANT, handle_sql_variant_as_string) conn.timeout = query_timeout if setencoding: From c67001cfd7a6cca941f421e61f69ce1a487d7641 Mon Sep 17 00:00:00 2001 From: akilude Date: Fri, 29 Mar 2024 15:49:43 +0530 Subject: [PATCH 4/5] Added testcase --- testapp/tests/test_fields.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/testapp/tests/test_fields.py b/testapp/tests/test_fields.py index 7f708e82..eab7c823 100644 --- a/testapp/tests/test_fields.py +++ b/testapp/tests/test_fields.py @@ -4,6 +4,7 @@ from django.test import TestCase from ..models import UUIDModel, Customer_name, Customer_address +from django.db import connections class TestUUIDField(TestCase): @@ -34,3 +35,15 @@ def test_random_order_by(self): names.append(list(Customer_name.objects.order_by('?'))) self.assertNotEqual(names.count(names[0]), 20) + + +class TestSQLVarient(TestCase): + def test_sql_varient(self): + connection = connections['default'] + with connection.cursor() as cursor: + cursor.execute("CREATE TABLE sqlVarientTest(targetCol sql_variant, colB INT)") + cursor.execute("INSERT INTO sqlVarientTest values (CAST(46279.1 as decimal(8,2)), 1689)") + cursor.execute("SELECT targetCol FROM sqlVarientTest") + + rows = cursor.fetchall() + self.assertEqual(len(rows), 1) From 6ada36a04840ef2a69023643971ab9be7c154b00 Mon Sep 17 00:00:00 2001 From: akilude Date: Sun, 7 Apr 2024 19:40:09 +0530 Subject: [PATCH 5/5] Fix typos --- testapp/tests/test_fields.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/testapp/tests/test_fields.py b/testapp/tests/test_fields.py index eab7c823..84186b31 100644 --- a/testapp/tests/test_fields.py +++ b/testapp/tests/test_fields.py @@ -37,13 +37,13 @@ def test_random_order_by(self): self.assertNotEqual(names.count(names[0]), 20) -class TestSQLVarient(TestCase): - def test_sql_varient(self): +class TestSQLVariant(TestCase): + def test_sql_variant(self): connection = connections['default'] with connection.cursor() as cursor: - cursor.execute("CREATE TABLE sqlVarientTest(targetCol sql_variant, colB INT)") - cursor.execute("INSERT INTO sqlVarientTest values (CAST(46279.1 as decimal(8,2)), 1689)") - cursor.execute("SELECT targetCol FROM sqlVarientTest") + cursor.execute("CREATE TABLE sqlVariantTest(targetCol sql_variant, colB INT)") + cursor.execute("INSERT INTO sqlVariantTest values (CAST(46279.1 as decimal(8,2)), 1689)") + cursor.execute("SELECT targetCol FROM sqlVariantTest") rows = cursor.fetchall() self.assertEqual(len(rows), 1)