Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arel: make Or nodes "Nary" like And #51492

Merged
merged 1 commit into from
Apr 4, 2024
Merged

Conversation

casperisfine
Copy link
Contributor

Fix: #51386

This significantly reduce the depth of the tree for large OR conditions. I was initially a bit on the fence about that fix, but given that And is already implemented this way, I see no reasons not to do the same.

Amusingly, the reported repro script now makes SQLite fail:

SQLite3::SQLException: Expression tree is too large (maximum depth 1000)

FYI: @markedmondson

Fix: rails#51386

This significantly reduce the depth of the tree for large `OR`
conditions. I was initially a bit on the fence about that fix,
but given that `And` is already implemented this way, I see no
reasons not to do the same.

Amusingly, the reported repro script now makes SQLite fail:

```ruby
SQLite3::SQLException: Expression tree is too large (maximum depth 1000)
```
@byroot byroot requested a review from jhawthorn April 4, 2024 13:05
Copy link
Member

@matthewd matthewd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree we shouldn't backport, given the (albeit internal) API change -- but yeah this seems like a nice improvement even just for the general consistency with And

@byroot byroot merged commit 6d42bf4 into rails:main Apr 4, 2024
4 checks passed
@nertzy
Copy link
Contributor

nertzy commented May 31, 2024

I noticed (via a "canary" build test failure in pg_search's test suite) that this introduces a breaking change to the constructor of Arel::Nodes::Or.

It now requires an Array/Enumerable argument instead of two separate arguments.

A cursory search of GitHub shows a few different codebases that rely on this interface.

Would there be any interest in reintroducing (and probably deprecating?) the previous constructor interface?

Either way, I can release an update to pg_search that detects the arity of the method and switches between the two implementations.

I understand that the Arel constructors are considered an "internal" API, so I will accept whatever you think is best here.

@byroot
Copy link
Member

byroot commented Jun 1, 2024

I understand that the Arel constructors are considered an "internal" API

Yeah, it would be weird to emit a deprecation warning for something that's a private API.

I think it would be best if the caller was feature testing to handle compatibility:

if Arel::Nodes::Or.instance_method(:initialize).arity == 1 # Active Record 7.2+
  def conditions
    config.features
      .reject { |_feature_name, feature_options| feature_options && feature_options[:sort_only] }
      .map { |feature_name, _feature_options| feature_for(feature_name).conditions }
      .inject { |accumulator, expression| Arel::Nodes::Or.new([accumulator, expression]) }
  end
else
  def conditions
    config.features
      .reject { |_feature_name, feature_options| feature_options && feature_options[:sort_only] }
      .map { |feature_name, _feature_options| feature_for(feature_name).conditions }
      .inject { |accumulator, expression| Arel::Nodes::Or.new(accumulator, expression) }
  end
end

I totally understand this will cause issues with multiple gems, and even some private codebase, but I'm a bit afraid of creating a precendent by deprecating private APIs. @rafaelfranca what do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Large arel tree causes ActiveRecord preloader to throw SystemStackError
4 participants