Opened 2 years ago

Closed 2 years ago

#34103 closed Bug (fixed)

Queries with duplicate params incorrectly logged for Oracle

Reported by: Ahmet Kucuk Owned by: David Sanders
Component: Database layer (models, ORM) Version: 3.2
Severity: Normal Keywords: Oracle, ORM, Compiler
Cc: David Sanders Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

When you try to update a value using Coalesce, Oracle compiler decides to filter by 0 rather than passed filter id 1.

TestTable.objects.filter(id=1).update(test_count=Coalesce(F('test_count'), Value(0), output_field=IntegerField()) + 0)

UPDATE "testtable" SET "test_count" = (COALESCE("testtable"."test_count", 0) + 1) WHERE "testtable"."id" = 0

If you pass more fields, it is still evaluated as 0.

TestTable.objects.filter(id=1).update(test_count=Coalesce(F('test_count'), Value(0), output_field=IntegerField()) + 0, test_count2=Coalesce(F('test_count2'), Value(0), output_field=IntegerField()) + 10)

Change History (8)

comment:1 by David Sanders, 2 years ago

Cc: David Sanders added
Component: UncategorizedDatabase layer (models, ORM)
Triage Stage: UnreviewedAccepted

Thanks for reporting that ♥️

I was able to reproduce on latest main.

comment:2 by David Sanders, 2 years ago

It looks like this bug occurs when the expression Value(x) + x is supplied causing it to attempt to filter by x. If the expression uses different values like Value(x) + y then it filters correctly.

Confirmed this does not occur on Postgres or SQLite.

>>> Test.objects.filter(pk=1).update(test=Value(0) + 0)
UPDATE "TICKET_34103_TEST"
   SET "TEST" = (0 + 0)
 WHERE "TICKET_34103_TEST"."ID" = 0

>>> Test.objects.filter(pk=1).update(test=Value(42) + 42)
UPDATE "TICKET_34103_TEST"
   SET "TEST" = (42 + 42)
 WHERE "TICKET_34103_TEST"."ID" = 42

>>> Test.objects.filter(pk=1).update(test=Value(1) + 2)
UPDATE "TICKET_34103_TEST"
   SET "TEST" = (1 + 2)
 WHERE "TICKET_34103_TEST"."ID" = 1

comment:3 by David Sanders, 2 years ago

After looking into the issue further, the problem isn't with the query executed - only the query that's logged:

Rerunning the above with logging enabled via LOGGING we can see the params are correct but the query logged is not:

>>> foo = Test.objects.create(test=10)
(0.001) INSERT INTO "TICKET_34103_TEST" ("TEST") VALUES (10) RETURNING "TICKET_34103_TEST"."ID" INTO <django.db.backends.oracle.utils.InsertVar object at 0x107a7e710>; args=(10, <django.db.backends.oracle.utils.InsertVar object at 0x107a7e710>); alias=default

>>> Test.objects.filter(pk=foo.pk).update(test=Value(42) + 42)
(0.002) UPDATE "TICKET_34103_TEST" SET "TEST" = (42 + 42) WHERE "TICKET_34103_TEST"."ID" = 42; args=(42, 42, 4); alias=default

>>> foo.refresh_from_db()
(log omitted)

>>> foo.test
84

comment:4 by David Sanders, 2 years ago

Summary: Oracle Coalesce Generates Bad SQLOracle update query incorrectly logged

comment:5 by David Sanders, 2 years ago

Has patch: set
Keywords: Coalesce removed
Owner: changed from nobody to David Sanders
Status: newassigned
Summary: Oracle update query incorrectly loggedQueries with duplicate params incorrectly logged for Oracle
Type: UncategorizedBug

comment:6 by David Sanders, 2 years ago

Patch needs improvement: set

comment:7 by Mariusz Felisiak, 2 years ago

Patch needs improvement: unset
Triage Stage: AcceptedReady for checkin

comment:8 by Mariusz Felisiak <felisiak.mariusz@…>, 2 years ago

Resolution: fixed
Status: assignedclosed

In 64b3c41:

Fixed #34103 -- Fixed logging SQL queries with duplicate parameters on Oracle.

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