Skip to content

Commit 0959c1d

Browse files
authored
feat: support default value when inserting data (#854)
1 parent e428a84 commit 0959c1d

File tree

8 files changed

+224
-52
lines changed

8 files changed

+224
-52
lines changed

src/datanode/src/error.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,26 @@ pub enum Error {
295295

296296
#[snafu(display("Cannot find requested database: {}-{}", catalog, schema))]
297297
DatabaseNotFound { catalog: String, schema: String },
298+
299+
#[snafu(display(
300+
"Failed to build default value, column: {}, source: {}",
301+
column,
302+
source
303+
))]
304+
ColumnDefaultValue {
305+
column: String,
306+
#[snafu(backtrace)]
307+
source: datatypes::error::Error,
308+
},
309+
310+
#[snafu(display(
311+
"No valid default value can be build automatically, column: {}",
312+
column,
313+
))]
314+
ColumnNoneDefaultValue {
315+
column: String,
316+
backtrace: Backtrace,
317+
},
298318
}
299319

300320
pub type Result<T> = std::result::Result<T, Error>;
@@ -363,6 +383,8 @@ impl ErrorExt for Error {
363383
Error::BumpTableId { source, .. } => source.status_code(),
364384
Error::MissingNodeId { .. } => StatusCode::InvalidArguments,
365385
Error::MissingMetasrvOpts { .. } => StatusCode::InvalidArguments,
386+
Error::ColumnDefaultValue { source, .. } => source.status_code(),
387+
Error::ColumnNoneDefaultValue { .. } => StatusCode::InvalidArguments,
366388
}
367389
}
368390

src/datanode/src/sql/insert.rs

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use catalog::CatalogManagerRef;
1616
use common_query::Output;
1717
use datatypes::data_type::DataType;
18-
use datatypes::prelude::ConcreteDataType;
18+
use datatypes::schema::ColumnSchema;
1919
use datatypes::vectors::MutableVector;
2020
use snafu::{ensure, OptionExt, ResultExt};
2121
use sql::ast::Value as SqlValue;
@@ -25,11 +25,14 @@ use table::engine::TableReference;
2525
use table::requests::*;
2626

2727
use crate::error::{
28-
CatalogSnafu, ColumnNotFoundSnafu, ColumnValuesNumberMismatchSnafu, InsertSnafu,
29-
ParseSqlValueSnafu, Result, TableNotFoundSnafu,
28+
CatalogSnafu, ColumnDefaultValueSnafu, ColumnNoneDefaultValueSnafu, ColumnNotFoundSnafu,
29+
ColumnValuesNumberMismatchSnafu, InsertSnafu, ParseSqlSnafu, ParseSqlValueSnafu, Result,
30+
TableNotFoundSnafu,
3031
};
3132
use crate::sql::{SqlHandler, SqlRequest};
3233

34+
const DEFAULT_PLACEHOLDER_VALUE: &str = "default";
35+
3336
impl SqlHandler {
3437
pub(crate) async fn insert(&self, req: InsertRequest) -> Result<Output> {
3538
// FIXME(dennis): table_ref is used in InsertSnafu and the req is consumed
@@ -72,17 +75,13 @@ impl SqlHandler {
7275
};
7376
let rows_num = values.len();
7477

75-
let mut columns_builders: Vec<(&String, &ConcreteDataType, Box<dyn MutableVector>)> =
78+
let mut columns_builders: Vec<(&ColumnSchema, Box<dyn MutableVector>)> =
7679
Vec::with_capacity(columns_num);
7780

7881
if columns.is_empty() {
7982
for column_schema in schema.column_schemas() {
8083
let data_type = &column_schema.data_type;
81-
columns_builders.push((
82-
&column_schema.name,
83-
data_type,
84-
data_type.create_mutable_vector(rows_num),
85-
));
84+
columns_builders.push((column_schema, data_type.create_mutable_vector(rows_num)));
8685
}
8786
} else {
8887
for column_name in columns {
@@ -94,11 +93,7 @@ impl SqlHandler {
9493
}
9594
})?;
9695
let data_type = &column_schema.data_type;
97-
columns_builders.push((
98-
column_name,
99-
data_type,
100-
data_type.create_mutable_vector(rows_num),
101-
));
96+
columns_builders.push((column_schema, data_type.create_mutable_vector(rows_num)));
10297
}
10398
}
10499

@@ -112,10 +107,8 @@ impl SqlHandler {
112107
}
113108
);
114109

115-
for (sql_val, (column_name, data_type, builder)) in
116-
row.iter().zip(columns_builders.iter_mut())
117-
{
118-
add_row_to_vector(column_name, data_type, sql_val, builder)?;
110+
for (sql_val, (column_schema, builder)) in row.iter().zip(columns_builders.iter_mut()) {
111+
add_row_to_vector(column_schema, sql_val, builder)?;
119112
}
120113
}
121114

@@ -125,21 +118,34 @@ impl SqlHandler {
125118
table_name: table_ref.table.to_string(),
126119
columns_values: columns_builders
127120
.into_iter()
128-
.map(|(c, _, mut b)| (c.to_owned(), b.to_vector()))
121+
.map(|(cs, mut b)| (cs.name.to_string(), b.to_vector()))
129122
.collect(),
130123
}))
131124
}
132125
}
133126

134127
fn add_row_to_vector(
135-
column_name: &str,
136-
data_type: &ConcreteDataType,
128+
column_schema: &ColumnSchema,
137129
sql_val: &SqlValue,
138130
builder: &mut Box<dyn MutableVector>,
139131
) -> Result<()> {
140-
let value = statements::sql_value_to_value(column_name, data_type, sql_val)
141-
.context(ParseSqlValueSnafu)?;
132+
let value = if replace_default(sql_val) {
133+
column_schema
134+
.create_default()
135+
.context(ColumnDefaultValueSnafu {
136+
column: column_schema.name.to_string(),
137+
})?
138+
.context(ColumnNoneDefaultValueSnafu {
139+
column: column_schema.name.to_string(),
140+
})?
141+
} else {
142+
statements::sql_value_to_value(&column_schema.name, &column_schema.data_type, sql_val)
143+
.context(ParseSqlSnafu)?
144+
};
142145
builder.push_value_ref(value.as_value_ref()).unwrap();
143-
144146
Ok(())
145147
}
148+
149+
fn replace_default(sql_val: &SqlValue) -> bool {
150+
matches!(sql_val, SqlValue::Placeholder(s) if s.to_lowercase() == DEFAULT_PLACEHOLDER_VALUE)
151+
}

src/datatypes/src/schema/column_schema.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,14 @@ impl ColumnSchema {
150150
}
151151
mutable_vector.to_vector()
152152
}
153+
154+
/// Creates a default value for this column.
155+
///
156+
/// If the column is `NOT NULL` but doesn't has `DEFAULT` value supplied, returns `Ok(None)`.
157+
pub fn create_default(&self) -> Result<Option<Value>> {
158+
self.create_default_vector(1)
159+
.map(|vec_ref_option| vec_ref_option.map(|vec_ref| vec_ref.get(0)))
160+
}
153161
}
154162

155163
impl TryFrom<&Field> for ColumnSchema {
@@ -337,4 +345,34 @@ mod tests {
337345
let expect: VectorRef = Arc::new(Int32Vector::from_slice(&[0, 0, 0, 0]));
338346
assert_eq!(expect, vector);
339347
}
348+
349+
#[test]
350+
fn test_column_schema_single_create_default_null() {
351+
// Implicit default null.
352+
let column_schema = ColumnSchema::new("test", ConcreteDataType::int32_datatype(), true);
353+
let v = column_schema.create_default().unwrap().unwrap();
354+
assert!(v.is_null());
355+
356+
// Explicit default null.
357+
let column_schema = ColumnSchema::new("test", ConcreteDataType::int32_datatype(), true)
358+
.with_default_constraint(Some(ColumnDefaultConstraint::null_value()))
359+
.unwrap();
360+
let v = column_schema.create_default().unwrap().unwrap();
361+
assert!(v.is_null());
362+
}
363+
364+
#[test]
365+
fn test_column_schema_single_create_default_not_null() {
366+
let column_schema = ColumnSchema::new("test", ConcreteDataType::int32_datatype(), true)
367+
.with_default_constraint(Some(ColumnDefaultConstraint::Value(Value::Int32(6))))
368+
.unwrap();
369+
let v = column_schema.create_default().unwrap().unwrap();
370+
assert_eq!(v, Value::Int32(6));
371+
}
372+
373+
#[test]
374+
fn test_column_schema_single_no_default() {
375+
let column_schema = ColumnSchema::new("test", ConcreteDataType::int32_datatype(), false);
376+
assert!(column_schema.create_default().unwrap().is_none());
377+
}
340378
}

src/frontend/src/error.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,26 @@ pub enum Error {
378378
#[snafu(backtrace)]
379379
source: common_grpc_expr::error::Error,
380380
},
381+
382+
#[snafu(display(
383+
"Failed to build default value, column: {}, source: {}",
384+
column,
385+
source
386+
))]
387+
ColumnDefaultValue {
388+
column: String,
389+
#[snafu(backtrace)]
390+
source: datatypes::error::Error,
391+
},
392+
393+
#[snafu(display(
394+
"No valid default value can be build automatically, column: {}",
395+
column,
396+
))]
397+
ColumnNoneDefaultValue {
398+
column: String,
399+
backtrace: Backtrace,
400+
},
381401
}
382402

383403
pub type Result<T> = std::result::Result<T, Error>;
@@ -457,6 +477,8 @@ impl ErrorExt for Error {
457477
Error::EncodeSubstraitLogicalPlan { source } => source.status_code(),
458478
Error::BuildVector { source, .. } => source.status_code(),
459479
Error::InvokeDatanode { source } => source.status_code(),
480+
Error::ColumnDefaultValue { source, .. } => source.status_code(),
481+
Error::ColumnNoneDefaultValue { .. } => StatusCode::InvalidArguments,
460482
}
461483
}
462484

src/frontend/src/sql.rs

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,18 @@
1414

1515
use common_error::snafu::ensure;
1616
use datatypes::data_type::DataType;
17-
use datatypes::prelude::{ConcreteDataType, MutableVector};
17+
use datatypes::prelude::MutableVector;
18+
use datatypes::schema::ColumnSchema;
1819
use snafu::{OptionExt, ResultExt};
1920
use sql::ast::Value as SqlValue;
2021
use sql::statements;
2122
use sql::statements::insert::Insert;
2223
use table::requests::InsertRequest;
2324
use table::TableRef;
2425

25-
use crate::error::{self, BuildVectorSnafu, Result};
26+
use crate::error::{self, Result};
27+
28+
const DEFAULT_PLACEHOLDER_VALUE: &str = "default";
2629

2730
// TODO(fys): Extract the common logic in datanode and frontend in the future.
2831
#[allow(dead_code)]
@@ -40,17 +43,13 @@ pub(crate) fn insert_to_request(table: &TableRef, stmt: Insert) -> Result<Insert
4043
};
4144
let rows_num = values.len();
4245

43-
let mut columns_builders: Vec<(&String, &ConcreteDataType, Box<dyn MutableVector>)> =
46+
let mut columns_builders: Vec<(&ColumnSchema, Box<dyn MutableVector>)> =
4447
Vec::with_capacity(columns_num);
4548

4649
if columns.is_empty() {
4750
for column_schema in schema.column_schemas() {
4851
let data_type = &column_schema.data_type;
49-
columns_builders.push((
50-
&column_schema.name,
51-
data_type,
52-
data_type.create_mutable_vector(rows_num),
53-
));
52+
columns_builders.push((column_schema, data_type.create_mutable_vector(rows_num)));
5453
}
5554
} else {
5655
for column_name in columns {
@@ -61,11 +60,7 @@ pub(crate) fn insert_to_request(table: &TableRef, stmt: Insert) -> Result<Insert
6160
}
6261
})?;
6362
let data_type = &column_schema.data_type;
64-
columns_builders.push((
65-
column_name,
66-
data_type,
67-
data_type.create_mutable_vector(rows_num),
68-
));
63+
columns_builders.push((column_schema, data_type.create_mutable_vector(rows_num)));
6964
}
7065
}
7166

@@ -78,10 +73,8 @@ pub(crate) fn insert_to_request(table: &TableRef, stmt: Insert) -> Result<Insert
7873
}
7974
);
8075

81-
for (sql_val, (column_name, data_type, builder)) in
82-
row.iter().zip(columns_builders.iter_mut())
83-
{
84-
add_row_to_vector(column_name, data_type, sql_val, builder)?;
76+
for (sql_val, (column_schema, builder)) in row.iter().zip(columns_builders.iter_mut()) {
77+
add_row_to_vector(column_schema, sql_val, builder)?;
8578
}
8679
}
8780

@@ -91,21 +84,33 @@ pub(crate) fn insert_to_request(table: &TableRef, stmt: Insert) -> Result<Insert
9184
table_name,
9285
columns_values: columns_builders
9386
.into_iter()
94-
.map(|(c, _, mut b)| (c.to_owned(), b.to_vector()))
87+
.map(|(cs, mut b)| (cs.name.to_string(), b.to_vector()))
9588
.collect(),
9689
})
9790
}
9891

9992
fn add_row_to_vector(
100-
column_name: &str,
101-
data_type: &ConcreteDataType,
93+
column_schema: &ColumnSchema,
10294
sql_val: &SqlValue,
10395
builder: &mut Box<dyn MutableVector>,
10496
) -> Result<()> {
105-
let value = statements::sql_value_to_value(column_name, data_type, sql_val)
106-
.context(error::ParseSqlSnafu)?;
107-
builder
108-
.push_value_ref(value.as_value_ref())
109-
.context(BuildVectorSnafu { value })?;
97+
let value = if replace_default(sql_val) {
98+
column_schema
99+
.create_default()
100+
.context(error::ColumnDefaultValueSnafu {
101+
column: column_schema.name.to_string(),
102+
})?
103+
.context(error::ColumnNoneDefaultValueSnafu {
104+
column: column_schema.name.to_string(),
105+
})?
106+
} else {
107+
statements::sql_value_to_value(&column_schema.name, &column_schema.data_type, sql_val)
108+
.context(error::ParseSqlSnafu)?
109+
};
110+
builder.push_value_ref(value.as_value_ref()).unwrap();
110111
Ok(())
111112
}
113+
114+
fn replace_default(sql_val: &SqlValue) -> bool {
115+
matches!(sql_val, SqlValue::Placeholder(s) if s.to_lowercase() == DEFAULT_PLACEHOLDER_VALUE)
116+
}

src/sql/src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ pub enum Error {
131131
#[snafu(backtrace)]
132132
source: api::error::Error,
133133
},
134+
135+
#[snafu(display("Invalid sql value: {}", value))]
136+
InvalidSqlValue { value: String, backtrace: Backtrace },
134137
}
135138

136139
impl ErrorExt for Error {
@@ -156,6 +159,7 @@ impl ErrorExt for Error {
156159
UnsupportedAlterTableStatement { .. } => StatusCode::InvalidSyntax,
157160
SerializeColumnDefaultConstraint { source, .. } => source.status_code(),
158161
ConvertToGrpcDataType { source, .. } => source.status_code(),
162+
InvalidSqlValue { .. } => StatusCode::InvalidArguments,
159163
}
160164
}
161165

src/sql/src/statements.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ use crate::ast::{
3939
Value as SqlValue,
4040
};
4141
use crate::error::{
42-
self, ColumnTypeMismatchSnafu, ConvertToGrpcDataTypeSnafu, ParseSqlValueSnafu, Result,
43-
SerializeColumnDefaultConstraintSnafu, UnsupportedDefaultValueSnafu,
42+
self, ColumnTypeMismatchSnafu, ConvertToGrpcDataTypeSnafu, InvalidSqlValueSnafu,
43+
ParseSqlValueSnafu, Result, SerializeColumnDefaultConstraintSnafu,
44+
UnsupportedDefaultValueSnafu,
4445
};
4546

4647
// TODO(LFC): Get rid of this function, use session context aware version of "table_idents_to_full_name" instead.
@@ -222,6 +223,7 @@ pub fn sql_value_to_value(
222223
parse_string_to_value(column_name, s.to_owned(), data_type)?
223224
}
224225
SqlValue::HexStringLiteral(s) => parse_hex_string(s)?,
226+
SqlValue::Placeholder(s) => return InvalidSqlValueSnafu { value: s }.fail(),
225227
_ => todo!("Other sql value"),
226228
})
227229
}
@@ -720,4 +722,14 @@ mod tests {
720722
assert!(!column_schema.is_nullable());
721723
assert!(!column_schema.is_time_index());
722724
}
725+
726+
#[test]
727+
pub fn test_parse_placeholder_value() {
728+
assert!(sql_value_to_value(
729+
"test",
730+
&ConcreteDataType::string_datatype(),
731+
&SqlValue::Placeholder("default".into())
732+
)
733+
.is_err());
734+
}
723735
}

0 commit comments

Comments
 (0)