diff --git a/src/common/function/src/function_registry.rs b/src/common/function/src/function_registry.rs index ef6fb67de6a6..04eb673b56ce 100644 --- a/src/common/function/src/function_registry.rs +++ b/src/common/function/src/function_registry.rs @@ -21,6 +21,7 @@ use once_cell::sync::Lazy; use crate::function::FunctionRef; use crate::scalars::aggregate::{AggregateFunctionMetaRef, AggregateFunctions}; use crate::scalars::date::DateFunction; +use crate::scalars::expression::ExpressionFunction; use crate::scalars::math::MathFunction; use crate::scalars::numpy::NumpyFunction; use crate::scalars::timestamp::TimestampFunction; @@ -80,6 +81,7 @@ pub static FUNCTION_REGISTRY: Lazy> = Lazy::new(|| { NumpyFunction::register(&function_registry); TimestampFunction::register(&function_registry); DateFunction::register(&function_registry); + ExpressionFunction::register(&function_registry); // Aggregate functions AggregateFunctions::register(&function_registry); diff --git a/src/common/function/src/scalars/expression.rs b/src/common/function/src/scalars/expression.rs index 363d9acb6475..573202f6e282 100644 --- a/src/common/function/src/scalars/expression.rs +++ b/src/common/function/src/scalars/expression.rs @@ -14,8 +14,22 @@ mod binary; mod ctx; +mod is_null; mod unary; +use std::sync::Arc; + pub use binary::scalar_binary_op; pub use ctx::EvalContext; pub use unary::scalar_unary_op; + +use crate::function_registry::FunctionRegistry; +use crate::scalars::expression::is_null::IsNullFunction; + +pub(crate) struct ExpressionFunction; + +impl ExpressionFunction { + pub fn register(registry: &FunctionRegistry) { + registry.register(Arc::new(IsNullFunction)); + } +} diff --git a/src/common/function/src/scalars/expression/is_null.rs b/src/common/function/src/scalars/expression/is_null.rs new file mode 100644 index 000000000000..17258fe76b9b --- /dev/null +++ b/src/common/function/src/scalars/expression/is_null.rs @@ -0,0 +1,109 @@ +// Copyright 2023 Greptime Team +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::fmt; +use std::fmt::Display; +use std::sync::Arc; + +use common_query::error; +use common_query::error::{ArrowComputeSnafu, InvalidFuncArgsSnafu}; +use common_query::prelude::{Signature, Volatility}; +use datafusion::arrow::array::ArrayRef; +use datafusion::arrow::compute::is_null; +use datatypes::data_type::ConcreteDataType; +use datatypes::prelude::VectorRef; +use datatypes::vectors::Helper; +use snafu::{ensure, ResultExt}; + +use crate::function::{Function, FunctionContext}; + +const NAME: &str = "isnull"; + +/// The function to find remainders +#[derive(Clone, Debug, Default)] +pub struct IsNullFunction; + +impl Display for IsNullFunction { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", NAME.to_ascii_uppercase()) + } +} + +impl Function for IsNullFunction { + fn name(&self) -> &str { + NAME + } + + fn return_type(&self, _: &[ConcreteDataType]) -> common_query::error::Result { + Ok(ConcreteDataType::boolean_datatype()) + } + + fn signature(&self) -> Signature { + Signature::any(1, Volatility::Immutable) + } + + fn eval( + &self, + _func_ctx: FunctionContext, + columns: &[VectorRef], + ) -> common_query::error::Result { + ensure!( + columns.len() == 1, + InvalidFuncArgsSnafu { + err_msg: format!( + "The length of the args is not correct, expect exactly one, have: {}", + columns.len() + ), + } + ); + let values = &columns[0]; + let arrow_array = &values.to_arrow_array(); + let result = is_null(arrow_array).context(ArrowComputeSnafu)?; + + Helper::try_into_vector(Arc::new(result) as ArrayRef).context(error::FromArrowArraySnafu) + } +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use common_query::prelude::TypeSignature; + use datatypes::scalars::ScalarVector; + use datatypes::vectors::{BooleanVector, Float32Vector}; + + use super::*; + #[test] + fn test_is_null_function() { + let is_null = IsNullFunction; + assert_eq!("isnull", is_null.name()); + assert_eq!( + ConcreteDataType::boolean_datatype(), + is_null.return_type(&[]).unwrap() + ); + assert_eq!( + is_null.signature(), + Signature { + type_signature: TypeSignature::Any(1), + volatility: Volatility::Immutable + } + ); + let values = vec![None, Some(3.0), None]; + + let args: Vec = vec![Arc::new(Float32Vector::from(values))]; + let vector = is_null.eval(FunctionContext::default(), &args).unwrap(); + let expect: VectorRef = Arc::new(BooleanVector::from_vec(vec![true, false, true])); + assert_eq!(expect, vector); + } +} diff --git a/tests/cases/standalone/common/function/expression.result b/tests/cases/standalone/common/function/expression.result new file mode 100644 index 000000000000..3ca3af11f3e2 --- /dev/null +++ b/tests/cases/standalone/common/function/expression.result @@ -0,0 +1,47 @@ +SELECT ISNULL(null); + ++-------------------------+ +| isnull(NULL) | ++-------------------------+ +| true | ++-------------------------+ + +SELECT ISNULL(1); + ++-------------------------+ +| isnull(1) | ++-------------------------+ +| false | ++-------------------------+ + +SELECT ISNULL(-1); + ++-------------------------+ +| isnull(-1) | ++-------------------------+ +| false | ++-------------------------+ + +SELECT ISNULL(1.0); + ++-------------------------+ +| isnull(1.0) | ++-------------------------+ +| false | ++-------------------------+ + +SELECT ISNULL(true); + ++-------------------------+ +| isnull(true) | ++-------------------------+ +| false | ++-------------------------+ + +SELECT ISNULL('string'); + ++-------------------------+ +| isnull(Utf8("string")) | ++-------------------------+ +| false | ++-------------------------+ \ No newline at end of file diff --git a/tests/cases/standalone/common/function/expression.sql b/tests/cases/standalone/common/function/expression.sql new file mode 100644 index 000000000000..d44bce133b7d --- /dev/null +++ b/tests/cases/standalone/common/function/expression.sql @@ -0,0 +1,11 @@ +SELECT ISNULL(null); + +SELECT ISNULL(1); + +SELECT ISNULL(-1); + +SELECT ISNULL(1.0); + +SELECT ISNULL(true); + +SELECT ISNULL('string'); \ No newline at end of file