From: Mike Bayer Date: Tue, 8 Nov 2016 02:41:11 +0000 (-0500) Subject: Put include_table=True for DO UPDATE..WHERE, but not ON CONFLICT X-Git-Tag: rel_1_1_4~15 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=942c2429c033255979b6a55de836b9b26370673e;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Put include_table=True for DO UPDATE..WHERE, but not ON CONFLICT Fixed regression caused by the fix in :ticket:`3807` (version 1.1.0) where we ensured that the tablename was qualified in the WHERE clause of the DO UPDATE portion of PostgreSQL's ON CONFLICT, however you *cannot* put the table name in the WHERE clause in the actual ON CONFLICT itself. This was an incorrect assumption, so that portion of the change in :ticket:`3807` is rolled back. Change-Id: I442d8629496a8e405b54711cfcf487761810ae8a Fixes: #3846 Fixes: #3807 --- diff --git a/doc/build/changelog/changelog_11.rst b/doc/build/changelog/changelog_11.rst index afa4389a88..d8f785556a 100644 --- a/doc/build/changelog/changelog_11.rst +++ b/doc/build/changelog/changelog_11.rst @@ -21,6 +21,17 @@ .. changelog:: :version: 1.1.4 + .. change:: + :tags: bug, postgresql + :tickets: 3846, 3807 + + Fixed regression caused by the fix in :ticket:`3807` (version 1.1.0) + where we ensured that the tablename was qualified in the WHERE clause + of the DO UPDATE portion of PostgreSQL's ON CONFLICT, however you + *cannot* put the table name in the WHERE clause in the actual ON + CONFLICT itself. This was an incorrect assumption, so that portion + of the change in :ticket:`3807` is rolled back. + .. change:: :tags: bug, orm :tickets: 3845 diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py index 9898e4ba4e..4c82325f56 100644 --- a/lib/sqlalchemy/dialects/postgresql/base.py +++ b/lib/sqlalchemy/dialects/postgresql/base.py @@ -1433,6 +1433,7 @@ class PGCompiler(compiler.SQLCompiler): target_text += ' WHERE %s' % \ self.process( clause.inferred_target_whereclause, + include_table=False, use_schema=False ) else: diff --git a/test/dialect/postgresql/test_compiler.py b/test/dialect/postgresql/test_compiler.py index 52dd699fc6..3e7f584bf7 100644 --- a/test/dialect/postgresql/test_compiler.py +++ b/test/dialect/postgresql/test_compiler.py @@ -1205,7 +1205,7 @@ class InsertOnConflictTest(fixtures.TestBase, AssertsCompiledSQL): self.assert_compile(i, 'INSERT INTO mytable (name) VALUES ' "(%(name)s) ON CONFLICT (name) " - "WHERE mytable.name > %(name_1)s " + "WHERE name > %(name_1)s " 'DO UPDATE SET name = excluded.name') def test_do_update_index_elements_where_target_multivalues(self): @@ -1223,7 +1223,7 @@ class InsertOnConflictTest(fixtures.TestBase, AssertsCompiledSQL): "INSERT INTO mytable (name) " "VALUES (%(name_m0)s), (%(name_m1)s), (%(name_m2)s) " "ON CONFLICT (name) " - "WHERE mytable.name > %(name_1)s " + "WHERE name > %(name_1)s " "DO UPDATE SET name = excluded.name", checkparams={ 'name_1': 'm', 'name_m0': 'foo', @@ -1246,7 +1246,7 @@ class InsertOnConflictTest(fixtures.TestBase, AssertsCompiledSQL): self.assert_compile(i, 'INSERT INTO mytable (name) VALUES ' "(%(name)s) ON CONFLICT (name) " - "WHERE mytable.name > %(name_1)s " + "WHERE name > %(name_1)s " 'DO UPDATE SET name = excluded.name') def test_do_update_unnamed_exclude_constraint_target(self): @@ -1259,7 +1259,7 @@ class InsertOnConflictTest(fixtures.TestBase, AssertsCompiledSQL): self.assert_compile(i, 'INSERT INTO mytable (name) VALUES ' "(%(name)s) ON CONFLICT (name, description) " - "WHERE mytable.description != %(description_1)s " + "WHERE description != %(description_1)s " 'DO UPDATE SET name = excluded.name') def test_do_update_add_whereclause(self): @@ -1275,7 +1275,7 @@ class InsertOnConflictTest(fixtures.TestBase, AssertsCompiledSQL): self.assert_compile(i, 'INSERT INTO mytable (name) VALUES ' "(%(name)s) ON CONFLICT (name, description) " - "WHERE mytable.description != %(description_1)s " + "WHERE description != %(description_1)s " 'DO UPDATE SET name = excluded.name ' "WHERE mytable.name != %(name_1)s " "AND mytable.description != %(description_2)s") @@ -1292,7 +1292,7 @@ class InsertOnConflictTest(fixtures.TestBase, AssertsCompiledSQL): self.assert_compile(i, 'INSERT INTO mytable (name) VALUES ' "(%(name)s) ON CONFLICT (name, description) " - "WHERE mytable.description != %(description_1)s " + "WHERE description != %(description_1)s " 'DO UPDATE SET name = excluded.name ' "WHERE mytable.name != excluded.name") diff --git a/test/dialect/postgresql/test_on_conflict.py b/test/dialect/postgresql/test_on_conflict.py index 154d3fe585..9cfe4432a4 100644 --- a/test/dialect/postgresql/test_on_conflict.py +++ b/test/dialect/postgresql/test_on_conflict.py @@ -28,6 +28,12 @@ class OnConflictTest(fixtures.TablesTest): Column('login_email', String(50)), Column('lets_index_this', String(50)) ) + cls.unique_partial_index = schema.Index( + 'idx_unique_partial_name', + users_xtra.c.name, users_xtra.c.lets_index_this, + unique=True, + postgresql_where=users_xtra.c.lets_index_this == 'unique_name') + cls.unique_constraint = schema.UniqueConstraint( users_xtra.c.login_email, name='uq_login_email') cls.bogus_index = schema.Index( @@ -405,6 +411,44 @@ class OnConflictTest(fixtures.TablesTest): lets_index_this='bogus') ) + def test_on_conflict_do_update_exotic_targets_six(self): + users = self.tables.users_xtra + + with testing.db.connect() as conn: + conn.execute( + insert(users), + dict( + id=1, name='name1', + login_email='mail1@gmail.com', + lets_index_this='unique_name' + ) + ) + + i = insert(users) + i = i.on_conflict_do_update( + index_elements=self.unique_partial_index.columns, + index_where=self.unique_partial_index.dialect_options + ['postgresql']['where'], + set_=dict( + name=i.excluded.name, + login_email=i.excluded.login_email), + ) + + conn.execute( + i, + [ + dict(name='name1', login_email='mail2@gmail.com', + lets_index_this='unique_name'), + ] + ) + + eq_( + conn.execute(users.select()).fetchall(), + [ + (1, 'name1', 'mail2@gmail.com', 'unique_name'), + ] + ) + def test_on_conflict_do_update_no_row_actually_affected(self): users = self.tables.users_xtra