diff --git a/Cargo.lock b/Cargo.lock index 888f34f05245..c0bbae37fd71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1664,6 +1664,7 @@ name = "common-function" version = "0.4.4" dependencies = [ "arc-swap", + "build-data", "chrono-tz 0.6.3", "common-error", "common-macro", diff --git a/src/common/function/Cargo.toml b/src/common/function/Cargo.toml index 31a212d21035..3db195668e60 100644 --- a/src/common/function/Cargo.toml +++ b/src/common/function/Cargo.toml @@ -6,6 +6,7 @@ license.workspace = true [dependencies] arc-swap = "1.0" +build-data = "0.1" chrono-tz = "0.6" common-error.workspace = true common-macro.workspace = true diff --git a/src/common/function/src/scalars/function.rs b/src/common/function/src/function.rs similarity index 100% rename from src/common/function/src/scalars/function.rs rename to src/common/function/src/function.rs diff --git a/src/common/function/src/scalars/function_registry.rs b/src/common/function/src/function_registry.rs similarity index 96% rename from src/common/function/src/scalars/function_registry.rs rename to src/common/function/src/function_registry.rs index 5d6751df7503..a1274779c3a0 100644 --- a/src/common/function/src/scalars/function_registry.rs +++ b/src/common/function/src/function_registry.rs @@ -18,12 +18,13 @@ use std::sync::{Arc, RwLock}; use once_cell::sync::Lazy; +use crate::function::FunctionRef; use crate::scalars::aggregate::{AggregateFunctionMetaRef, AggregateFunctions}; use crate::scalars::date::DateFunction; -use crate::scalars::function::FunctionRef; use crate::scalars::math::MathFunction; use crate::scalars::numpy::NumpyFunction; use crate::scalars::timestamp::TimestampFunction; +use crate::system::SystemFunction; #[derive(Default)] pub struct FunctionRegistry { @@ -79,7 +80,7 @@ pub static FUNCTION_REGISTRY: Lazy> = Lazy::new(|| { DateFunction::register(&function_registry); AggregateFunctions::register(&function_registry); - + SystemFunction::register(&function_registry); Arc::new(function_registry) }); diff --git a/src/common/function/src/lib.rs b/src/common/function/src/lib.rs index 5d3ab6d42069..e8bf35bc19dc 100644 --- a/src/common/function/src/lib.rs +++ b/src/common/function/src/lib.rs @@ -13,5 +13,8 @@ // limitations under the License. pub mod scalars; +pub mod system; +pub mod function; +pub mod function_registry; pub mod helper; diff --git a/src/common/function/src/scalars.rs b/src/common/function/src/scalars.rs index 3aa19632e7df..143d3f9cbbcd 100644 --- a/src/common/function/src/scalars.rs +++ b/src/common/function/src/scalars.rs @@ -13,16 +13,11 @@ // limitations under the License. pub mod aggregate; -mod date; +pub(crate) mod date; pub mod expression; -pub mod function; -pub mod function_registry; pub mod math; pub mod numpy; #[cfg(test)] pub(crate) mod test; -mod timestamp; +pub(crate) mod timestamp; pub mod udf; - -pub use function::{Function, FunctionRef}; -pub use function_registry::{FunctionRegistry, FUNCTION_REGISTRY}; diff --git a/src/common/function/src/scalars/aggregate.rs b/src/common/function/src/scalars/aggregate.rs index 829296498078..7ed453098318 100644 --- a/src/common/function/src/scalars/aggregate.rs +++ b/src/common/function/src/scalars/aggregate.rs @@ -33,7 +33,7 @@ pub use polyval::PolyvalAccumulatorCreator; pub use scipy_stats_norm_cdf::ScipyStatsNormCdfAccumulatorCreator; pub use scipy_stats_norm_pdf::ScipyStatsNormPdfAccumulatorCreator; -use crate::scalars::FunctionRegistry; +use crate::function_registry::FunctionRegistry; /// A function creates `AggregateFunctionCreator`. /// "Aggregator" *is* AggregatorFunction. Since the later one is long, we named an short alias for it. diff --git a/src/common/function/src/scalars/date.rs b/src/common/function/src/scalars/date.rs index 0e16019d527b..86b0c7db6202 100644 --- a/src/common/function/src/scalars/date.rs +++ b/src/common/function/src/scalars/date.rs @@ -19,7 +19,7 @@ mod date_sub; use date_add::DateAddFunction; use date_sub::DateSubFunction; -use crate::scalars::function_registry::FunctionRegistry; +use crate::function_registry::FunctionRegistry; pub(crate) struct DateFunction; diff --git a/src/common/function/src/scalars/date/date_add.rs b/src/common/function/src/scalars/date/date_add.rs index e299f7947297..1052acb86863 100644 --- a/src/common/function/src/scalars/date/date_add.rs +++ b/src/common/function/src/scalars/date/date_add.rs @@ -22,8 +22,8 @@ use datatypes::value::ValueRef; use datatypes::vectors::VectorRef; use snafu::ensure; +use crate::function::{Function, FunctionContext}; use crate::helper; -use crate::scalars::function::{Function, FunctionContext}; /// A function adds an interval value to Timestamp, Date or DateTime, and return the result. #[derive(Clone, Debug, Default)] @@ -149,7 +149,6 @@ mod tests { }; use super::{DateAddFunction, *}; - use crate::scalars::Function; #[test] fn test_date_add_misc() { diff --git a/src/common/function/src/scalars/date/date_sub.rs b/src/common/function/src/scalars/date/date_sub.rs index 15660850f558..b1f87e880ab7 100644 --- a/src/common/function/src/scalars/date/date_sub.rs +++ b/src/common/function/src/scalars/date/date_sub.rs @@ -22,8 +22,8 @@ use datatypes::value::ValueRef; use datatypes::vectors::VectorRef; use snafu::ensure; +use crate::function::{Function, FunctionContext}; use crate::helper; -use crate::scalars::function::{Function, FunctionContext}; /// A function subtracts an interval value to Timestamp, Date or DateTime, and return the result. #[derive(Clone, Debug, Default)] @@ -150,7 +150,6 @@ mod tests { }; use super::{DateSubFunction, *}; - use crate::scalars::Function; #[test] fn test_date_sub_misc() { diff --git a/src/common/function/src/scalars/math.rs b/src/common/function/src/scalars/math.rs index b38bf553b804..1e9609c5171d 100644 --- a/src/common/function/src/scalars/math.rs +++ b/src/common/function/src/scalars/math.rs @@ -28,9 +28,8 @@ pub use pow::PowFunction; pub use rate::RateFunction; use snafu::ResultExt; -use super::function::FunctionContext; -use super::Function; -use crate::scalars::function_registry::FunctionRegistry; +use crate::function::{Function, FunctionContext}; +use crate::function_registry::FunctionRegistry; pub(crate) struct MathFunction; diff --git a/src/common/function/src/scalars/math/pow.rs b/src/common/function/src/scalars/math/pow.rs index 5a1922a4fc70..5e6cc0f089e5 100644 --- a/src/common/function/src/scalars/math/pow.rs +++ b/src/common/function/src/scalars/math/pow.rs @@ -25,8 +25,8 @@ use datatypes::with_match_primitive_type_id; use num::traits::Pow; use num_traits::AsPrimitive; +use crate::function::{Function, FunctionContext}; use crate::scalars::expression::{scalar_binary_op, EvalContext}; -use crate::scalars::function::{Function, FunctionContext}; #[derive(Clone, Debug, Default)] pub struct PowFunction; @@ -83,6 +83,7 @@ mod tests { use datatypes::vectors::{Float32Vector, Int8Vector}; use super::*; + use crate::function::FunctionContext; #[test] fn test_pow_function() { let pow = PowFunction; diff --git a/src/common/function/src/scalars/math/rate.rs b/src/common/function/src/scalars/math/rate.rs index 4b6e160916df..7afc07177d1d 100644 --- a/src/common/function/src/scalars/math/rate.rs +++ b/src/common/function/src/scalars/math/rate.rs @@ -23,7 +23,7 @@ use datatypes::prelude::*; use datatypes::vectors::{Helper, VectorRef}; use snafu::ResultExt; -use crate::scalars::function::{Function, FunctionContext}; +use crate::function::{Function, FunctionContext}; /// generates rates from a sequence of adjacent data points. #[derive(Clone, Debug, Default)] diff --git a/src/common/function/src/scalars/numpy.rs b/src/common/function/src/scalars/numpy.rs index 7e1c1145bd83..33c82d44e3d6 100644 --- a/src/common/function/src/scalars/numpy.rs +++ b/src/common/function/src/scalars/numpy.rs @@ -19,7 +19,7 @@ use std::sync::Arc; use clip::ClipFunction; -use crate::scalars::function_registry::FunctionRegistry; +use crate::function_registry::FunctionRegistry; pub(crate) struct NumpyFunction; diff --git a/src/common/function/src/scalars/numpy/clip.rs b/src/common/function/src/scalars/numpy/clip.rs index cdcc4d562220..02e1256207c8 100644 --- a/src/common/function/src/scalars/numpy/clip.rs +++ b/src/common/function/src/scalars/numpy/clip.rs @@ -24,8 +24,8 @@ use datatypes::prelude::*; use datatypes::vectors::PrimitiveVector; use paste::paste; +use crate::function::{Function, FunctionContext}; use crate::scalars::expression::{scalar_binary_op, EvalContext}; -use crate::scalars::function::{Function, FunctionContext}; /// numpy.clip function, #[derive(Clone, Debug, Default)] diff --git a/src/common/function/src/scalars/test.rs b/src/common/function/src/scalars/test.rs index 1ffef23be545..573c2e715b1b 100644 --- a/src/common/function/src/scalars/test.rs +++ b/src/common/function/src/scalars/test.rs @@ -20,8 +20,8 @@ use common_query::prelude::{Signature, Volatility}; use datatypes::data_type::ConcreteDataType; use datatypes::prelude::VectorRef; +use crate::function::{Function, FunctionContext}; use crate::scalars::expression::{scalar_binary_op, EvalContext}; -use crate::scalars::function::{Function, FunctionContext}; #[derive(Clone, Default)] pub(crate) struct TestAndFunction; diff --git a/src/common/function/src/scalars/timestamp.rs b/src/common/function/src/scalars/timestamp.rs index 395b8b244379..fecf884ce02b 100644 --- a/src/common/function/src/scalars/timestamp.rs +++ b/src/common/function/src/scalars/timestamp.rs @@ -19,7 +19,7 @@ mod to_unixtime; use greatest::GreatestFunction; use to_unixtime::ToUnixtimeFunction; -use crate::scalars::function_registry::FunctionRegistry; +use crate::function_registry::FunctionRegistry; pub(crate) struct TimestampFunction; diff --git a/src/common/function/src/scalars/timestamp/greatest.rs b/src/common/function/src/scalars/timestamp/greatest.rs index db116dc04598..fd3fe0a16897 100644 --- a/src/common/function/src/scalars/timestamp/greatest.rs +++ b/src/common/function/src/scalars/timestamp/greatest.rs @@ -27,7 +27,7 @@ use datatypes::prelude::ConcreteDataType; use datatypes::vectors::{Helper, VectorRef}; use snafu::{ensure, ResultExt}; -use crate::scalars::function::{Function, FunctionContext}; +use crate::function::{Function, FunctionContext}; #[derive(Clone, Debug, Default)] pub struct GreatestFunction; @@ -113,10 +113,7 @@ mod tests { use datatypes::value::Value; use datatypes::vectors::{DateVector, StringVector, Vector}; - use super::GreatestFunction; - use crate::scalars::function::FunctionContext; - use crate::scalars::Function; - + use super::*; #[test] fn test_greatest_takes_string_vector() { let function = GreatestFunction; diff --git a/src/common/function/src/scalars/timestamp/to_unixtime.rs b/src/common/function/src/scalars/timestamp/to_unixtime.rs index 0bd8c2255e5e..4d914ecba919 100644 --- a/src/common/function/src/scalars/timestamp/to_unixtime.rs +++ b/src/common/function/src/scalars/timestamp/to_unixtime.rs @@ -23,7 +23,7 @@ use datatypes::prelude::ConcreteDataType; use datatypes::vectors::{Int64Vector, VectorRef}; use snafu::ensure; -use crate::scalars::function::{Function, FunctionContext}; +use crate::function::{Function, FunctionContext}; /// A function to convert the column into the unix timestamp in seconds. #[derive(Clone, Debug, Default)] @@ -152,7 +152,6 @@ mod tests { }; use super::{ToUnixtimeFunction, *}; - use crate::scalars::Function; #[test] fn test_string_to_unixtime() { diff --git a/src/common/function/src/scalars/udf.rs b/src/common/function/src/scalars/udf.rs index bf332720a2e3..da67f321bf8c 100644 --- a/src/common/function/src/scalars/udf.rs +++ b/src/common/function/src/scalars/udf.rs @@ -23,7 +23,7 @@ use datatypes::prelude::*; use datatypes::vectors::Helper; use snafu::ResultExt; -use crate::scalars::function::{FunctionContext, FunctionRef}; +use crate::function::{FunctionContext, FunctionRef}; /// Create a ScalarUdf from function. pub fn create_udf(func: FunctionRef) -> ScalarUdf { @@ -72,7 +72,7 @@ mod tests { use datatypes::vectors::{BooleanVector, ConstantVector}; use super::*; - use crate::scalars::function::Function; + use crate::function::Function; use crate::scalars::test::TestAndFunction; #[test] diff --git a/src/common/function/src/system.rs b/src/common/function/src/system.rs new file mode 100644 index 000000000000..2f34c99d1600 --- /dev/null +++ b/src/common/function/src/system.rs @@ -0,0 +1,29 @@ +// 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. + +pub mod build; + +use std::sync::Arc; + +use build::BuildFunction; + +use crate::function_registry::FunctionRegistry; + +pub(crate) struct SystemFunction; + +impl SystemFunction { + pub fn register(registry: &FunctionRegistry) { + registry.register(Arc::new(BuildFunction)); + } +} diff --git a/src/common/function/src/system/build.rs b/src/common/function/src/system/build.rs new file mode 100644 index 000000000000..43433ce425ce --- /dev/null +++ b/src/common/function/src/system/build.rs @@ -0,0 +1,102 @@ +// 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::sync::Arc; + +use common_query::error::Result; +use common_query::prelude::{Signature, Volatility}; +use datatypes::prelude::*; +use datatypes::vectors::{StringVector, VectorRef}; + +use crate::function::{Function, FunctionContext}; + +const DEFAULT_VALUE: &str = "unknown"; + +/// Generates build information +#[derive(Clone, Debug, Default)] +pub struct BuildFunction; + +impl fmt::Display for BuildFunction { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "BUILD") + } +} + +impl Function for BuildFunction { + fn name(&self) -> &str { + "build" + } + + fn return_type(&self, _input_types: &[ConcreteDataType]) -> Result { + Ok(ConcreteDataType::string_datatype()) + } + + fn signature(&self) -> Signature { + Signature::uniform( + 0, + vec![ConcreteDataType::string_datatype()], + Volatility::Immutable, + ) + } + + fn eval(&self, _func_ctx: FunctionContext, _columns: &[VectorRef]) -> Result { + let build_info = format!( + "branch: {}\ncommit: {}\ncommit short: {}\ndirty: {}\nversion: {}", + build_data::get_git_branch().unwrap_or_else(|_| DEFAULT_VALUE.to_string()), + build_data::get_git_commit().unwrap_or_else(|_| DEFAULT_VALUE.to_string()), + build_data::get_git_commit_short().unwrap_or_else(|_| DEFAULT_VALUE.to_string()), + build_data::get_git_dirty().map_or(DEFAULT_VALUE.to_string(), |v| v.to_string()), + env!("CARGO_PKG_VERSION") + ); + + let v = Arc::new(StringVector::from(vec![build_info])); + Ok(v) + } +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use common_query::prelude::TypeSignature; + + use super::*; + #[test] + fn test_build_function() { + let build = BuildFunction; + assert_eq!("build", build.name()); + assert_eq!( + ConcreteDataType::string_datatype(), + build.return_type(&[]).unwrap() + ); + assert!(matches!(build.signature(), + Signature { + type_signature: TypeSignature::Uniform(0, valid_types), + volatility: Volatility::Immutable + } if valid_types == vec![ConcreteDataType::string_datatype()] + )); + let build_info = format!( + "branch: {}\ncommit: {}\ncommit short: {}\ndirty: {}\nversion: {}", + build_data::get_git_branch().unwrap_or_else(|_| DEFAULT_VALUE.to_string()), + build_data::get_git_commit().unwrap_or_else(|_| DEFAULT_VALUE.to_string()), + build_data::get_git_commit_short().unwrap_or_else(|_| DEFAULT_VALUE.to_string()), + build_data::get_git_dirty().map_or(DEFAULT_VALUE.to_string(), |v| v.to_string()), + env!("CARGO_PKG_VERSION") + ); + let vector = build.eval(FunctionContext::default(), &[]).unwrap(); + let expect: VectorRef = Arc::new(StringVector::from(vec![build_info])); + assert_eq!(expect, vector); + } +} diff --git a/src/datanode/src/tests.rs b/src/datanode/src/tests.rs index b5926c0c2230..abf1064de826 100644 --- a/src/datanode/src/tests.rs +++ b/src/datanode/src/tests.rs @@ -17,8 +17,8 @@ use std::sync::Arc; use async_trait::async_trait; use common_error::ext::BoxedError; +use common_function::function::FunctionRef; use common_function::scalars::aggregate::AggregateFunctionMetaRef; -use common_function::scalars::FunctionRef; use common_query::prelude::ScalarUdf; use common_query::Output; use common_recordbatch::SendableRecordBatchStream; diff --git a/src/query/src/datafusion.rs b/src/query/src/datafusion.rs index b0b7c55ebfb1..a05093e32978 100644 --- a/src/query/src/datafusion.rs +++ b/src/query/src/datafusion.rs @@ -24,9 +24,9 @@ use std::sync::Arc; use async_trait::async_trait; use common_base::Plugins; use common_error::ext::BoxedError; +use common_function::function::FunctionRef; use common_function::scalars::aggregate::AggregateFunctionMetaRef; use common_function::scalars::udf::create_udf; -use common_function::scalars::FunctionRef; use common_query::physical_plan::{DfPhysicalPlanAdapter, PhysicalPlan, PhysicalPlanAdapter}; use common_query::prelude::ScalarUdf; use common_query::Output; diff --git a/src/query/src/query_engine.rs b/src/query/src/query_engine.rs index 9e94037ba3aa..ec271a818fc9 100644 --- a/src/query/src/query_engine.rs +++ b/src/query/src/query_engine.rs @@ -22,8 +22,9 @@ use std::sync::Arc; use async_trait::async_trait; use catalog::CatalogManagerRef; use common_base::Plugins; +use common_function::function::FunctionRef; +use common_function::function_registry::FUNCTION_REGISTRY; use common_function::scalars::aggregate::AggregateFunctionMetaRef; -use common_function::scalars::{FunctionRef, FUNCTION_REGISTRY}; use common_query::prelude::ScalarUdf; use common_query::Output; use datatypes::schema::Schema; diff --git a/src/script/src/python/engine.rs b/src/script/src/python/engine.rs index 61f603232a74..30c7fbca193f 100644 --- a/src/script/src/python/engine.rs +++ b/src/script/src/python/engine.rs @@ -21,7 +21,8 @@ use std::task::{Context, Poll}; use async_trait::async_trait; use common_error::ext::BoxedError; -use common_function::scalars::{Function, FUNCTION_REGISTRY}; +use common_function::function::Function; +use common_function::function_registry::FUNCTION_REGISTRY; use common_query::error::{PyUdfSnafu, UdfTempRecordBatchSnafu}; use common_query::prelude::Signature; use common_query::Output; @@ -150,7 +151,7 @@ impl Function for PyUDF { fn eval( &self, - _func_ctx: common_function::scalars::function::FunctionContext, + _func_ctx: common_function::function::FunctionContext, columns: &[datatypes::vectors::VectorRef], ) -> common_query::error::Result { // FIXME(discord9): exec_parsed require a RecordBatch(basically a Vector+Schema), where schema can't pop out from nowhere, right? diff --git a/src/script/src/python/pyo3/builtins.rs b/src/script/src/python/pyo3/builtins.rs index 6051a5307b99..c4c10cc0e499 100644 --- a/src/script/src/python/pyo3/builtins.rs +++ b/src/script/src/python/pyo3/builtins.rs @@ -14,7 +14,8 @@ use std::sync::Arc; -use common_function::scalars::{FunctionRef, FUNCTION_REGISTRY}; +use common_function::function::FunctionRef; +use common_function::function_registry::FUNCTION_REGISTRY; use datafusion::arrow::array::{ArrayRef, NullArray}; use datafusion::physical_plan::expressions; use datafusion_expr::ColumnarValue; diff --git a/src/script/src/python/rspython/builtins.rs b/src/script/src/python/rspython/builtins.rs index 8521a4dc9858..da8c3d6a51a8 100644 --- a/src/script/src/python/rspython/builtins.rs +++ b/src/script/src/python/rspython/builtins.rs @@ -288,9 +288,9 @@ pub(crate) mod greptime_builtin { use std::sync::Arc; use arrow::compute::kernels::{aggregate, boolean}; - use common_function::scalars::function::FunctionContext; + use common_function::function::{Function, FunctionContext, FunctionRef}; + use common_function::function_registry::FUNCTION_REGISTRY; use common_function::scalars::math::PowFunction; - use common_function::scalars::{Function, FunctionRef, FUNCTION_REGISTRY}; use datafusion::arrow::datatypes::DataType as ArrowDataType; use datafusion::dataframe::DataFrame as DfDataFrame; use datafusion::physical_plan::expressions; diff --git a/tests/cases/standalone/common/function/system.result b/tests/cases/standalone/common/function/system.result new file mode 100644 index 000000000000..0e054d1fecd5 --- /dev/null +++ b/tests/cases/standalone/common/function/system.result @@ -0,0 +1,10 @@ +-- SQLNESS REPLACE branch:\s+.+ branch: BRANCH +-- SQLNESS REPLACE commit:\s+.+ commit: COMMIT +-- SQLNESS REPLACE commit+\s+short:\s+.+ commit short: COMMIT SHORT +-- SQLNESS REPLACE dirty:\s+.+ dirty: DIRTY +-- SQLNESS REPLACE version:\s+.+ version: VERSION +-- SQLNESS REPLACE [\s\-]+ +SELECT build(); + +++|build()|++|branch:BRANCH|commit:COMMIT|commitshort:COMMITSHORT|dirty:DIRTY|version:VERSION++ + diff --git a/tests/cases/standalone/common/function/system.sql b/tests/cases/standalone/common/function/system.sql new file mode 100644 index 000000000000..af5393721470 --- /dev/null +++ b/tests/cases/standalone/common/function/system.sql @@ -0,0 +1,7 @@ +-- SQLNESS REPLACE branch:\s+.+ branch: BRANCH +-- SQLNESS REPLACE commit:\s+.+ commit: COMMIT +-- SQLNESS REPLACE commit+\s+short:\s+.+ commit short: COMMIT SHORT +-- SQLNESS REPLACE dirty:\s+.+ dirty: DIRTY +-- SQLNESS REPLACE version:\s+.+ version: VERSION +-- SQLNESS REPLACE [\s\-]+ +SELECT build();