Opened 8 years ago

Closed 8 years ago

#26433 closed Bug (fixed)

Bug: annotating using When(id__in=[], ...) returns empty queryset

Reported by: Kevin Marsh Owned by: nobody
Component: Database layer (models, ORM) Version: 1.9
Severity: Normal Keywords:
Cc: 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

qs = MyModel.objects.all().annotate(
    field=models.Case(
        models.When(id__in=[], then=models.Value(True)),
        default=models.Value(False),
        output_field=models.BooleanField()
    )
)

This results in slightly inconsistent behaviour, qs is an empty queryset (irregardless of how many items are in the original queryset before annotating) and calling qs.count will always return 0. However calling str(qs.query) raises EmptyResultSet which is presumably the correct behaviour?

I've attached a failing test better showcasing this.

Attachments (1)

tests.py (2.2 KB ) - added by Kevin Marsh 8 years ago.
failing tests

Download all attachments as: .zip

Change History (8)

by Kevin Marsh, 8 years ago

Attachment: tests.py added

failing tests

comment:1 by Anssi Kääriäinen, 8 years ago

Triage Stage: UnreviewedAccepted

This is close to the problem mentioned in #26430. Here Case.as_sql() could just catch the EmptyResultSet and instead return sql "1 = 0". But I wonder if we are able to avoid the EmptyResultSet completely by the following approach.

  1. Instead of raising EmptyResultSet we generate sql, params = "1 = %s", (EMPTY_PARAM,).
  2. EMPTY_PARAM is converted to 0 when the SQL is executed.
  3. We check for EMPTY_PARAM in the params inside WhereNode and do necessary conversions for full/empty resultset cases when generating the SQL.
  4. When generating the SQL for a queryset which isn't a subquery of another queryset, we check for existence of EMPTY_PARAM in the params generated for the where clause. If one is found, we know we don't need to execute the queryset at all.
  5. In all other cases we run the query with the empty param. The condition is always going to fail in the generated SQL, but that is exactly what we want for this ticket.

This should also solve #26430 by the "isn't a subquery" condition in rule 3.

Last edited 8 years ago by Anssi Kääriäinen (previous) (diff)

comment:2 by Simon Charette, 8 years ago

Has patch: set

comment:3 by Tim Graham, 8 years ago

Patch needs improvement: set

There's a test failure on PostgreSQL.

comment:4 by Johannes Dollinger, 8 years ago

Patch needs improvement: unset

comment:5 by Tim Graham, 8 years ago

Patch needs improvement: set

comment:6 by Tim Graham, 8 years ago

Patch needs improvement: unset
Triage Stage: AcceptedReady for checkin

comment:7 by Tim Graham <timograham@…>, 8 years ago

Resolution: fixed
Status: newclosed

In 1410616:

Fixed #26433 -- Fixed Case expressions with empty When.

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