]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed issue within the :meth:`.Insert.from_select` construct whereby
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 9 Dec 2015 23:15:25 +0000 (18:15 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 9 Dec 2015 23:15:25 +0000 (18:15 -0500)
the :class:`.Select` construct would have its ``._raw_columns``
collection mutated in-place when compiling the :class:`.Insert`
construct, when the target :class:`.Table` has Python-side defaults.
The :class:`.Select` construct would compile standalone with the
erroneous column present subsequent to compilation of the
:class:`.Insert`, and the the :class:`.Insert` statement itself would
fail on a second compile attempt due to duplicate bound parameters.
fixes #3603

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

index 21a8f3e6fddc255bb5a0f31df2168502f4c130f7..a07f2db213e87f6d782daa40703294604f8d836c 100644 (file)
 .. changelog::
     :version: 1.0.10
 
+    .. change::
+        :tags: bug, sql
+        :tickets: 3603
+        :versions: 1.1.0b1
+
+        Fixed issue within the :meth:`.Insert.from_select` construct whereby
+        the :class:`.Select` construct would have its ``._raw_columns``
+        collection mutated in-place when compiling the :class:`.Insert`
+        construct, when the target :class:`.Table` has Python-side defaults.
+        The :class:`.Select` construct would compile standalone with the
+        erroneous column present subsequent to compilation of the
+        :class:`.Insert`, and the the :class:`.Insert` statement itself would
+        fail on a second compile attempt due to duplicate bound parameters.
+
     .. change::
         :tags: bug, mysql
         :tickets: 3602
index 67a8f09de65f9600560ffa900b23b2821a29b708..18b96018d468fed2d4ae6f208a9b6f1a2aa3bdfd 100644 (file)
@@ -196,8 +196,9 @@ def _scan_insert_from_select_cols(
     if add_select_cols:
         values.extend(add_select_cols)
         compiler._insert_from_select = compiler._insert_from_select._generate()
-        compiler._insert_from_select._raw_columns += tuple(
-            expr for col, expr in add_select_cols)
+        compiler._insert_from_select._raw_columns = \
+            tuple(compiler._insert_from_select._raw_columns) + tuple(
+                expr for col, expr in add_select_cols)
 
 
 def _scan_cols(
index bdaf4f38c6378e7aa01408202f5faa1d7717780a..ea4de032c8359c379cd435b1b4c4cd3ff132e807 100644 (file)
@@ -319,6 +319,32 @@ class InsertTest(_InsertTestBase, fixtures.TablesTest, AssertsCompiledSQL):
             checkparams={"name_1": "foo", "foo": None}
         )
 
+    def test_insert_from_select_dont_mutate_raw_columns(self):
+        # test [ticket:3603]
+        from sqlalchemy import table
+        table_ = table(
+            'mytable',
+            Column('foo', String),
+            Column('bar', String, default='baz'),
+        )
+
+        stmt = select([table_.c.foo])
+        insert = table_.insert().from_select(['foo'], stmt)
+
+        self.assert_compile(stmt, "SELECT mytable.foo FROM mytable")
+        self.assert_compile(
+            insert,
+            "INSERT INTO mytable (foo, bar) "
+            "SELECT mytable.foo, :bar AS anon_1 FROM mytable"
+        )
+        self.assert_compile(stmt, "SELECT mytable.foo FROM mytable")
+        self.assert_compile(
+            insert,
+            "INSERT INTO mytable (foo, bar) "
+            "SELECT mytable.foo, :bar AS anon_1 FROM mytable"
+        )
+
+
     def test_insert_mix_select_values_exception(self):
         table1 = self.tables.mytable
         sel = select([table1.c.myid, table1.c.name]).where(