use std::convert::{TryFrom, TryInto};
use codec::prelude::NumberDecoder;
use tidb_query_datatype::{EvalType, FieldTypeAccessor};
use tipb::{Expr, ExprType, FieldType};
use super::super::function::RpnFnMeta;
use super::expr::{RpnExpression, RpnExpressionNode};
use tidb_query_common::Result;
use tidb_query_datatype::codec::data_type::*;
use tidb_query_datatype::codec::mysql::{EnumDecoder, JsonDecoder, MAX_FSP};
use tidb_query_datatype::expr::EvalContext;
use tidb_query_datatype::match_template_evaltype;
#[derive(Debug)]
pub struct RpnExpressionBuilder(Vec<RpnExpressionNode>);
impl RpnExpressionBuilder {
pub fn check_expr_tree_supported(c: &Expr) -> Result<()> {
box_try!(EvalType::try_from(c.get_field_type().as_accessor().tp()));
match c.get_tp() {
ExprType::ScalarFunc => {
super::super::map_expr_node_to_rpn_func(c)?;
for n in c.get_children() {
RpnExpressionBuilder::check_expr_tree_supported(n)?;
}
}
ExprType::Null => {}
ExprType::Int64 => {}
ExprType::Uint64 => {}
ExprType::String | ExprType::Bytes => {}
ExprType::Float32 | ExprType::Float64 => {}
ExprType::MysqlTime => {}
ExprType::MysqlDuration => {}
ExprType::MysqlDecimal => {}
ExprType::MysqlJson => {}
ExprType::ColumnRef => {}
_ => return Err(other_err!("Blacklist expression type {:?}", c.get_tp())),
}
Ok(())
}
pub fn is_expr_eval_to_scalar(c: &Expr) -> Result<bool> {
match c.get_tp() {
ExprType::Null
| ExprType::Int64
| ExprType::Uint64
| ExprType::String
| ExprType::Bytes
| ExprType::Float32
| ExprType::Float64
| ExprType::MysqlTime
| ExprType::MysqlDuration
| ExprType::MysqlDecimal
| ExprType::MysqlJson => Ok(true),
ExprType::ScalarFunc => Ok(false),
ExprType::ColumnRef => Ok(false),
_ => Err(other_err!("Unsupported expression type {:?}", c.get_tp())),
}
}
pub fn build_from_expr_tree(
tree_node: Expr,
ctx: &mut EvalContext,
max_columns: usize,
) -> Result<RpnExpression> {
let mut expr_nodes = Vec::new();
append_rpn_nodes_recursively(
tree_node,
&mut expr_nodes,
ctx,
super::super::map_expr_node_to_rpn_func,
max_columns,
)?;
Ok(RpnExpression::from(expr_nodes))
}
#[cfg(test)]
pub fn build_from_expr_tree_with_fn_mapper<F>(
tree_node: Expr,
fn_mapper: F,
max_columns: usize,
) -> Result<RpnExpression>
where
F: Fn(&Expr) -> Result<RpnFnMeta> + Copy,
{
let mut expr_nodes = Vec::new();
append_rpn_nodes_recursively(
tree_node,
&mut expr_nodes,
&mut EvalContext::default(),
fn_mapper,
max_columns,
)?;
Ok(RpnExpression::from(expr_nodes))
}
pub fn new_for_test() -> Self {
Self(Vec::new())
}
pub fn push_fn_call_for_test(
mut self,
func_meta: RpnFnMeta,
args_len: usize,
return_field_type: impl Into<FieldType>,
) -> Self {
let node = RpnExpressionNode::FnCall {
func_meta,
args_len,
field_type: return_field_type.into(),
metadata: Box::new(()),
};
self.0.push(node);
self
}
#[cfg(test)]
pub fn push_fn_call_with_metadata(
mut self,
func_meta: RpnFnMeta,
args_len: usize,
return_field_type: impl Into<FieldType>,
metadata: Box<dyn std::any::Any + Send>,
) -> Self {
let node = RpnExpressionNode::FnCall {
func_meta,
args_len,
field_type: return_field_type.into(),
metadata,
};
self.0.push(node);
self
}
pub fn push_constant_for_test(mut self, value: impl Into<ScalarValue>) -> Self {
let value = value.into();
let field_type = value
.eval_type()
.into_certain_field_type_tp_for_test()
.into();
let node = RpnExpressionNode::Constant { value, field_type };
self.0.push(node);
self
}
#[cfg(test)]
pub fn push_constant_with_field_type(
mut self,
value: impl Into<ScalarValue>,
field_type: impl Into<FieldType>,
) -> Self {
let node = RpnExpressionNode::Constant {
value: value.into(),
field_type: field_type.into(),
};
self.0.push(node);
self
}
pub fn push_column_ref_for_test(mut self, offset: usize) -> Self {
let node = RpnExpressionNode::ColumnRef { offset };
self.0.push(node);
self
}
pub fn build_for_test(self) -> RpnExpression {
RpnExpression::from(self.0)
}
}
impl AsRef<[RpnExpressionNode]> for RpnExpressionBuilder {
fn as_ref(&self) -> &[RpnExpressionNode] {
self.0.as_ref()
}
}
fn append_rpn_nodes_recursively<F>(
tree_node: Expr,
rpn_nodes: &mut Vec<RpnExpressionNode>,
ctx: &mut EvalContext,
fn_mapper: F,
max_columns: usize,
) -> Result<()>
where
F: Fn(&Expr) -> Result<RpnFnMeta> + Copy,
{
match tree_node.get_tp() {
ExprType::ScalarFunc => {
handle_node_fn_call(tree_node, rpn_nodes, ctx, fn_mapper, max_columns)
}
ExprType::ColumnRef => handle_node_column_ref(tree_node, rpn_nodes, max_columns),
_ => handle_node_constant(tree_node, rpn_nodes, ctx),
}
}
#[inline]
fn handle_node_column_ref(
tree_node: Expr,
rpn_nodes: &mut Vec<RpnExpressionNode>,
max_columns: usize,
) -> Result<()> {
let offset = tree_node
.get_val()
.read_i64()
.map_err(|_| other_err!("Unable to decode column reference offset from the request"))?
as usize;
if offset >= max_columns {
return Err(other_err!(
"Invalid column offset (schema has {} columns, access index {})",
max_columns,
offset
));
}
rpn_nodes.push(RpnExpressionNode::ColumnRef { offset });
Ok(())
}
#[inline]
fn handle_node_fn_call<F>(
mut tree_node: Expr,
rpn_nodes: &mut Vec<RpnExpressionNode>,
ctx: &mut EvalContext,
fn_mapper: F,
max_columns: usize,
) -> Result<()>
where
F: Fn(&Expr) -> Result<RpnFnMeta> + Copy,
{
let func_meta = fn_mapper(&tree_node)?;
(func_meta.validator_ptr)(&tree_node).map_err(|e| {
other_err!(
"Invalid {} (sig = {:?}) signature: {}",
func_meta.name,
tree_node.get_sig(),
e
)
})?;
let metadata = (func_meta.metadata_expr_ptr)(&mut tree_node)?;
let args: Vec<_> = tree_node.take_children().into();
let args_len = args.len();
for arg in args {
append_rpn_nodes_recursively(arg, rpn_nodes, ctx, fn_mapper, max_columns)?;
}
rpn_nodes.push(RpnExpressionNode::FnCall {
func_meta,
args_len,
field_type: tree_node.take_field_type(),
metadata,
});
Ok(())
}
#[inline]
fn handle_node_constant(
mut tree_node: Expr,
rpn_nodes: &mut Vec<RpnExpressionNode>,
ctx: &mut EvalContext,
) -> Result<()> {
let eval_type = box_try!(EvalType::try_from(
tree_node.get_field_type().as_accessor().tp()
));
let scalar_value = match tree_node.get_tp() {
ExprType::Null => get_scalar_value_null(eval_type),
ExprType::Int64 if eval_type == EvalType::Int => {
extract_scalar_value_int64(tree_node.take_val())?
}
ExprType::Uint64 if eval_type == EvalType::Int => {
extract_scalar_value_uint64(tree_node.take_val())?
}
ExprType::String | ExprType::Bytes if eval_type == EvalType::Bytes => {
extract_scalar_value_bytes(tree_node.take_val())?
}
ExprType::Float32 | ExprType::Float64 if eval_type == EvalType::Real => {
extract_scalar_value_float(tree_node.take_val())?
}
ExprType::MysqlTime if eval_type == EvalType::DateTime => {
extract_scalar_value_date_time(tree_node.take_val(), tree_node.get_field_type(), ctx)?
}
ExprType::MysqlDuration if eval_type == EvalType::Duration => {
extract_scalar_value_duration(tree_node.take_val())?
}
ExprType::MysqlDecimal if eval_type == EvalType::Decimal => {
extract_scalar_value_decimal(tree_node.take_val())?
}
ExprType::MysqlJson if eval_type == EvalType::Json => {
extract_scalar_value_json(tree_node.take_val())?
}
ExprType::MysqlEnum if eval_type == EvalType::Enum => {
extract_scalar_value_enum(tree_node.take_val(), tree_node.get_field_type())?
}
expr_type => {
return Err(other_err!(
"Unexpected ExprType {:?} and EvalType {:?}",
expr_type,
eval_type
));
}
};
rpn_nodes.push(RpnExpressionNode::Constant {
value: scalar_value,
field_type: tree_node.take_field_type(),
});
Ok(())
}
#[inline]
fn get_scalar_value_null(eval_type: EvalType) -> ScalarValue {
match_template_evaltype! {
TT, match eval_type {
EvalType::TT => ScalarValue::TT(None),
}
}
}
#[inline]
fn extract_scalar_value_int64(val: Vec<u8>) -> Result<ScalarValue> {
let value = val
.as_slice()
.read_i64()
.map_err(|_| other_err!("Unable to decode int64 from the request"))?;
Ok(ScalarValue::Int(Some(value)))
}
#[inline]
fn extract_scalar_value_uint64(val: Vec<u8>) -> Result<ScalarValue> {
let value = val
.as_slice()
.read_u64()
.map_err(|_| other_err!("Unable to decode uint64 from the request"))?;
Ok(ScalarValue::Int(Some(value as i64)))
}
#[inline]
fn extract_scalar_value_bytes(val: Vec<u8>) -> Result<ScalarValue> {
Ok(ScalarValue::Bytes(Some(val)))
}
#[inline]
fn extract_scalar_value_float(val: Vec<u8>) -> Result<ScalarValue> {
let value = val
.as_slice()
.read_f64()
.map_err(|_| other_err!("Unable to decode float from the request"))?;
Ok(ScalarValue::Real(Real::new(value).ok()))
}
#[inline]
fn extract_scalar_value_date_time(
val: Vec<u8>,
field_type: &FieldType,
ctx: &mut EvalContext,
) -> Result<ScalarValue> {
let v = val
.as_slice()
.read_u64()
.map_err(|_| other_err!("Unable to decode date time from the request"))?;
let fsp = field_type.as_accessor().decimal() as i8;
let value = DateTime::from_packed_u64(ctx, v, field_type.as_accessor().tp().try_into()?, fsp)
.map_err(|_| other_err!("Unable to decode date time from the request"))?;
Ok(ScalarValue::DateTime(Some(value)))
}
#[inline]
fn extract_scalar_value_duration(val: Vec<u8>) -> Result<ScalarValue> {
let n = val
.as_slice()
.read_i64()
.map_err(|_| other_err!("Unable to decode duration from the request"))?;
let value = Duration::from_nanos(n, MAX_FSP)
.map_err(|_| other_err!("Unable to decode duration from the request"))?;
Ok(ScalarValue::Duration(Some(value)))
}
#[inline]
fn extract_scalar_value_decimal(val: Vec<u8>) -> Result<ScalarValue> {
use tidb_query_datatype::codec::mysql::DecimalDecoder;
let value = val
.as_slice()
.read_decimal()
.map_err(|_| other_err!("Unable to decode decimal from the request"))?;
Ok(ScalarValue::Decimal(Some(value)))
}
#[inline]
fn extract_scalar_value_json(val: Vec<u8>) -> Result<ScalarValue> {
let value = val
.as_slice()
.read_json()
.map_err(|_| other_err!("Unable to decode json from the request"))?;
Ok(ScalarValue::Json(Some(value)))
}
#[inline]
fn extract_scalar_value_enum(val: Vec<u8>, field_type: &FieldType) -> Result<ScalarValue> {
let value = val
.as_slice()
.read_enum_uint(field_type)
.map_err(|_| other_err!("Unable to decode enum from the request"))?;
Ok(ScalarValue::Enum(Some(value)))
}
#[cfg(test)]
mod tests {
use super::*;
use tidb_query_codegen::rpn_fn;
use tidb_query_datatype::FieldTypeTp;
use tipb::ScalarFuncSig;
use tipb_helper::ExprDefBuilder;
use tidb_query_common::Result;
#[rpn_fn(nullable)]
fn fn_a(_v: Option<&i64>) -> Result<Option<Real>> {
unreachable!()
}
#[rpn_fn(nullable)]
fn fn_b(_v1: Option<&Real>, _v2: Option<&Real>) -> Result<Option<i64>> {
unreachable!()
}
#[rpn_fn(nullable)]
fn fn_c(_v1: Option<&i64>, _v2: Option<&i64>, _v3: Option<&i64>) -> Result<Option<i64>> {
unreachable!()
}
#[rpn_fn(nullable)]
fn fn_d(_v1: Option<&Real>, _v2: Option<&Real>, _v3: Option<&Real>) -> Result<Option<Real>> {
unreachable!()
}
#[rpn_fn(nullable)]
fn fn_e(_v1: Option<&Int>, _v2: Option<&Real>) -> Result<Option<Bytes>> {
unreachable!()
}
#[rpn_fn(nullable, varg)]
fn fn_f(_v: &[Option<&Int>]) -> Result<Option<Real>> {
unreachable!()
}
#[rpn_fn(nullable, varg, min_args = 2)]
fn fn_g(_v: &[Option<&Real>]) -> Result<Option<Int>> {
unreachable!()
}
#[rpn_fn(nullable, raw_varg, min_args = 1)]
fn fn_h(_v: &[ScalarValueRef<'_>]) -> Result<Option<Real>> {
unreachable!()
}
fn fn_mapper(expr: &Expr) -> Result<RpnFnMeta> {
Ok(match expr.get_sig() {
ScalarFuncSig::CastIntAsInt => fn_a_fn_meta(),
ScalarFuncSig::CastIntAsReal => fn_b_fn_meta(),
ScalarFuncSig::CastIntAsString => fn_c_fn_meta(),
ScalarFuncSig::CastIntAsDecimal => fn_d_fn_meta(),
ScalarFuncSig::CastIntAsTime => fn_e_fn_meta(),
ScalarFuncSig::CastIntAsDuration => fn_f_fn_meta(),
ScalarFuncSig::CastIntAsJson => fn_g_fn_meta(),
ScalarFuncSig::CastRealAsInt => fn_h_fn_meta(),
_ => unreachable!(),
})
}
#[test]
fn test_validator_fixed_args_fn() {
let node = ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsTime, FieldTypeTp::VarChar)
.push_child(ExprDefBuilder::constant_int(1))
.push_child(ExprDefBuilder::constant_real(3.0))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_ok());
let node = ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsTime, FieldTypeTp::LongLong)
.push_child(ExprDefBuilder::constant_int(1))
.push_child(ExprDefBuilder::constant_real(3.0))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_err());
let node = ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsTime, FieldTypeTp::VarChar)
.push_child(ExprDefBuilder::constant_int(1))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_err());
let node = ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsTime, FieldTypeTp::VarChar)
.push_child(ExprDefBuilder::constant_int(1))
.push_child(ExprDefBuilder::constant_real(3.0))
.push_child(ExprDefBuilder::constant_real(1.0))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_err());
let node = ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsTime, FieldTypeTp::VarChar)
.push_child(ExprDefBuilder::constant_int(1))
.push_child(ExprDefBuilder::constant_int(5))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_err());
}
#[test]
fn test_validator_vargs_fn() {
let node =
ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsDuration, FieldTypeTp::Double)
.push_child(ExprDefBuilder::constant_int(1))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_ok());
let node =
ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsDuration, FieldTypeTp::Double)
.push_child(ExprDefBuilder::constant_int(1))
.push_child(ExprDefBuilder::constant_int(5))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_ok());
let node =
ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsDuration, FieldTypeTp::Double)
.push_child(ExprDefBuilder::constant_int(1))
.push_child(ExprDefBuilder::constant_int(5))
.push_child(ExprDefBuilder::constant_int(4))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_ok());
let node =
ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsDuration, FieldTypeTp::LongLong)
.push_child(ExprDefBuilder::constant_int(1))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_err());
let node =
ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsDuration, FieldTypeTp::Double)
.push_child(ExprDefBuilder::constant_real(1.0))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_err());
let node =
ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsDuration, FieldTypeTp::Double)
.push_child(ExprDefBuilder::constant_int(1))
.push_child(ExprDefBuilder::constant_real(1.0))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_err());
let node =
ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsDuration, FieldTypeTp::Double)
.push_child(ExprDefBuilder::constant_real(3.0))
.push_child(ExprDefBuilder::constant_real(1.0))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_err());
let node =
ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsDuration, FieldTypeTp::Double)
.push_child(ExprDefBuilder::constant_real(3.0))
.push_child(ExprDefBuilder::constant_real(1.0))
.push_child(ExprDefBuilder::constant_int(1))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_err());
}
#[test]
fn test_validator_vargs_fn_with_min_args() {
let node = ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsJson, FieldTypeTp::LongLong)
.push_child(ExprDefBuilder::constant_real(3.0))
.push_child(ExprDefBuilder::constant_real(5.0))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_ok());
let node = ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsJson, FieldTypeTp::LongLong)
.push_child(ExprDefBuilder::constant_real(3.0))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_err());
let node = ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsJson, FieldTypeTp::Double)
.push_child(ExprDefBuilder::constant_real(3.0))
.push_child(ExprDefBuilder::constant_real(5.0))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_err());
let node = ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsJson, FieldTypeTp::LongLong)
.push_child(ExprDefBuilder::constant_real(3.0))
.push_child(ExprDefBuilder::constant_real(5.0))
.push_child(ExprDefBuilder::constant_int(42))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_err());
}
#[test]
fn test_validator_raw_vargs_fn_with_min_args() {
let node = ExprDefBuilder::scalar_func(ScalarFuncSig::CastRealAsInt, FieldTypeTp::Double)
.push_child(ExprDefBuilder::constant_real(3.0))
.push_child(ExprDefBuilder::constant_int(5))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_ok());
let node =
ExprDefBuilder::scalar_func(ScalarFuncSig::CastRealAsInt, FieldTypeTp::Double).build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_err());
let node = ExprDefBuilder::scalar_func(ScalarFuncSig::CastRealAsInt, FieldTypeTp::LongLong)
.push_child(ExprDefBuilder::constant_real(3.0))
.push_child(ExprDefBuilder::constant_int(5))
.build();
let exp = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0);
assert!(exp.is_err());
}
#[test]
#[allow(clippy::float_cmp)]
fn test_append_rpn_nodes_recursively() {
let node =
ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsDecimal, FieldTypeTp::Double)
.push_child(ExprDefBuilder::constant_null(FieldTypeTp::Double))
.push_child(
ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsInt, FieldTypeTp::Double)
.push_child(
ExprDefBuilder::scalar_func(
ScalarFuncSig::CastIntAsString,
FieldTypeTp::LongLong,
)
.push_child(ExprDefBuilder::constant_int(7))
.push_child(ExprDefBuilder::constant_int(3))
.push_child(ExprDefBuilder::constant_int(11)),
),
)
.push_child(
ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsInt, FieldTypeTp::Double)
.push_child(
ExprDefBuilder::scalar_func(
ScalarFuncSig::CastIntAsReal,
FieldTypeTp::LongLong,
)
.push_child(ExprDefBuilder::constant_real(-1.5))
.push_child(ExprDefBuilder::constant_real(100.12)),
),
)
.build();
let mut it = RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node, fn_mapper, 0)
.unwrap()
.into_inner()
.into_iter();
assert!(it.next().unwrap().constant_value().as_real().is_none());
assert_eq!(7, *it.next().unwrap().constant_value().as_int().unwrap());
assert_eq!(3, *it.next().unwrap().constant_value().as_int().unwrap());
assert_eq!(11, *it.next().unwrap().constant_value().as_int().unwrap());
assert_eq!(it.next().unwrap().fn_call_func().name, "fn_c");
assert_eq!(it.next().unwrap().fn_call_func().name, "fn_a");
assert_eq!(
Real::new(-1.5).ok().as_ref(),
it.next().unwrap().constant_value().as_real()
);
assert_eq!(
Real::new(100.12).ok().as_ref(),
it.next().unwrap().constant_value().as_real()
);
assert_eq!(it.next().unwrap().fn_call_func().name, "fn_b");
assert_eq!(it.next().unwrap().fn_call_func().name, "fn_a");
assert_eq!(it.next().unwrap().fn_call_func().name, "fn_d");
assert!(it.next().is_none())
}
#[test]
fn test_max_columns_check() {
let node = ExprDefBuilder::column_ref(0, FieldTypeTp::LongLong).build();
assert!(
RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(node.clone(), fn_mapper, 0)
.is_err()
);
for i in 1..10 {
assert!(
RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(
node.clone(),
fn_mapper,
i
)
.is_ok()
);
}
let node = ExprDefBuilder::column_ref(3, FieldTypeTp::LongLong).build();
for i in 0..=3 {
assert!(
RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(
node.clone(),
fn_mapper,
i
)
.is_err()
);
}
for i in 4..10 {
assert!(
RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(
node.clone(),
fn_mapper,
i
)
.is_ok()
);
}
let node =
ExprDefBuilder::scalar_func(ScalarFuncSig::CastIntAsString, FieldTypeTp::LongLong)
.push_child(ExprDefBuilder::column_ref(1, FieldTypeTp::LongLong))
.push_child(ExprDefBuilder::column_ref(2, FieldTypeTp::LongLong))
.push_child(ExprDefBuilder::column_ref(5, FieldTypeTp::LongLong))
.build();
for i in 0..=5 {
assert!(
RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(
node.clone(),
fn_mapper,
i
)
.is_err()
);
}
for i in 6..10 {
assert!(
RpnExpressionBuilder::build_from_expr_tree_with_fn_mapper(
node.clone(),
fn_mapper,
i
)
.is_ok()
);
}
}
}