]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Add NCHAR to Oracle dialect
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 19 Feb 2019 17:13:04 +0000 (12:13 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 19 Feb 2019 17:13:04 +0000 (12:13 -0500)
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

doc/build/changelog/unreleased_12/4506.rst [new file with mode: 0644]
doc/build/dialects/oracle.rst
lib/sqlalchemy/dialects/oracle/__init__.py
lib/sqlalchemy/dialects/oracle/base.py
test/dialect/oracle/test_types.py

diff --git a/doc/build/changelog/unreleased_12/4506.rst b/doc/build/changelog/unreleased_12/4506.rst
new file mode 100644 (file)
index 0000000..2fa9874
--- /dev/null
@@ -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.
+
index f8e9f891ae543b7dee129ad103b5d32927fe8524..7bb0d8c23a856fcca25b51b6751700352130f7a3 100644 (file)
@@ -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:
 
index 1db7dba4cf975a155a575cca20ca083eb9a51ffc..9f1e15be446b93a16443df290b0e26b876ef6b43 100644 (file)
@@ -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",
index 95a6c1d21effe26efee9ab9aa7cbbf8f245afe92..9f0b23e12e568003de6d2118661d8dfe111a5fdf 100644 (file)
@@ -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)
index 5af5459ff83430105bfea44dbc382ebe836ea4c0..ae673b1faed8d5e607555257fd40d0cdc87c755f 100644 (file)
@@ -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):