]> 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:30 +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

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 645bedf1775e0895050e962a96ab7e4621089cb3..27075191dec2cca52f0a1b0f6d11cbe359ddec4d 100644 (file)
@@ -213,7 +213,7 @@ class OnConflictClause(ClauseElement):
         if constraint is not None:
             if not isinstance(constraint, str) and isinstance(
                 constraint,
-                (schema.Index, schema.Constraint, ext.ExcludeConstraint),
+                (schema.Constraint, ext.ExcludeConstraint),
             ):
                 constraint = getattr(constraint, "name") or constraint
 
index 3cdad78f0ebef428b5d43a28041682c95ac2c838..8ef0f158ef7a2bc4e81dc8d49a2587dc263d95c4 100644 (file)
@@ -682,6 +682,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