-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Implement Eq
, PartialEq
, Hash
for dyn PhysicalExpr
#13005
Changes from 6 commits
4181cb2
5e9257c
1aa787d
8b4ef56
66fdd18
f1917fa
4a69b2c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,11 +17,10 @@ | |
|
||
mod kernels; | ||
|
||
use std::hash::{Hash, Hasher}; | ||
use std::hash::Hash; | ||
use std::{any::Any, sync::Arc}; | ||
|
||
use crate::intervals::cp_solver::{propagate_arithmetic, propagate_comparison}; | ||
use crate::physical_expr::down_cast_any_ref; | ||
use crate::PhysicalExpr; | ||
|
||
use arrow::array::*; | ||
|
@@ -48,7 +47,7 @@ use kernels::{ | |
}; | ||
|
||
/// Binary expression | ||
#[derive(Debug, Hash, Clone)] | ||
#[derive(Debug, Clone, Eq)] | ||
pub struct BinaryExpr { | ||
left: Arc<dyn PhysicalExpr>, | ||
op: Operator, | ||
|
@@ -57,6 +56,24 @@ pub struct BinaryExpr { | |
fail_on_overflow: bool, | ||
} | ||
|
||
// Manually derive PartialEq and Hash to work around https://github.com/rust-lang/rust/issues/78808 | ||
impl PartialEq for BinaryExpr { | ||
fn eq(&self, other: &Self) -> bool { | ||
self.left.eq(&other.left) | ||
&& self.op.eq(&other.op) | ||
&& self.right.eq(&other.right) | ||
&& self.fail_on_overflow.eq(&other.fail_on_overflow) | ||
} | ||
} | ||
impl Hash for BinaryExpr { | ||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { | ||
self.left.hash(state); | ||
self.op.hash(state); | ||
self.right.hash(state); | ||
self.fail_on_overflow.hash(state); | ||
} | ||
} | ||
|
||
impl BinaryExpr { | ||
/// Create new binary expression | ||
pub fn new( | ||
|
@@ -477,11 +494,6 @@ impl PhysicalExpr for BinaryExpr { | |
} | ||
} | ||
|
||
fn dyn_hash(&self, state: &mut dyn Hasher) { | ||
let mut s = state; | ||
self.hash(&mut s); | ||
} | ||
|
||
/// For each operator, [`BinaryExpr`] has distinct rules. | ||
/// TODO: There may be rules specific to some data types and expression ranges. | ||
fn get_properties(&self, children: &[ExprProperties]) -> Result<ExprProperties> { | ||
|
@@ -525,20 +537,6 @@ impl PhysicalExpr for BinaryExpr { | |
} | ||
} | ||
|
||
impl PartialEq<dyn Any> for BinaryExpr { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removing this is great |
||
fn eq(&self, other: &dyn Any) -> bool { | ||
down_cast_any_ref(other) | ||
.downcast_ref::<Self>() | ||
.map(|x| { | ||
self.left.eq(&x.left) | ||
&& self.op == x.op | ||
&& self.right.eq(&x.right) | ||
&& self.fail_on_overflow.eq(&x.fail_on_overflow) | ||
}) | ||
.unwrap_or(false) | ||
} | ||
} | ||
|
||
/// Casts dictionary array to result type for binary numerical operators. Such operators | ||
/// between array and scalar produce a dictionary array other than primitive array of the | ||
/// same operators between array and array. This leads to inconsistent result types causing | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,11 +16,10 @@ | |
// under the License. | ||
|
||
use std::borrow::Cow; | ||
use std::hash::{Hash, Hasher}; | ||
use std::hash::Hash; | ||
use std::{any::Any, sync::Arc}; | ||
|
||
use crate::expressions::try_cast; | ||
use crate::physical_expr::down_cast_any_ref; | ||
use crate::PhysicalExpr; | ||
|
||
use arrow::array::*; | ||
|
@@ -37,7 +36,7 @@ use itertools::Itertools; | |
|
||
type WhenThen = (Arc<dyn PhysicalExpr>, Arc<dyn PhysicalExpr>); | ||
|
||
#[derive(Debug, Hash)] | ||
#[derive(Debug, Hash, PartialEq, Eq)] | ||
enum EvalMethod { | ||
/// CASE WHEN condition THEN result | ||
/// [WHEN ...] | ||
|
@@ -80,7 +79,7 @@ enum EvalMethod { | |
/// [WHEN ...] | ||
/// [ELSE result] | ||
/// END | ||
#[derive(Debug, Hash)] | ||
#[derive(Debug, Hash, PartialEq, Eq)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How can it permit auto derivation of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, this is probably the strangest part of the bug. If you have double wrappers around There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we create a ticket to remove those impl's once the bug is resolved? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about #13196? |
||
pub struct CaseExpr { | ||
/// Optional base expression that can be compared to literal values in the "when" expressions | ||
expr: Option<Arc<dyn PhysicalExpr>>, | ||
|
@@ -506,39 +505,6 @@ impl PhysicalExpr for CaseExpr { | |
)?)) | ||
} | ||
} | ||
|
||
fn dyn_hash(&self, state: &mut dyn Hasher) { | ||
let mut s = state; | ||
self.hash(&mut s); | ||
} | ||
} | ||
|
||
impl PartialEq<dyn Any> for CaseExpr { | ||
fn eq(&self, other: &dyn Any) -> bool { | ||
down_cast_any_ref(other) | ||
.downcast_ref::<Self>() | ||
.map(|x| { | ||
let expr_eq = match (&self.expr, &x.expr) { | ||
(Some(expr1), Some(expr2)) => expr1.eq(expr2), | ||
(None, None) => true, | ||
_ => false, | ||
}; | ||
let else_expr_eq = match (&self.else_expr, &x.else_expr) { | ||
(Some(expr1), Some(expr2)) => expr1.eq(expr2), | ||
(None, None) => true, | ||
_ => false, | ||
}; | ||
expr_eq | ||
&& else_expr_eq | ||
&& self.when_then_expr.len() == x.when_then_expr.len() | ||
&& self.when_then_expr.iter().zip(x.when_then_expr.iter()).all( | ||
|((when1, then1), (when2, then2))| { | ||
when1.eq(when2) && then1.eq(then2) | ||
}, | ||
) | ||
}) | ||
.unwrap_or(false) | ||
} | ||
} | ||
|
||
/// Create a CASE expression | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can add some documentation here explaining why this is needed and what it is used for
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added in f1917fa.