Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 24 additions & 11 deletions datafusion/sql/src/expr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ use datafusion_expr::{
};

use crate::planner::{ContextProvider, PlannerContext, SqlToRel};
use datafusion_functions_nested::expr_fn::array_has;
use datafusion_functions_nested::expr_fn::{array_has, array_max, array_min};

mod binary_op;
mod function;
Expand Down Expand Up @@ -612,16 +612,29 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
planner_context,
),
_ => {
if compare_op != BinaryOperator::Eq {
plan_err!(
"Unsupported AnyOp: '{compare_op}', only '=' is supported"
)
} else {
let left_expr =
self.sql_to_expr(*left, schema, planner_context)?;
let right_expr =
self.sql_to_expr(*right, schema, planner_context)?;
Ok(array_has(right_expr, left_expr))
let left_expr = self.sql_to_expr(*left, schema, planner_context)?;
let right_expr = self.sql_to_expr(*right, schema, planner_context)?;
match compare_op {
BinaryOperator::Eq => Ok(array_has(right_expr, left_expr)),
BinaryOperator::NotEq => Ok(array_min(right_expr.clone())
.not_eq(left_expr.clone())
.or(array_max(right_expr).not_eq(left_expr))
.is_true()),
BinaryOperator::Gt => {
Ok(array_min(right_expr).lt(left_expr).is_true())
}
BinaryOperator::Lt => {
Ok(array_max(right_expr).gt(left_expr).is_true())
}
BinaryOperator::GtEq => {
Ok(array_min(right_expr).lt_eq(left_expr).is_true())
}
BinaryOperator::LtEq => {
Ok(array_max(right_expr).gt_eq(left_expr).is_true())
Comment thread
buraksenn marked this conversation as resolved.
Outdated
}
_ => plan_err!(
"Unsupported AnyOp: '{compare_op}', only '=', '<>', '>', '<', '>=', '<=' are supported"
),
}
}
},
Expand Down
182 changes: 180 additions & 2 deletions datafusion/sqllogictest/test_files/array.slt
Original file line number Diff line number Diff line change
Expand Up @@ -7003,8 +7003,186 @@ select count(*) from arrays where 'X'=any(column3);
----
0

query error DataFusion error: Error during planning: Unsupported AnyOp: '>', only '=' is supported
select count(*) from arrays where 'X'>any(column3);
# any operator with comparison operators
# Use inline arrays so the test data is visible and the needle (5)
# falls within the range of some arrays but not others.
statement ok
CREATE TABLE any_op_test AS VALUES
(1, make_array(1, 2, 3)),
(2, make_array(4, 5, 6)),
(3, make_array(7, 8, 9)),
(4, make_array(3, 5, 7));

# 5 > ANY(arr): true when array_min < 5
# row1: min=1 < 5 ✓, row2: min=4 < 5 ✓, row3: min=7 < 5 ✗, row4: min=3 < 5 ✓
query I?
select column1, column2 from any_op_test where 5 > any(column2) order by column1;
----
1 [1, 2, 3]
2 [4, 5, 6]
4 [3, 5, 7]

# 5 >= ANY(arr): true when array_min <= 5
# row1: min=1 <= 5 ✓, row2: min=4 <= 5 ✓, row3: min=7 <= 5 ✗, row4: min=3 <= 5 ✓
query I?
select column1, column2 from any_op_test where 5 >= any(column2) order by column1;
----
1 [1, 2, 3]
2 [4, 5, 6]
4 [3, 5, 7]

# 5 < ANY(arr): true when array_max > 5
# row1: max=3 > 5 ✗, row2: max=6 > 5 ✓, row3: max=9 > 5 ✓, row4: max=7 > 5 ✓
query I?
select column1, column2 from any_op_test where 5 < any(column2) order by column1;
----
2 [4, 5, 6]
3 [7, 8, 9]
4 [3, 5, 7]

# 5 <= ANY(arr): true when array_max >= 5
# row1: max=3 >= 5 ✗, row2: max=6 >= 5 ✓, row3: max=9 >= 5 ✓, row4: max=7 >= 5 ✓
query I?
select column1, column2 from any_op_test where 5 <= any(column2) order by column1;
----
2 [4, 5, 6]
3 [7, 8, 9]
4 [3, 5, 7]

# 5 <> ANY(arr): true when array_min != 5 OR array_max != 5
# row1: [1,2,3] min=1!=5 ✓, row2: [4,5,6] min=4!=5 ✓, row3: [7,8,9] min=7!=5 ✓, row4: [3,5,7] min=3!=5 ✓
query I?
select column1, column2 from any_op_test where 5 <> any(column2) order by column1;
----
1 [1, 2, 3]
2 [4, 5, 6]
3 [7, 8, 9]
4 [3, 5, 7]

# For a single-element array where the element equals the needle, <> should return false
query B
select 5 <> any(make_array(5));
----
false

# For a uniform array [5,5,5], <> should also return false
query B
select 5 <> any(make_array(5, 5, 5));
----
false
Comment thread
Dandandan marked this conversation as resolved.

# Empty array: all operators should return false (no elements satisfy the condition)
query B
select 5 = any(make_array());
----
false

query B
select 5 <> any(make_array());
----
false

Comment thread
buraksenn marked this conversation as resolved.
query B
select 5 > any(make_array());
----
false

query B
select 5 < any(make_array());
----
false

query B
select 5 >= any(make_array());
----
false

query B
select 5 <= any(make_array());
----
false

# Mixed NULL + non-NULL array where no non-NULL element satisfies the condition
# These return false (NULLs are skipped by array_min/array_max)
query B
select 5 > any(make_array(6, NULL));
----
false

query B
select 5 < any(make_array(3, NULL));
----
false

query B
select 5 >= any(make_array(6, NULL));
----
false

query B
select 5 <= any(make_array(3, NULL));
----
false

# Mixed NULL + non-NULL array where a non-NULL element satisfies the condition
query B
select 5 > any(make_array(3, NULL));
----
true

query B
select 5 < any(make_array(6, NULL));
----
true

query B
select 5 >= any(make_array(5, NULL));
----
true

query B
select 5 <= any(make_array(5, NULL));
----
true

query B
select 5 <> any(make_array(3, NULL));
----
true

query B
select 5 <> any(make_array(5, NULL));
----
false

# All-NULL array: all operators should return false
query B
select 5 > any(make_array(NULL::INT, NULL::INT));
----
false

query B
select 5 < any(make_array(NULL::INT, NULL::INT));
----
false

query B
select 5 >= any(make_array(NULL::INT, NULL::INT));
----
false

query B
select 5 <= any(make_array(NULL::INT, NULL::INT));
----
false

query B
select 5 <> any(make_array(NULL::INT, NULL::INT));
----
false

statement ok
DROP TABLE any_op_test;

## array_distinct

Expand Down
Loading