Skip to content

Conversation

sinsoku
Copy link
Contributor

@sinsoku sinsoku commented Jan 7, 2020

An error occurs when you pass a relation with SQL comments to the or method.

class Post
  scope :active, -> { where(active: true).annotate("active posts") }
end

Post.where("created_at > ?", Time.current.beginning_of_month)
  .or(Post.active)
#=> ArgumentError (Relation passed to #or must be structurally compatible. Incompatible values: [:annotate])

In order to work without ArgumentError, it changes the or method to ignore SQL comments in the argument.

Ref: #38145 (comment)

@kamipo
Copy link
Member

kamipo commented Jan 7, 2020

How do you think optimizer_hints should behave?

@sinsoku
Copy link
Contributor Author

sinsoku commented Jan 8, 2020

Sorry, I haven't used optimizer_hints yet, so I'm not very familiar with it.
I don't know how to behave in case of conflicting conditions.

Post.optimizer_hints("MAX_EXECUTION_TIME(50000)").or(
  Post.optimizer_hints("MAX_EXECUTION_TIME(20000)"))
#=> ?

@sinsoku
Copy link
Contributor Author

sinsoku commented Jan 8, 2020

I found the following description in the MySQL documentation.

When a hint comment contains multiple hints, the possibility of duplicates and conflicts exists. The following general guidelines apply. For specific hint types, additional rules may apply, as indicated in the hint descriptions.

  • Duplicate hints: For a hint such as /*+ MRR(idx1) MRR(idx1) */, MySQL uses the first hint and issues a warning about the duplicate hint.
  • Conflicting hints: For a hint such as /*+ MRR(idx1) NO_MRR(idx1) */, MySQL uses the first hint and issues a warning about the second conflicting hint.

ref: https://dev.mysql.com/doc/refman/5.7/en/optimizer-hints.html

The query when the condition conflicts is valid (although there is a warning), so I think that it is no problem to simply combine the values.
I would like to support optimizer_hints in this PR.

@rails-bot
Copy link

rails-bot bot commented Apr 10, 2020

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
Thank you for your contributions.

@rails-bot rails-bot bot added the stale label Apr 10, 2020
@rails-bot rails-bot bot removed the stale label Apr 17, 2020
@sinsoku
Copy link
Contributor Author

sinsoku commented Apr 17, 2020

I don't come up with a use case for using optimizer_hints with the or method, so this PR only covers annotate.
If someone wants to use optimizer_hints with the or method, they will make a PR.

@kamipo
Copy link
Member

kamipo commented May 17, 2020

To work or without ArgumentError in that case, is not enough just ignore annotate/optimizer_hints?

or is focused to combine where-like clauses by not AND but OR.
Allowing (and defining) to combine non where-like clauses is the notable design change for or to me.

@sinsoku
Copy link
Contributor Author

sinsoku commented May 20, 2020

Sure, that's enough.
I'll fix it.

@sinsoku sinsoku force-pushed the or_with_annotate branch 2 times, most recently from 81511b8 to c4e30fc Compare May 24, 2020 04:59
# they must differ only by #where (if no #group has been defined) or #having (if a #group is
# present). Neither relation may have a #limit, #offset, or #distinct set.
# they must differ only by #where (if no #group has been defined), #having (if a #group is
# present), #annotate or #optimizer_hints. Neither relation may have a #limit, #offset, or #distinct set.
Copy link
Member

Choose a reason for hiding this comment

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

I'm not excited to talk about the annotate and the optimizer_hints in the same breath with the where and the having.

We had hit the structually incompatible error on several occasions in the past (#29461, ea61391), in that time, we just relaxed the limitation to address the error, but didn't mention about what values are allowed/ignored.

I agree that there is room for improvement in the doc, but how about discussing it in another PR about how to improve it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for telling me related pull requests.
I understood.

I reverted the changes in doc and force-pushed.

@@ -139,6 +139,14 @@ def test_or_with_scope_on_association
end
end

def test_or_with_annotate
quoted_posts = Post.quoted_table_name
Copy link
Member

Choose a reason for hiding this comment

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

The quoted_table_name should be escaped by Regexp.escape, since it is qouted as [posts] in SQLServer.

Suggested change
quoted_posts = Post.quoted_table_name
quoted_posts = Regexp.escape(Post.quoted_table_name)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for your review. I updated.

An error occurs when you pass a relation with SQL comments to the `or` method.

```ruby
class Post
  scope :active, -> { where(active: true).annotate("active posts") }
end

Post.where("created_at > ?", Time.current.beginning_of_month)
  .or(Post.active)
```

In order to work without `ArgumentError`, it changes the `or` method to ignore
SQL comments in the argument.

Ref: rails#38145 (comment)
@sinsoku sinsoku force-pushed the or_with_annotate branch from 70aa580 to 26a60c4 Compare May 24, 2020 13:43
@kamipo kamipo merged commit 660c491 into rails:master May 24, 2020
@kamipo
Copy link
Member

kamipo commented May 24, 2020

Thanks!

kamipo added a commit that referenced this pull request May 24, 2020
Allow relations with different SQL comments in the `or` method
@sinsoku sinsoku deleted the or_with_annotate branch May 24, 2020 15:00
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.

2 participants