From: Mike Bayer Date: Fri, 30 Sep 2016 13:23:50 +0000 (-0400) Subject: Escape literal string values passed to server_default X-Git-Tag: rel_1_1_0~15 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=079df65dc0f71ea4d1771b6ae17e13242c766517;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Escape literal string values passed to server_default A string sent as a column default via the :paramref:`.Column.server_default` parameter is now escaped for quotes. This change is backwards compatible with code that may have been working around this previously. Change-Id: I341298a76cc67bc0a53df4ab51ab9379f2294cdd Fixes: #3809 --- diff --git a/doc/build/changelog/changelog_11.rst b/doc/build/changelog/changelog_11.rst index af22fd6bc8..af21717079 100644 --- a/doc/build/changelog/changelog_11.rst +++ b/doc/build/changelog/changelog_11.rst @@ -21,6 +21,17 @@ .. changelog:: :version: 1.1.0 + .. change:: + :tags: bug, sql + :tickets: 3809 + + A string sent as a column default via the + :paramref:`.Column.server_default` parameter is now escaped for quotes. + + .. seealso:: + + :ref:`change_3809` + .. change:: :tags: bug, postgresql :tickets: 3807 diff --git a/doc/build/changelog/migration_11.rst b/doc/build/changelog/migration_11.rst index c85f1bf1f9..e514f4dbbd 100644 --- a/doc/build/changelog/migration_11.rst +++ b/doc/build/changelog/migration_11.rst @@ -1180,6 +1180,31 @@ statement:: :ticket:`2551` +.. _change_3809: + +String server_default now literal quoted +---------------------------------------- + +A server default passed to :paramref:`.Column.server_default` as a plain +Python string that has quotes embedded is now +passed through the literal quoting system:: + + >>> from sqlalchemy.schema import MetaData, Table, Column, CreateTable + >>> from sqlalchemy.types import String + >>> t = Table('t', MetaData(), Column('x', String(), server_default="hi ' there")) + >>> print CreateTable(t) + + CREATE TABLE t ( + x VARCHAR DEFAULT 'hi '' there' + ) + +Previously the quote would render directly. This change may be backwards +incompatible for applications with such a use case who were working around +the issue. + + +:ticket:`3809` + .. _change_3049: Support for RANGE and ROWS specification within window functions diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index a7954f10a2..a2dbcee5c3 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -2494,7 +2494,8 @@ class DDLCompiler(Compiled): def get_column_default_string(self, column): if isinstance(column.server_default, schema.DefaultClause): if isinstance(column.server_default.arg, util.string_types): - return "'%s'" % column.server_default.arg + return self.sql_compiler.render_literal_value( + column.server_default.arg, sqltypes.STRINGTYPE) else: return self.sql_compiler.process( column.server_default.arg, literal_binds=True) diff --git a/test/sql/test_defaults.py b/test/sql/test_defaults.py index 57af1e536e..1b033fce8f 100644 --- a/test/sql/test_defaults.py +++ b/test/sql/test_defaults.py @@ -24,6 +24,9 @@ class DDLTest(fixtures.TestBase, AssertsCompiledSQL): __dialect__ = 'default' def test_string(self): + # note: that the datatype is an Integer here doesn't matter, + # the server_default is interpreted independently of the + # column's datatype. m = MetaData() t = Table('t', m, Column('x', Integer, server_default='5')) self.assert_compile( @@ -31,6 +34,14 @@ class DDLTest(fixtures.TestBase, AssertsCompiledSQL): "CREATE TABLE t (x INTEGER DEFAULT '5')" ) + def test_string_w_quotes(self): + m = MetaData() + t = Table('t', m, Column('x', Integer, server_default="5'6")) + self.assert_compile( + CreateTable(t), + "CREATE TABLE t (x INTEGER DEFAULT '5''6')" + ) + def test_text(self): m = MetaData() t = Table('t', m, Column('x', Integer, server_default=text('5 + 8'))) @@ -39,6 +50,23 @@ class DDLTest(fixtures.TestBase, AssertsCompiledSQL): "CREATE TABLE t (x INTEGER DEFAULT 5 + 8)" ) + def test_text_w_quotes(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_literal_binds_w_quotes(self): + m = MetaData() + t = Table('t', m, Column('x', Integer, + server_default=literal("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(