From: Mike Bayer Date: Fri, 26 May 2017 15:24:25 +0000 (-0400) Subject: Add placeholder XML support X-Git-Tag: rel_1_2_0b1~40 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b1369b47217558779a5b8a17ecd945cedd608dc7;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Add placeholder XML support Added a placeholder type :class:`.mssql.XML` to the SQL Server dialect, so that a reflected table which includes this type can be re-rendered as a CREATE TABLE. The type has no special round-trip behavior nor does it currently support additional qualifying arguments. Change-Id: I651fa729bd8e9b31a0b5effe0839aff077d77c46 Fixes: #3973 --- diff --git a/doc/build/changelog/changelog_11.rst b/doc/build/changelog/changelog_11.rst index 66f6bb45ad..cde9b45cce 100644 --- a/doc/build/changelog/changelog_11.rst +++ b/doc/build/changelog/changelog_11.rst @@ -44,6 +44,17 @@ any case, and cx_Oracle 6.x has removed the connection-level "twophase" flag upon which this feature relied. + .. change:: 3973 + :tags: bug, mssql + :tickets: 3973 + :versions: 1.2.0b1 + + Added a placeholder type :class:`.mssql.XML` to the SQL Server + dialect, so that a reflected table which includes this type can + be re-rendered as a CREATE TABLE. The type has no special round-trip + behavior nor does it currently support additional qualifying + arguments. + .. changelog:: :version: 1.1.10 :released: Friday, May 19, 2017 diff --git a/doc/build/dialects/mssql.rst b/doc/build/dialects/mssql.rst index 490ecaccf5..acc9710e52 100644 --- a/doc/build/dialects/mssql.rst +++ b/doc/build/dialects/mssql.rst @@ -26,75 +26,78 @@ construction arguments, are as follows: .. autoclass:: BIT :members: __init__ - + .. autoclass:: CHAR :members: __init__ - + .. autoclass:: DATETIME2 :members: __init__ - + .. autoclass:: DATETIMEOFFSET :members: __init__ - + .. autoclass:: IMAGE :members: __init__ - + .. autoclass:: MONEY :members: __init__ - + .. autoclass:: NCHAR :members: __init__ - + .. autoclass:: NTEXT :members: __init__ - + .. autoclass:: NVARCHAR :members: __init__ - + .. autoclass:: REAL :members: __init__ - + .. autoclass:: SMALLDATETIME :members: __init__ - + .. autoclass:: SMALLMONEY :members: __init__ - + .. autoclass:: SQL_VARIANT :members: __init__ - + .. autoclass:: TEXT :members: __init__ - + .. autoclass:: TIME :members: __init__ - + .. autoclass:: TINYINT :members: __init__ - + .. autoclass:: UNIQUEIDENTIFIER :members: __init__ - + .. autoclass:: VARCHAR :members: __init__ - + + +.. autoclass:: XML + :members: __init__ PyODBC diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py index 0399cbd90d..00c43bba6a 100644 --- a/lib/sqlalchemy/dialects/mssql/base.py +++ b/lib/sqlalchemy/dialects/mssql/base.py @@ -830,6 +830,20 @@ class IMAGE(sqltypes.LargeBinary): __visit_name__ = 'IMAGE' +class XML(sqltypes.Text): + """MSSQL XML type. + + This is a placeholder type for reflection purposes that does not include + any Python-side datatype support. It also does not currently support + additional arguments, such as "CONTENT", "DOCUMENT", + "xml_schema_collection". + + .. versionadded:: 1.1.11 + + """ + __visit_name__ = 'XML' + + class BIT(sqltypes.TypeEngine): __visit_name__ = 'BIT' @@ -898,6 +912,7 @@ ischema_names = { 'bit': BIT, 'real': REAL, 'image': IMAGE, + 'xml': XML, 'timestamp': TIMESTAMP, 'money': MONEY, 'smallmoney': SMALLMONEY, @@ -1014,6 +1029,9 @@ class MSTypeCompiler(compiler.GenericTypeCompiler): def visit_IMAGE(self, type_, **kw): return "IMAGE" + def visit_XML(self, type_, **kw): + return "XML" + def visit_VARBINARY(self, type_, **kw): return self._extend( "VARBINARY", diff --git a/test/dialect/mssql/test_reflection.py b/test/dialect/mssql/test_reflection.py index 5e17709b4e..2f705d8a36 100644 --- a/test/dialect/mssql/test_reflection.py +++ b/test/dialect/mssql/test_reflection.py @@ -11,9 +11,9 @@ from sqlalchemy.engine.reflection import Inspector from sqlalchemy import util from sqlalchemy.dialects.mssql.information_schema import CoerceUnicode, tables from sqlalchemy.dialects.mssql import base +from sqlalchemy.testing import mock - -class ReflectionTest(fixtures.TestBase, ComparesTables): +class ReflectionTest(fixtures.TestBase, ComparesTables, AssertsCompiledSQL): __only_on__ = 'mssql' __backend__ = True @@ -63,6 +63,32 @@ class ReflectionTest(fixtures.TestBase, ComparesTables): self.assert_tables_equal(users, reflected_users) self.assert_tables_equal(addresses, reflected_addresses) + @testing.provide_metadata + def _test_specific_type(self, type_obj, ddl): + metadata = self.metadata + + table = Table( + 'type_test', metadata, + Column('col1', type_obj) + ) + table.create() + + m2 = MetaData() + table2 = Table('type_test', m2, autoload_with=testing.db) + self.assert_compile( + schema.CreateTable(table2), + "CREATE TABLE type_test (col1 %s NULL)" % ddl + ) + + def test_xml_type(self): + self._test_specific_type(mssql.XML, "XML") + + def test_image_type(self): + self._test_specific_type(mssql.IMAGE, "IMAGE") + + def test_money_type(self): + self._test_specific_type(mssql.MONEY, "MONEY") + @testing.provide_metadata def test_identity(self): metadata = self.metadata @@ -86,7 +112,9 @@ class ReflectionTest(fixtures.TestBase, ComparesTables): testing.db.execute(""" create table foo (id integer primary key, data xml) """) - t1 = Table('foo', metadata, autoload=True) + with mock.patch.object( + testing.db.dialect, "ischema_names", {"int": mssql.INTEGER}): + t1 = Table('foo', metadata, autoload=True) assert isinstance(t1.c.id.type, Integer) assert isinstance(t1.c.data.type, types.NullType)