From: Mike Bayer Date: Thu, 22 Dec 2022 23:14:31 +0000 (-0500) Subject: expand out Index if passed to "constraint" X-Git-Tag: rel_1_4_46~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=667e2e6d62dcdff8e08eec6dd76c25815dfc03cd;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git expand out Index if passed to "constraint" Fixed bug where the PostgreSQL :paramref:`_postgresql.OnConflictClause.constraint` parameter would accept an :class:`.Index` object, however would not expand this index out into its individual index expressions, instead rendering its name in an ON CONFLICT ON CONSTRAINT clause, which is not accepted by PostgreSQL; the "constraint name" form only accepts unique or exclude constraint names. The parameter continues to accept the index but now expands it out into its component expressions for the render. Fixes: #9023 Change-Id: I6baf243e26bfe578bf3f193c162dd7a623b6ede9 (cherry picked from commit 5cc18bb80077e98418b4a8066c0bc628209f3ada) --- diff --git a/doc/build/changelog/unreleased_14/9023.rst b/doc/build/changelog/unreleased_14/9023.rst new file mode 100644 index 0000000000..d17a0cc983 --- /dev/null +++ b/doc/build/changelog/unreleased_14/9023.rst @@ -0,0 +1,12 @@ +.. change:: + :tags: bug, postgresql + :tickets: 9023 + + Fixed bug where the PostgreSQL + :paramref:`_postgresql.OnConflictClause.constraint` parameter would accept + an :class:`.Index` object, however would not expand this index out into its + individual index expressions, instead rendering its name in an ON CONFLICT + ON CONSTRAINT clause, which is not accepted by PostgreSQL; the "constraint + name" form only accepts unique or exclude constraint names. The parameter + continues to accept the index but now expands it out into its component + expressions for the render. diff --git a/lib/sqlalchemy/dialects/postgresql/dml.py b/lib/sqlalchemy/dialects/postgresql/dml.py index b483774db3..e7b126b3eb 100644 --- a/lib/sqlalchemy/dialects/postgresql/dml.py +++ b/lib/sqlalchemy/dialects/postgresql/dml.py @@ -188,7 +188,7 @@ class OnConflictClause(ClauseElement): if constraint is not None: if not isinstance(constraint, util.string_types) and isinstance( constraint, - (schema.Index, schema.Constraint, ext.ExcludeConstraint), + (schema.Constraint, ext.ExcludeConstraint), ): constraint = getattr(constraint, "name") or constraint diff --git a/test/dialect/postgresql/test_on_conflict.py b/test/dialect/postgresql/test_on_conflict.py index 508f691c51..ab46342f5f 100644 --- a/test/dialect/postgresql/test_on_conflict.py +++ b/test/dialect/postgresql/test_on_conflict.py @@ -675,6 +675,45 @@ class OnConflictTest(fixtures.TablesTest): [(1, "name1", "mail2@gmail.com", "unique_name")], ) + def test_on_conflict_do_update_constraint_can_be_index(self, connection): + """test #9023""" + + users = self.tables.users_xtra + + connection.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( + constraint=self.unique_partial_index, + set_=dict( + name=i.excluded.name, login_email=i.excluded.login_email + ), + ) + + connection.execute( + i, + [ + dict( + name="name1", + login_email="mail2@gmail.com", + lets_index_this="unique_name", + ) + ], + ) + + eq_( + connection.execute(users.select()).fetchall(), + [(1, "name1", "mail2@gmail.com", "unique_name")], + ) + def test_on_conflict_do_update_no_row_actually_affected(self, connection): users = self.tables.users_xtra