--- /dev/null
+.. change::
+ :tags: bug, postgresql
+ :tickets: 6581
+
+ Fixed issue where using the PostgreSQL "INSERT..ON CONFLICT" structure
+ would fail to work with the psycopg2 driver if it were used in an
+ "executemany" context along with bound parameters in the "SET" clause, due
+ to the implicit use of the psycopg2 fast execution helpers which are not
+ appropriate for this style of INSERT statement. Additional checks to
+ exclude this kind of statement from that particular extension have been
+ added.
[value for c, expr, value in crud_params]
)
text += " VALUES (%s)" % insert_single_values_expr
- if toplevel:
+ if toplevel and insert_stmt._post_values_clause is None:
+ # don't assign insert_single_values_expr if _post_values_clause
+ # is present. what this means concretely is that the
+ # "fast insert executemany helper" won't be used, in other
+ # words we won't convert "executemany()" of many parameter
+ # sets into a single INSERT with many elements in VALUES.
+ # We can't apply that optimization safely if for example the
+ # statement includes a clause like "ON CONFLICT DO UPDATE"
self.insert_single_values_expr = insert_single_values_expr
if insert_stmt._post_values_clause is not None:
[(1, "name1")],
)
+ def test_on_conflict_do_update_set_executemany(self, connection):
+ """test #6581"""
+
+ users = self.tables.users
+
+ connection.execute(
+ users.insert(),
+ [dict(id=1, name="name1"), dict(id=2, name="name2")],
+ )
+
+ i = insert(users)
+ i = i.on_conflict_do_update(
+ index_elements=[users.c.id],
+ set_={"id": i.excluded.id, "name": i.excluded.name + ".5"},
+ )
+ connection.execute(
+ i,
+ [
+ dict(id=1, name="name1"),
+ dict(id=2, name="name2"),
+ dict(id=3, name="name3"),
+ ],
+ )
+
+ eq_(
+ connection.execute(users.select().order_by(users.c.id)).fetchall(),
+ [(1, "name1.5"), (2, "name2.5"), (3, "name3")],
+ )
+
def test_on_conflict_do_update_schema(self, connection):
users = self.tables.get("%s.users_schema" % config.test_schema)