#32688: The ON CONFLICT sql suffix creates a syntax error on m2m inserts
-----------------------------------------+------------------------
               Reporter:  Malik A. Rumi  |          Owner:  nobody
                   Type:  Uncategorized  |         Status:  new
              Component:  Uncategorized  |        Version:  3.2
               Severity:  Normal         |       Keywords:
           Triage Stage:  Unreviewed     |      Has patch:  0
    Needs documentation:  0              |    Needs tests:  0
Patch needs improvement:  0              |  Easy pickings:  0
                  UI/UX:  0              |
-----------------------------------------+------------------------
 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.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/32688>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/052.ae222a1e00d532562c1e48b11e1bcf84%40djangoproject.com.

Reply via email to