Skip to content

Fix whereIn/orWhereIn with empty lists, qualify OR columns, add whereNotIn to the query builder - #395

Merged
techmahedy merged 1 commit into
doppar:4.xfrom
techmahedy:fix/empty-where-in-matches-null-text
Oct 30, 2026
Merged

techmahedy merged 1 commit into
doppar:4.xfrom
techmahedy:fix/empty-where-in-matches-null-text

Conversation

@techmahedy

Copy link
Copy Markdown
Member

Pull Request Checklist

Q A
Branch? 4.x
Bug fix? yes
New feature? no
Deprecations? no
Issues -
License MIT

Description

Fixes a bug in whereIn() / orWhereIn() with an empty list, plus the related problems in the same methods, in both the model builder and the plain query builder.

1. An empty IN list compared the column to the string 'NULL'

whereIn($field, []) was turned into where($field, '=', 'NULL'), which binds the text 'NULL', not SQL NULL. An empty IN must match nothing, but:

  • Text columns: it matched rows whose value is the text NULL. whereIn('label', [])->delete() really deleted such a row, and update() modified it.
  • Integer columns on MySQL: MySQL casts 'NULL' to 0, so reads matched rows equal to 0. In strict mode, delete() and update() threw SQLSTATE[22007], so a normal "no ids selected" bulk action crashed.

Empty lists are now registered as an IN condition and compiled by the existing condition compiler, which already produced 1=0 for an empty IN and 1=1 for an empty NOT IN.

2. Related problems in the same methods

  • orWhereIn did not qualify its column the way whereIn does, so on a join it failed with "ambiguous column". Both now qualify bare columns. Already-qualified columns are left alone.
  • The plain builder's whereIn broke on an aliased table. It built items as i.id, a syntax error. All IN conditions now use the alias (i.id), including items i without as.
  • The plain query builder had no whereNotIn / orWhereNotIn. The call fell through to __call and produced a syntax error. Both are added.
  • Associative lists (['a' => 1, 'b' => 2]) could not be bound. Values are now re-indexed.

Changes

  • Added addInCondition() and tableReference() to InteractsWithConditionBinding, which both builders already use.
  • Moved tableReference() out of InteractsWithSoftDeleteScope into that trait. Only the two builders use either trait.
  • whereIn, orWhereIn, whereNotIn and orWhereNotIn on both builders delegate to addInCondition(). The private addNotInCondition() on the model builder is gone.
  • Added EmptyWhereInTest with 87 tests that run against both builders.

Checklist

  • Tests have been added or updated
  • Documentation has been updated if necessary
  • Code follows the project coding standards
  • All tests pass locally

@techmahedy techmahedy added the bug Something isn't working label Oct 30, 2026
@techmahedy
techmahedy merged commit c9f36f5 into doppar:4.x Oct 30, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant