]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Literal values within a :class:`.DefaultClause`, which is invoked
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 9 Feb 2015 19:58:26 +0000 (14:58 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 9 Feb 2015 19:58:26 +0000 (14:58 -0500)
when using the :paramref:`.Column.server_default` parameter, will
now be rendered using the "inline" compiler, so that they are rendered
as-is, rather than as bound parameters.
fixes #3087

doc/build/changelog/changelog_10.rst
doc/build/changelog/migration_10.rst
lib/sqlalchemy/sql/compiler.py
test/sql/test_defaults.py

index 10d6dc786d9ceecaae3a9c94b91aac0e3a5b0e0f..277fe28f8d5df5a6c6de803aed3710d95a680ce2 100644 (file)
     series as well.  For changes that are specific to 1.0 with an emphasis
     on compatibility concerns, see :doc:`/changelog/migration_10`.
 
+    .. change::
+        :tags: feature, sql
+        :tickets: 3087
+
+        Literal values within a :class:`.DefaultClause`, which is invoked
+        when using the :paramref:`.Column.server_default` parameter, will
+        now be rendered using the "inline" compiler, so that they are rendered
+        as-is, rather than as bound parameters.
+
+        .. seealso::
+
+            :ref:`change_3087`
+
     .. change::
         :tags: feature, oracle
         :pullreq: github:152
 
-        Added support for cx_oracle connections to a specific service 
-        name, as opposed to a tns name, by passing ``?service_name=<name>`` 
+        Added support for cx_oracle connections to a specific service
+        name, as opposed to a tns name, by passing ``?service_name=<name>``
         to the URL.  Pull request courtesy SÅ‚awomir Ehlert.
 
     .. change::
index efb4b26e59cad0cf26cc1771d1aac2ca52eea322..651679dfdc7247a11fa2c0abd28488a67179d2a6 100644 (file)
@@ -669,6 +669,41 @@ Will render::
 The feature can be disabled using
 :paramref:`.Insert.from_select.include_defaults`.
 
+.. _change_3087:
+
+Column server defaults now render literal values
+------------------------------------------------
+
+The "literal binds" compiler flag is switched on when a
+:class:`.DefaultClause`, set up by :paramref:`.Column.server_default`
+is present as a SQL expression to be compiled.  This allows literals
+embedded in SQL to render correctly, such as::
+
+    from sqlalchemy import Table, Column, MetaData, Text
+    from sqlalchemy.schema import CreateTable
+    from sqlalchemy.dialects.postgresql import ARRAY, array
+    from sqlalchemy.dialects import postgresql
+
+    metadata = MetaData()
+
+    tbl = Table("derp", metadata,
+        Column("arr", ARRAY(Text),
+                    server_default=array(["foo", "bar", "baz"])),
+    )
+
+    print(CreateTable(tbl).compile(dialect=postgresql.dialect()))
+
+Now renders::
+
+    CREATE TABLE derp (
+        arr TEXT[] DEFAULT ARRAY['foo', 'bar', 'baz']
+    )
+
+Previously, the literal values ``"foo", "bar", "baz"`` would render as
+bound parameters, which are useless in DDL.
+
+:ticket:`3087`
+
 .. _feature_3184:
 
 UniqueConstraint is now part of the Table reflection process
index da62b14348b739d3b295fecc1bc7c6200671ba4a..f8f4d1dda9172a79e80073c9286e23e21b5c3616 100644 (file)
@@ -2279,7 +2279,8 @@ class DDLCompiler(Compiled):
             if isinstance(column.server_default.arg, util.string_types):
                 return "'%s'" % column.server_default.arg
             else:
-                return self.sql_compiler.process(column.server_default.arg)
+                return self.sql_compiler.process(
+                    column.server_default.arg, literal_binds=True)
         else:
             return None
 
index 48505dd8cbc6d5ce86fcf2f9ef1ca99ae3585b87..ecf3dcc4d24b1c95fffe940f41463169c696b844 100644 (file)
@@ -1,7 +1,8 @@
-from sqlalchemy.testing import eq_, assert_raises_message, assert_raises
+from sqlalchemy.testing import eq_, assert_raises_message, \
+    assert_raises, AssertsCompiledSQL
 import datetime
-from sqlalchemy.schema import CreateSequence, DropSequence
-from sqlalchemy.sql import select, text
+from sqlalchemy.schema import CreateSequence, DropSequence, CreateTable
+from sqlalchemy.sql import select, text, literal_column
 import sqlalchemy as sa
 from sqlalchemy import testing
 from sqlalchemy.testing import engines
@@ -19,6 +20,72 @@ import itertools
 t = f = f2 = ts = currenttime = metadata = default_generator = None
 
 
+class DDLTest(fixtures.TestBase, AssertsCompiledSQL):
+    __dialect__ = 'default'
+
+    def test_string(self):
+        m = MetaData()
+        t = Table('t', m, Column('x', Integer, server_default='5'))
+        self.assert_compile(
+            CreateTable(t),
+            "CREATE TABLE t (x INTEGER DEFAULT '5')"
+        )
+
+    def test_text(self):
+        m = MetaData()
+        t = Table('t', m, Column('x', Integer, server_default=text('5 + 8')))
+        self.assert_compile(
+            CreateTable(t),
+            "CREATE TABLE t (x INTEGER DEFAULT 5 + 8)"
+        )
+
+    def test_text_literal_binds(self):
+        m = MetaData()
+        t = Table(
+            't', m,
+            Column(
+                'x', Integer, server_default=text('q + :x1').bindparams(x1=7)))
+        self.assert_compile(
+            CreateTable(t),
+            "CREATE TABLE t (x INTEGER DEFAULT q + 7)"
+        )
+
+    def test_sqlexpr(self):
+        m = MetaData()
+        t = Table('t', m, Column(
+            'x', Integer,
+            server_default=literal_column('a') + literal_column('b'))
+        )
+        self.assert_compile(
+            CreateTable(t),
+            "CREATE TABLE t (x INTEGER DEFAULT a + b)"
+        )
+
+    def test_literal_binds_plain(self):
+        m = MetaData()
+        t = Table('t', m, Column(
+            'x', Integer,
+            server_default=literal('a') + literal('b'))
+        )
+        self.assert_compile(
+            CreateTable(t),
+            "CREATE TABLE t (x INTEGER DEFAULT 'a' || 'b')"
+        )
+
+    def test_literal_binds_pgarray(self):
+        from sqlalchemy.dialects.postgresql import ARRAY, array
+        m = MetaData()
+        t = Table('t', m, Column(
+            'x', ARRAY(Integer),
+            server_default=array([1, 2, 3]))
+        )
+        self.assert_compile(
+            CreateTable(t),
+            "CREATE TABLE t (x INTEGER[] DEFAULT ARRAY[1, 2, 3])",
+            dialect='postgresql'
+        )
+
+
 class DefaultTest(fixtures.TestBase):
     __backend__ = True