From 5b497675b16bc731688f739f76cbd50910cc0785 Mon Sep 17 00:00:00 2001 From: RinChanNOWWW Date: Wed, 8 Mar 2023 18:48:47 +0800 Subject: [PATCH 1/6] New expr: Catch. --- src/query/expression/src/evaluator.rs | 57 +++++++++++++++++ src/query/expression/src/expression.rs | 76 +++++++++++++++++++++++ src/query/expression/src/utils/display.rs | 3 + 3 files changed, 136 insertions(+) diff --git a/src/query/expression/src/evaluator.rs b/src/query/expression/src/evaluator.rs index a465212a4c696..e75d01abd4abe 100644 --- a/src/query/expression/src/evaluator.rs +++ b/src/query/expression/src/evaluator.rs @@ -164,6 +164,31 @@ impl<'a> Evaluator<'a> { self.run_cast(*span, expr.data_type(), dest_type, value) } } + Expr::Catch { + expr, data_type, .. + } => Ok(match self.run(expr) { + Ok(value) => match value { + Value::Scalar(scalar) => { + Value::Scalar(Scalar::Tuple(vec![scalar, Scalar::Null])) + } + Value::Column(col) => { + let len = col.len(); + Value::Column(Column::Tuple { + fields: vec![col, Column::Null { len }], + len, + }) + } + }, + Err(err) => { + let msg = err.to_string(); + let res_type = &data_type.as_tuple().unwrap()[0]; + let res_val = + ColumnBuilder::repeat(&res_type.default_value().as_ref(), 1, res_type) + .build_scalar(); + let err_val = Scalar::String(msg.into_bytes()); + Value::Scalar(Scalar::Tuple(vec![res_val, err_val])) + } + }), }; #[cfg(debug_assertions)] @@ -769,6 +794,38 @@ impl<'a, Index: ColumnIndex> ConstantFolder<'a, Index> { new_domain, ) } + Expr::Catch { + span, + data_type, + expr, + } => { + let (inner, inner_domain) = self.fold_once(expr); + let inner_type = &data_type.as_tuple().unwrap()[0]; + + // If the inner expression is constant, we can safely remove the `catch` expression. + if inner.as_constant().is_some() { + return (inner, inner_domain); + } + + match inner_domain.as_ref().and_then(Domain::as_singleton) { + Some(scalar) => ( + Expr::Constant { + span: *span, + scalar, + data_type: inner_type.clone(), + }, + inner_domain, + ), + None => ( + Expr::Catch { + span: *span, + data_type: data_type.clone(), + expr: Box::new(inner), + }, + None, + ), + } + } Expr::FunctionCall { span, id, diff --git a/src/query/expression/src/expression.rs b/src/query/expression/src/expression.rs index 981555dab89c7..a076a280f1891 100644 --- a/src/query/expression/src/expression.rs +++ b/src/query/expression/src/expression.rs @@ -97,6 +97,11 @@ pub enum Expr { expr: Box>, dest_type: DataType, }, + Catch { + span: Span, + data_type: DataType, + expr: Box>, + }, FunctionCall { span: Span, id: FunctionID, @@ -133,6 +138,11 @@ pub enum RemoteExpr { expr: Box>, dest_type: DataType, }, + Catch { + span: Span, + expr: Box>, + data_type: DataType, + }, FunctionCall { span: Span, id: FunctionID, @@ -284,6 +294,7 @@ impl Expr { Expr::Constant { data_type, .. } => data_type, Expr::ColumnRef { data_type, .. } => data_type, Expr::Cast { dest_type, .. } => dest_type, + Expr::Catch { data_type, .. } => data_type, Expr::FunctionCall { return_type, .. } => return_type, } } @@ -295,6 +306,7 @@ impl Expr { buf.insert(id.clone(), data_type.clone()); } Expr::Cast { expr, .. } => walk(expr, buf), + Expr::Catch { expr, .. } => walk(expr, buf), Expr::FunctionCall { args, .. } => args.iter().for_each(|expr| walk(expr, buf)), Expr::Constant { .. } => (), } @@ -357,6 +369,9 @@ impl Expr { format!("CAST({} AS {dest_type})", expr.sql_display()) } } + Expr::Catch { expr, .. } => { + format!("CATCH({})", expr.sql_display()) + } Expr::FunctionCall { function, args, .. } => { match (function.signature.name.as_str(), args.as_slice()) { ("and", [ref lhs, ref rhs]) => { @@ -461,6 +476,15 @@ impl Expr { expr: Box::new(expr.project_column_ref(f)), dest_type: dest_type.clone(), }, + Expr::Catch { + span, + expr, + data_type, + } => Expr::Catch { + span: *span, + expr: Box::new(expr.project_column_ref(f)), + data_type: data_type.clone(), + }, Expr::FunctionCall { span, id, @@ -512,6 +536,15 @@ impl Expr { expr: Box::new(expr.as_remote_expr()), dest_type: dest_type.clone(), }, + Expr::Catch { + span, + expr, + data_type, + } => RemoteExpr::Catch { + span: *span, + expr: Box::new(expr.as_remote_expr()), + data_type: data_type.clone(), + }, Expr::FunctionCall { span, id, @@ -534,12 +567,37 @@ impl Expr { Expr::Constant { .. } => true, Expr::ColumnRef { .. } => true, Expr::Cast { expr, .. } => expr.is_deterministic(), + Expr::Catch { expr, .. } => expr.is_deterministic(), Expr::FunctionCall { function, args, .. } => { !function.signature.property.non_deterministic && args.iter().all(|arg| arg.is_deterministic()) } } } + + fn span(&self) -> Span { + match self { + Expr::Constant { span, .. } => *span, + Expr::ColumnRef { span, .. } => *span, + Expr::Cast { span, .. } => *span, + Expr::Catch { span, .. } => *span, + Expr::FunctionCall { span, .. } => *span, + } + } + + pub fn wrap_catch(&self) -> Self { + match self { + Expr::Catch { .. } => self.clone(), + expr => Expr::Catch { + span: expr.span(), + expr: Box::new(expr.clone()), + data_type: DataType::Tuple(vec![ + expr.data_type().clone(), + DataType::Nullable(Box::new(DataType::String)), + ]), + }, + } + } } impl Expr { @@ -589,6 +647,15 @@ impl Expr { expr: Box::new(expr.project_column_ref_with_unnest_offset(f, offset)), dest_type: dest_type.clone(), }, + Expr::Catch { + span, + expr, + data_type, + } => Expr::Catch { + span: *span, + expr: Box::new(expr.project_column_ref_with_unnest_offset(f, offset)), + data_type: data_type.clone(), + }, Expr::FunctionCall { span, id, @@ -645,6 +712,15 @@ impl RemoteExpr { expr: Box::new(expr.as_expr(fn_registry)), dest_type: dest_type.clone(), }, + RemoteExpr::Catch { + span, + expr, + data_type, + } => Expr::Catch { + span: *span, + expr: Box::new(expr.as_expr(fn_registry)), + data_type: data_type.clone(), + }, RemoteExpr::FunctionCall { span, id, diff --git a/src/query/expression/src/utils/display.rs b/src/query/expression/src/utils/display.rs index 26ada9427b3e8..8dc7478426197 100755 --- a/src/query/expression/src/utils/display.rs +++ b/src/query/expression/src/utils/display.rs @@ -600,6 +600,9 @@ impl Display for Expr { write!(f, "CAST({expr} AS {dest_type})") } } + Expr::Catch { expr, .. } => { + write!(f, "CATCH({expr})") + } Expr::FunctionCall { function, args, From 729e53bf5388b5d55f3c9a4cb27b7b3b7bfede6c Mon Sep 17 00:00:00 2001 From: RinChanNOWWW Date: Thu, 9 Mar 2023 21:17:58 +0800 Subject: [PATCH 2/6] Fix Catch and introduce EvalResult. --- src/query/expression/src/evaluator.rs | 193 +++++++++++++++++++------- src/query/expression/src/function.rs | 59 +++++--- 2 files changed, 178 insertions(+), 74 deletions(-) diff --git a/src/query/expression/src/evaluator.rs b/src/query/expression/src/evaluator.rs index e75d01abd4abe..3fd748ae629cc 100644 --- a/src/query/expression/src/evaluator.rs +++ b/src/query/expression/src/evaluator.rs @@ -13,8 +13,11 @@ // limitations under the License. use std::collections::HashMap; +use std::ops::Not; use common_arrow::arrow::bitmap; +use common_arrow::arrow::bitmap::Bitmap; +use common_arrow::arrow::bitmap::MutableBitmap; use common_exception::ErrorCode; use common_exception::Result; use common_exception::Span; @@ -43,6 +46,9 @@ use crate::FunctionContext; use crate::FunctionDomain; use crate::FunctionRegistry; +pub(crate) type EvalError = (Span, Value, Bitmap, String); +pub(crate) type EvalResult = std::result::Result; + pub struct Evaluator<'a> { input_columns: &'a DataBlock, func_ctx: FunctionContext, @@ -113,7 +119,15 @@ impl<'a> Evaluator<'a> { new_evaluator.run(expr) } + #[inline] pub fn run(&self, expr: &Expr) -> Result> { + match self.run_impl(expr) { + Ok(v) => Ok(v), + Err((span, _, _, msg)) => Err(ErrorCode::Internal(msg).set_span(span)), + } + } + + pub fn run_impl(&self, expr: &Expr) -> EvalResult> { #[cfg(debug_assertions)] self.check_expr(expr); @@ -129,8 +143,8 @@ impl<'a> Evaluator<'a> { } => { let cols = args .iter() - .map(|expr| self.run(expr)) - .collect::>>()?; + .map(|expr| self.run_impl(expr)) + .collect::>>()?; assert!( cols.iter() .filter_map(|val| match val { @@ -146,9 +160,10 @@ impl<'a> Evaluator<'a> { validity: None, errors: None, tz: self.func_ctx.tz, + already_rendered: false, }; let result = (function.eval)(cols_ref.as_slice(), &mut ctx); - ctx.render_error(*span, &cols, &function.signature.name)?; + ctx.render_error(*span, &cols, &result, &function.signature.name)?; Ok(result) } Expr::Cast { @@ -157,7 +172,7 @@ impl<'a> Evaluator<'a> { expr, dest_type, } => { - let value = self.run(expr)?; + let value = self.run_impl(expr)?; if *is_try { self.run_try_cast(*span, expr.data_type(), dest_type, value) } else { @@ -166,7 +181,7 @@ impl<'a> Evaluator<'a> { } Expr::Catch { expr, data_type, .. - } => Ok(match self.run(expr) { + } => Ok(match self.run_impl(expr) { Ok(value) => match value { Value::Scalar(scalar) => { Value::Scalar(Scalar::Tuple(vec![scalar, Scalar::Null])) @@ -179,14 +194,26 @@ impl<'a> Evaluator<'a> { }) } }, - Err(err) => { - let msg = err.to_string(); - let res_type = &data_type.as_tuple().unwrap()[0]; - let res_val = - ColumnBuilder::repeat(&res_type.default_value().as_ref(), 1, res_type) - .build_scalar(); - let err_val = Scalar::String(msg.into_bytes()); - Value::Scalar(Scalar::Tuple(vec![res_val, err_val])) + Err((_, value, bitmap, err)) => { + let num_rows = self.input_columns.num_rows(); + let inner_type = data_type.as_tuple().unwrap().first().unwrap(); + let value_col = value.convert_to_full_column(inner_type, num_rows); + let err_scalar = Scalar::String(err.into_bytes()); + let err_col = + ColumnBuilder::repeat(&err_scalar.as_ref(), num_rows, &DataType::String) + .build(); + + // If the element in the bitmap is true, + // it means the corresponding row is error. + let bitmap = bitmap.not(); + let err_col = Column::Nullable(Box::new(NullableColumn { + column: err_col, + validity: bitmap, + })); + Value::Column(Column::Tuple { + fields: vec![value_col, err_col], + len: num_rows, + }) } }), }; @@ -228,7 +255,7 @@ impl<'a> Evaluator<'a> { src_type: &DataType, dest_type: &DataType, value: Value, - ) -> Result> { + ) -> EvalResult> { if src_type == dest_type { return Ok(value); } @@ -269,17 +296,27 @@ impl<'a> Evaluator<'a> { other => unreachable!("source: {}", other), }, (DataType::Nullable(inner_src_ty), _) => match value { - Value::Scalar(Scalar::Null) => Err(ErrorCode::Internal(format!( - "unable to cast type `{src_type}` to type `{dest_type}`" - )) - .set_span(span)), + Value::Scalar(Scalar::Null) => { + let mut bitmap = MutableBitmap::new(); + bitmap.extend_constant(self.input_columns.num_rows(), false); + return Err(( + span, + Value::Scalar(dest_type.default_value()), + bitmap.into(), + format!("unable to cast type `{src_type}` to type `{dest_type}`"), + )); + } Value::Scalar(_) => self.run_cast(span, inner_src_ty, dest_type, value), Value::Column(Column::Nullable(col)) => { if col.validity.unset_bits() > 0 { - return Err(ErrorCode::Internal(format!( - "unable to cast `NULL` to type `{dest_type}`" - )) - .set_span(span)); + let mut bitmap = MutableBitmap::new(); + bitmap.extend_constant(self.input_columns.num_rows(), false); + return Err(( + span, + Value::Scalar(dest_type.default_value()), + bitmap.into(), + format!("unable to cast type `NULL` to type `{dest_type}`"), + )); } let column = self .run_cast(span, inner_src_ty, dest_type, Value::Column(col.column))? @@ -386,7 +423,7 @@ impl<'a> Evaluator<'a> { self.run_cast(span, src_ty, dest_ty, Value::Scalar(field)) .map(|val| val.into_scalar().unwrap()) }) - .collect::>>()?; + .collect::>>()?; Ok(Value::Scalar(Scalar::Tuple(new_fields))) } Value::Column(Column::Tuple { fields, len }) => { @@ -398,7 +435,7 @@ impl<'a> Evaluator<'a> { self.run_cast(span, src_ty, dest_ty, Value::Column(field)) .map(|val| val.into_column().unwrap()) }) - .collect::>()?; + .collect::>()?; Ok(Value::Column(Column::Tuple { fields: new_fields, len, @@ -408,10 +445,16 @@ impl<'a> Evaluator<'a> { } } - _ => Err(ErrorCode::Internal(format!( - "unable to cast type `{src_type}` to type `{dest_type}`" - )) - .set_span(span)), + _ => { + let mut bitmap = MutableBitmap::new(); + bitmap.extend_constant(self.input_columns.num_rows(), false); + Err(( + span, + Value::Scalar(dest_type.default_value()), + bitmap.into(), + format!("unable to cast type `{src_type}` to type `{dest_type}`"), + )) + } } } @@ -421,7 +464,7 @@ impl<'a> Evaluator<'a> { src_type: &DataType, dest_type: &DataType, value: Value, - ) -> Result> { + ) -> EvalResult> { if src_type == dest_type { return Ok(value); } @@ -567,7 +610,7 @@ impl<'a> Evaluator<'a> { .into_scalar() .unwrap()) }) - .collect::>()?; + .collect::>()?; Ok(Value::Scalar(Scalar::Tuple(new_fields))) } Value::Column(Column::Tuple { fields, len }) => { @@ -581,7 +624,7 @@ impl<'a> Evaluator<'a> { .into_column() .unwrap()) }) - .collect::>()?; + .collect::>()?; let new_col = Column::Tuple { fields: new_fields, len, @@ -592,10 +635,16 @@ impl<'a> Evaluator<'a> { } } - _ => Err(ErrorCode::Internal(format!( - "unable to cast type `{src_type}` to type `{dest_type}`" - )) - .set_span(span)), + _ => { + let mut bitmap = MutableBitmap::new(); + bitmap.extend_constant(self.input_columns.num_rows(), false); + Err(( + span, + Value::Scalar(dest_type.default_value()), + bitmap.into(), + format!("unable to cast type `{src_type}` to type `{dest_type}`"), + )) + } } } @@ -606,7 +655,7 @@ impl<'a> Evaluator<'a> { dest_type: &DataType, value: Value, cast_fn: &str, - ) -> Result>> { + ) -> EvalResult>> { let expr = Expr::ColumnRef { span, id: 0, @@ -641,7 +690,7 @@ impl<'a> Evaluator<'a> { num_rows, ); let evaluator = Evaluator::new(&block, self.func_ctx, self.fn_registry); - Ok(Some(evaluator.run(&cast_expr)?)) + Ok(Some(evaluator.run_impl(&cast_expr)?)) } } @@ -799,28 +848,70 @@ impl<'a, Index: ColumnIndex> ConstantFolder<'a, Index> { data_type, expr, } => { - let (inner, inner_domain) = self.fold_once(expr); + let (inner_expr, inner_domain) = self.fold_once(expr); let inner_type = &data_type.as_tuple().unwrap()[0]; - // If the inner expression is constant, we can safely remove the `catch` expression. - if inner.as_constant().is_some() { - return (inner, inner_domain); - } - - match inner_domain.as_ref().and_then(Domain::as_singleton) { - Some(scalar) => ( - Expr::Constant { + if inner_expr.as_constant().is_some() { + return ( + Expr::Catch { span: *span, - scalar, - data_type: inner_type.clone(), + data_type: data_type.clone(), + expr: Box::new(inner_expr), }, - inner_domain, - ), + inner_domain.map(|d| { + Domain::Tuple(vec![ + d, + Domain::Nullable(NullableDomain { + has_null: true, + value: None, + }), + ]) + }), + ); + } + + match inner_domain { + // If the inner domain is not None, + // it means the inner expr will not throw an error. + Some(d) => match d.as_singleton() { + Some(scalar) => ( + Expr::Catch { + span: *span, + data_type: data_type.clone(), + expr: Box::new(Expr::Constant { + span: *span, + scalar, + data_type: inner_type.clone(), + }), + }, + Some(Domain::Tuple(vec![ + d, + Domain::Nullable(NullableDomain { + has_null: true, + value: None, + }), + ])), + ), + None => ( + Expr::Catch { + span: *span, + data_type: data_type.clone(), + expr: Box::new(inner_expr), + }, + Some(Domain::Tuple(vec![ + d, + Domain::Nullable(NullableDomain { + has_null: true, + value: None, + }), + ])), + ), + }, None => ( Expr::Catch { span: *span, data_type: data_type.clone(), - expr: Box::new(inner), + expr: Box::new(inner_expr), }, None, ), diff --git a/src/query/expression/src/function.rs b/src/query/expression/src/function.rs index 38a18c499aac7..97a6d31c546da 100755 --- a/src/query/expression/src/function.rs +++ b/src/query/expression/src/function.rs @@ -18,8 +18,6 @@ use std::sync::Arc; use common_arrow::arrow::bitmap::Bitmap; use common_arrow::arrow::bitmap::MutableBitmap; -use common_exception::ErrorCode; -use common_exception::Result; use common_exception::Span; use itertools::Itertools; use serde::Deserialize; @@ -36,6 +34,7 @@ use crate::values::Value; use crate::values::ValueRef; use crate::Column; use crate::ColumnIndex; +use crate::EvalResult; use crate::Expr; use crate::FunctionDomain; use crate::Scalar; @@ -66,6 +65,8 @@ pub struct EvalContext<'a> { /// default value in nullable's inner column. pub validity: Option, pub errors: Option<(MutableBitmap, String)>, + /// Some error is already rendered, so we don't need to render it again. + pub already_rendered: bool, } impl<'a> EvalContext<'a> { @@ -93,29 +94,41 @@ impl<'a> EvalContext<'a> { } } - pub fn render_error(&self, span: Span, args: &[Value], func_name: &str) -> Result<()> { + #[inline] + pub fn set_already_rendered(&mut self) { + self.already_rendered = true; + } + + pub fn render_error( + &self, + span: Span, + args: &[Value], + result: &Value, + func_name: &str, + ) -> EvalResult<()> { match &self.errors { Some((valids, error)) => { - let first_error_row = valids - .iter() - .enumerate() - .filter(|(_, valid)| !valid) - .take(1) - .next() - .unwrap() - .0; - let args = args - .iter() - .map(|arg| { - let arg_ref = arg.as_ref(); - arg_ref.index(first_error_row).unwrap().to_string() - }) - .join(", "); - - Err(ErrorCode::Internal(format!( - "{error} while evaluating function `{func_name}({args})`" - )) - .set_span(span)) + let msg = if self.already_rendered { + error.clone() + } else { + let first_error_row = valids + .iter() + .enumerate() + .filter(|(_, valid)| !valid) + .take(1) + .next() + .unwrap() + .0; + let args = args + .iter() + .map(|arg| { + let arg_ref = arg.as_ref(); + arg_ref.index(first_error_row).unwrap().to_string() + }) + .join(", "); + format!("{error} while evaluating function `{func_name}({args})`") + }; + Err((span, result.clone(), valids.clone().into(), msg)) } None => Ok(()), } From 746f127ddd439bdf3ad17ce035af09e8beccc5bc Mon Sep 17 00:00:00 2001 From: RinChanNOWWW Date: Thu, 9 Mar 2023 21:18:41 +0800 Subject: [PATCH 3/6] Modify if and multi_if. --- src/query/expression/src/type_check.rs | 13 +- src/query/functions/src/scalars/control.rs | 130 +++++++++++++++--- .../functions/tests/it/scalars/control.rs | 19 +++ .../tests/it/scalars/testdata/control.txt | 103 ++++++++++++-- .../query/02_function/02_0010_function_if | 37 ++++- 5 files changed, 265 insertions(+), 37 deletions(-) diff --git a/src/query/expression/src/type_check.rs b/src/query/expression/src/type_check.rs index 6728aaedb7ea3..d5ac3592af173 100755 --- a/src/query/expression/src/type_check.rs +++ b/src/query/expression/src/type_check.rs @@ -77,10 +77,21 @@ pub fn check( args, params, } => { - let args_expr: Vec<_> = args + let mut args_expr: Vec<_> = args .iter() .map(|arg| check(arg, fn_registry)) .try_collect()?; + + if name == "if" || name == "multi_if" { + args_expr + .iter_mut() + .skip(1) + .step_by(2) + .for_each(|expr| *expr = expr.wrap_catch()); + let last = args_expr.last_mut().unwrap(); + *last = last.wrap_catch() + } + check_function(*span, name, params, &args_expr, fn_registry) } } diff --git a/src/query/functions/src/scalars/control.rs b/src/query/functions/src/scalars/control.rs index 337db0e7e9055..6f60400f16fb9 100644 --- a/src/query/functions/src/scalars/control.rs +++ b/src/query/functions/src/scalars/control.rs @@ -17,6 +17,7 @@ use std::sync::Arc; use common_expression::types::boolean::BooleanDomain; use common_expression::types::nullable::NullableColumn; use common_expression::types::nullable::NullableDomain; +use common_expression::types::AnyType; use common_expression::types::BooleanType; use common_expression::types::DataType; use common_expression::types::GenericType; @@ -34,6 +35,33 @@ use common_expression::ScalarRef; use common_expression::Value; use common_expression::ValueRef; +/// Each result argument of `if` and `multi_if` is a tuple of (value, error). +/// This function is used to split the [`ValueRef`] into the two parts. +#[inline] +fn unwrap_error<'a>( + val_with_error: &ValueRef<'a, AnyType>, +) -> (ValueRef<'a, AnyType>, ValueRef<'a, AnyType>) { + match val_with_error { + ValueRef::Scalar(scalar) => { + let inner = scalar.as_tuple().unwrap(); + let value = inner.first().unwrap().clone(); + let error = inner.last().unwrap().clone(); + (ValueRef::Scalar(value), ValueRef::Scalar(error)) + } + ValueRef::Column(col) => { + let (inner_col, _) = col.as_tuple().unwrap(); + let value = ValueRef::Column(inner_col.first().unwrap().clone()); + let error = ValueRef::Column(inner_col.last().unwrap().clone()); + (value, error) + } + } +} + +#[inline(always)] +fn unwrap_domain(domain: &Domain) -> Domain { + domain.as_tuple().unwrap()[0].clone() +} + pub fn register(registry: &mut FunctionRegistry) { // special case for multi_if to have better performance in fixed size loop registry.register_function_factory("if", |_, args_type| { @@ -45,8 +73,14 @@ pub fn register(registry: &mut FunctionRegistry) { name: "if".to_string(), args_type: vec![ DataType::Nullable(Box::new(DataType::Boolean)), - DataType::Generic(0), - DataType::Generic(0), + DataType::Tuple(vec![ + DataType::Generic(0), + DataType::Nullable(Box::new(DataType::String)), + ]), + DataType::Tuple(vec![ + DataType::Generic(0), + DataType::Nullable(Box::new(DataType::String)), + ]), ], return_type: DataType::Generic(0), property: FunctionProperty::default(), @@ -67,16 +101,16 @@ pub fn register(registry: &mut FunctionRegistry) { let domain = match (has_true, has_null_or_false) { (true, false) => { - return FunctionDomain::Domain(args_domain[1].clone()); + return FunctionDomain::Domain(unwrap_domain(&args_domain[1])); } (false, true) => None, - (true, true) => Some(args_domain[1].clone()), + (true, true) => Some(unwrap_domain(&args_domain[1])), _ => unreachable!(), }; FunctionDomain::Domain(match domain { - Some(domain) => domain.merge(args_domain.last().unwrap()), - None => args_domain.last().unwrap().clone(), + Some(domain) => domain.merge(&unwrap_domain(args_domain.last().unwrap())), + None => unwrap_domain(args_domain.last().unwrap()), }) }), eval: Box::new(|args, ctx| { @@ -88,6 +122,12 @@ pub fn register(registry: &mut FunctionRegistry) { let mut output_builder = ColumnBuilder::with_capacity(&ctx.generics[0], len.unwrap_or(1)); + let (values1, errors1) = unwrap_error(&args[1]); + let (values2, errors2) = unwrap_error(&args[2]); + + let values = vec![values1, values2]; + let errors = vec![errors1, errors2]; + for row_idx in 0..(len.unwrap_or(1)) { let flag = match &args[0] { ValueRef::Scalar(ScalarRef::Null) => false, @@ -98,13 +138,28 @@ pub fn register(registry: &mut FunctionRegistry) { })) => validity.get_bit(row_idx) && cond_col.get_bit(row_idx), _ => unreachable!(), }; - let result_idx = if flag { 1 } else { 2 }; - match &args[result_idx] { + let result_idx = 1 - flag as usize; // if flag { 0 } else { 1 } + match &errors[result_idx] { + ValueRef::Column(Column::Nullable(col)) => { + match unsafe { &col.index_unchecked(row_idx) } { + Some(ScalarRef::String(err)) => { + ctx.set_error(row_idx, &String::from_utf8_lossy(err)); + ctx.set_already_rendered(); + output_builder.push_default(); + continue; + } + _ => {} + } + } + _ => {} + } + match &values[result_idx] { ValueRef::Scalar(scalar) => { output_builder.push(scalar.clone()); } ValueRef::Column(col) => { - output_builder.push(col.index(row_idx).unwrap()); + let inner = unsafe { col.index_unchecked(row_idx) }; + output_builder.push(inner); } } } @@ -124,10 +179,16 @@ pub fn register(registry: &mut FunctionRegistry) { .flat_map(|_| { [ DataType::Nullable(Box::new(DataType::Boolean)), - DataType::Generic(0), + DataType::Tuple(vec![ + DataType::Generic(0), + DataType::Nullable(Box::new(DataType::String)), + ]), ] }) - .chain([DataType::Generic(0)]) + .chain([DataType::Tuple(vec![ + DataType::Generic(0), + DataType::Nullable(Box::new(DataType::String)), + ])]) .collect(); Some(Arc::new(Function { @@ -154,32 +215,35 @@ pub fn register(registry: &mut FunctionRegistry) { }; match (&mut domain, has_true, has_null_or_false) { (None, true, false) => { - return FunctionDomain::Domain(args_domain[cond_idx + 1].clone()); + return FunctionDomain::Domain(unwrap_domain( + &args_domain[cond_idx + 1], + )); } (None, false, true) => { continue; } (None, true, true) => { - domain = Some(args_domain[cond_idx + 1].clone()); + domain = Some(unwrap_domain(&args_domain[cond_idx + 1])); } (Some(prev_domain), true, false) => { return FunctionDomain::Domain( - prev_domain.merge(&args_domain[cond_idx + 1]), + prev_domain.merge(&unwrap_domain(&args_domain[cond_idx + 1])), ); } (Some(_), false, true) => { continue; } (Some(prev_domain), true, true) => { - domain = Some(prev_domain.merge(&args_domain[cond_idx + 1])); + domain = + Some(prev_domain.merge(&unwrap_domain(&args_domain[cond_idx + 1]))); } (_, false, false) => unreachable!(), } } FunctionDomain::Domain(match domain { - Some(domain) => domain.merge(args_domain.last().unwrap()), - None => args_domain.last().unwrap().clone(), + Some(domain) => domain.merge(&unwrap_domain(args_domain.last().unwrap())), + None => unwrap_domain(args_domain.last().unwrap()), }) }), eval: Box::new(|args, ctx| { @@ -190,6 +254,14 @@ pub fn register(registry: &mut FunctionRegistry) { let mut output_builder = ColumnBuilder::with_capacity(&ctx.generics[0], len.unwrap_or(1)); + + let (values, errors) = args + .iter() + .skip(1) + .step_by(2) + .chain(vec![args.last().unwrap()]) + .map(unwrap_error) + .unzip::<_, _, Vec<_>, Vec<_>>(); for row_idx in 0..(len.unwrap_or(1)) { let result_idx = (0..args.len() - 1) .step_by(2) @@ -204,19 +276,33 @@ pub fn register(registry: &mut FunctionRegistry) { }) .map(|idx| { // The next argument of true condition is the value to return. - idx + 1 + idx / 2 }) .unwrap_or_else(|| { // If no true condition is found, the last argument is the value to return. - args.len() - 1 + values.len() - 1 }); - - match &args[result_idx] { + match &errors[result_idx] { + ValueRef::Column(Column::Nullable(col)) => { + match unsafe { &col.index_unchecked(row_idx) } { + Some(ScalarRef::String(err)) => { + ctx.set_error(row_idx, &String::from_utf8_lossy(err)); + ctx.set_already_rendered(); + output_builder.push_default(); + continue; + } + _ => {} + } + } + _ => {} + } + match &values[result_idx] { ValueRef::Scalar(scalar) => { output_builder.push(scalar.clone()); } ValueRef::Column(col) => { - output_builder.push(col.index(row_idx).unwrap()); + let inner = unsafe { col.index_unchecked(row_idx) }; + output_builder.push(inner); } } } diff --git a/src/query/functions/tests/it/scalars/control.rs b/src/query/functions/tests/it/scalars/control.rs index 922b31948b3cf..8583dbb432d24 100644 --- a/src/query/functions/tests/it/scalars/control.rs +++ b/src/query/functions/tests/it/scalars/control.rs @@ -38,6 +38,9 @@ fn test_multi_if(file: &mut impl Write) { run_ast(file, "multi_if(true, 1, true, NULL, 2)", &[]); run_ast(file, "multi_if(true, 1, NULL)", &[]); run_ast(file, "multi_if(false, 1, NULL)", &[]); + run_ast(file, "multi_if(true, 1, 1 / 0)", &[]); + run_ast(file, "multi_if(false, 1 / 0, 1)", &[]); + run_ast(file, "multi_if(false, 1, 1 / 0)", &[]); run_ast(file, "multi_if(cond_a, expr_true, expr_else)", &[ ( "cond_a", @@ -101,6 +104,22 @@ fn test_multi_if(file: &mut impl Write) { ("expr_else", Int64Type::from_data(vec![9i64, 10, 11, 12])), ], ); + run_ast(file, "multi_if(cond_a, 1 / expr_a, expr_else)", &[ + ( + "cond_a", + BooleanType::from_data(vec![true, true, false, false]), + ), + ("expr_a", Int64Type::from_data(vec![1i64, 2, 0, 4])), + ("expr_else", Int64Type::from_data(vec![9i64, 10, 11, 12])), + ]); + run_ast(file, "multi_if(cond_a, 1 / expr_a, expr_else)", &[ + ( + "cond_a", + BooleanType::from_data(vec![true, true, true, false]), + ), + ("expr_a", Int64Type::from_data(vec![1i64, 2, 0, 4])), + ("expr_else", Int64Type::from_data(vec![9i64, 10, 11, 12])), + ]); } fn test_is_not_null(file: &mut impl Write) { diff --git a/src/query/functions/tests/it/scalars/testdata/control.txt b/src/query/functions/tests/it/scalars/testdata/control.txt index 619100db69871..7a97d7610b8a1 100644 --- a/src/query/functions/tests/it/scalars/testdata/control.txt +++ b/src/query/functions/tests/it/scalars/testdata/control.txt @@ -1,6 +1,6 @@ ast : multi_if(false, 1, false, 2, NULL) raw expr : multi_if(false, 1_u8, false, 2_u8, NULL) -checked expr : multi_if(CAST(false AS Boolean NULL), CAST(1_u8 AS UInt8 NULL), CAST(false AS Boolean NULL), CAST(2_u8 AS UInt8 NULL), CAST(NULL AS UInt8 NULL)) +checked expr : multi_if(CAST(false AS Boolean NULL), CAST(CATCH(1_u8) AS Tuple(UInt8 NULL, String NULL)), CAST(false AS Boolean NULL), CAST(CATCH(2_u8) AS Tuple(UInt8 NULL, String NULL)), CAST(CATCH(NULL) AS Tuple(UInt8 NULL, String NULL))) optimized expr : NULL output type : UInt8 NULL output domain : {NULL} @@ -9,7 +9,7 @@ output : NULL ast : multi_if(true, 1, NULL, 2, NULL) raw expr : multi_if(true, 1_u8, NULL, 2_u8, NULL) -checked expr : multi_if(CAST(true AS Boolean NULL), CAST(1_u8 AS UInt8 NULL), CAST(NULL AS Boolean NULL), CAST(2_u8 AS UInt8 NULL), CAST(NULL AS UInt8 NULL)) +checked expr : multi_if(CAST(true AS Boolean NULL), CAST(CATCH(1_u8) AS Tuple(UInt8 NULL, String NULL)), CAST(NULL AS Boolean NULL), CAST(CATCH(2_u8) AS Tuple(UInt8 NULL, String NULL)), CAST(CATCH(NULL) AS Tuple(UInt8 NULL, String NULL))) optimized expr : 1_u8 output type : UInt8 NULL output domain : {1..=1} @@ -18,7 +18,7 @@ output : 1 ast : multi_if(false, 1, true, 2, NULL) raw expr : multi_if(false, 1_u8, true, 2_u8, NULL) -checked expr : multi_if(CAST(false AS Boolean NULL), CAST(1_u8 AS UInt8 NULL), CAST(true AS Boolean NULL), CAST(2_u8 AS UInt8 NULL), CAST(NULL AS UInt8 NULL)) +checked expr : multi_if(CAST(false AS Boolean NULL), CAST(CATCH(1_u8) AS Tuple(UInt8 NULL, String NULL)), CAST(true AS Boolean NULL), CAST(CATCH(2_u8) AS Tuple(UInt8 NULL, String NULL)), CAST(CATCH(NULL) AS Tuple(UInt8 NULL, String NULL))) optimized expr : 2_u8 output type : UInt8 NULL output domain : {2..=2} @@ -27,7 +27,7 @@ output : 2 ast : multi_if(true, 1, true, 2, NULL) raw expr : multi_if(true, 1_u8, true, 2_u8, NULL) -checked expr : multi_if(CAST(true AS Boolean NULL), CAST(1_u8 AS UInt8 NULL), CAST(true AS Boolean NULL), CAST(2_u8 AS UInt8 NULL), CAST(NULL AS UInt8 NULL)) +checked expr : multi_if(CAST(true AS Boolean NULL), CAST(CATCH(1_u8) AS Tuple(UInt8 NULL, String NULL)), CAST(true AS Boolean NULL), CAST(CATCH(2_u8) AS Tuple(UInt8 NULL, String NULL)), CAST(CATCH(NULL) AS Tuple(UInt8 NULL, String NULL))) optimized expr : 1_u8 output type : UInt8 NULL output domain : {1..=1} @@ -36,7 +36,7 @@ output : 1 ast : multi_if(true, 1, true, NULL, 2) raw expr : multi_if(true, 1_u8, true, NULL, 2_u8) -checked expr : multi_if(CAST(true AS Boolean NULL), CAST(1_u8 AS UInt8 NULL), CAST(true AS Boolean NULL), CAST(NULL AS UInt8 NULL), CAST(2_u8 AS UInt8 NULL)) +checked expr : multi_if(CAST(true AS Boolean NULL), CAST(CATCH(1_u8) AS Tuple(UInt8 NULL, String NULL)), CAST(true AS Boolean NULL), CAST(CATCH(NULL) AS Tuple(UInt8 NULL, String NULL)), CAST(CATCH(2_u8) AS Tuple(UInt8 NULL, String NULL))) optimized expr : 1_u8 output type : UInt8 NULL output domain : {1..=1} @@ -45,7 +45,7 @@ output : 1 ast : multi_if(true, 1, NULL) raw expr : multi_if(true, 1_u8, NULL) -checked expr : multi_if(CAST(true AS Boolean NULL), CAST(1_u8 AS UInt8 NULL), CAST(NULL AS UInt8 NULL)) +checked expr : multi_if(CAST(true AS Boolean NULL), CAST(CATCH(1_u8) AS Tuple(UInt8 NULL, String NULL)), CAST(CATCH(NULL) AS Tuple(UInt8 NULL, String NULL))) optimized expr : 1_u8 output type : UInt8 NULL output domain : {1..=1} @@ -54,16 +54,64 @@ output : 1 ast : multi_if(false, 1, NULL) raw expr : multi_if(false, 1_u8, NULL) -checked expr : multi_if(CAST(false AS Boolean NULL), CAST(1_u8 AS UInt8 NULL), CAST(NULL AS UInt8 NULL)) +checked expr : multi_if(CAST(false AS Boolean NULL), CAST(CATCH(1_u8) AS Tuple(UInt8 NULL, String NULL)), CAST(CATCH(NULL) AS Tuple(UInt8 NULL, String NULL))) optimized expr : NULL output type : UInt8 NULL output domain : {NULL} output : NULL +ast : multi_if(true, 1, 1 / 0) +raw expr : multi_if(true, 1_u8, divide(1_u8, 0_u8)) +checked expr : multi_if(CAST(true AS Boolean NULL), CAST(CATCH(1_u8) AS Tuple(Float64, String NULL)), CATCH(divide(1_u8, 0_u8))) +optimized expr : multi_if(true, (1_f64, NULL), CATCH(divide(1_u8, 0_u8))) +evaluation: ++--------+---------+ +| | Output | ++--------+---------+ +| Type | Float64 | +| Domain | Unknown | +| Row 0 | 1 | ++--------+---------+ +evaluation (internal): ++--------+--------------+ +| Column | Data | ++--------+--------------+ +| Output | Float64([1]) | ++--------+--------------+ + + +ast : multi_if(false, 1 / 0, 1) +raw expr : multi_if(false, divide(1_u8, 0_u8), 1_u8) +checked expr : multi_if(CAST(false AS Boolean NULL), CATCH(divide(1_u8, 0_u8)), CAST(CATCH(1_u8) AS Tuple(Float64, String NULL))) +optimized expr : multi_if(false, CATCH(divide(1_u8, 0_u8)), (1_f64, NULL)) +evaluation: ++--------+---------+ +| | Output | ++--------+---------+ +| Type | Float64 | +| Domain | Unknown | +| Row 0 | 1 | ++--------+---------+ +evaluation (internal): ++--------+--------------+ +| Column | Data | ++--------+--------------+ +| Output | Float64([1]) | ++--------+--------------+ + + +error: + --> SQL:1:1 + | +1 | multi_if(false, 1, 1 / 0) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ divided by zero while evaluating function `divide(1, 0)` + + + ast : multi_if(cond_a, expr_true, expr_else) raw expr : multi_if(cond_a::Boolean, expr_true::Int64, expr_else::Int64 NULL) -checked expr : multi_if(CAST(cond_a AS Boolean NULL), CAST(expr_true AS Int64 NULL), expr_else) +checked expr : multi_if(CAST(cond_a AS Boolean NULL), CAST(CATCH(expr_true) AS Tuple(Int64 NULL, String NULL)), CATCH(expr_else)) evaluation: +--------+---------------+-----------+------------------+------------------+ | | cond_a | expr_true | expr_else | Output | @@ -88,7 +136,7 @@ evaluation (internal): ast : multi_if(cond_a, expr_true, expr_else) raw expr : multi_if(cond_a::Boolean, expr_true::Int64, expr_else::Int64 NULL) -checked expr : multi_if(CAST(cond_a AS Boolean NULL), CAST(expr_true AS Int64 NULL), expr_else) +checked expr : multi_if(CAST(cond_a AS Boolean NULL), CAST(CATCH(expr_true) AS Tuple(Int64 NULL, String NULL)), CATCH(expr_else)) evaluation: +--------+---------------+-----------+------------------+------------------+ | | cond_a | expr_true | expr_else | Output | @@ -113,7 +161,7 @@ evaluation (internal): ast : multi_if(cond_a, expr_a, cond_b, expr_b, expr_else) raw expr : multi_if(cond_a::Boolean, expr_a::Int64, cond_b::Boolean NULL, expr_b::Int64, expr_else::Int64 NULL) -checked expr : multi_if(CAST(cond_a AS Boolean NULL), CAST(expr_a AS Int64 NULL), cond_b, CAST(expr_b AS Int64 NULL), expr_else) +checked expr : multi_if(CAST(cond_a AS Boolean NULL), CAST(CATCH(expr_a) AS Tuple(Int64 NULL, String NULL)), cond_b, CAST(CATCH(expr_b) AS Tuple(Int64 NULL, String NULL)), CATCH(expr_else)) evaluation: +--------+---------------+---------+-----------------+---------+-------------------+-------------------+ | | cond_a | expr_a | cond_b | expr_b | expr_else | Output | @@ -140,7 +188,7 @@ evaluation (internal): ast : multi_if(cond_a, expr_a, cond_b, expr_b, expr_else) raw expr : multi_if(cond_a::Boolean, expr_a::Int64, cond_b::Boolean, expr_b::Int64, expr_else::Int64) -checked expr : multi_if(CAST(cond_a AS Boolean NULL), expr_a, CAST(cond_b AS Boolean NULL), expr_b, expr_else) +checked expr : multi_if(CAST(cond_a AS Boolean NULL), CATCH(expr_a), CAST(cond_b AS Boolean NULL), CATCH(expr_b), CATCH(expr_else)) evaluation: +--------+---------------+---------+---------------+---------+-----------+----------+ | | cond_a | expr_a | cond_b | expr_b | expr_else | Output | @@ -165,6 +213,39 @@ evaluation (internal): +-----------+------------------------+ +ast : multi_if(cond_a, 1 / expr_a, expr_else) +raw expr : multi_if(cond_a::Boolean, divide(1_u8, expr_a::Int64), expr_else::Int64) +checked expr : multi_if(CAST(cond_a AS Boolean NULL), CATCH(divide(1_u8, expr_a)), CAST(CATCH(expr_else) AS Tuple(Float64, String NULL))) +evaluation: ++--------+---------------+---------+-----------+---------+ +| | cond_a | expr_a | expr_else | Output | ++--------+---------------+---------+-----------+---------+ +| Type | Boolean | Int64 | Int64 | Float64 | +| Domain | {FALSE, TRUE} | {0..=4} | {9..=12} | Unknown | +| Row 0 | true | 1 | 9 | 1 | +| Row 1 | true | 2 | 10 | 0.5 | +| Row 2 | false | 0 | 11 | 11 | +| Row 3 | false | 4 | 12 | 12 | ++--------+---------------+---------+-----------+---------+ +evaluation (internal): ++-----------+---------------------------+ +| Column | Data | ++-----------+---------------------------+ +| cond_a | Boolean([0b____0011]) | +| expr_a | Int64([1, 2, 0, 4]) | +| expr_else | Int64([9, 10, 11, 12]) | +| Output | Float64([1, 0.5, 11, 12]) | ++-----------+---------------------------+ + + +error: + --> SQL:1:1 + | +1 | multi_if(cond_a, 1 / expr_a, expr_else) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ divided by zero while evaluating function `divide(1, 0)` + + + ast : is_not_null(1) raw expr : is_not_null(1_u8) checked expr : is_not_null(CAST(1_u8 AS UInt8 NULL)) diff --git a/tests/sqllogictests/suites/query/02_function/02_0010_function_if b/tests/sqllogictests/suites/query/02_function/02_0010_function_if index 5a64a448244a0..7c74b1c3783a1 100644 --- a/tests/sqllogictests/suites/query/02_function/02_0010_function_if +++ b/tests/sqllogictests/suites/query/02_function/02_0010_function_if @@ -34,6 +34,29 @@ select if(number<1, true, null) from numbers(3) order by number NULL NULL +query F +select if(number<4, number, number / 0) from numbers(3) order by number +---- +0.0 +1.0 +2.0 + +query F +select if(number>4, number / 0, number) from numbers(3) order by number +---- +0.0 +1.0 +2.0 + +statement error 1001 +select if(number<4, number / 0, number) from numbers(3) order by number + +query F +select if (number > 0, 1 / number, null) from numbers(2); +---- +NULL +1.0 + query T select typeof(if(number % 3 = 0, to_uint32(1), to_int64(3))) from numbers(10) limit 1 @@ -64,6 +87,17 @@ multi-if statement error 1065 select multi_if(number = 4, 3) from numbers(1) +query F +select multi_if(number = 1, number, number = 0, number, number / 0) from numbers(1) +---- +0.0 + +query F +select multi_if (number > 0, 1 / number, null) from numbers(2); +---- +NULL +1.0 + query T select multi_if(number = 4, 3::VARIANT, number = 5, null, number = 6, 'a'::VARIANT, null) from numbers(10) ---- @@ -117,6 +151,3 @@ NULL 1 NULL NULL statement ok drop table t - - - From 2e6125921817dc0866a4c8330e0bdef9966b8e9a Mon Sep 17 00:00:00 2001 From: RinChanNOWWW Date: Thu, 9 Mar 2023 22:13:09 +0800 Subject: [PATCH 4/6] Fix clippy. --- src/query/functions/src/scalars/control.rs | 40 +++++++++------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/src/query/functions/src/scalars/control.rs b/src/query/functions/src/scalars/control.rs index 6f60400f16fb9..9a72677050543 100644 --- a/src/query/functions/src/scalars/control.rs +++ b/src/query/functions/src/scalars/control.rs @@ -139,19 +139,15 @@ pub fn register(registry: &mut FunctionRegistry) { _ => unreachable!(), }; let result_idx = 1 - flag as usize; // if flag { 0 } else { 1 } - match &errors[result_idx] { - ValueRef::Column(Column::Nullable(col)) => { - match unsafe { &col.index_unchecked(row_idx) } { - Some(ScalarRef::String(err)) => { - ctx.set_error(row_idx, &String::from_utf8_lossy(err)); - ctx.set_already_rendered(); - output_builder.push_default(); - continue; - } - _ => {} - } + if let ValueRef::Column(Column::Nullable(col)) = &errors[result_idx] { + if let Some(ScalarRef::String(err)) = + unsafe { &col.index_unchecked(row_idx) } + { + ctx.set_error(row_idx, &String::from_utf8_lossy(err)); + ctx.set_already_rendered(); + output_builder.push_default(); + continue; } - _ => {} } match &values[result_idx] { ValueRef::Scalar(scalar) => { @@ -282,19 +278,15 @@ pub fn register(registry: &mut FunctionRegistry) { // If no true condition is found, the last argument is the value to return. values.len() - 1 }); - match &errors[result_idx] { - ValueRef::Column(Column::Nullable(col)) => { - match unsafe { &col.index_unchecked(row_idx) } { - Some(ScalarRef::String(err)) => { - ctx.set_error(row_idx, &String::from_utf8_lossy(err)); - ctx.set_already_rendered(); - output_builder.push_default(); - continue; - } - _ => {} - } + if let ValueRef::Column(Column::Nullable(col)) = &errors[result_idx] { + if let Some(ScalarRef::String(err)) = + unsafe { &col.index_unchecked(row_idx) } + { + ctx.set_error(row_idx, &String::from_utf8_lossy(err)); + ctx.set_already_rendered(); + output_builder.push_default(); + continue; } - _ => {} } match &values[result_idx] { ValueRef::Scalar(scalar) => { From 64adf0b7df9900aed9410ca8861384eb653fa7ad Mon Sep 17 00:00:00 2001 From: RinChanNOWWW Date: Thu, 9 Mar 2023 22:19:00 +0800 Subject: [PATCH 5/6] Fix. --- src/query/expression/src/evaluator.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/query/expression/src/evaluator.rs b/src/query/expression/src/evaluator.rs index 3fd748ae629cc..cbb900dba461c 100644 --- a/src/query/expression/src/evaluator.rs +++ b/src/query/expression/src/evaluator.rs @@ -301,7 +301,7 @@ impl<'a> Evaluator<'a> { bitmap.extend_constant(self.input_columns.num_rows(), false); return Err(( span, - Value::Scalar(dest_type.default_value()), + Value::Scalar(Scalar::default_value(dest_type)), bitmap.into(), format!("unable to cast type `{src_type}` to type `{dest_type}`"), )); @@ -313,7 +313,7 @@ impl<'a> Evaluator<'a> { bitmap.extend_constant(self.input_columns.num_rows(), false); return Err(( span, - Value::Scalar(dest_type.default_value()), + Value::Scalar(Scalar::default_value(dest_type)), bitmap.into(), format!("unable to cast type `NULL` to type `{dest_type}`"), )); @@ -450,7 +450,7 @@ impl<'a> Evaluator<'a> { bitmap.extend_constant(self.input_columns.num_rows(), false); Err(( span, - Value::Scalar(dest_type.default_value()), + Value::Scalar(Scalar::default_value(dest_type)), bitmap.into(), format!("unable to cast type `{src_type}` to type `{dest_type}`"), )) @@ -640,7 +640,7 @@ impl<'a> Evaluator<'a> { bitmap.extend_constant(self.input_columns.num_rows(), false); Err(( span, - Value::Scalar(dest_type.default_value()), + Value::Scalar(Scalar::default_value(dest_type)), bitmap.into(), format!("unable to cast type `{src_type}` to type `{dest_type}`"), )) From 4b9c7c4e7c5697a6a97274cf481b60531ff6cd07 Mon Sep 17 00:00:00 2001 From: RinChanNOWWW Date: Fri, 10 Mar 2023 09:13:25 +0800 Subject: [PATCH 6/6] Fix test results. --- Cargo.lock | 2 +- src/query/expression/src/evaluator.rs | 6 +++--- .../sqllogictests/suites/mode/standalone/explain/limit.test | 2 +- .../suites/mode/standalone/explain/subquery.test | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 428478c5ab61c..c536ae19b82ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6113,7 +6113,7 @@ dependencies = [ [[package]] name = "openraft" version = "0.8.3" -source = "git+https://github.com/drmingdrmer/openraft?tag=v0.8.3-alpha.1#fc8cf0a20dcc9f53977fa55a037f16cf23cb7c26" +source = "git+https://github.com/drmingdrmer/openraft?tag=v0.8.3-alpha.2#ae28352a303d14dddbb20cd351d2c93d0b8db3a4" dependencies = [ "anyerror", "anyhow", diff --git a/src/query/expression/src/evaluator.rs b/src/query/expression/src/evaluator.rs index cbb900dba461c..16f2c6ca5b21b 100644 --- a/src/query/expression/src/evaluator.rs +++ b/src/query/expression/src/evaluator.rs @@ -299,12 +299,12 @@ impl<'a> Evaluator<'a> { Value::Scalar(Scalar::Null) => { let mut bitmap = MutableBitmap::new(); bitmap.extend_constant(self.input_columns.num_rows(), false); - return Err(( + Err(( span, Value::Scalar(Scalar::default_value(dest_type)), bitmap.into(), format!("unable to cast type `{src_type}` to type `{dest_type}`"), - )); + )) } Value::Scalar(_) => self.run_cast(span, inner_src_ty, dest_type, value), Value::Column(Column::Nullable(col)) => { @@ -315,7 +315,7 @@ impl<'a> Evaluator<'a> { span, Value::Scalar(Scalar::default_value(dest_type)), bitmap.into(), - format!("unable to cast type `NULL` to type `{dest_type}`"), + format!("unable to cast `NULL` to type `{dest_type}`"), )); } let column = self diff --git a/tests/sqllogictests/suites/mode/standalone/explain/limit.test b/tests/sqllogictests/suites/mode/standalone/explain/limit.test index 29395898c8728..39ee2a439b369 100644 --- a/tests/sqllogictests/suites/mode/standalone/explain/limit.test +++ b/tests/sqllogictests/suites/mode/standalone/explain/limit.test @@ -81,7 +81,7 @@ Limit ├── aggregate functions: [] ├── estimated rows: 0.33 └── Filter - ├── filters: [is_true(CAST(t.number (#0) AS UInt64 NULL) = TRY_CAST(if(CAST(is_not_null(scalar_subquery_4 (#4)) AS Boolean NULL), CAST(scalar_subquery_4 (#4) AS Int64 NULL), 0) AS UInt64 NULL))] + ├── filters: [is_true(CAST(t.number (#0) AS UInt64 NULL) = TRY_CAST(if(CAST(is_not_null(scalar_subquery_4 (#4)) AS Boolean NULL), CAST(CATCH(scalar_subquery_4 (#4)) AS Tuple(Int64 NULL, String NULL)), (0, NULL)) AS UInt64 NULL))] ├── estimated rows: 0.33 └── HashJoin ├── join type: SINGLE diff --git a/tests/sqllogictests/suites/mode/standalone/explain/subquery.test b/tests/sqllogictests/suites/mode/standalone/explain/subquery.test index 30d363b2f76dc..6c416eebe5ba1 100644 --- a/tests/sqllogictests/suites/mode/standalone/explain/subquery.test +++ b/tests/sqllogictests/suites/mode/standalone/explain/subquery.test @@ -2,7 +2,7 @@ query T explain select t.number from numbers(1) as t, numbers(1) as t1 where t.number = (select count(*) from numbers(1) as t2, numbers(1) as t3 where t.number = t2.number) ---- Filter -├── filters: [is_true(CAST(t.number (#0) AS UInt64 NULL) = TRY_CAST(if(CAST(is_not_null(scalar_subquery_4 (#4)) AS Boolean NULL), CAST(scalar_subquery_4 (#4) AS Int64 NULL), 0) AS UInt64 NULL))] +├── filters: [is_true(CAST(t.number (#0) AS UInt64 NULL) = TRY_CAST(if(CAST(is_not_null(scalar_subquery_4 (#4)) AS Boolean NULL), CAST(CATCH(scalar_subquery_4 (#4)) AS Tuple(Int64 NULL, String NULL)), (0, NULL)) AS UInt64 NULL))] ├── estimated rows: 0.33 └── HashJoin ├── join type: SINGLE @@ -337,7 +337,7 @@ query T explain select t.number from numbers(1) as t, numbers(1) as t1 where (select count(*) = 1 from numbers(1) where t.number = number) and t.number = t1.number ---- Filter -├── filters: [is_true(try_to_boolean(TRY_CAST(if(CAST(is_not_null(scalar_subquery_3 (#3)) AS Boolean NULL), CAST(TRY_CAST(scalar_subquery_3 (#3) AS UInt64 NULL) AS Int64 NULL), 0) AS UInt64 NULL)))] +├── filters: [is_true(try_to_boolean(TRY_CAST(if(CAST(is_not_null(scalar_subquery_3 (#3)) AS Boolean NULL), CAST(CATCH(TRY_CAST(scalar_subquery_3 (#3) AS UInt64 NULL)) AS Tuple(Int64 NULL, String NULL)), (0, NULL)) AS UInt64 NULL)))] ├── estimated rows: 0.33 └── HashJoin ├── join type: SINGLE