From: Mike Bayer Date: Tue, 19 Feb 2019 17:13:04 +0000 (-0500) Subject: Add NCHAR to Oracle dialect X-Git-Tag: rel_1_3_0~11^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5fe9da55c72effe8f8425be339375dd904277ef2;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Add NCHAR to Oracle dialect Added support for reflection of the :class:`.NCHAR` datatype to the Oracle dialect, and added :class:`.NCHAR` to the list of types exported by the Oracle dialect. Fixes: #4506 Change-Id: I3a120b9ad714cbd0ebd8064519f43cf57e99d920 --- diff --git a/doc/build/changelog/unreleased_12/4506.rst b/doc/build/changelog/unreleased_12/4506.rst new file mode 100644 index 0000000000..2fa9874903 --- /dev/null +++ b/doc/build/changelog/unreleased_12/4506.rst @@ -0,0 +1,8 @@ +.. change:: + :tags: bug, oracle + :tickets: 4506 + + Added support for reflection of the :class:`.NCHAR` datatype to the Oracle + dialect, and added :class:`.NCHAR` to the list of types exported by the + Oracle dialect. + diff --git a/doc/build/dialects/oracle.rst b/doc/build/dialects/oracle.rst index f8e9f891ae..7bb0d8c23a 100644 --- a/doc/build/dialects/oracle.rst +++ b/doc/build/dialects/oracle.rst @@ -14,10 +14,13 @@ they originate from :mod:`sqlalchemy.types` or from the local dialect:: from sqlalchemy.dialects.oracle import \ BFILE, BLOB, CHAR, CLOB, DATE, \ - DOUBLE_PRECISION, FLOAT, INTERVAL, LONG, NCLOB, \ + DOUBLE_PRECISION, FLOAT, INTERVAL, LONG, NCLOB, NCHAR, \ NUMBER, NVARCHAR, NVARCHAR2, RAW, TIMESTAMP, VARCHAR, \ VARCHAR2 +.. versionadded:: 1.2.19 Added :class:`.NCHAR` to the list of datatypes + exported by the Oracle dialect. + Types which are specific to Oracle, or have Oracle-specific construction arguments, are as follows: diff --git a/lib/sqlalchemy/dialects/oracle/__init__.py b/lib/sqlalchemy/dialects/oracle/__init__.py index 1db7dba4cf..9f1e15be44 100644 --- a/lib/sqlalchemy/dialects/oracle/__init__.py +++ b/lib/sqlalchemy/dialects/oracle/__init__.py @@ -19,6 +19,7 @@ from .base import DOUBLE_PRECISION from .base import FLOAT from .base import INTERVAL from .base import LONG +from .base import NCHAR from .base import NCLOB from .base import NUMBER from .base import NVARCHAR @@ -36,6 +37,7 @@ __all__ = ( "VARCHAR", "NVARCHAR", "CHAR", + "NCHAR", "DATE", "NUMBER", "BLOB", diff --git a/lib/sqlalchemy/dialects/oracle/base.py b/lib/sqlalchemy/dialects/oracle/base.py index 95a6c1d21e..9f0b23e12e 100644 --- a/lib/sqlalchemy/dialects/oracle/base.py +++ b/lib/sqlalchemy/dialects/oracle/base.py @@ -364,6 +364,7 @@ from ...types import CHAR from ...types import CLOB from ...types import FLOAT from ...types import INTEGER +from ...types import NCHAR from ...types import NVARCHAR from ...types import TIMESTAMP from ...types import VARCHAR @@ -523,6 +524,7 @@ ischema_names = { "VARCHAR2": VARCHAR, "NVARCHAR2": NVARCHAR, "CHAR": CHAR, + "NCHAR": NCHAR, "DATE": DATE, "NUMBER": NUMBER, "BLOB": BLOB, @@ -1514,7 +1516,7 @@ class OracleDialect(default.DefaultDialect): elif coltype == "FLOAT": # TODO: support "precision" here as "binary_precision" coltype = FLOAT() - elif coltype in ("VARCHAR2", "NVARCHAR2", "CHAR"): + elif coltype in ("VARCHAR2", "NVARCHAR2", "CHAR", "NCHAR"): coltype = self.ischema_names.get(coltype)(length) elif "WITH TIME ZONE" in coltype: coltype = TIMESTAMP(timezone=True) diff --git a/test/dialect/oracle/test_types.py b/test/dialect/oracle/test_types.py index 5af5459ff8..ae673b1fae 100644 --- a/test/dialect/oracle/test_types.py +++ b/test/dialect/oracle/test_types.py @@ -782,23 +782,37 @@ class TypesTest(fixtures.TestBase): @testing.provide_metadata def test_reflect_nvarchar(self): metadata = self.metadata - Table("tnv", metadata, Column("data", sqltypes.NVARCHAR(255))) + Table( + "tnv", + metadata, + Column("nv_data", sqltypes.NVARCHAR(255)), + Column("c_data", sqltypes.NCHAR(20)), + ) metadata.create_all() m2 = MetaData(testing.db) t2 = Table("tnv", m2, autoload=True) - assert isinstance(t2.c.data.type, sqltypes.NVARCHAR) + assert isinstance(t2.c.nv_data.type, sqltypes.NVARCHAR) + assert isinstance(t2.c.c_data.type, sqltypes.NCHAR) if testing.against("oracle+cx_oracle"): assert isinstance( - t2.c.data.type.dialect_impl(testing.db.dialect), + t2.c.nv_data.type.dialect_impl(testing.db.dialect), + cx_oracle._OracleUnicodeStringNCHAR, + ) + + assert isinstance( + t2.c.c_data.type.dialect_impl(testing.db.dialect), cx_oracle._OracleUnicodeStringNCHAR, ) data = u("m’a réveillé.") - t2.insert().execute(data=data) - res = t2.select().execute().first()["data"] - eq_(res, data) - assert isinstance(res, util.text_type) + with testing.db.connect() as conn: + conn.execute(t2.insert(), dict(nv_data=data, c_data=data)) + nv_data, c_data = conn.execute(t2.select()).first() + eq_(nv_data, data) + eq_(c_data, data + (" " * 7)) # char is space padded + assert isinstance(nv_data, util.text_type) + assert isinstance(c_data, util.text_type) @testing.provide_metadata def test_reflect_unicode_no_nvarchar(self): @@ -830,6 +844,7 @@ class TypesTest(fixtures.TestBase): Column("c1", VARCHAR(50)), Column("c2", NVARCHAR(250)), Column("c3", CHAR(200)), + Column("c4", NCHAR(180)), ) t1.create() m2 = MetaData(testing.db) @@ -837,6 +852,7 @@ class TypesTest(fixtures.TestBase): eq_(t2.c.c1.type.length, 50) eq_(t2.c.c2.type.length, 250) eq_(t2.c.c3.type.length, 200) + eq_(t2.c.c4.type.length, 180) @testing.provide_metadata def test_long_type(self):