From 3eccb360472118ecb7e72dcddbf07eeac6fd5908 Mon Sep 17 00:00:00 2001 From: Yingwen Date: Tue, 5 Sep 2023 10:33:29 +0800 Subject: [PATCH] feat: avoid using vector to get default value (#2323) --- src/common/time/src/timestamp.rs | 12 +++ src/datatypes/src/schema/column_schema.rs | 17 +++- src/datatypes/src/schema/constraint.rs | 97 +++++++++++++++++------ 3 files changed, 98 insertions(+), 28 deletions(-) diff --git a/src/common/time/src/timestamp.rs b/src/common/time/src/timestamp.rs index 2a066e9906..e3507b385d 100644 --- a/src/common/time/src/timestamp.rs +++ b/src/common/time/src/timestamp.rs @@ -54,6 +54,18 @@ impl Timestamp { } } + /// Creates current timestamp in specific time `unit`. + pub fn current_time(unit: TimeUnit) -> Timestamp { + let now = chrono::Utc::now(); + let value = match unit { + TimeUnit::Second => now.timestamp(), + TimeUnit::Millisecond => now.timestamp_millis(), + TimeUnit::Microsecond => now.timestamp_micros(), + TimeUnit::Nanosecond => now.timestamp_nanos(), + }; + Timestamp { value, unit } + } + /// Subtracts a duration from timestamp. /// # Note /// The result time unit remains unchanged even if `duration` has a different unit with `self`. diff --git a/src/datatypes/src/schema/column_schema.rs b/src/datatypes/src/schema/column_schema.rs index 600eed1353..39a5405898 100644 --- a/src/datatypes/src/schema/column_schema.rs +++ b/src/datatypes/src/schema/column_schema.rs @@ -161,8 +161,21 @@ impl ColumnSchema { /// /// If the column is `NOT NULL` but doesn't has `DEFAULT` value supplied, returns `Ok(None)`. pub fn create_default(&self) -> Result> { - self.create_default_vector(1) - .map(|vec_ref_option| vec_ref_option.map(|vec_ref| vec_ref.get(0))) + match &self.default_constraint { + Some(c) => c + .create_default(&self.data_type, self.is_nullable) + .map(Some), + None => { + if self.is_nullable { + // No default constraint, use null as default value. + ColumnDefaultConstraint::null_value() + .create_default(&self.data_type, self.is_nullable) + .map(Some) + } else { + Ok(None) + } + } + } } } diff --git a/src/datatypes/src/schema/constraint.rs b/src/datatypes/src/schema/constraint.rs index 2d6d0d9e58..b00a8d7dca 100644 --- a/src/datatypes/src/schema/constraint.rs +++ b/src/datatypes/src/schema/constraint.rs @@ -14,7 +14,7 @@ use std::fmt::{Display, Formatter}; -use common_time::util; +use common_time::{util, Timestamp}; use serde::{Deserialize, Serialize}; use snafu::{ensure, ResultExt}; @@ -150,6 +150,28 @@ impl ColumnDefaultConstraint { } } + /// Create a default value for given `data_type`. + /// + /// If `is_nullable` is `true`, then this method would returns error if the created + /// default value is null. + pub fn create_default(&self, data_type: &ConcreteDataType, is_nullable: bool) -> Result { + match self { + ColumnDefaultConstraint::Function(expr) => { + // Functions should also ensure its return value is not null when + // is_nullable is true. + match &expr[..] { + CURRENT_TIMESTAMP => create_current_timestamp(data_type), + _ => error::UnsupportedDefaultExprSnafu { expr }.fail(), + } + } + ColumnDefaultConstraint::Value(v) => { + ensure!(is_nullable || !v.is_null(), error::NullDefaultSnafu); + + Ok(v.clone()) + } + } + } + /// Returns true if this constraint might creates NULL. fn maybe_null(&self) -> bool { // Once we support more functions, we may return true if given function @@ -158,6 +180,18 @@ impl ColumnDefaultConstraint { } } +fn create_current_timestamp(data_type: &ConcreteDataType) -> Result { + let Some(timestamp_type) = data_type.as_timestamp() else { + return error::DefaultValueTypeSnafu { + reason: format!("Not support to assign current timestamp to {data_type:?} type"), + } + .fail(); + }; + + let unit = timestamp_type.unit(); + Ok(Value::Timestamp(Timestamp::current_time(unit))) +} + fn create_current_timestamp_vector( data_type: &ConcreteDataType, num_rows: usize, @@ -246,7 +280,7 @@ mod tests { } #[test] - fn test_create_default_vector_by_value() { + fn test_create_default_by_value() { let constraint = ColumnDefaultConstraint::Value(Value::Int32(10)); let data_type = ConcreteDataType::int32_datatype(); let v = constraint @@ -254,55 +288,65 @@ mod tests { .unwrap(); let expect: VectorRef = Arc::new(Int32Vector::from_values(vec![10; 4])); assert_eq!(expect, v); + let v = constraint.create_default(&data_type, false).unwrap(); + assert_eq!(Value::Int32(10), v); } #[test] fn test_create_default_vector_by_func() { let constraint = ColumnDefaultConstraint::Function(CURRENT_TIMESTAMP.to_string()); + let check_value = |v| { + assert!( + matches!(v, Value::Timestamp(_)), + "v {:?} is not timestamp", + v + ); + }; + let check_vector = |v: VectorRef| { + assert_eq!(4, v.len()); + assert!( + matches!(v.get(0), Value::Timestamp(_)), + "v {:?} is not timestamp", + v.get(0) + ); + }; + // Timestamp type. let data_type = ConcreteDataType::timestamp_millisecond_datatype(); let v = constraint .create_default_vector(&data_type, false, 4) .unwrap(); - assert_eq!(4, v.len()); - assert!( - matches!(v.get(0), Value::Timestamp(_)), - "v {:?} is not timestamp", - v.get(0) - ); + check_vector(v); + + let v = constraint.create_default(&data_type, false).unwrap(); + check_value(v); let data_type = ConcreteDataType::timestamp_second_datatype(); let v = constraint .create_default_vector(&data_type, false, 4) .unwrap(); - assert_eq!(4, v.len()); - assert!( - matches!(v.get(0), Value::Timestamp(_)), - "v {:?} is not timestamp", - v.get(0) - ); + check_vector(v); + + let v = constraint.create_default(&data_type, false).unwrap(); + check_value(v); let data_type = ConcreteDataType::timestamp_microsecond_datatype(); let v = constraint .create_default_vector(&data_type, false, 4) .unwrap(); - assert_eq!(4, v.len()); - assert!( - matches!(v.get(0), Value::Timestamp(_)), - "v {:?} is not timestamp", - v.get(0) - ); + check_vector(v); + + let v = constraint.create_default(&data_type, false).unwrap(); + check_value(v); let data_type = ConcreteDataType::timestamp_nanosecond_datatype(); let v = constraint .create_default_vector(&data_type, false, 4) .unwrap(); - assert_eq!(4, v.len()); - assert!( - matches!(v.get(0), Value::Timestamp(_)), - "v {:?} is not timestamp", - v.get(0) - ); + check_vector(v); + + let v = constraint.create_default(&data_type, false).unwrap(); + check_value(v); // Int64 type. let data_type = ConcreteDataType::int64_datatype(); @@ -321,6 +365,7 @@ mod tests { assert!(constraint .create_default_vector(&data_type, false, 4) .is_err()); + assert!(constraint.create_default(&data_type, false).is_err()); } #[test]