1use common_time::timezone::Timezone;
16use datatypes::prelude::ConcreteDataType;
17use datatypes::schema::constraint::{CURRENT_TIMESTAMP, CURRENT_TIMESTAMP_FN};
18use datatypes::schema::{ColumnDefaultConstraint, ColumnSchema};
19use snafu::ensure;
20use sqlparser::ast::ValueWithSpan;
21pub use sqlparser::ast::{
22 BinaryOperator, ColumnDef, ColumnOption, ColumnOptionDef, DataType, Expr, Function,
23 FunctionArg, FunctionArgExpr, FunctionArguments, Ident, ObjectName, SqlOption, TableConstraint,
24 TimezoneInfo, UnaryOperator, Value as SqlValue, Visit, VisitMut, Visitor, VisitorMut,
25 visit_expressions_mut, visit_statements_mut,
26};
27
28use crate::convert::{sql_number_to_value, sql_value_to_value};
29use crate::error::{Result, UnsupportedDefaultValueSnafu};
30
31pub fn parse_column_default_constraint(
32 column_name: &str,
33 data_type: &ConcreteDataType,
34 opts: &[ColumnOptionDef],
35 timezone: Option<&Timezone>,
36) -> Result<Option<ColumnDefaultConstraint>> {
37 if let Some(opt) = opts
38 .iter()
39 .find(|o| matches!(o.option, ColumnOption::Default(_)))
40 {
41 ensure!(
42 !data_type.is_json(),
43 UnsupportedDefaultValueSnafu {
44 column_name,
45 reason: "json column cannot have a default value",
46 }
47 );
48
49 let default_constraint = match &opt.option {
50 ColumnOption::Default(Expr::Value(v)) => {
51 let schema = ColumnSchema::new(column_name, data_type.clone(), true);
52 ColumnDefaultConstraint::Value(sql_value_to_value(
53 &schema, &v.value, timezone, None, false,
54 )?)
55 }
56 ColumnOption::Default(Expr::Function(func)) => {
57 let mut func = format!("{func}").to_lowercase();
58 if func == CURRENT_TIMESTAMP {
60 func = CURRENT_TIMESTAMP_FN.to_string();
61 }
62 ColumnDefaultConstraint::Function(func.to_lowercase())
64 }
65
66 ColumnOption::Default(Expr::UnaryOp { op, expr }) => {
67 if let (
71 UnaryOperator::Minus,
72 Expr::Value(ValueWithSpan {
73 value: SqlValue::Number(n, _),
74 span: _,
75 }),
76 ) = (op, expr.as_ref())
77 {
78 return Ok(Some(ColumnDefaultConstraint::Value(sql_number_to_value(
79 data_type,
80 &format!("-{n}"),
81 )?)));
82 }
83
84 if let Expr::Value(v) = &**expr {
85 let value = sql_value_to_value(
86 &ColumnSchema::new(column_name, data_type.clone(), true),
87 &v.value,
88 timezone,
89 Some(*op),
90 false,
91 )?;
92 ColumnDefaultConstraint::Value(value)
93 } else {
94 return UnsupportedDefaultValueSnafu {
95 column_name,
96 reason: format!("expr '{expr}' not supported"),
97 }
98 .fail();
99 }
100 }
101 ColumnOption::Default(others) => {
102 return UnsupportedDefaultValueSnafu {
103 column_name,
104 reason: format!("expr '{others}' not supported"),
105 }
106 .fail();
107 }
108 _ => {
109 return UnsupportedDefaultValueSnafu {
110 column_name,
111 reason: format!("option '{}' not supported", opt.option),
112 }
113 .fail();
114 }
115 };
116
117 Ok(Some(default_constraint))
118 } else {
119 Ok(None)
120 }
121}
122
123#[cfg(test)]
124mod test {
125 use std::assert_matches::assert_matches;
126
127 use datatypes::prelude::{ConcreteDataType, Value};
128 use datatypes::types::BooleanType;
129
130 use super::*;
131
132 #[test]
133 pub fn test_parse_column_default_constraint() {
134 let bool_value = sqlparser::ast::Value::Boolean(true);
135
136 let opts = vec![
137 ColumnOptionDef {
138 name: None,
139 option: ColumnOption::Default(Expr::Value(bool_value.into())),
140 },
141 ColumnOptionDef {
142 name: None,
143 option: ColumnOption::NotNull,
144 },
145 ];
146
147 let constraint = parse_column_default_constraint(
148 "coll",
149 &ConcreteDataType::Boolean(BooleanType),
150 &opts,
151 None,
152 )
153 .unwrap();
154
155 assert_matches!(
156 constraint,
157 Some(ColumnDefaultConstraint::Value(Value::Boolean(true)))
158 );
159
160 let opts = vec![ColumnOptionDef {
162 name: None,
163 option: ColumnOption::Default(Expr::UnaryOp {
164 op: UnaryOperator::Minus,
165 expr: Box::new(Expr::Value(
166 SqlValue::Number("32768".to_string(), false).into(),
167 )),
168 }),
169 }];
170
171 let constraint = parse_column_default_constraint(
172 "coll",
173 &ConcreteDataType::int16_datatype(),
174 &opts,
175 None,
176 )
177 .unwrap();
178
179 assert_matches!(
180 constraint,
181 Some(ColumnDefaultConstraint::Value(Value::Int16(-32768)))
182 );
183 }
184
185 #[test]
186 fn test_incorrect_default_value_issue_3479() {
187 let opts = vec![ColumnOptionDef {
188 name: None,
189 option: ColumnOption::Default(Expr::Value(
190 SqlValue::Number("0.047318541668048164".into(), false).into(),
191 )),
192 }];
193 let constraint = parse_column_default_constraint(
194 "coll",
195 &ConcreteDataType::float64_datatype(),
196 &opts,
197 None,
198 )
199 .unwrap()
200 .unwrap();
201 assert_eq!("0.047318541668048164", constraint.to_string());
202 let encoded: Vec<u8> = constraint.clone().try_into().unwrap();
203 let decoded = ColumnDefaultConstraint::try_from(encoded.as_ref()).unwrap();
204 assert_eq!(decoded, constraint);
205 }
206}