]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
expand out Index if passed to "constraint"
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 22 Dec 2022 23:14:31 +0000 (18:14 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 22 Dec 2022 23:15:40 +0000 (18:15 -0500)
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)

doc/build/changelog/unreleased_14/9023.rst [new file with mode: 0644]
lib/sqlalchemy/dialects/postgresql/dml.py
test/dialect/postgresql/test_on_conflict.py

diff --git a/doc/build/changelog/unreleased_14/9023.rst b/doc/build/changelog/unreleased_14/9023.rst
new file mode 100644 (file)
index 0000000..d17a0cc
--- /dev/null
@@ -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.
index b483774db3ed304fd69a132f4642725d2680e58b..e7b126b3eb53b561e413e71714d2039404fe8c21 100644 (file)
@@ -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
 
index 508f691c51413308bc5565bca1084a1df9b8bf2f..ab46342f5fc8b16fe83fc83de4f15af0a272b016 100644 (file)
@@ -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