Omitting $start in entityQuery->range() does not return full result set

Created on 10 January 2024, 12 months ago
Updated 6 February 2024, 11 months ago

Problem/Motivation

There is a discrepancy between the documentation of the entityQuery ::range() method and its observed behavior.

The documentation says that if the $start parameter is omitted, the range should be reset (and hence should return the full result set):

  /**
   * Defines the range of the query.
   *
   * @param int|null $start
   *   (optional) The first record from the result set to return. If NULL,
   *   removes any range directives that are set.
   * @param int|null $length
   *   (optional) The maximum number of rows to return. If $start and $length
   *   are NULL, then a complete result set will be generated. If $start is
   *   not NULL and $length is NULL, then an empty result set will be
   *   generated.
   *
   * @return $this
   */
  public function range($start = NULL, $length = NULL);

However, in the current implementation, when $start is NULL, and $length is set, the full result set is NOT returned. Instead it returns the number of results passed in $length.

We should either update the documentation to match the existing behavior, or change the behavior.

Steps to reproduce

\Drupal::entityQuery('field_storage_config')->range(NULL, 1)->execute();

Expected result: all records are returned.
Actual result: 1 record is returned.

Proposed resolution

We should either fix the implementation, or change the documentation to match the existing behavior.

Updating the documentation is probably the best solution since it will not affect existing projects.

Remaining tasks

Decide on a solution and implement.

User interface changes

API changes

Data model changes

Release notes snippet

๐Ÿ› Bug report
Status

Needs work

Version

11.0 ๐Ÿ”ฅ

Component
Entityย  โ†’

Last updated about 17 hours ago

  • Maintained by
  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom @catch
  • ๐Ÿ‡จ๐Ÿ‡ญSwitzerland @berdir
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany @hchonov
Created by

๐Ÿ‡ง๐Ÿ‡ฌBulgaria pfrenssen Sofia

Live updates comments and jobs are added and updated live.
  • Needs issue summary update

    Issue summaries save everyone time if they are kept up-to-date. See Update issue summary task instructions.

Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @pfrenssen
  • First commit to issue fork.
  • Status changed to Needs review 12 months ago
  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia shalini_jha

    I have tested the query and if $length value is set in range(NULL,1), so query will return 1 record only, so i have updated the doc comment for this and added a MR, please review.

  • Pipeline finished with Success
    12 months ago
    Total: 607s
    #75428
  • ๐Ÿ‡จ๐Ÿ‡ฆCanada Charlie ChX Negyesi ๐ŸCanada

    The entity query backend for SQL -- as it does for many things -- passes range unaltered to the database query. It does so for many things. While we certainly had the intention to make the system work for any storage backend, they were not implemented at the same time: note the time gap between #1801726: EntityFieldQuery v2 โ†’ and #1846454: Add Entity query to Config entities โ†’ . Also note how hard it was to query config -- the current implementation didn't appear until #50 (!) in the latter. No wonder small details like range NULL simply was overlooked. A test for "// Add a range to a query without a start parameter" was added but, alas, this used a 0 start instead of a NULL start.

    $start NULL then got documented many, many years later in #2711739: Missing summary/param/return docs for several QueryInterface methods โ†’ by copy-pasting the doxygen from Database/Query/SelectInterface::range() to Entity/Query/QueryInterface::range() however as this issue shows, not all backends implements range() this way. Indeed, in core we have a KeyValueStore and a Config backend and both does array_slice($result, $this->range['start'], $this->range['length'], TRUE); completely ignoring the fact that $this->range['start'] can be NULL. I am quite surprised more modern PHP doesn't complain a NULL is passed where an int is expected, it sure does like to complain when a NULL is passed in lieu of a string. It's possible it'll start complaining indeed in the future so if the issue ends up with allowing NULL for a start then this definitely needs to be fixed by a simple type cast.

    There are multiple ways forward. Deciding is up to you. I am just an old ghost haunting the issue queues. And it's entirely possible there are yet more ways forward I missed. As this issue shows what we all know too well: I certainly can overlook the obvious.

    1. Keep the behavior as is and change the doxygen to say: $start NULL has undefined behavior. This is the most BC friendly way. The only code change here would be to the array_slice() calls: add int typecasts.
    2. Keep the doxygen and change QueryBase to remove $this->range if NULL is passed in. I think -- but of course all this needs confirmation from someone more knowledgable about current affairs -- this would be an API change and might be tricky to navigate through the BC policy. Once again, I think -- but again please double check -- adhering to BC policies this would take many releases: first passing in NULL would need to be depreciated because the behavior of it changes for non-SQL stored entities and instead of passing NULL to $range there would need to be a new method to remove previously set range. Then, if it is desirable to arrive back to where we are now then in the next release depreciate the new method and remove the NULL depreciation. Then finally remove the new method.

    One more thing to note: while currently removing range is perhaps not a common thing to want but maybe with the alter hook finally implemented there might be more use cases for it in the future.

  • Status changed to Needs work 12 months ago
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States smustgrave

    MR is showing 1000s of change so that needs to be addressed.

    Can't tell if there is test coverage but there should be.

  • ๐Ÿ‡ง๐Ÿ‡ฌBulgaria pfrenssen Sofia

    What is also interesting is that the sister method Select::range() _does_ implement this as documented. So for simplicity it would be good to align these two implementations.

    I am also wondering the impact of changing this, I would hazard a guess that there would be comparatively few calls to ->range(NULL, 1) in the wild since this pattern looks a but unnatural. But they will undoubtedly exist, and might happen when passing through data from elsewhere (for example REST API calls might pass 1 parameter only).

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom catch

    I think at least in this issue we should change the documentation to match the existing behaviour, because you can use range(NULL, NULL) to explicitly remove the range anyway.

    In slack @chx suggested deprecating the current behaviour when only the first parameter is null, to later throw an exception - maybe we could do that for other range implementations too (in a follow-up) so that people have to use NULL, NULL for that case?

  • Status changed to Needs review 11 months ago
  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia shalini_jha

    I have checked MR showing 1000+ changes. I think this issue needs a rebase.
    please let me know if any other changes required for work on this issue.
    Thanks

  • Status changed to Needs work 11 months ago
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States smustgrave

    Issue isnโ€™t mergeable so not ready for review just yet.

  • Pipeline finished with Success
    11 months ago
    Total: 564s
    #84579
  • Status changed to Needs review 11 months ago
  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia shalini_jha

    I have fixed the mergeable issues, please review.
    Thanks

  • Status changed to Needs work 11 months ago
  • The Needs Review Queue Bot โ†’ tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

    This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

    Consult the Drupal Contributor Guide โ†’ to find step-by-step guides for working with issues.

  • ๐Ÿ‡บ๐Ÿ‡ธUnited States dww

    All issues and MRs in the core queue should target the 11.x branch. Bug fixes will be backported to the right branch(es) as appropriate. But we always fix everything in "main" first, only we don't have a "main" right now and we're using "11.x" as "main" for now...

    Please move the MR target branch back to 11.x, and rebase 3413834-omitting-start-in against 11.x.

    Thanks!
    -Derek

  • Pipeline finished with Success
    11 months ago
    #85790
  • Merge request !6418issues:3413834 updated the doc comment โ†’ (Open) created by shalini_jha
  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia shalini_jha

    shalini_jha โ†’ changed the visibility of the branch 3413834-omitting-start-in to hidden.

  • Pipeline finished with Success
    11 months ago
    Total: 683s
    #85802
  • Status changed to Needs review 11 months ago
  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia shalini_jha

    HI , i have added a new MR for this changes against 11.x. please review.

  • Status changed to Needs work 11 months ago
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States smustgrave

    #8 seems to still have an open question

    In slack @chx suggested deprecating the current behaviour when only the first parameter is null, to later throw an exception - maybe we could do that for other range implementations too (in a follow-up) so that people have to use NULL, NULL for that case?

    Issue summary also still appears to be under discussion.

Production build 0.71.5 2024