summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/build/changelog/changelog_10.rst14
-rw-r--r--lib/sqlalchemy/sql/crud.py5
-rw-r--r--test/sql/test_insert.py26
3 files changed, 43 insertions, 2 deletions
diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst
index 21a8f3e6f..a07f2db21 100644
--- a/doc/build/changelog/changelog_10.rst
+++ b/doc/build/changelog/changelog_10.rst
@@ -19,6 +19,20 @@
: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
:versions: 1.1.0b1
diff --git a/lib/sqlalchemy/sql/crud.py b/lib/sqlalchemy/sql/crud.py
index 67a8f09de..18b96018d 100644
--- a/lib/sqlalchemy/sql/crud.py
+++ b/lib/sqlalchemy/sql/crud.py
@@ -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(
diff --git a/test/sql/test_insert.py b/test/sql/test_insert.py
index bdaf4f38c..ea4de032c 100644
--- a/test/sql/test_insert.py
+++ b/test/sql/test_insert.py
@@ -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(