]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
PostgreSQL Insert.on_conflict_do_update: respect compile_kwargs
authorLoïc Simon <loic.simon@napta.io>
Wed, 4 Feb 2026 21:42:10 +0000 (22:42 +0100)
committerLoïc Simon <loic.simon@napta.io>
Wed, 4 Feb 2026 21:42:10 +0000 (22:42 +0100)
Fixes: #13110
doc/build/changelog/unreleased_21/13110.rst [new file with mode: 0644]
lib/sqlalchemy/dialects/postgresql/base.py
test/dialect/postgresql/test_compiler.py

diff --git a/doc/build/changelog/unreleased_21/13110.rst b/doc/build/changelog/unreleased_21/13110.rst
new file mode 100644 (file)
index 0000000..c37b8e1
--- /dev/null
@@ -0,0 +1,7 @@
+.. change::
+    :tags: bug, postgresql
+    :tickets: 13110
+
+    Fixed issue where :meth:`_postgresql.Insert.on_conflict_do_update`
+    parameters were not respecting compilation options such as
+    ``literal_binds=True``.  Pull request courtesy Loïc Simon.
index e54fd0a6589f7a0c829707936e79bcabcbd635c3..be50b41d96cb243d13b97a9193383bcca5175be4 100644 (file)
@@ -2370,10 +2370,11 @@ class PGCompiler(compiler.SQLCompiler):
                 for c in clause.inferred_target_elements
             )
             if clause.inferred_target_whereclause is not None:
+                whereclause_kw = dict(kw)
+                whereclause_kw.update(include_table=False, use_schema=False)
                 target_text += " WHERE %s" % self.process(
                     clause.inferred_target_whereclause,
-                    include_table=False,
-                    use_schema=False,
+                    **whereclause_kw,
                 )
         else:
             target_text = ""
@@ -2400,6 +2401,8 @@ class PGCompiler(compiler.SQLCompiler):
 
         insert_statement = self.stack[-1]["selectable"]
         cols = insert_statement.table.c
+        set_kw = dict(kw)
+        set_kw.update(use_schema=False)
         for c in cols:
             col_key = c.key
 
@@ -2416,7 +2419,7 @@ class PGCompiler(compiler.SQLCompiler):
                 and value.type._isnull
             ):
                 value = value._with_binary_element_type(c.type)
-            value_text = self.process(value.self_group(), use_schema=False)
+            value_text = self.process(value.self_group(), **set_kw)
 
             key_text = self.preparer.quote(c.name)
             action_set_ops.append("%s = %s" % (key_text, value_text))
@@ -2439,14 +2442,16 @@ class PGCompiler(compiler.SQLCompiler):
                 )
                 value_text = self.process(
                     coercions.expect(roles.ExpressionElementRole, v),
-                    use_schema=False,
+                    **set_kw,
                 )
                 action_set_ops.append("%s = %s" % (key_text, value_text))
 
         action_text = ", ".join(action_set_ops)
         if clause.update_whereclause is not None:
+            where_kw = dict(kw)
+            where_kw.update(include_table=True, use_schema=False)
             action_text += " WHERE %s" % self.process(
-                clause.update_whereclause, include_table=True, use_schema=False
+                clause.update_whereclause, **where_kw
             )
 
         return "ON CONFLICT %s DO UPDATE SET %s" % (target_text, action_text)
index 45db03404228519ae8135e6dcb62a1351d1449d8..53294241018fa262870e21a2496dd67c4a51adea 100644 (file)
@@ -4103,6 +4103,31 @@ class InsertOnConflictTest(
             },
         )
 
+    def test_on_conflict_literal_binds(self):
+        i = insert(self.table_with_metadata).values(myid=1, name="foo")
+        i = i.on_conflict_do_update(
+            index_elements=["myid"],
+            set_=OrderedDict(
+                [("name", "I'm a name"), ("other_param", literal("this too"))]
+            ),
+            where=self.table_with_metadata.c.name == "foo",
+            index_where=self.goofy_index.dialect_options["postgresql"][
+                "where"
+            ],
+        )
+        with expect_warnings(
+            "Additional column names not matching any column keys"
+        ):
+            self.assert_compile(
+                i,
+                "INSERT INTO mytable (myid, name) VALUES (1, 'foo')"
+                " ON CONFLICT (myid) WHERE name > 'm' DO UPDATE"
+                " SET name = 'I''m a name', other_param = 'this too'"
+                " WHERE mytable.name = 'foo'",
+                {},
+                literal_binds=True,
+            )
+
 
 class DistinctOnTest(
     fixtures.MappedTest,