#37316: Functions need a way to mark themselves as volatile
-------------------------------------+-------------------------------------
Reporter: Jacob Walls | Type: New
| feature
Status: new | Component: Database
| layer (models, ORM)
Version: dev | 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
-------------------------------------+-------------------------------------
In the ORM, expressions are hashed based on their type and arguments.
Because random functions like `UUID7()` aren't marked as volatile,
repeated expressions can hash to the same thing, leading to inappropriate
deduplication later when compiling `ORDER BY` and `GROUP BY`:
For example, these group by expressions get deduplicated:
{{{#!py
from django.contrib.auth.models import User
from django.db import models
from django.db.models.functions import Floor, Random
def roll(faces):
return Floor(Random() * faces) + 1
def run():
User.objects.bulk_create([User(username=str(i)) for i in range(1,
13)])
qs = User.objects.values(
first_roll=roll(6),
tie_break_roll=roll(6),
).annotate(total=models.Count("pk"))
print(qs)
}}}
{{{#!sql
SELECT (FLOOR((RANDOM() * 6)) + 1) AS "first_roll",
(FLOOR((RANDOM() * 6)) + 1) AS "tie_break_roll",
COUNT("auth_user"."id") AS "total"
FROM "auth_user"
GROUP BY 2
LIMIT 21
}}}
I would have expected `GROUP BY 1, 2`.
In addition to `GROUP BY`, some other areas to check are deduplication in
`ORDER BY`, `get_extra_select()` for `distinct()`, and `get_qualify_sql()`
for `Window()` functions.
Noticed while reviewing #37222.
--
Ticket URL: <
https://code.djangoproject.com/ticket/37316>
Django <
https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.