feat: add build() function to return the database build info (#2919)

* feat: add build function and register it

build() function to return the database build info #2909

* refactor: fix typos and change code structure

* test: add test for build()

* refactor: cargo fmt and eliminate warnings

* Apply suggestions from code review

Co-authored-by: Weny Xu <wenymedia@gmail.com>

* refactor: move system.sql to a new directory

---------

Co-authored-by: Weny Xu <wenymedia@gmail.com>
This commit is contained in:
Yue Deng
2023-12-13 17:02:00 +08:00
committed by GitHub
parent fec3fcf4ef
commit 3d651522c2
30 changed files with 187 additions and 41 deletions

1
Cargo.lock generated
View File

@@ -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",

View File

@@ -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

View File

@@ -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<Arc<FunctionRegistry>> = Lazy::new(|| {
DateFunction::register(&function_registry);
AggregateFunctions::register(&function_registry);
SystemFunction::register(&function_registry);
Arc::new(function_registry)
});

View File

@@ -13,5 +13,8 @@
// limitations under the License.
pub mod scalars;
pub mod system;
pub mod function;
pub mod function_registry;
pub mod helper;

View File

@@ -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};

View File

@@ -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.

View File

@@ -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;

View File

@@ -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() {

View File

@@ -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() {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)]

View File

@@ -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;

View File

@@ -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, <https://numpy.org/doc/stable/reference/generated/numpy.clip.html>
#[derive(Clone, Debug, Default)]

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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() {

View File

@@ -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]

View File

@@ -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));
}
}

View File

@@ -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<ConcreteDataType> {
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<VectorRef> {
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);
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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<datatypes::vectors::VectorRef> {
// FIXME(discord9): exec_parsed require a RecordBatch(basically a Vector+Schema), where schema can't pop out from nowhere, right?

View File

@@ -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;

View File

@@ -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;

View File

@@ -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++

View File

@@ -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();