@@ -2503,9 +2503,22 @@ impl Window {
2503
2503
// Manual implementation needed because of `schema` field. Comparison excludes this field.
2504
2504
impl PartialOrd for Window {
2505
2505
fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
2506
- match self . input . partial_cmp ( & other. input ) {
2507
- Some ( Ordering :: Equal ) => self . window_expr . partial_cmp ( & other. window_expr ) ,
2508
- cmp => cmp,
2506
+ match self . input . partial_cmp ( & other. input ) ? {
2507
+ Ordering :: Equal => { } // continue
2508
+ not_equal => return Some ( not_equal) ,
2509
+ }
2510
+
2511
+ match self . window_expr . partial_cmp ( & other. window_expr ) ? {
2512
+ Ordering :: Equal => { } // continue
2513
+ not_equal => return Some ( not_equal) ,
2514
+ }
2515
+
2516
+ // Contract for PartialOrd and PartialEq consistency requires that
2517
+ // a == b if and only if partial_cmp(a, b) == Some(Equal).
2518
+ if self == other {
2519
+ Some ( Ordering :: Equal )
2520
+ } else {
2521
+ None
2509
2522
}
2510
2523
}
2511
2524
}
@@ -4268,22 +4281,20 @@ fn get_unnested_list_datatype_recursive(
4268
4281
4269
4282
#[ cfg( test) ]
4270
4283
mod tests {
4271
-
4272
4284
use super :: * ;
4273
4285
use crate :: builder:: LogicalTableSource ;
4274
4286
use crate :: logical_plan:: table_scan;
4287
+ use crate :: test:: function_stub:: { count, count_udaf} ;
4275
4288
use crate :: {
4276
4289
binary_expr, col, exists, in_subquery, lit, placeholder, scalar_subquery,
4277
4290
GroupingSet ,
4278
4291
} ;
4279
-
4280
4292
use datafusion_common:: tree_node:: {
4281
4293
TransformedResult , TreeNodeRewriter , TreeNodeVisitor ,
4282
4294
} ;
4283
4295
use datafusion_common:: { not_impl_err, Constraint , ScalarValue } ;
4284
4296
use insta:: { assert_debug_snapshot, assert_snapshot} ;
4285
-
4286
- use crate :: test:: function_stub:: count;
4297
+ use std:: hash:: DefaultHasher ;
4287
4298
4288
4299
fn employee_schema ( ) -> Schema {
4289
4300
Schema :: new ( vec ! [
@@ -4687,6 +4698,63 @@ mod tests {
4687
4698
) ;
4688
4699
}
4689
4700
4701
+ #[ test]
4702
+ fn test_partial_eq_hash_and_partial_ord ( ) {
4703
+ let empty_values = Arc :: new ( LogicalPlan :: EmptyRelation ( EmptyRelation {
4704
+ produce_one_row : true ,
4705
+ schema : Arc :: new ( DFSchema :: empty ( ) ) ,
4706
+ } ) ) ;
4707
+
4708
+ let count_window_function = |schema| {
4709
+ Window :: try_new_with_schema (
4710
+ vec ! [ Expr :: WindowFunction ( Box :: new( WindowFunction :: new(
4711
+ WindowFunctionDefinition :: AggregateUDF ( count_udaf( ) ) ,
4712
+ vec![ ] ,
4713
+ ) ) ) ] ,
4714
+ Arc :: clone ( & empty_values) ,
4715
+ Arc :: new ( schema) ,
4716
+ )
4717
+ . unwrap ( )
4718
+ } ;
4719
+
4720
+ let schema_without_metadata = || {
4721
+ DFSchema :: from_unqualified_fields (
4722
+ vec ! [ Field :: new( "count" , DataType :: Int64 , false ) ] . into ( ) ,
4723
+ HashMap :: new ( ) ,
4724
+ )
4725
+ . unwrap ( )
4726
+ } ;
4727
+
4728
+ let schema_with_metadata = || {
4729
+ DFSchema :: from_unqualified_fields (
4730
+ vec ! [ Field :: new( "count" , DataType :: Int64 , false ) ] . into ( ) ,
4731
+ [ ( "key" . to_string ( ) , "value" . to_string ( ) ) ] . into ( ) ,
4732
+ )
4733
+ . unwrap ( )
4734
+ } ;
4735
+
4736
+ // A Window
4737
+ let f = count_window_function ( schema_without_metadata ( ) ) ;
4738
+
4739
+ // Same like `f`, different instance
4740
+ let f2 = count_window_function ( schema_without_metadata ( ) ) ;
4741
+ assert_eq ! ( f, f2) ;
4742
+ assert_eq ! ( hash( & f) , hash( & f2) ) ;
4743
+ assert_eq ! ( f. partial_cmp( & f2) , Some ( Ordering :: Equal ) ) ;
4744
+
4745
+ // Same like `f`, except for schema metadata
4746
+ let o = count_window_function ( schema_with_metadata ( ) ) ;
4747
+ assert_ne ! ( f, o) ;
4748
+ assert_ne ! ( hash( & f) , hash( & o) ) ; // hash can collide for different values but does not collide in this test
4749
+ assert_eq ! ( f. partial_cmp( & o) , None ) ;
4750
+ }
4751
+
4752
+ fn hash < T : Hash > ( value : & T ) -> u64 {
4753
+ let hasher = & mut DefaultHasher :: new ( ) ;
4754
+ value. hash ( hasher) ;
4755
+ hasher. finish ( )
4756
+ }
4757
+
4690
4758
#[ test]
4691
4759
fn projection_expr_schema_mismatch ( ) -> Result < ( ) > {
4692
4760
let empty_schema = Arc :: new ( DFSchema :: empty ( ) ) ;
0 commit comments