From 4ca1b694e4d37199975587fce67d083575f17080 Mon Sep 17 00:00:00 2001 From: Xin Li Date: Tue, 16 Jul 2024 22:18:36 +0800 Subject: [PATCH] Followup Support NULL literals in where clause --- datafusion/expr/src/logical_plan/plan.rs | 2 +- .../optimizer/src/analyzer/type_coercion.rs | 17 +++++++++++++++-- datafusion/sqllogictest/test_files/misc.slt | 13 +++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/datafusion/expr/src/logical_plan/plan.rs b/datafusion/expr/src/logical_plan/plan.rs index 3bf877de90ab..4cfd0add90e7 100644 --- a/datafusion/expr/src/logical_plan/plan.rs +++ b/datafusion/expr/src/logical_plan/plan.rs @@ -2091,7 +2091,7 @@ impl Filter { // construction (such as with correlated subqueries) so we make a best effort here and // ignore errors resolving the expression against the schema. if let Ok(predicate_type) = predicate.get_type(input.schema()) { - if predicate_type != DataType::Boolean { + if predicate_type != DataType::Boolean && predicate_type != DataType::Null { return plan_err!( "Cannot create filter with non-boolean predicate '{predicate}' returning {predicate_type}" ); diff --git a/datafusion/optimizer/src/analyzer/type_coercion.rs b/datafusion/optimizer/src/analyzer/type_coercion.rs index 80a8c864e431..f511c8607adc 100644 --- a/datafusion/optimizer/src/analyzer/type_coercion.rs +++ b/datafusion/optimizer/src/analyzer/type_coercion.rs @@ -47,8 +47,9 @@ use datafusion_expr::type_coercion::{is_datetime, is_utf8_or_large_utf8}; use datafusion_expr::utils::merge_schema; use datafusion_expr::{ is_false, is_not_false, is_not_true, is_not_unknown, is_true, is_unknown, not, - type_coercion, AggregateFunction, AggregateUDF, Expr, ExprSchemable, LogicalPlan, - Operator, ScalarUDF, Signature, WindowFrame, WindowFrameBound, WindowFrameUnits, + type_coercion, AggregateFunction, AggregateUDF, Expr, ExprSchemable, Filter, + LogicalPlan, Operator, ScalarUDF, Signature, WindowFrame, WindowFrameBound, + WindowFrameUnits, }; use crate::analyzer::AnalyzerRule; @@ -86,6 +87,18 @@ fn analyze_internal( external_schema: &DFSchema, plan: LogicalPlan, ) -> Result> { + if let LogicalPlan::Filter(Filter { + predicate, input, .. + }) = &plan + { + if predicate == &Expr::Literal(ScalarValue::Null) { + return Ok(Transformed::yes(LogicalPlan::Filter(Filter::try_new( + Expr::Literal(ScalarValue::Boolean(Some(false))), + Arc::clone(input), + )?))); + } + } + // get schema representing all available input fields. This is used for data type // resolution only, so order does not matter here let mut schema = merge_schema(plan.inputs()); diff --git a/datafusion/sqllogictest/test_files/misc.slt b/datafusion/sqllogictest/test_files/misc.slt index 848cdc943914..7937b502c3ba 100644 --- a/datafusion/sqllogictest/test_files/misc.slt +++ b/datafusion/sqllogictest/test_files/misc.slt @@ -24,3 +24,16 @@ query TT? select 'foo', '', NULL ---- foo (empty) NULL + +query I +select 1 where NULL +---- + +query I +select 1 where NULL and 1 = 1 +---- + +query I +select 1 where NULL or 1 = 1 +---- +1 \ No newline at end of file