summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2015-02-09 14:58:26 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2015-02-09 14:58:26 -0500
commit81aa5b376eb80793e3734eb420b82872d2941d6f (patch)
tree4da2b193cdf4197580cf05e7794f1dc723b58ad0
parent53da71fcc2e82c1e6f7b174436043c06257af927 (diff)
downloadsqlalchemy-81aa5b376eb80793e3734eb420b82872d2941d6f.tar.gz
- 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. fixes #3087
-rw-r--r--doc/build/changelog/changelog_10.rst17
-rw-r--r--doc/build/changelog/migration_10.rst35
-rw-r--r--lib/sqlalchemy/sql/compiler.py3
-rw-r--r--test/sql/test_defaults.py73
4 files changed, 122 insertions, 6 deletions
diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst
index 10d6dc786..277fe28f8 100644
--- a/doc/build/changelog/changelog_10.rst
+++ b/doc/build/changelog/changelog_10.rst
@@ -24,11 +24,24 @@
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::
diff --git a/doc/build/changelog/migration_10.rst b/doc/build/changelog/migration_10.rst
index efb4b26e5..651679dfd 100644
--- a/doc/build/changelog/migration_10.rst
+++ b/doc/build/changelog/migration_10.rst
@@ -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
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index da62b1434..f8f4d1dda 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -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
diff --git a/test/sql/test_defaults.py b/test/sql/test_defaults.py
index 48505dd8c..ecf3dcc4d 100644
--- a/test/sql/test_defaults.py
+++ b/test/sql/test_defaults.py
@@ -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