1use common_time::timezone::Timezone;
16use datatypes::prelude::ConcreteDataType;
17use datatypes::schema::ColumnDefaultConstraint;
18use datatypes::schema::constraint::{CURRENT_TIMESTAMP, CURRENT_TIMESTAMP_FN};
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)) => ColumnDefaultConstraint::Value(
51 sql_value_to_value(column_name, data_type, &v.value, timezone, None, false)?,
52 ),
53 ColumnOption::Default(Expr::Function(func)) => {
54 let mut func = format!("{func}").to_lowercase();
55 if func == CURRENT_TIMESTAMP {
57 func = CURRENT_TIMESTAMP_FN.to_string();
58 }
59 ColumnDefaultConstraint::Function(func.to_lowercase())
61 }
62
63 ColumnOption::Default(Expr::UnaryOp { op, expr }) => {
64 if let (
68 UnaryOperator::Minus,
69 Expr::Value(ValueWithSpan {
70 value: SqlValue::Number(n, _),
71 span: _,
72 }),
73 ) = (op, expr.as_ref())
74 {
75 return Ok(Some(ColumnDefaultConstraint::Value(sql_number_to_value(
76 data_type,
77 &format!("-{n}"),
78 )?)));
79 }
80
81 if let Expr::Value(v) = &**expr {
82 let value = sql_value_to_value(
83 column_name,
84 data_type,
85 &v.value,
86 timezone,
87 Some(*op),
88 false,
89 )?;
90 ColumnDefaultConstraint::Value(value)
91 } else {
92 return UnsupportedDefaultValueSnafu {
93 column_name,
94 reason: format!("expr '{expr}' not supported"),
95 }
96 .fail();
97 }
98 }
99 ColumnOption::Default(others) => {
100 return UnsupportedDefaultValueSnafu {
101 column_name,
102 reason: format!("expr '{others}' not supported"),
103 }
104 .fail();
105 }
106 _ => {
107 return UnsupportedDefaultValueSnafu {
108 column_name,
109 reason: format!("option '{}' not supported", opt.option),
110 }
111 .fail();
112 }
113 };
114
115 Ok(Some(default_constraint))
116 } else {
117 Ok(None)
118 }
119}
120
121#[cfg(test)]
122mod test {
123 use std::assert_matches::assert_matches;
124
125 use datatypes::prelude::{ConcreteDataType, Value};
126 use datatypes::types::BooleanType;
127
128 use super::*;
129
130 #[test]
131 pub fn test_parse_column_default_constraint() {
132 let bool_value = sqlparser::ast::Value::Boolean(true);
133
134 let opts = vec![
135 ColumnOptionDef {
136 name: None,
137 option: ColumnOption::Default(Expr::Value(bool_value.into())),
138 },
139 ColumnOptionDef {
140 name: None,
141 option: ColumnOption::NotNull,
142 },
143 ];
144
145 let constraint = parse_column_default_constraint(
146 "coll",
147 &ConcreteDataType::Boolean(BooleanType),
148 &opts,
149 None,
150 )
151 .unwrap();
152
153 assert_matches!(
154 constraint,
155 Some(ColumnDefaultConstraint::Value(Value::Boolean(true)))
156 );
157
158 let opts = vec![ColumnOptionDef {
160 name: None,
161 option: ColumnOption::Default(Expr::UnaryOp {
162 op: UnaryOperator::Minus,
163 expr: Box::new(Expr::Value(
164 SqlValue::Number("32768".to_string(), false).into(),
165 )),
166 }),
167 }];
168
169 let constraint = parse_column_default_constraint(
170 "coll",
171 &ConcreteDataType::int16_datatype(),
172 &opts,
173 None,
174 )
175 .unwrap();
176
177 assert_matches!(
178 constraint,
179 Some(ColumnDefaultConstraint::Value(Value::Int16(-32768)))
180 );
181 }
182
183 #[test]
184 fn test_incorrect_default_value_issue_3479() {
185 let opts = vec![ColumnOptionDef {
186 name: None,
187 option: ColumnOption::Default(Expr::Value(
188 SqlValue::Number("0.047318541668048164".into(), false).into(),
189 )),
190 }];
191 let constraint = parse_column_default_constraint(
192 "coll",
193 &ConcreteDataType::float64_datatype(),
194 &opts,
195 None,
196 )
197 .unwrap()
198 .unwrap();
199 assert_eq!("0.047318541668048164", constraint.to_string());
200 let encoded: Vec<u8> = constraint.clone().try_into().unwrap();
201 let decoded = ColumnDefaultConstraint::try_from(encoded.as_ref()).unwrap();
202 assert_eq!(decoded, constraint);
203 }
204}