1use std::ops::ControlFlow;
16
17use datatypes::data_type::DataType as GreptimeDataType;
18use sqlparser::ast::{
19 DataType, ExactNumberInfo, Expr, Function, FunctionArg, FunctionArgExpr, FunctionArgumentList,
20 Ident, ObjectName, Value,
21};
22
23use crate::ast::ObjectNamePartExt;
24use crate::error::Result;
25use crate::statements::alter::AlterTableOperation;
26use crate::statements::create::{CreateExternalTable, CreateTable};
27use crate::statements::statement::Statement;
28use crate::statements::transform::TransformRule;
29use crate::statements::{TimezoneInfo, sql_data_type_to_concrete_data_type};
30
31pub(crate) struct TypeAliasTransformRule;
52
53impl TransformRule for TypeAliasTransformRule {
54 fn visit_statement(&self, stmt: &mut Statement) -> Result<()> {
55 match stmt {
56 Statement::CreateTable(CreateTable { columns, .. }) => {
57 columns
58 .iter_mut()
59 .for_each(|column| replace_type_alias(column.mut_data_type()));
60 }
61 Statement::CreateExternalTable(CreateExternalTable { columns, .. }) => {
62 columns
63 .iter_mut()
64 .for_each(|column| replace_type_alias(column.mut_data_type()));
65 }
66 Statement::AlterTable(alter_table) => {
67 if let AlterTableOperation::ModifyColumnType { target_type, .. } =
68 alter_table.alter_operation_mut()
69 {
70 replace_type_alias(target_type)
71 } else if let AlterTableOperation::AddColumns { add_columns, .. } =
72 alter_table.alter_operation_mut()
73 {
74 for add_column in add_columns {
75 replace_type_alias(&mut add_column.column_def.data_type);
76 }
77 }
78 }
79 _ => {}
80 }
81
82 Ok(())
83 }
84
85 fn visit_expr(&self, expr: &mut Expr) -> ControlFlow<()> {
86 fn cast_expr_to_arrow_cast_func(expr: Expr, cast_type: String) -> Function {
87 Function {
88 name: ObjectName::from(vec![Ident::new("arrow_cast")]),
89 args: sqlparser::ast::FunctionArguments::List(FunctionArgumentList {
90 args: vec![
91 FunctionArg::Unnamed(FunctionArgExpr::Expr(expr)),
92 FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
93 Value::SingleQuotedString(cast_type).into(),
94 ))),
95 ],
96 duplicate_treatment: None,
97 clauses: vec![],
98 }),
99 filter: None,
100 null_treatment: None,
101 over: None,
102 parameters: sqlparser::ast::FunctionArguments::None,
103 within_group: vec![],
104 uses_odbc_syntax: false,
105 }
106 }
107
108 match expr {
109 Expr::Cast {
114 expr: cast_expr,
115 data_type,
116 ..
117 } if get_type_by_alias(data_type).is_some() => {
118 let new_type = get_type_by_alias(data_type).unwrap();
120 if let Ok(new_type) = sql_data_type_to_concrete_data_type(&new_type) {
121 *expr = Expr::Function(cast_expr_to_arrow_cast_func(
122 (**cast_expr).clone(),
123 new_type.as_arrow_type().to_string(),
124 ));
125 }
126 }
127
128 Expr::Cast {
131 data_type: DataType::Timestamp(precision, zone),
132 expr: cast_expr,
133 ..
134 } => {
135 if let Ok(concrete_type) =
136 sql_data_type_to_concrete_data_type(&DataType::Timestamp(*precision, *zone))
137 {
138 let new_type = concrete_type.as_arrow_type();
139 *expr = Expr::Function(cast_expr_to_arrow_cast_func(
140 (**cast_expr).clone(),
141 new_type.to_string(),
142 ));
143 }
144 }
145
146 _ => {}
148 }
149
150 ControlFlow::<()>::Continue(())
151 }
152}
153
154fn replace_type_alias(data_type: &mut DataType) {
155 if let Some(new_type) = get_type_by_alias(data_type) {
156 *data_type = new_type;
157 }
158}
159
160pub(crate) fn get_type_by_alias(data_type: &DataType) -> Option<DataType> {
164 match data_type {
165 DataType::Custom(name, tokens) if name.0.len() == 1 && tokens.is_empty() => {
166 get_data_type_by_alias_name(name.0[0].to_string_unquoted().as_str())
167 }
168 DataType::Int2(None) => Some(DataType::SmallInt(None)),
169 DataType::Int4(None) => Some(DataType::Int(None)),
170 DataType::Int8(None) => Some(DataType::BigInt(None)),
171 DataType::Int16 => Some(DataType::SmallInt(None)),
172 DataType::Int32 => Some(DataType::Int(None)),
173 DataType::Int64 => Some(DataType::BigInt(None)),
174 DataType::UInt8 => Some(DataType::TinyIntUnsigned(None)),
175 DataType::UInt16 => Some(DataType::SmallIntUnsigned(None)),
176 DataType::UInt32 => Some(DataType::IntUnsigned(None)),
177 DataType::UInt64 => Some(DataType::BigIntUnsigned(None)),
178 DataType::Float4 => Some(DataType::Float(ExactNumberInfo::None)),
179 DataType::Float8 => Some(DataType::Double(ExactNumberInfo::None)),
180 DataType::Float32 => Some(DataType::Float(ExactNumberInfo::None)),
181 DataType::Float64 => Some(DataType::Double(ExactNumberInfo::None)),
182 DataType::Bool => Some(DataType::Boolean),
183 DataType::Datetime(_) => Some(DataType::Timestamp(Some(6), TimezoneInfo::None)),
184 _ => None,
185 }
186}
187
188pub(crate) fn get_data_type_by_alias_name(name: &str) -> Option<DataType> {
196 match name.to_uppercase().as_ref() {
197 "TIMESTAMP_S" | "TIMESTAMP_SEC" | "TIMESTAMPSECOND" => {
199 Some(DataType::Timestamp(Some(0), TimezoneInfo::None))
200 }
201
202 "TIMESTAMP_MS" | "TIMESTAMPMILLISECOND" => {
203 Some(DataType::Timestamp(Some(3), TimezoneInfo::None))
204 }
205 "TIMESTAMP_US" | "TIMESTAMPMICROSECOND" | "DATETIME" => {
206 Some(DataType::Timestamp(Some(6), TimezoneInfo::None))
207 }
208 "TIMESTAMP_NS" | "TIMESTAMPNANOSECOND" => {
209 Some(DataType::Timestamp(Some(9), TimezoneInfo::None))
210 }
211 "INT2" => Some(DataType::SmallInt(None)),
213 "INT4" => Some(DataType::Int(None)),
214 "INT8" => Some(DataType::BigInt(None)),
215 "INT16" => Some(DataType::SmallInt(None)),
216 "INT32" => Some(DataType::Int(None)),
217 "INT64" => Some(DataType::BigInt(None)),
218 "UINT8" => Some(DataType::TinyIntUnsigned(None)),
219 "UINT16" => Some(DataType::SmallIntUnsigned(None)),
220 "UINT32" => Some(DataType::IntUnsigned(None)),
221 "UINT64" => Some(DataType::BigIntUnsigned(None)),
222 "FLOAT4" => Some(DataType::Float(ExactNumberInfo::None)),
223 "FLOAT8" => Some(DataType::Double(ExactNumberInfo::None)),
224 "FLOAT32" => Some(DataType::Float(ExactNumberInfo::None)),
225 "FLOAT64" => Some(DataType::Double(ExactNumberInfo::None)),
226 "TINYTEXT" | "MEDIUMTEXT" | "LONGTEXT" => Some(DataType::Text),
228 _ => None,
229 }
230}
231
232#[cfg(test)]
233mod tests {
234 use sqlparser::dialect::GenericDialect;
235
236 use super::*;
237 use crate::parser::{ParseOptions, ParserContext};
238 use crate::statements::transform_statements;
239
240 #[test]
241 fn test_get_data_type_by_alias_name() {
242 assert_eq!(
243 get_data_type_by_alias_name("float64"),
244 Some(DataType::Double(ExactNumberInfo::None))
245 );
246 assert_eq!(
247 get_data_type_by_alias_name("Float64"),
248 Some(DataType::Double(ExactNumberInfo::None))
249 );
250 assert_eq!(
251 get_data_type_by_alias_name("FLOAT64"),
252 Some(DataType::Double(ExactNumberInfo::None))
253 );
254 assert_eq!(
255 get_data_type_by_alias_name("float32"),
256 Some(DataType::Float(ExactNumberInfo::None))
257 );
258 assert_eq!(
259 get_data_type_by_alias_name("float8"),
260 Some(DataType::Double(ExactNumberInfo::None))
261 );
262 assert_eq!(
263 get_data_type_by_alias_name("float4"),
264 Some(DataType::Float(ExactNumberInfo::None))
265 );
266 assert_eq!(
267 get_data_type_by_alias_name("int8"),
268 Some(DataType::BigInt(None))
269 );
270 assert_eq!(
271 get_data_type_by_alias_name("int4"),
272 Some(DataType::Int(None))
273 );
274 assert_eq!(
275 get_data_type_by_alias_name("int2"),
276 Some(DataType::SmallInt(None))
277 );
278 assert_eq!(
279 get_data_type_by_alias_name("INT16"),
280 Some(DataType::SmallInt(None))
281 );
282 assert_eq!(
283 get_data_type_by_alias_name("INT32"),
284 Some(DataType::Int(None))
285 );
286 assert_eq!(
287 get_data_type_by_alias_name("INT64"),
288 Some(DataType::BigInt(None))
289 );
290 assert_eq!(
291 get_data_type_by_alias_name("Uint8"),
292 Some(DataType::TinyIntUnsigned(None))
293 );
294 assert_eq!(
295 get_data_type_by_alias_name("UINT16"),
296 Some(DataType::SmallIntUnsigned(None))
297 );
298 assert_eq!(
299 get_data_type_by_alias_name("UINT32"),
300 Some(DataType::IntUnsigned(None))
301 );
302 assert_eq!(
303 get_data_type_by_alias_name("uint64"),
304 Some(DataType::BigIntUnsigned(None))
305 );
306
307 assert_eq!(
308 get_data_type_by_alias_name("TimestampSecond"),
309 Some(DataType::Timestamp(Some(0), TimezoneInfo::None))
310 );
311 assert_eq!(
312 get_data_type_by_alias_name("Timestamp_s"),
313 Some(DataType::Timestamp(Some(0), TimezoneInfo::None))
314 );
315 assert_eq!(
316 get_data_type_by_alias_name("Timestamp_sec"),
317 Some(DataType::Timestamp(Some(0), TimezoneInfo::None))
318 );
319
320 assert_eq!(
321 get_data_type_by_alias_name("TimestampMilliSecond"),
322 Some(DataType::Timestamp(Some(3), TimezoneInfo::None))
323 );
324 assert_eq!(
325 get_data_type_by_alias_name("Timestamp_ms"),
326 Some(DataType::Timestamp(Some(3), TimezoneInfo::None))
327 );
328
329 assert_eq!(
330 get_data_type_by_alias_name("TimestampMicroSecond"),
331 Some(DataType::Timestamp(Some(6), TimezoneInfo::None))
332 );
333 assert_eq!(
334 get_data_type_by_alias_name("Timestamp_us"),
335 Some(DataType::Timestamp(Some(6), TimezoneInfo::None))
336 );
337
338 assert_eq!(
339 get_data_type_by_alias_name("TimestampNanoSecond"),
340 Some(DataType::Timestamp(Some(9), TimezoneInfo::None))
341 );
342 assert_eq!(
343 get_data_type_by_alias_name("Timestamp_ns"),
344 Some(DataType::Timestamp(Some(9), TimezoneInfo::None))
345 );
346 assert_eq!(
347 get_data_type_by_alias_name("TinyText"),
348 Some(DataType::Text)
349 );
350 assert_eq!(
351 get_data_type_by_alias_name("MediumText"),
352 Some(DataType::Text)
353 );
354 assert_eq!(
355 get_data_type_by_alias_name("LongText"),
356 Some(DataType::Text)
357 );
358 }
359
360 fn test_timestamp_alias(alias: &str, expected: &str) {
361 let sql = format!("SELECT TIMESTAMP '2020-01-01 01:23:45.12345678'::{alias}");
362 let mut stmts =
363 ParserContext::create_with_dialect(&sql, &GenericDialect {}, ParseOptions::default())
364 .unwrap();
365 transform_statements(&mut stmts).unwrap();
366
367 match &stmts[0] {
368 Statement::Query(q) => assert_eq!(
369 format!(
370 "SELECT arrow_cast(TIMESTAMP '2020-01-01 01:23:45.12345678', 'Timestamp({expected})')"
371 ),
372 q.to_string()
373 ),
374 _ => unreachable!(),
375 }
376 }
377
378 fn test_timestamp_precision_type(precision: i32, expected: &str) {
379 test_timestamp_alias(&format!("Timestamp({precision})"), expected);
380 }
381
382 #[test]
383 fn test_boolean_alias() {
384 let sql = "CREATE TABLE test(b bool, ts TIMESTAMP TIME INDEX)";
385 let mut stmts =
386 ParserContext::create_with_dialect(sql, &GenericDialect {}, ParseOptions::default())
387 .unwrap();
388 transform_statements(&mut stmts).unwrap();
389
390 match &stmts[0] {
391 Statement::CreateTable(c) => assert_eq!(
392 "CREATE TABLE test (\n b BOOLEAN,\n ts TIMESTAMP NOT NULL,\n TIME INDEX (ts)\n)\nENGINE=mito\n",
393 c.to_string()
394 ),
395 _ => unreachable!(),
396 }
397 }
398
399 #[test]
400 fn test_transform_timestamp_alias() {
401 test_timestamp_alias("TimestampSecond", "s");
403 test_timestamp_alias("Timestamp_s", "s");
404 test_timestamp_alias("TimestampMillisecond", "ms");
405 test_timestamp_alias("Timestamp_ms", "ms");
406 test_timestamp_alias("TimestampMicrosecond", "µs");
407 test_timestamp_alias("Timestamp_us", "µs");
408 test_timestamp_alias("TimestampNanosecond", "ns");
409 test_timestamp_alias("Timestamp_ns", "ns");
410 test_timestamp_precision_type(0, "s");
412 test_timestamp_precision_type(3, "ms");
413 test_timestamp_precision_type(6, "µs");
414 test_timestamp_precision_type(9, "ns");
415 }
416
417 #[test]
418 fn test_create_sql_with_type_alias() {
419 let sql = r#"
420CREATE TABLE data_types (
421 s string,
422 tt tinytext,
423 mt mediumtext,
424 lt longtext,
425 i2 int2,
426 i4 int4,
427 i8 int8,
428 sint int16,
429 i int32,
430 bint int64,
431 v varchar,
432 f4 float4,
433 f8 float8,
434 f float32,
435 d float64,
436 b boolean,
437 vb varbinary,
438 dt date,
439 dtt datetime,
440 ts0 TimestampSecond,
441 ts3 TimestampMillisecond,
442 ts6 TimestampMicrosecond,
443 ts9 TimestampNanosecond DEFAULT CURRENT_TIMESTAMP TIME INDEX,
444 PRIMARY KEY(s));"#;
445
446 let mut stmts =
447 ParserContext::create_with_dialect(sql, &GenericDialect {}, ParseOptions::default())
448 .unwrap();
449 transform_statements(&mut stmts).unwrap();
450
451 match &stmts[0] {
452 Statement::CreateTable(c) => {
453 let expected = r#"CREATE TABLE data_types (
454 s STRING,
455 tt TINYTEXT,
456 mt MEDIUMTEXT,
457 lt LONGTEXT,
458 i2 SMALLINT,
459 i4 INT,
460 i8 BIGINT,
461 sint SMALLINT,
462 i INT,
463 bint BIGINT,
464 v VARCHAR,
465 f4 FLOAT,
466 f8 DOUBLE,
467 f FLOAT,
468 d DOUBLE,
469 b BOOLEAN,
470 vb VARBINARY,
471 dt DATE,
472 dtt TIMESTAMP(6),
473 ts0 TIMESTAMP(0),
474 ts3 TIMESTAMP(3),
475 ts6 TIMESTAMP(6),
476 ts9 TIMESTAMP(9) DEFAULT CURRENT_TIMESTAMP NOT NULL,
477 TIME INDEX (ts9),
478 PRIMARY KEY (s)
479)
480ENGINE=mito
481"#;
482
483 assert_eq!(expected, c.to_string());
484 }
485 _ => unreachable!(),
486 }
487 }
488}