diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-08-31 11:30:03 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-08-31 11:30:03 -0400 |
commit | c39ff9978dbb77cbea4f1ee08234887d8aa1b165 (patch) | |
tree | f0d21317e0fc58a0eb3dc5c3487cd8d75a0fd7ec | |
parent | 956907a4b15f6dcc492582a7ad03706ff62d96fb (diff) | |
download | sqlalchemy-c39ff9978dbb77cbea4f1ee08234887d8aa1b165.tar.gz |
- Fixed regression in 1.0-released default-processor for multi-VALUES
insert statement, :ticket:`3288`, where the column type for the
default-holding column would not be propagated to the compiled
statement in the case where the default was being used,
leading to bind-level type handlers not being invoked.
fixes #3520
-rw-r--r-- | doc/build/changelog/changelog_10.rst | 11 | ||||
-rw-r--r-- | lib/sqlalchemy/sql/crud.py | 1 | ||||
-rw-r--r-- | test/sql/test_defaults.py | 37 | ||||
-rw-r--r-- | test/sql/test_insert.py | 31 |
4 files changed, 64 insertions, 16 deletions
diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst index a9a3486c1..d12a51350 100644 --- a/doc/build/changelog/changelog_10.rst +++ b/doc/build/changelog/changelog_10.rst @@ -19,6 +19,17 @@ :version: 1.0.9 .. change:: + :tags: bug, sql + :versions: 1.1.0b1 + :tickets: 3520 + + Fixed regression in 1.0-released default-processor for multi-VALUES + insert statement, :ticket:`3288`, where the column type for the + default-holding column would not be propagated to the compiled + statement in the case where the default was being used, + leading to bind-level type handlers not being invoked. + + .. change:: :tags: bug, examples :versions: 1.1.0b1 diff --git a/lib/sqlalchemy/sql/crud.py b/lib/sqlalchemy/sql/crud.py index 2e39f6b36..e6f16b698 100644 --- a/lib/sqlalchemy/sql/crud.py +++ b/lib/sqlalchemy/sql/crud.py @@ -319,6 +319,7 @@ class _multiparam_column(elements.ColumnElement): self.key = "%s_%d" % (original.key, index + 1) self.original = original self.default = original.default + self.type = original.type def __eq__(self, other): return isinstance(other, _multiparam_column) and \ diff --git a/test/sql/test_defaults.py b/test/sql/test_defaults.py index 7f4d5d30a..673085cf7 100644 --- a/test/sql/test_defaults.py +++ b/test/sql/test_defaults.py @@ -123,6 +123,14 @@ class DefaultTest(fixtures.TestBase): def gen_default(cls, ctx): return "hi" + class MyType(TypeDecorator): + impl = String(50) + + def process_bind_param(self, value, dialect): + if value is not None: + value = "BIND" + value + return value + # select "count(1)" returns different results on different DBs also # correct for "current_date" compatible as column default, value # differences @@ -211,7 +219,10 @@ class DefaultTest(fixtures.TestBase): server_default='ddl'), # python method w/ context - Column('col10', String(20), default=MyClass.gen_default) + Column('col10', String(20), default=MyClass.gen_default), + + # fixed default w/ type that has bound processor + Column('col11', MyType(), default='foo') ) t.create() @@ -391,7 +402,7 @@ class DefaultTest(fixtures.TestBase): today = datetime.date.today() eq_(l.fetchall(), [ (x, 'imthedefault', f, ts, ts, ctexec, True, False, - 12, today, 'py', 'hi') + 12, today, 'py', 'hi', 'BINDfoo') for x in range(51, 54)]) t.insert().execute(col9=None) @@ -401,7 +412,7 @@ class DefaultTest(fixtures.TestBase): eq_(t.select(t.c.col1 == 54).execute().fetchall(), [(54, 'imthedefault', f, ts, ts, ctexec, True, False, - 12, today, None, 'hi')]) + 12, today, None, 'hi', 'BINDfoo')]) def test_insertmany(self): t.insert().execute({}, {}, {}) @@ -411,11 +422,11 @@ class DefaultTest(fixtures.TestBase): today = datetime.date.today() eq_(l.fetchall(), [(51, 'imthedefault', f, ts, ts, ctexec, True, False, - 12, today, 'py', 'hi'), + 12, today, 'py', 'hi', 'BINDfoo'), (52, 'imthedefault', f, ts, ts, ctexec, True, False, - 12, today, 'py', 'hi'), + 12, today, 'py', 'hi', 'BINDfoo'), (53, 'imthedefault', f, ts, ts, ctexec, True, False, - 12, today, 'py', 'hi')]) + 12, today, 'py', 'hi', 'BINDfoo')]) @testing.requires.multivalues_inserts def test_insert_multivalues(self): @@ -427,11 +438,11 @@ class DefaultTest(fixtures.TestBase): today = datetime.date.today() eq_(l.fetchall(), [(51, 'imthedefault', f, ts, ts, ctexec, True, False, - 12, today, 'py', 'hi'), + 12, today, 'py', 'hi', 'BINDfoo'), (52, 'imthedefault', f, ts, ts, ctexec, True, False, - 12, today, 'py', 'hi'), + 12, today, 'py', 'hi', 'BINDfoo'), (53, 'imthedefault', f, ts, ts, ctexec, True, False, - 12, today, 'py', 'hi')]) + 12, today, 'py', 'hi', 'BINDfoo')]) def test_no_embed_in_sql(self): """Using a DefaultGenerator, Sequence, DefaultClause @@ -498,11 +509,11 @@ class DefaultTest(fixtures.TestBase): today = datetime.date.today() eq_(l.fetchall(), [(51, 'im the update', f2, ts, ts, ctexec, False, False, - 13, today, 'py', 'hi'), + 13, today, 'py', 'hi', 'BINDfoo'), (52, 'im the update', f2, ts, ts, ctexec, True, False, - 13, today, 'py', 'hi'), + 13, today, 'py', 'hi', 'BINDfoo'), (53, 'im the update', f2, ts, ts, ctexec, True, False, - 13, today, 'py', 'hi')]) + 13, today, 'py', 'hi', 'BINDfoo')]) @testing.fails_on('firebird', 'Data type unknown') def test_update(self): @@ -514,7 +525,7 @@ class DefaultTest(fixtures.TestBase): l = l.first() eq_(l, (pk, 'im the update', f2, None, None, ctexec, True, False, - 13, datetime.date.today(), 'py', 'hi')) + 13, datetime.date.today(), 'py', 'hi', 'BINDfoo')) eq_(11, f2) @testing.fails_on('firebird', 'Data type unknown') diff --git a/test/sql/test_insert.py b/test/sql/test_insert.py index 3c533d75f..f66f0b391 100644 --- a/test/sql/test_insert.py +++ b/test/sql/test_insert.py @@ -5,7 +5,7 @@ from sqlalchemy import Column, Integer, MetaData, String, Table,\ from sqlalchemy.dialects import mysql, postgresql from sqlalchemy.engine import default from sqlalchemy.testing import AssertsCompiledSQL,\ - assert_raises_message, fixtures + assert_raises_message, fixtures, eq_ from sqlalchemy.sql import crud @@ -694,8 +694,21 @@ class MultirowTest(_InsertTestBase, fixtures.TablesTest, AssertsCompiledSQL): 'foo_2': None # evaluated later } + stmt = table.insert().values(values) + + eq_( + dict([ + (k, v.type._type_affinity) + for (k, v) in + stmt.compile(dialect=postgresql.dialect()).binds.items()]), + { + 'foo': Integer, 'data_2': String, 'id_0': Integer, + 'id_2': Integer, 'foo_1': Integer, 'data_1': String, + 'id_1': Integer, 'foo_2': Integer, 'data_0': String} + ) + self.assert_compile( - table.insert().values(values), + stmt, 'INSERT INTO sometable (id, data, foo) VALUES ' '(%(id_0)s, %(data_0)s, %(foo)s), ' '(%(id_1)s, %(data_1)s, %(foo_1)s), ' @@ -728,8 +741,20 @@ class MultirowTest(_InsertTestBase, fixtures.TablesTest, AssertsCompiledSQL): 'foo_2': None, # evaluated later } + stmt = table.insert().values(values) + eq_( + dict([ + (k, v.type._type_affinity) + for (k, v) in + stmt.compile(dialect=postgresql.dialect()).binds.items()]), + { + 'foo': Integer, 'data_2': String, 'id_0': Integer, + 'id_2': Integer, 'foo_1': Integer, 'data_1': String, + 'id_1': Integer, 'foo_2': Integer, 'data_0': String} + ) + self.assert_compile( - table.insert().values(values), + stmt, "INSERT INTO sometable (id, data, foo) VALUES " "(%(id_0)s, %(data_0)s, %(foo)s), " "(%(id_1)s, %(data_1)s, %(foo_1)s), " |