tests_fuzz/translator/mysql/
alter_expr.rs1use std::fmt::Display;
16
17use common_query::AddColumnLocation;
18use datatypes::data_type::ConcreteDataType;
19use sql::statements::concrete_data_type_to_sql_data_type;
20
21use crate::error::{Error, Result};
22use crate::ir::alter_expr::AlterTableOperation;
23use crate::ir::create_expr::ColumnOption;
24use crate::ir::{AlterTableExpr, Column};
25use crate::translator::common::CommonAlterTableTranslator;
26use crate::translator::DslTranslator;
27
28pub struct AlterTableExprTranslator;
29
30impl DslTranslator<AlterTableExpr, String> for AlterTableExprTranslator {
31 type Error = Error;
32
33 fn translate(&self, input: &AlterTableExpr) -> Result<String> {
34 Ok(match &input.alter_kinds {
35 AlterTableOperation::AddColumn { column, location } => {
36 Self::format_add_column(&input.table_name, column, location)
37 }
38 AlterTableOperation::RenameTable { new_table_name } => {
39 Self::format_rename(&input.table_name, new_table_name)
40 }
41 AlterTableOperation::ModifyDataType { column } => {
42 Self::format_modify_data_type(&input.table_name, column)
43 }
44 _ => CommonAlterTableTranslator.translate(input)?,
45 })
46 }
47}
48
49impl AlterTableExprTranslator {
50 fn format_rename(name: impl Display, new_name: impl Display) -> String {
51 format!("ALTER TABLE {name} RENAME {new_name};")
52 }
53
54 fn format_add_column(
55 name: impl Display,
56 column: &Column,
57 location: &Option<AddColumnLocation>,
58 ) -> String {
59 format!(
60 "{};",
61 vec![
62 format!(
63 "ALTER TABLE {name} ADD COLUMN {}",
64 Self::format_column(column)
65 ),
66 Self::format_location(location).unwrap_or_default(),
67 ]
68 .into_iter()
69 .filter(|s| !s.is_empty())
70 .collect::<Vec<_>>()
71 .join(" ")
72 )
73 }
74
75 fn format_modify_data_type(name: impl Display, column: &Column) -> String {
76 format!(
77 "ALTER TABLE {name} MODIFY COLUMN {};",
78 Self::format_column(column)
79 )
80 }
81
82 fn format_location(location: &Option<AddColumnLocation>) -> Option<String> {
83 location.as_ref().map(|location| match location {
84 AddColumnLocation::First => "FIRST".to_string(),
85 AddColumnLocation::After { column_name } => format!("AFTER {column_name}"),
86 })
87 }
88
89 fn format_column(column: &Column) -> String {
90 vec![
91 column.name.to_string(),
92 Self::format_column_type(&column.column_type),
93 Self::format_column_options(&column.options),
94 ]
95 .into_iter()
96 .filter(|s| !s.is_empty())
97 .collect::<Vec<_>>()
98 .join(" ")
99 }
100
101 fn format_column_type(column_type: &ConcreteDataType) -> String {
102 concrete_data_type_to_sql_data_type(column_type)
104 .unwrap()
105 .to_string()
106 }
107
108 fn format_column_options(options: &[ColumnOption]) -> String {
109 options
110 .iter()
111 .map(|option| option.to_string())
112 .collect::<Vec<_>>()
113 .join(" ")
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use std::str::FromStr;
120
121 use common_base::readable_size::ReadableSize;
122 use common_query::AddColumnLocation;
123 use common_time::Duration;
124 use datatypes::data_type::ConcreteDataType;
125
126 use super::AlterTableExprTranslator;
127 use crate::ir::alter_expr::{AlterTableOperation, AlterTableOption, Ttl};
128 use crate::ir::create_expr::ColumnOption;
129 use crate::ir::{AlterTableExpr, Column};
130 use crate::translator::DslTranslator;
131
132 #[test]
133 fn test_alter_table_expr() {
134 let alter_expr = AlterTableExpr {
135 table_name: "test".into(),
136 alter_kinds: AlterTableOperation::AddColumn {
137 column: Column {
138 name: "host".into(),
139 column_type: ConcreteDataType::string_datatype(),
140 options: vec![ColumnOption::PrimaryKey],
141 },
142 location: Some(AddColumnLocation::First),
143 },
144 };
145
146 let output = AlterTableExprTranslator.translate(&alter_expr).unwrap();
147 assert_eq!(
148 "ALTER TABLE test ADD COLUMN host STRING PRIMARY KEY FIRST;",
149 output
150 );
151
152 let alter_expr = AlterTableExpr {
153 table_name: "test".into(),
154 alter_kinds: AlterTableOperation::RenameTable {
155 new_table_name: "foo".into(),
156 },
157 };
158
159 let output = AlterTableExprTranslator.translate(&alter_expr).unwrap();
160 assert_eq!("ALTER TABLE test RENAME foo;", output);
161
162 let alter_expr = AlterTableExpr {
163 table_name: "test".into(),
164 alter_kinds: AlterTableOperation::DropColumn { name: "foo".into() },
165 };
166
167 let output = AlterTableExprTranslator.translate(&alter_expr).unwrap();
168 assert_eq!("ALTER TABLE test DROP COLUMN foo;", output);
169
170 let alter_expr = AlterTableExpr {
171 table_name: "test".into(),
172 alter_kinds: AlterTableOperation::ModifyDataType {
173 column: Column {
174 name: "host".into(),
175 column_type: ConcreteDataType::string_datatype(),
176 options: vec![],
177 },
178 },
179 };
180
181 let output = AlterTableExprTranslator.translate(&alter_expr).unwrap();
182 assert_eq!("ALTER TABLE test MODIFY COLUMN host STRING;", output);
183 }
184
185 #[test]
186 fn test_alter_table_expr_set_table_options() {
187 let alter_expr = AlterTableExpr {
188 table_name: "test".into(),
189 alter_kinds: AlterTableOperation::SetTableOptions {
190 options: vec![
191 AlterTableOption::Ttl(Ttl::Duration(Duration::new_second(60))),
192 AlterTableOption::TwcsTimeWindow(Duration::new_second(60)),
193 AlterTableOption::TwcsMaxOutputFileSize(ReadableSize::from_str("1GB").unwrap()),
194 AlterTableOption::TwcsTriggerFileNum(5),
195 ],
196 },
197 };
198
199 let output = AlterTableExprTranslator.translate(&alter_expr).unwrap();
200 let expected = concat!(
201 "ALTER TABLE test SET 'ttl' = '60s', ",
202 "'compaction.twcs.time_window' = '60s', ",
203 "'compaction.twcs.max_output_file_size' = '1.0GiB', ",
204 "'compaction.twcs.trigger_file_num' = '5';"
205 );
206 assert_eq!(expected, output);
207 }
208
209 #[test]
210 fn test_alter_table_expr_unset_table_options() {
211 let alter_expr = AlterTableExpr {
212 table_name: "test".into(),
213 alter_kinds: AlterTableOperation::UnsetTableOptions {
214 keys: vec!["ttl".into(), "compaction.twcs.time_window".into()],
215 },
216 };
217
218 let output = AlterTableExprTranslator.translate(&alter_expr).unwrap();
219 let expected = "ALTER TABLE test UNSET 'ttl', 'compaction.twcs.time_window';";
220 assert_eq!(expected, output);
221 }
222}