]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed regression in 1.0-released default-processor for multi-VALUES
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 31 Aug 2015 15:30:03 +0000 (11:30 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 31 Aug 2015 15:30:03 +0000 (11:30 -0400)
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

doc/build/changelog/changelog_10.rst
lib/sqlalchemy/sql/crud.py
test/sql/test_defaults.py
test/sql/test_insert.py

index a9a3486c1502da28248b4e081995e8b22819b52c..d12a51350f5341a2852a85e562ab75068e8a05a6 100644 (file)
 .. changelog::
     :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
index 2e39f6b36c1b7413dca3520490b9126f48dccfef..e6f16b698a8f437a7e3433f3214b002d990cae06 100644 (file)
@@ -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 \
index 7f4d5d30a3ca1446c8916b03d5df41e7e4a99329..673085cf77b2934426c81aad6d8b42bf94ab1fa7 100644 (file)
@@ -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')
index 3c533d75fdb92f7d2b388d783f32b416b69beba3..f66f0b391cd8fbdb9cb70e0a20a91e4200e117d4 100644 (file)
@@ -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), "