[PR #10444] Make Paginator-internal query cacheable in the query cache #12367

Open
opened 2026-01-22 16:13:50 +01:00 by admin · 0 comments
Owner

Original Pull Request: https://github.com/doctrine/orm/pull/10444

State: closed
Merged: Yes


Make the Paginator-internal query (... WHERE ... IN (id, id2, id3...)) cacheable in the query cache again.

Background

When the Paginator creates the internal subquery that does the actual result limiting, it has to take DBAL type conversions for the identifier column of the paginated root entity into account (#7820, fixed in #7821).

In order to perform this type conversion, we need to know the DBAL type class for the root entity's #[Id], and we have to figure it out based on a given (arbitrary) DQL query. This requires DQL parsing and inspecting the AST, so #7821 placed the conversion code in the WhereInWalker where all the necessary information is available.

The problem is that type conversion has to happen every time the paginator is run, but the query that results from running WhereInWalker would be kept in the query cache. This was reported in #7837 and fixed by #7865, by making this particular query expire every time. The query must not be cached, since the necessary ID type conversion happens as a side-effect of running the WhereInWalker.

Current status

The Paginator internal query that uses WhereInWalker has its DQL re-parsed and transformed in every request.

Suggested solution

This PR moves the code that determines the DBAL type out of WhereInWalker into a dedicated SQL walker class, RootTypeWalker.

RootTypeWalker uses a hack  clever trick to report the type back: It sets the type as the resulting "SQL" string. The benefit is that RootTypeWalker results can be cached in the query cache themselves. Only the first time a given DQL query has to be paginated, we need to run this walker to find out the root entity's ID type. After that, the type will be returned from the query cache.

With the type information being provided, Paginator can take care of the necessary conversions by itself. This happens every time the Paginator is used.

The internal query that uses WhereInWalker can be cached again since it no longer has side effects.

**Original Pull Request:** https://github.com/doctrine/orm/pull/10444 **State:** closed **Merged:** Yes --- Make the `Paginator`-internal query (`... WHERE ... IN (id, id2, id3...)`) cacheable in the query cache again. #### Background When the Paginator creates the internal subquery that does the actual result limiting, it has to take DBAL type conversions for the identifier column of the paginated root entity into account (#7820, fixed in #7821). In order to perform this type conversion, we need to know the DBAL type class for the root entity's `#[Id]`, and we have to figure it out based on a given (arbitrary) DQL query. This requires DQL parsing and inspecting the AST, so #7821 placed the conversion code in the `WhereInWalker` where all the necessary information is available. The problem is that type conversion has to happen every time the paginator is run, but the query that results from running `WhereInWalker` would be kept in the query cache. This was reported in #7837 and fixed by #7865, by making this particular query expire every time. The query must not be cached, since the necessary ID type conversion happens as a side-effect of running the `WhereInWalker`. #### Current status The Paginator internal query that uses `WhereInWalker` has its DQL re-parsed and transformed in every request. #### Suggested solution This PR moves the code that determines the DBAL type out of `WhereInWalker` into a dedicated SQL walker class, `RootTypeWalker`. `RootTypeWalker` uses a ~hack~  clever trick to report the type back: It sets the type as the resulting "SQL" string. The benefit is that `RootTypeWalker` results can be cached in the query cache themselves. Only the first time a given DQL query has to be paginated, we need to run this walker to find out the root entity's ID type. After that, the type will be returned from the query cache. With the type information being provided, `Paginator` can take care of the necessary conversions by itself. This happens every time the Paginator is used. The internal query that uses `WhereInWalker` can be cached again since it no longer has side effects.
admin added the pull-request label 2026-01-22 16:13:50 +01:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#12367