use static_assertions::assert_eq_size;
use std::any::Any;
use std::convert::TryFrom;
use std::marker::PhantomData;
use tidb_query_datatype::{EvalType, FieldTypeAccessor};
use tipb::{Expr, FieldType};
use super::expr_eval::LogicalRows;
use super::RpnStackNode;
use tidb_query_common::Result;
use tidb_query_datatype::codec::data_type::*;
use tidb_query_datatype::expr::EvalContext;
#[derive(Clone, Copy)]
pub struct RpnFnMeta {
pub name: &'static str,
pub validator_ptr: fn(expr: &Expr) -> Result<()>,
pub metadata_expr_ptr: fn(expr: &mut Expr) -> Result<Box<dyn Any + Send>>,
#[allow(clippy::type_complexity)]
pub fn_ptr: fn(
ctx: &mut EvalContext,
output_rows: usize,
args: &[RpnStackNode<'_>],
extra: &mut RpnFnCallExtra<'_>,
metadata: &(dyn Any + Send),
) -> Result<VectorValue>,
}
impl std::fmt::Debug for RpnFnMeta {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)
}
}
pub struct RpnFnCallExtra<'a> {
pub ret_field_type: &'a FieldType,
}
pub trait RpnFnArg: std::fmt::Debug {
type Type;
fn get(&self, row: usize) -> Self::Type;
fn get_bit_vec(&self) -> (Option<&BitVec>, bool);
}
#[derive(Clone, Copy, Debug)]
pub struct ScalarArg<'a, T: EvaluableRef<'a>>(Option<T>, PhantomData<&'a T>);
impl<'a, T: EvaluableRef<'a>> ScalarArg<'a, T> {
pub fn new(data: Option<T>) -> Self {
Self(data, PhantomData)
}
}
impl<'a, T: EvaluableRef<'a>> RpnFnArg for ScalarArg<'a, T> {
type Type = Option<T>;
#[inline]
fn get(&self, _row: usize) -> Option<T> {
self.0.clone()
}
#[inline]
fn get_bit_vec(&self) -> (Option<&BitVec>, bool) {
(None, self.0.is_some())
}
}
#[derive(Clone, Copy, Debug)]
pub struct VectorArg<'a, T: 'a + EvaluableRef<'a>, C: 'a + ChunkRef<'a, T>> {
physical_col: C,
logical_rows: LogicalRows<'a>,
_phantom: PhantomData<T>,
}
impl<'a, T: EvaluableRef<'a>, C: 'a + ChunkRef<'a, T>> RpnFnArg for VectorArg<'a, T, C> {
type Type = Option<T>;
#[inline]
fn get(&self, row: usize) -> Option<T> {
let logical_index = self.logical_rows.get_idx(row);
self.physical_col.get_option_ref(logical_index)
}
#[inline]
fn get_bit_vec(&self) -> (Option<&BitVec>, bool) {
(
Some(self.physical_col.get_bit_vec()),
self.logical_rows.is_ident(),
)
}
}
pub trait ArgDef: std::fmt::Debug {}
#[derive(Debug)]
pub struct Arg<A: RpnFnArg, Rem: ArgDef> {
arg: A,
rem: Rem,
}
impl<A: RpnFnArg, Rem: ArgDef> ArgDef for Arg<A, Rem> {}
impl<A: RpnFnArg, Rem: ArgDef> Arg<A, Rem> {
#[inline]
pub fn extract(&self, row: usize) -> (A::Type, &Rem) {
(self.arg.get(row), &self.rem)
}
#[inline]
pub fn get_bit_vec(&self) -> ((Option<&BitVec>, bool), &Rem) {
(self.arg.get_bit_vec(), &self.rem)
}
}
#[derive(Debug)]
pub struct Null;
impl ArgDef for Null {}
pub trait Evaluator<'a> {
fn eval(
self,
def: impl ArgDef,
ctx: &mut EvalContext,
output_rows: usize,
args: &'a [RpnStackNode<'a>],
extra: &mut RpnFnCallExtra<'_>,
metadata: &(dyn Any + Send),
) -> Result<VectorValue>;
}
pub struct ArgConstructor<'a, A: EvaluableRef<'a>, E: Evaluator<'a>> {
arg_index: usize,
inner: E,
_phantom: PhantomData<&'a A>,
}
impl<'a, A: EvaluableRef<'a>, E: Evaluator<'a>> ArgConstructor<'a, A, E> {
#[inline]
pub fn new(arg_index: usize, inner: E) -> Self {
ArgConstructor {
arg_index,
inner,
_phantom: PhantomData,
}
}
}
impl<'a, A: EvaluableRef<'a>, E: Evaluator<'a>> Evaluator<'a> for ArgConstructor<'a, A, E> {
fn eval(
self,
def: impl ArgDef,
ctx: &mut EvalContext,
output_rows: usize,
args: &'a [RpnStackNode<'a>],
extra: &mut RpnFnCallExtra<'_>,
metadata: &(dyn Any + Send),
) -> Result<VectorValue> {
match &args[self.arg_index] {
RpnStackNode::Scalar { value, .. } => {
let v = A::borrow_scalar_value_ref(value.as_scalar_value_ref());
let new_def = Arg {
arg: ScalarArg::new(v),
rem: def,
};
self.inner
.eval(new_def, ctx, output_rows, args, extra, metadata)
}
RpnStackNode::Vector { value, .. } => {
let logical_rows = value.logical_rows_struct();
let v = A::borrow_vector_value(value.as_ref());
let new_def = Arg {
arg: VectorArg {
physical_col: v,
logical_rows,
_phantom: PhantomData,
},
rem: def,
};
self.inner
.eval(new_def, ctx, output_rows, args, extra, metadata)
}
}
}
}
pub fn validate_expr_return_type(expr: &Expr, et: EvalType) -> Result<()> {
let received_et = box_try!(EvalType::try_from(expr.get_field_type().as_accessor().tp()));
if et == received_et {
Ok(())
} else {
match (et, received_et) {
(EvalType::Int, EvalType::Enum) | (EvalType::Bytes, EvalType::Enum) => Ok(()),
_ => Err(other_err!("Expect `{}`, received `{}`", et, received_et)),
}
}
}
pub fn validate_expr_arguments_eq(expr: &Expr, args: usize) -> Result<()> {
let received_args = expr.get_children().len();
if received_args == args {
Ok(())
} else {
Err(other_err!(
"Expect {} arguments, received {}",
args,
received_args
))
}
}
pub fn validate_expr_arguments_gte(expr: &Expr, args: usize) -> Result<()> {
let received_args = expr.get_children().len();
if received_args >= args {
Ok(())
} else {
Err(other_err!(
"Expect at least {} arguments, received {}",
args,
received_args
))
}
}
pub fn validate_expr_arguments_lte(expr: &Expr, args: usize) -> Result<()> {
let received_args = expr.get_children().len();
if received_args <= args {
Ok(())
} else {
Err(other_err!(
"Expect at most {} arguments, received {}",
args,
received_args
))
}
}
assert_eq_size!(usize, Option<&Int>);
assert_eq_size!(usize, Option<&Real>);
assert_eq_size!(usize, Option<&Decimal>);
assert_eq_size!(usize, Option<&Bytes>);
assert_eq_size!(usize, Option<&DateTime>);
assert_eq_size!(usize, Option<&Duration>);
assert_eq_size!(usize, Option<&Json>);
thread_local! {
pub static VARG_PARAM_BUF: std::cell::RefCell<Vec<usize>> =
std::cell::RefCell::new(Vec::with_capacity(20));
pub static VARG_PARAM_BUF_BYTES_REF: std::cell::RefCell<Vec<Option<BytesRef<'static>>>> =
std::cell::RefCell::new(Vec::with_capacity(20));
pub static VARG_PARAM_BUF_JSON_REF: std::cell::RefCell<Vec<Option<JsonRef<'static>>>> =
std::cell::RefCell::new(Vec::with_capacity(20));
pub static RAW_VARG_PARAM_BUF: std::cell::RefCell<Vec<ScalarValueRef<'static>>> =
std::cell::RefCell::new(Vec::with_capacity(20));
}
pub fn extract_metadata_from_val<T: protobuf::Message + Default>(val: &[u8]) -> Result<T> {
if val.is_empty() {
Ok(T::default())
} else {
protobuf::parse_from_bytes::<T>(val)
.map_err(|e| other_err!("Decode metadata failed: {}", e))
}
}