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