From 048e111eabaf98bf413055a877a3675b7ff2c22f Mon Sep 17 00:00:00 2001 From: Fedomn Date: Sat, 24 Dec 2022 20:39:50 +0800 Subject: [PATCH] feat(planner): support idempotent for add cast method Signed-off-by: Fedomn --- .../binder/expression/bind_cast_expression.rs | 17 ++++---- .../expression/bind_comparison_expression.rs | 40 ++++++------------- .../expression/bind_conjunction_expression.rs | 26 +++--------- .../binder/query_node/plan_select_node.rs | 4 +- .../tableref/bind_expression_list_ref.rs | 4 +- src/planner_v2/function_binder.rs | 18 +++------ 6 files changed, 36 insertions(+), 73 deletions(-) diff --git a/src/planner_v2/binder/expression/bind_cast_expression.rs b/src/planner_v2/binder/expression/bind_cast_expression.rs index e98e5e0..f87ee69 100644 --- a/src/planner_v2/binder/expression/bind_cast_expression.rs +++ b/src/planner_v2/binder/expression/bind_cast_expression.rs @@ -18,19 +18,22 @@ pub struct BoundCastExpression { } impl BoundCastExpression { - pub fn add_cast_to_type( - expr: BoundExpression, + /// If source_expr return_type is same type as target_type, return source_expr directly, + /// otherwise, add a cast expression to the source_expr. + pub fn try_add_cast_to_type( + source_expr: BoundExpression, target_type: LogicalType, - alias: String, try_cast: bool, ) -> Result { - // TODO: enhance alias to reduce outside alias assignment - let source_type = expr.return_type(); - assert!(source_type != target_type); + let source_type = source_expr.return_type(); + if source_type == target_type { + return Ok(source_expr); + } let cast_function = DefaultCastFunctions::get_cast_function(&source_type, &target_type)?; + let alias = format!("cast({} as {}", source_expr.alias(), target_type); let base = BoundExpressionBase::new(alias, target_type); Ok(BoundExpression::BoundCastExpression( - BoundCastExpression::new(base, Box::new(expr), try_cast, cast_function), + BoundCastExpression::new(base, Box::new(source_expr), try_cast, cast_function), )) } } diff --git a/src/planner_v2/binder/expression/bind_comparison_expression.rs b/src/planner_v2/binder/expression/bind_comparison_expression.rs index d866a4c..f8db46e 100644 --- a/src/planner_v2/binder/expression/bind_comparison_expression.rs +++ b/src/planner_v2/binder/expression/bind_comparison_expression.rs @@ -23,38 +23,24 @@ impl ExpressionBinder<'_> { result_names: &mut Vec, result_types: &mut Vec, ) -> Result { - let mut return_names = vec![]; - let mut return_types = vec![]; - let mut bound_left = self.bind_expression(left, &mut return_names, &mut return_types)?; - let mut bound_right = self.bind_expression(right, &mut return_names, &mut return_types)?; + let mut bound_left = self.bind_expression(left, &mut vec![], &mut vec![])?; + let mut bound_right = self.bind_expression(right, &mut vec![], &mut vec![])?; let left_type = bound_left.return_type(); let right_type = bound_right.return_type(); + // cast the input types to the same type, now obtain the result type of the input types let input_type = LogicalType::max_logical_type(&left_type, &right_type)?; - if input_type != left_type { - let alias = format!("cast({} as {}", bound_left.alias(), input_type); - bound_left = BoundCastExpression::add_cast_to_type( - bound_left, - input_type.clone(), - alias.clone(), - true, - )?; - return_names[0] = alias; - return_types[0] = input_type.clone(); - } - if input_type != right_type { - let alias = format!("cast({} as {}", bound_right.alias(), input_type); - bound_right = BoundCastExpression::add_cast_to_type( - bound_right, - input_type.clone(), - alias.clone(), - true, - )?; - return_names[1] = alias; - return_types[1] = input_type.clone(); - } + bound_left = + BoundCastExpression::try_add_cast_to_type(bound_left, input_type.clone(), true)?; + bound_right = + BoundCastExpression::try_add_cast_to_type(bound_right, input_type.clone(), true)?; - result_names.push(format!("{}({},{})", op, return_names[0], return_names[1])); + result_names.push(format!( + "{}({},{})", + op, + bound_left.alias(), + bound_right.alias() + )); result_types.push(LogicalType::Boolean); let function = DefaultComparisonFunctions::get_comparison_function(op, &input_type)?; let base = BoundExpressionBase::new("".to_string(), LogicalType::Boolean); diff --git a/src/planner_v2/binder/expression/bind_conjunction_expression.rs b/src/planner_v2/binder/expression/bind_conjunction_expression.rs index 30f65ba..6342d0d 100644 --- a/src/planner_v2/binder/expression/bind_conjunction_expression.rs +++ b/src/planner_v2/binder/expression/bind_conjunction_expression.rs @@ -22,29 +22,15 @@ impl ExpressionBinder<'_> { result_types: &mut Vec, ) -> Result { let function = DefaultConjunctionFunctions::get_conjunction_function(op)?; + let mut return_names = vec![]; let mut left = self.bind_expression(left, &mut return_names, &mut vec![])?; + left = BoundCastExpression::try_add_cast_to_type(left, LogicalType::Boolean, true)?; + return_names[0] = left.alias(); let mut right = self.bind_expression(right, &mut return_names, &mut vec![])?; - if left.return_type() != LogicalType::Boolean { - let alias = format!("cast({} as {}", left.alias(), LogicalType::Boolean); - left = BoundCastExpression::add_cast_to_type( - left, - LogicalType::Boolean, - alias.clone(), - true, - )?; - return_names[0] = alias; - } - if right.return_type() != LogicalType::Boolean { - let alias = format!("cast({} as {}", right.alias(), LogicalType::Boolean); - right = BoundCastExpression::add_cast_to_type( - right, - LogicalType::Boolean, - alias.clone(), - true, - )?; - return_names[1] = alias; - } + right = BoundCastExpression::try_add_cast_to_type(right, LogicalType::Boolean, true)?; + return_names[1] = right.alias(); + result_names.push(format!("{}({},{})", op, return_names[0], return_names[1])); result_types.push(LogicalType::Boolean); let base = BoundExpressionBase::new("".to_string(), LogicalType::Boolean); diff --git a/src/planner_v2/binder/query_node/plan_select_node.rs b/src/planner_v2/binder/query_node/plan_select_node.rs index 808c010..3c50f76 100644 --- a/src/planner_v2/binder/query_node/plan_select_node.rs +++ b/src/planner_v2/binder/query_node/plan_select_node.rs @@ -49,11 +49,9 @@ impl Binder { { if source_type != target_type { // differing types, have to add a cast but may be lossy - let alias = node.base.expressioins[idx].alias(); - node.base.expressioins[idx] = BoundCastExpression::add_cast_to_type( + node.base.expressioins[idx] = BoundCastExpression::try_add_cast_to_type( node.base.expressioins[idx].clone(), target_type.clone(), - alias, false, )?; node.base.types[idx] = target_type.clone(); diff --git a/src/planner_v2/binder/tableref/bind_expression_list_ref.rs b/src/planner_v2/binder/tableref/bind_expression_list_ref.rs index a68f078..24cafcf 100644 --- a/src/planner_v2/binder/tableref/bind_expression_list_ref.rs +++ b/src/planner_v2/binder/tableref/bind_expression_list_ref.rs @@ -62,11 +62,9 @@ impl Binder { for exprs in bound_expr_list.iter_mut() { for (idx, bound_expr) in exprs.iter_mut().enumerate() { if bound_expr.return_type() != types[idx] { - let alias = bound_expr.alias().clone(); - *bound_expr = BoundCastExpression::add_cast_to_type( + *bound_expr = BoundCastExpression::try_add_cast_to_type( bound_expr.clone(), types[idx].clone(), - alias, false, )? } diff --git a/src/planner_v2/function_binder.rs b/src/planner_v2/function_binder.rs index 9fbae1c..f65a382 100644 --- a/src/planner_v2/function_binder.rs +++ b/src/planner_v2/function_binder.rs @@ -114,19 +114,11 @@ impl FunctionBinder { let mut new_children = vec![]; for (i, child) in children.into_iter().enumerate() { let target_type = &bound_function.arguments[i]; - let source_type = &child.return_type(); - if source_type == target_type { - // no need to cast - new_children.push(child); - } else { - // we need to cast - new_children.push(BoundCastExpression::add_cast_to_type( - child, - target_type.clone(), - "".to_string(), - true, - )?); - } + new_children.push(BoundCastExpression::try_add_cast_to_type( + child, + target_type.clone(), + true, + )?) } Ok(new_children) }