From dd95313c0b65af9f2c722272f69c132f4d09c9b6 Mon Sep 17 00:00:00 2001 From: NANASE Date: Thu, 31 Oct 2024 00:23:39 +0800 Subject: [PATCH] feat: add function CharLength & CharacterLength --- rust-toolchain | 2 +- src/db.rs | 4 ++ src/function/char_length.rs | 70 ++++++++++++++++++++++++++++++++++ src/function/mod.rs | 1 + tests/slt/sql_2016/E021_04.slt | 18 ++++----- 5 files changed, 84 insertions(+), 11 deletions(-) create mode 100644 src/function/char_length.rs diff --git a/rust-toolchain b/rust-toolchain index 7df939e8..5f739953 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2024-04-27 \ No newline at end of file +nightly-2024-10-18 \ No newline at end of file diff --git a/src/db.rs b/src/db.rs index a47b317c..fdfcda52 100644 --- a/src/db.rs +++ b/src/db.rs @@ -5,6 +5,7 @@ use crate::execution::{build_write, try_collect}; use crate::expression::function::scala::ScalarFunctionImpl; use crate::expression::function::table::TableFunctionImpl; use crate::expression::function::FunctionSummary; +use crate::function::char_length::CharLength; use crate::function::current_date::CurrentDate; use crate::function::lower::Lower; use crate::function::numbers::Numbers; @@ -50,6 +51,9 @@ impl DataBaseBuilder { scala_functions: Default::default(), table_functions: Default::default(), }; + builder = builder.register_scala_function(CharLength::new("char_length".to_lowercase())); + builder = + builder.register_scala_function(CharLength::new("character_length".to_lowercase())); builder = builder.register_scala_function(CurrentDate::new()); builder = builder.register_scala_function(Lower::new()); builder = builder.register_scala_function(Upper::new()); diff --git a/src/function/char_length.rs b/src/function/char_length.rs new file mode 100644 index 00000000..d23cc018 --- /dev/null +++ b/src/function/char_length.rs @@ -0,0 +1,70 @@ +use crate::catalog::ColumnRef; +use crate::errors::DatabaseError; +use crate::expression::function::scala::FuncMonotonicity; +use crate::expression::function::scala::ScalarFunctionImpl; +use crate::expression::function::FunctionSummary; +use crate::expression::ScalarExpression; +use crate::types::tuple::Tuple; +use crate::types::value::DataValue; +use crate::types::LogicalType; +use serde::Deserialize; +use serde::Serialize; +use sqlparser::ast::CharLengthUnits; +use std::sync::Arc; + +#[derive(Debug, Serialize, Deserialize)] +pub(crate) struct CharLength { + summary: FunctionSummary, +} + +impl CharLength { + pub(crate) fn new(function_name: String) -> Arc { + let arg_types = vec![LogicalType::Varchar(None, CharLengthUnits::Characters)]; + Arc::new(Self { + summary: FunctionSummary { + name: function_name, + arg_types, + }, + }) + } +} + +#[typetag::serde] +impl ScalarFunctionImpl for CharLength { + #[allow(unused_variables, clippy::redundant_closure_call)] + fn eval( + &self, + exprs: &[ScalarExpression], + tuples: &Tuple, + columns: &[ColumnRef], + ) -> Result { + let value = exprs[0].eval(tuples, columns)?; + let mut value = DataValue::clone(&value); + if !matches!(value.logical_type(), LogicalType::Varchar(_, _)) { + value = DataValue::clone(&value) + .cast(&LogicalType::Varchar(None, CharLengthUnits::Characters))?; + } + let mut length: u64 = 0; + if let DataValue::Utf8 { + value: Some(value), + ty, + unit, + } = &mut value + { + length = value.len() as u64; + } + Ok(DataValue::UInt64(Some(length))) + } + + fn monotonicity(&self) -> Option { + todo!() + } + + fn return_type(&self) -> &LogicalType { + &LogicalType::Varchar(None, CharLengthUnits::Characters) + } + + fn summary(&self) -> &FunctionSummary { + &self.summary + } +} diff --git a/src/function/mod.rs b/src/function/mod.rs index e48c7c2d..6c660c57 100644 --- a/src/function/mod.rs +++ b/src/function/mod.rs @@ -1,3 +1,4 @@ +pub(crate) mod char_length; pub(crate) mod current_date; pub(crate) mod lower; pub(crate) mod numbers; diff --git a/tests/slt/sql_2016/E021_04.slt b/tests/slt/sql_2016/E021_04.slt index dc7a3a52..ac401405 100644 --- a/tests/slt/sql_2016/E021_04.slt +++ b/tests/slt/sql_2016/E021_04.slt @@ -1,14 +1,12 @@ # E021-04: CHARACTER_LENGTH function -# TODO: CHARACTER_LENGTH()/CHAR_LENGTH() +query I +SELECT CHARACTER_LENGTH ( 'foo' ) +---- +3 -# query I -# SELECT CHARACTER_LENGTH ( 'foo' ) -# ---- -# 3 - -# query I -# SELECT CHAR_LENGTH ( 'foo' ) -# ---- -# 3 +query I +SELECT CHAR_LENGTH ( 'foo' ) +---- +3