Skip to content

Commit

Permalink
feat: add isnull function (#3360)
Browse files Browse the repository at this point in the history
* code fmt

* feat: add isnull function

* feat: add isnull function
  • Loading branch information
KKould authored Feb 22, 2024
1 parent 1dc4fec commit 578dd8f
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/common/function/src/function_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -80,6 +81,7 @@ pub static FUNCTION_REGISTRY: Lazy<Arc<FunctionRegistry>> = Lazy::new(|| {
NumpyFunction::register(&function_registry);
TimestampFunction::register(&function_registry);
DateFunction::register(&function_registry);
ExpressionFunction::register(&function_registry);

// Aggregate functions
AggregateFunctions::register(&function_registry);
Expand Down
14 changes: 14 additions & 0 deletions src/common/function/src/scalars/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
109 changes: 109 additions & 0 deletions src/common/function/src/scalars/expression/is_null.rs
Original file line number Diff line number Diff line change
@@ -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 check whether an expression is NULL
#[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<ConcreteDataType> {
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<VectorRef> {
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<VectorRef> = 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);
}
}
70 changes: 70 additions & 0 deletions tests/cases/standalone/common/function/expression.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
CREATE TABLE t(a INTEGER, ts timestamp time index);

Affected Rows: 0

INSERT INTO t VALUES (1, 1), (null, 2), (3, 3);

Affected Rows: 3

SELECT ISNULL(a) from t;

+-------------+
| isnull(t.a) |
+-------------+
| false |
| true |
| false |
+-------------+

SELECT ISNULL(null);

+--------------+
| isnull(NULL) |
+--------------+
| true |
+--------------+

SELECT ISNULL(1);

+------------------+
| isnull(Int64(1)) |
+------------------+
| false |
+------------------+

SELECT ISNULL(-1);

+-------------------+
| isnull(Int64(-1)) |
+-------------------+
| false |
+-------------------+

SELECT ISNULL(1.0);

+--------------------+
| isnull(Float64(1)) |
+--------------------+
| false |
+--------------------+

SELECT ISNULL(true);

+-----------------------+
| isnull(Boolean(true)) |
+-----------------------+
| false |
+-----------------------+

SELECT ISNULL('string');

+------------------------+
| isnull(Utf8("string")) |
+------------------------+
| false |
+------------------------+

DROP TABLE t;

Affected Rows: 0

19 changes: 19 additions & 0 deletions tests/cases/standalone/common/function/expression.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
CREATE TABLE t(a INTEGER, ts timestamp time index);

INSERT INTO t VALUES (1, 1), (null, 2), (3, 3);

SELECT ISNULL(a) from t;

SELECT ISNULL(null);

SELECT ISNULL(1);

SELECT ISNULL(-1);

SELECT ISNULL(1.0);

SELECT ISNULL(true);

SELECT ISNULL('string');

DROP TABLE t;

0 comments on commit 578dd8f

Please sign in to comment.