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::
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
-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
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