Opened 7 years ago

Last modified 7 years ago

#27862 closed Bug

Exists() feature generates invalid SQL query on postgres backend — at Version 1

Reported by: Vasily Stepanov Owned by: nobody
Component: Database layer (models, ORM) Version: 1.11
Severity: Release blocker Keywords: Queryset Subquery Exists
Cc: Matthew Schinckel 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 (last modified by Vasily Stepanov)

Exists() feature, implemented in #27149 ticket, not working properly on postgres backend.
This happens only in complex queries, where django has to use table aliases.
Consider the following models:

class Foo(models.Model):
    spam1 = models.ForeignKey('Spam', on_delete=models.CASCADE, related_name='+')
    spam2 = models.ForeignKey('Spam', on_delete=models.CASCADE, related_name='+')


class Bar(models.Model):
    name1 = models.CharField(max_length=200)
    name2 = models.CharField(max_length=200)


class Spam(models.Model):
    name = models.CharField(max_length=200)

And the code:

bars = models.Bar.objects.filter(
        name1=OuterRef('spam1__name'),
        name2=OuterRef('spam2__name'))

qs = models.Foo.objects.annotate(bars=Exists(bars))
qs = qs.filter(bars=True)

This SQL generated using django.db.backends.postgresql backend:

SELECT
    "demo_foo"."id", "demo_foo"."spam1_id",
    "demo_foo"."spam2_id",
    EXISTS(
        SELECT U0."id", U0."name1", U0."name2"
          FROM "demo_bar" U0
         WHERE (U0."name2" = ("demo_spam"."name") AND U0."name1" = ("T3"."name"))) AS "bars"
  FROM "demo_foo"
INNER JOIN "demo_spam" ON ("demo_foo"."spam2_id" = "demo_spam"."id")
INNER JOIN "demo_spam" T3 ON ("demo_foo"."spam1_id" = T3."id")
WHERE EXISTS(
    SELECT U0."id", U0."name1", U0."name2"
      FROM "demo_bar" U0
     WHERE (U0."name2" = ("demo_spam"."name") AND U0."name1" = ("T3"."name"))) = True

which ends up with this error:

django.db.utils.ProgrammingError: missing FROM-clause entry for table "T3"
LINE 1: ...."name1" = ("demo_spam"."name") AND U0."name2" = ("T3"."name...
                                                             ^

This happens because of quotes around T3.

SQL works as expected, if you remove these quotes and execute it manually.

Change History (1)

comment:1 by Vasily Stepanov, 7 years ago

Description: modified (diff)
Note: See TracTickets for help on using tickets.
Back to Top