Opened 3 years ago

Closed 3 years ago

#32688 closed Bug (needsinfo)

The ON CONFLICT sql suffix creates a syntax error on m2m inserts

Reported by: Malik A. Rumi Owned by: nobody
Component: Database layer (models, ORM) Version: 3.2
Severity: Normal Keywords:
Cc: Patrick K Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

When I made the leap from 1.11.5 to 3.1.1, I ran into this issue: Whenever I tried to insert on an m2m related model / field, I got this error:

ProgrammingError('syntax error at or near "ON"\nLINE 1: ...ry_tags" ("entry_id", "tag_id") VALUES (3353, 31) ON CONFLIC...\n 

I have never seen this error before, and the fact that it is excessively truncated [ one might even say, 'butchered' ], didn't help. The problem was that Django was adding this 'sql suffix' - "ON CONFLICT, DO NOTHING", to the end of my insert statement, and then Django turned around and treated it as a syntax error on my inserts. But there was no conflict! So the solution was obvious: stop Django from adding this unnecessary and irrelevant suffix.

A lot of digging led me to two files:
/home/malikarumi/.virtualenvs/legacy_insert/lib/python3.8/site-packages/django/db/backends/base/operations.py
/home/malikarumi/.virtualenvs/legacy_insert/lib/python3.8/site-packages/django/db/backends/postgresql/operations.py

In base/operations, the kwarg ignore_conflicts is set to False, while in postgresql/operations.py, it is set to None. Was this intentional? Because as I will show you in a moment, the code has examples of this variable taking on [True, False, None, and self.query.ignore_conflicts]. Digging further, I looked at /home/malikarumi/.virtualenvs/legacy_insert/lib/python3.8/site-packages/django/db/models/sql/subqueries.py, where ignore_conflicts is initially set to False in class InsertQuery(Query), and
/home/malikarumi/.virtualenvs/legacy_insert/lib/python3.8/site-packages/django/db/models/sql/compiler.py, where it is set to self.query.ignore_conflicts.

I found what I was looking for on lines 1382-3 of compiler.py:

# if ignore_conflicts_suffix_sql:
# result.append(ignore_conflicts_suffix_sql)

and on lines 284-5 of postgresql/operations.py:

# def ignore_conflicts_suffix_sql(self, ignore_conflicts=None):
# return 'ON CONFLICT DO NOTHING' if ignore_conflicts else super().ignore_conflicts_suffix_sql(ignore_conflicts)


After commenting them both out, my inserts proceed as normal. So, maybe I'm the only one with this issue. I don't know. I don't know why insert_conflicts seems to be able to take any arbitrary value. Even if it is a nullable Boolean, True, False, and None are not ==, so if False is passed down to a method expecting it to be None, then the alternate condition is going to be triggered. I don't know why this sql suffix was attached to my insert when there was no conflict, causing a syntax error and preventing me from adding new data.

If you think this is a bug, great. If not, at least I fixed the issue for me. Thanks.

Change History (6)

comment:1 by Mariusz Felisiak, 3 years ago

Component: UncategorizedDatabase layer (models, ORM)
Resolution: invalid
Status: newclosed

It looks that you're using unsupported version of PostgreSQL i.e. < 9.5.

comment:2 by Malik A. Rumi, 3 years ago

Yes, I am upgrading tonight. Do you think this is the cause? Can you explain how, or point me to some documents that will do the explaining? Thanks.

comment:3 by Simon Charette, 3 years ago

This is certainly the cause. PostgreSQL < 9.5 simply doesn't support the ON CONFLICT statement.

https://www.postgresql.org/docs/9.5/release-9-5.html#AEN131764

FWIW PostgresSQL 9.5 is EOL and 9.6 will also be in this situation a few weeks from now.

https://www.postgresql.org/support/versioning/

Last edited 3 years ago by Simon Charette (previous) (diff)

comment:4 by Patrick K, 3 years ago

I'm having the same issue with Postgres 11. Just trying to update an M2M field (with both set or add) leads to this error. It doesn't happen with Postgres 10 though.

Last edited 3 years ago by Patrick K (previous) (diff)

comment:5 by Patrick K, 3 years ago

Cc: Patrick K added
Resolution: invalid
Status: closednew
Type: UncategorizedBug

I'm not 100% sure, but I think this needs to be reopened. I can easily reproduce this with the admin interface when trying to save an M2M with Postgres 11. I do understand that Postgres 9.x is not supported anymore, but IMHO this should not happen with Postgres 11.

comment:6 by Mariusz Felisiak, 3 years ago

Resolution: needsinfo
Status: newclosed

I cannot reproduce this issue on PostgreSQL 11. Can you provide an SQL statement which crashes? or a sample project? and confirm your database version.

Note: See TracTickets for help on using tickets.
Back to Top