len() of an expression with an empty primary key generates invalid SQL #1581
Description
len() raises QuerySyntaxError for any query expression whose primary key is empty and that is not an Aggregation, including dj.U() & table, which the query-algebra spec documents as a single-row result.
Versions: v2.3.4 and master at 68fdea5, MySQL 8.0.
Reproduction
@schema
class File(dj.Manual):
definition = """
file_id : int32
---
filename : varchar(255)
"""
File.insert([(1, "a"), (2, "b")])
len(dj.U().aggr(File, n="count(*)")) # 1
len(dj.U() & File) # QuerySyntaxError
len(dj.U().aggr(File, n="count(*)").make_subquery()) # QuerySyntaxError
len(dj.U().aggr(File, n="count(*)").make_subquery() & "n = 2") # QuerySyntaxErrorExpected: 1 for each, or 0 when the restriction leaves no row. to_dicts() and bool() on the same expressions work.
Cause
QueryExpression.__len__ (expression.py:1163-1174) picks the single-column branch when len(primary_key) <= 1, so an empty primary key produces:
SELECT count(DISTINCT ) FROM ...Aggregation.__len__ is not affected, because it counts SELECT count(1) FROM (<subquery>).
Proposed fix
When the primary key is empty, the expression holds at most one row, so return int(bool(result)), or count over SELECT 1 FROM ... LIMIT 1. Add tests for len(dj.U() & T) on empty and non-empty T, and for len() of a restricted dj.U() aggregate subquery.
Related: #1580 (restricting a dj.U() aggregation).
Activity