1use std::fmt::{Debug, Display};
16
17use api::v1;
18use common_query::AddColumnLocation;
19use datatypes::schema::{FulltextOptions, SkippingIndexOptions};
20use itertools::Itertools;
21use serde::Serialize;
22use sqlparser::ast::{ColumnDef, DataType, Ident, ObjectName, TableConstraint};
23use sqlparser_derive::{Visit, VisitMut};
24
25#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
26pub struct AlterTable {
27 pub table_name: ObjectName,
28 pub alter_operation: AlterTableOperation,
29}
30
31impl AlterTable {
32 pub(crate) fn new(table_name: ObjectName, alter_operation: AlterTableOperation) -> Self {
33 Self {
34 table_name,
35 alter_operation,
36 }
37 }
38
39 pub fn table_name(&self) -> &ObjectName {
40 &self.table_name
41 }
42
43 pub fn alter_operation(&self) -> &AlterTableOperation {
44 &self.alter_operation
45 }
46
47 pub fn alter_operation_mut(&mut self) -> &mut AlterTableOperation {
48 &mut self.alter_operation
49 }
50}
51
52impl Display for AlterTable {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 let table_name = self.table_name();
55 let alter_operation = self.alter_operation();
56 write!(f, r#"ALTER TABLE {table_name} {alter_operation}"#)
57 }
58}
59
60#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
61pub enum AlterTableOperation {
62 AddConstraint(TableConstraint),
64 AddColumns {
66 add_columns: Vec<AddColumn>,
67 },
68 ModifyColumnType {
70 column_name: Ident,
71 target_type: DataType,
72 },
73 SetTableOptions {
75 options: Vec<KeyValueOption>,
76 },
77 UnsetTableOptions {
79 keys: Vec<String>,
80 },
81 DropColumn {
83 name: Ident,
84 },
85 RenameTable {
87 new_table_name: String,
88 },
89 SetIndex {
90 options: SetIndexOperation,
91 },
92 UnsetIndex {
93 options: UnsetIndexOperation,
94 },
95 DropDefaults {
96 columns: Vec<DropDefaultsOperation>,
97 },
98}
99
100#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
101pub struct DropDefaultsOperation(pub Ident);
103
104#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
105pub enum SetIndexOperation {
106 Fulltext {
108 column_name: Ident,
109 options: FulltextOptions,
110 },
111 Inverted { column_name: Ident },
113 Skipping {
115 column_name: Ident,
116 options: SkippingIndexOptions,
117 },
118}
119
120#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
121pub enum UnsetIndexOperation {
122 Fulltext { column_name: Ident },
124 Inverted { column_name: Ident },
126 Skipping { column_name: Ident },
128}
129
130#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
131pub struct AddColumn {
132 pub column_def: ColumnDef,
133 pub location: Option<AddColumnLocation>,
134 pub add_if_not_exists: bool,
135}
136
137impl Display for AddColumn {
138 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139 if let Some(location) = &self.location {
140 write!(f, "{} {location}", self.column_def)
141 } else {
142 write!(f, "{}", self.column_def)
143 }
144 }
145}
146
147impl Display for AlterTableOperation {
148 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149 match self {
150 AlterTableOperation::AddConstraint(constraint) => write!(f, r#"ADD {constraint}"#),
151 AlterTableOperation::AddColumns { add_columns } => {
152 let columns = add_columns
153 .iter()
154 .map(|add_column| format!("ADD COLUMN {add_column}"))
155 .join(", ");
156 write!(f, "{columns}")
157 }
158 AlterTableOperation::DropColumn { name } => write!(f, r#"DROP COLUMN {name}"#),
159 AlterTableOperation::RenameTable { new_table_name } => {
160 write!(f, r#"RENAME {new_table_name}"#)
161 }
162 AlterTableOperation::ModifyColumnType {
163 column_name,
164 target_type,
165 } => {
166 write!(f, r#"MODIFY COLUMN {column_name} {target_type}"#)
167 }
168 AlterTableOperation::SetTableOptions { options } => {
169 let kvs = options
170 .iter()
171 .map(|KeyValueOption { key, value }| {
172 if !value.is_empty() {
173 format!("'{key}'='{value}'")
174 } else {
175 format!("'{key}'=NULL")
176 }
177 })
178 .join(",");
179
180 write!(f, "SET {kvs}")
181 }
182 AlterTableOperation::UnsetTableOptions { keys } => {
183 let keys = keys.iter().map(|k| format!("'{k}'")).join(",");
184 write!(f, "UNSET {keys}")
185 }
186 AlterTableOperation::SetIndex { options } => match options {
187 SetIndexOperation::Fulltext {
188 column_name,
189 options,
190 } => {
191 write!(f, "MODIFY COLUMN {column_name} SET FULLTEXT INDEX WITH(analyzer={0}, case_sensitive={1}, backend={2})", options.analyzer, options.case_sensitive, options.backend)
192 }
193 SetIndexOperation::Inverted { column_name } => {
194 write!(f, "MODIFY COLUMN {column_name} SET INVERTED INDEX")
195 }
196 SetIndexOperation::Skipping {
197 column_name,
198 options,
199 } => {
200 write!(f, "MODIFY COLUMN {column_name} SET SKIPPING INDEX WITH(granularity={0}, index_type={1})", options.granularity, options.index_type)
201 }
202 },
203 AlterTableOperation::UnsetIndex { options } => match options {
204 UnsetIndexOperation::Fulltext { column_name } => {
205 write!(f, "MODIFY COLUMN {column_name} UNSET FULLTEXT INDEX")
206 }
207 UnsetIndexOperation::Inverted { column_name } => {
208 write!(f, "MODIFY COLUMN {column_name} UNSET INVERTED INDEX")
209 }
210 UnsetIndexOperation::Skipping { column_name } => {
211 write!(f, "MODIFY COLUMN {column_name} UNSET SKIPPING INDEX")
212 }
213 },
214 AlterTableOperation::DropDefaults { columns } => {
215 let columns = columns
216 .iter()
217 .map(|column| format!("ALTER {} DROP DEFAULT", column.0))
218 .join(", ");
219 write!(f, "{columns}")
220 }
221 }
222 }
223}
224
225#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
226pub struct KeyValueOption {
227 pub key: String,
228 pub value: String,
229}
230
231impl From<KeyValueOption> for v1::Option {
232 fn from(c: KeyValueOption) -> Self {
233 v1::Option {
234 key: c.key,
235 value: c.value,
236 }
237 }
238}
239
240#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
241pub struct AlterDatabase {
242 pub database_name: ObjectName,
243 pub alter_operation: AlterDatabaseOperation,
244}
245
246impl AlterDatabase {
247 pub(crate) fn new(database_name: ObjectName, alter_operation: AlterDatabaseOperation) -> Self {
248 Self {
249 database_name,
250 alter_operation,
251 }
252 }
253
254 pub fn database_name(&self) -> &ObjectName {
255 &self.database_name
256 }
257
258 pub fn alter_operation(&self) -> &AlterDatabaseOperation {
259 &self.alter_operation
260 }
261}
262
263impl Display for AlterDatabase {
264 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
265 let database_name = self.database_name();
266 let alter_operation = self.alter_operation();
267 write!(f, r#"ALTER DATABASE {database_name} {alter_operation}"#)
268 }
269}
270
271#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
272pub enum AlterDatabaseOperation {
273 SetDatabaseOption { options: Vec<KeyValueOption> },
274 UnsetDatabaseOption { keys: Vec<String> },
275}
276
277impl Display for AlterDatabaseOperation {
278 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
279 match self {
280 AlterDatabaseOperation::SetDatabaseOption { options } => {
281 let kvs = options
282 .iter()
283 .map(|KeyValueOption { key, value }| {
284 if !value.is_empty() {
285 format!("'{key}'='{value}'")
286 } else {
287 format!("'{key}'=NULL")
288 }
289 })
290 .join(",");
291
292 write!(f, "SET {kvs}")?;
293
294 Ok(())
295 }
296 AlterDatabaseOperation::UnsetDatabaseOption { keys } => {
297 let keys = keys.iter().map(|key| format!("'{key}'")).join(",");
298 write!(f, "UNSET {keys}")?;
299
300 Ok(())
301 }
302 }
303 }
304}
305
306#[cfg(test)]
307mod tests {
308 use std::assert_matches::assert_matches;
309
310 use crate::dialect::GreptimeDbDialect;
311 use crate::parser::{ParseOptions, ParserContext};
312 use crate::statements::statement::Statement;
313
314 #[test]
315 fn test_display_alter() {
316 let sql = r"ALTER DATABASE db SET 'a' = 'b', 'c' = 'd'";
317 let stmts =
318 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
319 .unwrap();
320 assert_eq!(1, stmts.len());
321 assert_matches!(&stmts[0], Statement::AlterDatabase { .. });
322
323 match &stmts[0] {
324 Statement::AlterDatabase(set) => {
325 let new_sql = format!("\n{}", set);
326 assert_eq!(
327 r#"
328ALTER DATABASE db SET 'a'='b','c'='d'"#,
329 &new_sql
330 );
331 }
332 _ => {
333 unreachable!();
334 }
335 }
336
337 let sql = r"ALTER DATABASE db UNSET 'a', 'c'";
338 let stmts =
339 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
340 .unwrap();
341 assert_eq!(1, stmts.len());
342
343 match &stmts[0] {
344 Statement::AlterDatabase(set) => {
345 let new_sql = format!("\n{}", set);
346 assert_eq!(
347 r#"
348ALTER DATABASE db UNSET 'a','c'"#,
349 &new_sql
350 );
351 }
352 _ => {
353 unreachable!();
354 }
355 }
356
357 let sql =
358 r"alter table monitor add column app string default 'shop' primary key, add foo INT;";
359 let stmts =
360 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
361 .unwrap();
362 assert_eq!(1, stmts.len());
363 assert_matches!(&stmts[0], Statement::AlterTable { .. });
364
365 match &stmts[0] {
366 Statement::AlterTable(set) => {
367 let new_sql = format!("\n{}", set);
368 assert_eq!(
369 r#"
370ALTER TABLE monitor ADD COLUMN app STRING DEFAULT 'shop' PRIMARY KEY, ADD COLUMN foo INT"#,
371 &new_sql
372 );
373 }
374 _ => {
375 unreachable!();
376 }
377 }
378
379 let sql = r"alter table monitor modify column load_15 string;";
380 let stmts =
381 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
382 .unwrap();
383 assert_eq!(1, stmts.len());
384 assert_matches!(&stmts[0], Statement::AlterTable { .. });
385
386 match &stmts[0] {
387 Statement::AlterTable(set) => {
388 let new_sql = format!("\n{}", set);
389 assert_eq!(
390 r#"
391ALTER TABLE monitor MODIFY COLUMN load_15 STRING"#,
392 &new_sql
393 );
394 }
395 _ => {
396 unreachable!();
397 }
398 }
399
400 let sql = r"alter table monitor drop column load_15;";
401 let stmts =
402 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
403 .unwrap();
404 assert_eq!(1, stmts.len());
405 assert_matches!(&stmts[0], Statement::AlterTable { .. });
406
407 match &stmts[0] {
408 Statement::AlterTable(set) => {
409 let new_sql = format!("\n{}", set);
410 assert_eq!(
411 r#"
412ALTER TABLE monitor DROP COLUMN load_15"#,
413 &new_sql
414 );
415 }
416 _ => {
417 unreachable!();
418 }
419 }
420
421 let sql = r"alter table monitor rename monitor_new;";
422 let stmts =
423 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
424 .unwrap();
425 assert_eq!(1, stmts.len());
426 assert_matches!(&stmts[0], Statement::AlterTable { .. });
427
428 match &stmts[0] {
429 Statement::AlterTable(set) => {
430 let new_sql = format!("\n{}", set);
431 assert_eq!(
432 r#"
433ALTER TABLE monitor RENAME monitor_new"#,
434 &new_sql
435 );
436 }
437 _ => {
438 unreachable!();
439 }
440 }
441
442 let sql = "ALTER TABLE monitor MODIFY COLUMN a SET FULLTEXT INDEX WITH(analyzer='English',case_sensitive='false',backend='bloom')";
443 let stmts =
444 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
445 .unwrap();
446 assert_eq!(1, stmts.len());
447 assert_matches!(&stmts[0], Statement::AlterTable { .. });
448
449 match &stmts[0] {
450 Statement::AlterTable(set) => {
451 let new_sql = format!("\n{}", set);
452 assert_eq!(
453 r#"
454ALTER TABLE monitor MODIFY COLUMN a SET FULLTEXT INDEX WITH(analyzer=English, case_sensitive=false, backend=bloom)"#,
455 &new_sql
456 );
457 }
458 _ => {
459 unreachable!();
460 }
461 }
462
463 let sql = "ALTER TABLE monitor MODIFY COLUMN a UNSET FULLTEXT INDEX";
464 let stmts =
465 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
466 .unwrap();
467 assert_eq!(1, stmts.len());
468 assert_matches!(&stmts[0], Statement::AlterTable { .. });
469
470 match &stmts[0] {
471 Statement::AlterTable(set) => {
472 let new_sql = format!("\n{}", set);
473 assert_eq!(
474 r#"
475ALTER TABLE monitor MODIFY COLUMN a UNSET FULLTEXT INDEX"#,
476 &new_sql
477 );
478 }
479 _ => {
480 unreachable!();
481 }
482 }
483
484 let sql = "ALTER TABLE monitor MODIFY COLUMN a SET INVERTED INDEX";
485 let stmts =
486 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
487 .unwrap();
488 assert_eq!(1, stmts.len());
489 assert_matches!(&stmts[0], Statement::AlterTable { .. });
490
491 match &stmts[0] {
492 Statement::AlterTable(set) => {
493 let new_sql = format!("\n{}", set);
494 assert_eq!(
495 r#"
496ALTER TABLE monitor MODIFY COLUMN a SET INVERTED INDEX"#,
497 &new_sql
498 );
499 }
500 _ => {
501 unreachable!();
502 }
503 }
504
505 let sql = "ALTER TABLE monitor ALTER a DROP DEFAULT";
506 let stmts =
507 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
508 .unwrap();
509 assert_eq!(1, stmts.len());
510 assert_matches!(&stmts[0], Statement::AlterTable { .. });
511
512 match &stmts[0] {
513 Statement::AlterTable(set) => {
514 let new_sql = format!("\n{}", set);
515 assert_eq!(
516 r#"
517ALTER TABLE monitor ALTER a DROP DEFAULT"#,
518 &new_sql
519 );
520 }
521 _ => {
522 unreachable!();
523 }
524 }
525 }
526}