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

Change Expr PartialOrd to not rely on comparing hash values #8932

Closed
alamb opened this issue Jan 21, 2024 · 6 comments · Fixed by #12481
Closed

Change Expr PartialOrd to not rely on comparing hash values #8932

alamb opened this issue Jan 21, 2024 · 6 comments · Fixed by #12481
Labels
bug Something isn't working help wanted Extra attention is needed

Comments

@alamb
Copy link
Contributor

alamb commented Jan 21, 2024

Describe the bug

As described on #8908, the PartialOrd implementation of Expr is based on comparing the hash values of the two nodes

This is problematic because there can be different orderings for the same expression:

  1. Different releases of ahash
  2. Different platforms (as we saw with Fix expr partial ord test #8908 / 35.0.0 release verification

Here is the current implementation

https://github.com/apache/arrow-datafusion/blob/b7e13a0af711477ad41450566c14430089edd3f2/datafusion/expr/src/expr.rs#L850-L862

To Reproduce

No response

Expected behavior

I expect that PartialOrd of Expr will not change -- we probably have to implement a real PartialOrd implementation that compares each field (or maybe derive)

Additional context

No response

@alamb alamb added the bug Something isn't working label Jan 21, 2024
@alamb
Copy link
Contributor Author

alamb commented Jan 21, 2024

@tustvold notes on #8908 (comment):

Edit: as suspected it looks like PartialEq is being derived using a proc macro, and is therefore inconsistent with this implementation of PartialOrd - https://github.com/apache/arrow-datafusion/blob/main/datafusion/expr/src/expr.rs#L87. In particular PartialOrd could claim things to be equal due to a hash collision, when PartialEq would indicate they are not

So my conclusion is that this is a latent bug waiting to happen (that will be very hard to track down if/when it does strike)

@alamb alamb added the help wanted Extra attention is needed label Jan 21, 2024
@alamb alamb changed the title Change Expr ordering so it does not rely on PartialOrd Change Expr PartialOrd to not rely on comparing hash values Jan 21, 2024
@ngli-me
Copy link
Contributor

ngli-me commented Sep 8, 2024

Hi, I'm new to this project and was poking through the issues, can I try working this one out?

It looks like, to remove the hash we would need to first compare by enum variant (it looks like based on the test that the declaration order determines the Ord). I see two solutions for this, either implementing a "discriminant" function to determine the variant ordering, or by having a lot of match arms.

In the case of equivalent variant, we can then compare by fields, looks like it should work for the majority of them.

Is that the right track?

@alamb
Copy link
Contributor Author

alamb commented Sep 9, 2024

Hi, I'm new to this project and was poking through the issues, can I try working this one out?

It looks like, to remove the hash we would need to first compare by enum variant (it looks like based on the test that the declaration order determines the Ord). I see two solutions for this, either implementing a "discriminant" function to determine the variant ordering, or by having a lot of match arms.

In the case of equivalent variant, we can then compare by fields, looks like it should work for the majority of them.

Is that the right track?

I think so . I don't think the actual relative order of Exprs is important, only that it is consistent

It might be worth figuring out how to break this work into some smaller PRs (rather than one large one) -- perhaps by implementing partial ord for sub fields / structs that are used in Expr before trying to do so for the whole thing.

@ngli-me
Copy link
Contributor

ngli-me commented Sep 9, 2024

Good idea! I went back through to check all the DF sub fields/structs, will start the work + breaking it down.

PartialOrd Status

  • Expr
  • Alias -> requires Expr, otherwise can derive
    • TableReference -> derives PartialOrd
  • Column
    • TableReference -> derives PartialOrd
  • DataType -> derives PartialOrd
  • ScalarValue -> has (manual implementation)
  • BinaryExpr -> depends on Expr
  • Like -> depends on Expr
  • Between -> depends on Expr
  • Case -> depends on Expr
  • Cast -> depends on Expr
  • TryCast -> depends on Expr
  • ScalarFunction -> depends on Expr
    • ScalarUDF (doable)
  • AggregateFunction -> similar to WindowFunction, but also requires Expr
    • Sort -> depends on Expr
  • WindowFunction (also uses Sort)
  • Inlist -> depends on Expr
  • Exists -> depends on Subquery
  • InSubquery -> depends on Expr and Subquery
  • Subquery -> also depends on Expr
    • LogicalPlan -> the subtypes of these require Expr and LogicalPlan, looks like this should be done near last
  • Wildcard
    • TableReference -> derives PartialOrd
    • WildcardOptions
      • PlannedReplaceSelectItem -> depends on expr
  • GroupingSet -> depends on Expr
  • Placeholder
  • OuterReferenceColumn
    • Datatype -> derives PartialOrd
    • Column -> derives PartialOrd
  • Unnest -> depends on Expr

@ngli-me
Copy link
Contributor

ngli-me commented Sep 14, 2024

I was going through the remaining subtypes/structs, and saw an issue that I wasn't sure how to resolve. While most of the remaining can derive PartialOrd, it looks like DFSchema can't, and since it has a dependency on a Hashmap. A similar problem happens in CreateExternalTable, which uses two Hashmaps. Not sure how to approach this, any advice would be appreciated!

@alamb
Copy link
Contributor Author

alamb commented Sep 14, 2024

I would personally suggest trying to simply ignore the contents of the schema for partial ord -- I think in general the other fields in structs should be enough to compute equality and ordering

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants