1#[cfg(feature = "enterprise")]
16pub mod trigger;
17
18use snafu::{ResultExt, ensure};
19use sqlparser::keywords::Keyword;
20use sqlparser::tokenizer::Token;
21
22use crate::ast::ObjectNamePartExt;
23use crate::error::{
24 self, InvalidDatabaseNameSnafu, InvalidFlowNameSnafu, InvalidTableNameSnafu, Result,
25};
26use crate::parser::ParserContext;
27use crate::statements::show::{
28 ShowColumns, ShowCreateDatabase, ShowCreateFlow, ShowCreateTable, ShowCreateTableVariant,
29 ShowCreateView, ShowDatabases, ShowFlowStatus, ShowFlows, ShowIndex, ShowKind, ShowProcessList,
30 ShowRegion, ShowSearchPath, ShowStatus, ShowTableStatus, ShowTables, ShowVariables, ShowViews,
31};
32use crate::statements::statement::Statement;
33
34impl ParserContext<'_> {
36 pub(crate) fn parse_show(&mut self) -> Result<Statement> {
39 #[cfg(feature = "enterprise")]
40 if self.consume_token("TRIGGERS") {
41 return self.parse_show_triggers();
42 }
43 self.consume_variables_scope();
44 if self.consume_token("DATABASES") || self.consume_token("SCHEMAS") {
45 self.parse_show_databases(false)
46 } else if self.matches_keyword(Keyword::TABLES) {
47 self.parser.next_token();
48 self.parse_show_tables(false)
49 } else if self.matches_keyword(Keyword::TABLE) {
50 self.parser.next_token();
51 if self.matches_keyword(Keyword::STATUS) {
52 self.parser.next_token();
53 self.parse_show_table_status()
54 } else {
55 self.unsupported(self.peek_token_as_string())
56 }
57 } else if self.consume_token("VIEWS") {
58 self.parse_show_views()
59 } else if self.consume_token("FLOWS") {
60 self.parse_show_flows()
61 } else if self.consume_token("FLOW") {
62 if self.consume_token("STATUS") {
63 self.parse_show_flow_status()
64 } else {
65 self.unsupported(self.peek_token_as_string())
66 }
67 } else if self.matches_keyword(Keyword::CHARSET) {
68 self.parser.next_token();
69 Ok(Statement::ShowCharset(self.parse_show_kind()?))
70 } else if self.matches_keyword(Keyword::CHARACTER) {
71 self.parser.next_token();
72
73 if self.matches_keyword(Keyword::SET) {
74 self.parser.next_token();
75 Ok(Statement::ShowCharset(self.parse_show_kind()?))
76 } else {
77 self.unsupported(self.peek_token_as_string())
78 }
79 } else if self.matches_keyword(Keyword::COLLATION) {
80 self.parser.next_token();
81 Ok(Statement::ShowCollation(self.parse_show_kind()?))
82 } else if self.matches_keyword(Keyword::COLUMNS) || self.matches_keyword(Keyword::FIELDS) {
83 self.parser.next_token();
85 self.parse_show_columns(false)
86 } else if self.consume_token("INDEX")
87 || self.consume_token("INDEXES")
88 || self.consume_token("KEYS")
89 {
90 self.parse_show_index()
92 } else if self.consume_token("REGIONS") || self.consume_token("REGION") {
93 self.parse_show_regions()
95 } else if self.consume_token("CREATE") {
96 #[cfg(feature = "enterprise")]
97 if self.consume_token("TRIGGER") {
98 return self.parse_show_create_trigger();
99 }
100
101 if self.consume_token("DATABASE") || self.consume_token("SCHEMA") {
102 self.parse_show_create_database()
103 } else if self.consume_token("TABLE") {
104 self.parse_show_create_table()
105 } else if self.consume_token("FLOW") {
106 self.parse_show_create_flow()
107 } else if self.consume_token("VIEW") {
108 self.parse_show_create_view()
109 } else {
110 self.unsupported(self.peek_token_as_string())
111 }
112 } else if self.consume_token("FULL") {
113 if self.consume_token("TABLES") {
114 self.parse_show_tables(true)
115 } else if self.consume_token("COLUMNS") || self.consume_token("FIELDS") {
116 self.parse_show_columns(true)
118 } else if self.consume_token("DATABASES") || self.consume_token("SCHEMAS") {
119 self.parse_show_databases(true)
120 } else if self.consume_token("PROCESSLIST") {
121 self.parse_show_processlist(true)
122 } else {
123 self.unsupported(self.peek_token_as_string())
124 }
125 } else if self.consume_token("VARIABLES") {
126 let variable = self
127 .parse_object_name()
128 .with_context(|_| error::UnexpectedSnafu {
129 expected: "a variable name",
130 actual: self.peek_token_as_string(),
131 })?;
132 Ok(Statement::ShowVariables(ShowVariables { variable }))
133 } else if self.consume_token("STATUS") {
134 Ok(Statement::ShowStatus(ShowStatus {}))
135 } else if self.consume_token("SEARCH_PATH") {
136 Ok(Statement::ShowSearchPath(ShowSearchPath {}))
137 } else if self.consume_token("PROCESSLIST") {
138 self.parse_show_processlist(false)
139 } else {
140 let variable = self
142 .parse_object_name()
143 .with_context(|_| error::UnexpectedSnafu {
144 expected: "a variable name",
145 actual: self.peek_token_as_string(),
146 })?;
147 Ok(Statement::ShowVariables(ShowVariables { variable }))
148 }
149 }
150
151 fn consume_variables_scope(&mut self) {
154 let scoped = matches!(
155 self.parser.peek_token().token,
156 Token::Word(w) if matches!(w.keyword, Keyword::GLOBAL | Keyword::SESSION | Keyword::LOCAL)
157 ) && matches!(
158 self.parser.peek_nth_token(1).token,
159 Token::Word(w) if matches!(w.keyword, Keyword::VARIABLES | Keyword::STATUS)
160 );
161 if scoped {
162 let _ = self.parser.next_token();
163 }
164 }
165
166 fn parse_show_create_database(&mut self) -> Result<Statement> {
167 let raw_database_name =
168 self.parse_object_name()
169 .with_context(|_| error::UnexpectedSnafu {
170 expected: "a database name",
171 actual: self.peek_token_as_string(),
172 })?;
173 let database_name = Self::canonicalize_object_name(raw_database_name)?;
174 ensure!(
175 !database_name.0.is_empty(),
176 InvalidDatabaseNameSnafu {
177 name: database_name.to_string(),
178 }
179 );
180 Ok(Statement::ShowCreateDatabase(ShowCreateDatabase {
181 database_name,
182 }))
183 }
184
185 fn parse_show_create_table(&mut self) -> Result<Statement> {
187 let raw_table_name = self
188 .parse_object_name()
189 .with_context(|_| error::UnexpectedSnafu {
190 expected: "a table name",
191 actual: self.peek_token_as_string(),
192 })?;
193 let table_name = Self::canonicalize_object_name(raw_table_name)?;
194 ensure!(
195 !table_name.0.is_empty(),
196 InvalidTableNameSnafu {
197 name: table_name.to_string(),
198 }
199 );
200 let mut variant = ShowCreateTableVariant::Original;
201 if self.consume_token("FOR") {
202 if self.consume_token("POSTGRES_FOREIGN_TABLE") {
203 variant = ShowCreateTableVariant::PostgresForeignTable;
204 } else {
205 self.unsupported(self.peek_token_as_string())?;
206 }
207 }
208
209 Ok(Statement::ShowCreateTable(ShowCreateTable {
210 table_name,
211 variant,
212 }))
213 }
214
215 fn parse_show_create_flow(&mut self) -> Result<Statement> {
216 let raw_flow_name = self
217 .parse_object_name()
218 .with_context(|_| error::UnexpectedSnafu {
219 expected: "a flow name",
220 actual: self.peek_token_as_string(),
221 })?;
222 let flow_name = Self::canonicalize_object_name(raw_flow_name)?;
223 ensure!(
224 !flow_name.0.is_empty(),
225 InvalidFlowNameSnafu {
226 name: flow_name.to_string(),
227 }
228 );
229 Ok(Statement::ShowCreateFlow(ShowCreateFlow { flow_name }))
230 }
231
232 fn parse_show_create_view(&mut self) -> Result<Statement> {
233 let raw_view_name = self
234 .parse_object_name()
235 .with_context(|_| error::UnexpectedSnafu {
236 expected: "a view name",
237 actual: self.peek_token_as_string(),
238 })?;
239 let view_name = Self::canonicalize_object_name(raw_view_name)?;
240 ensure!(
241 !view_name.0.is_empty(),
242 InvalidTableNameSnafu {
243 name: view_name.to_string(),
244 }
245 );
246 Ok(Statement::ShowCreateView(ShowCreateView { view_name }))
247 }
248
249 fn parse_show_table_name(&mut self) -> Result<String> {
250 self.parser.next_token();
251 let table_name = self
252 .parse_object_name()
253 .with_context(|_| error::UnexpectedSnafu {
254 expected: "a table name",
255 actual: self.peek_token_as_string(),
256 })?;
257
258 ensure!(
259 table_name.0.len() == 1,
260 InvalidDatabaseNameSnafu {
261 name: table_name.to_string(),
262 }
263 );
264
265 Ok(Self::canonicalize_object_name(table_name)?.0[0].to_string_unquoted())
267 }
268
269 fn parse_db_name(&mut self) -> Result<Option<String>> {
270 self.parser.next_token();
271 let db_name = self
272 .parse_object_name()
273 .with_context(|_| error::UnexpectedSnafu {
274 expected: "a database name",
275 actual: self.peek_token_as_string(),
276 })?;
277
278 ensure!(
279 db_name.0.len() == 1,
280 InvalidDatabaseNameSnafu {
281 name: db_name.to_string(),
282 }
283 );
284
285 Ok(Some(
287 Self::canonicalize_object_name(db_name)?.0[0].to_string_unquoted(),
288 ))
289 }
290
291 fn parse_show_columns(&mut self, full: bool) -> Result<Statement> {
292 let table = match self.parser.peek_token().token {
293 Token::Word(w) if matches!(w.keyword, Keyword::IN | Keyword::FROM) => {
295 self.parse_show_table_name()?
296 }
297 _ => {
298 return error::UnexpectedTokenSnafu {
299 expected: "{FROM | IN} table",
300 actual: self.peek_token_as_string(),
301 }
302 .fail();
303 }
304 };
305
306 let database = match self.parser.peek_token().token {
307 Token::EOF | Token::SemiColon => {
308 return Ok(Statement::ShowColumns(ShowColumns {
309 kind: ShowKind::All,
310 table,
311 database: None,
312 full,
313 }));
314 }
315
316 Token::Word(w) => match w.keyword {
318 Keyword::IN | Keyword::FROM => self.parse_db_name()?,
319
320 _ => None,
321 },
322 _ => None,
323 };
324
325 let kind = self.parse_show_kind()?;
326
327 Ok(Statement::ShowColumns(ShowColumns {
328 kind,
329 database,
330 table,
331 full,
332 }))
333 }
334
335 fn parse_show_kind(&mut self) -> Result<ShowKind> {
336 match self.parser.peek_token().token {
337 Token::EOF | Token::SemiColon => Ok(ShowKind::All),
338 Token::Word(w) => match w.keyword {
339 Keyword::LIKE => {
340 self.parser.next_token();
341 Ok(ShowKind::Like(
342 self.parser.parse_identifier().with_context(|_| {
343 error::UnexpectedSnafu {
344 expected: "LIKE",
345 actual: self.peek_token_as_string(),
346 }
347 })?,
348 ))
349 }
350 Keyword::WHERE => {
351 self.parser.next_token();
352 Ok(ShowKind::Where(self.parser.parse_expr().with_context(
353 |_| error::UnexpectedSnafu {
354 expected: "some valid expression",
355 actual: self.peek_token_as_string(),
356 },
357 )?))
358 }
359 _ => self.unsupported(self.peek_token_as_string()),
360 },
361 _ => self.unsupported(self.peek_token_as_string()),
362 }
363 }
364
365 fn parse_show_index(&mut self) -> Result<Statement> {
366 let table = match self.parser.peek_token().token {
367 Token::Word(w) if matches!(w.keyword, Keyword::IN | Keyword::FROM) => {
369 self.parse_show_table_name()?
370 }
371 _ => {
372 return error::UnexpectedTokenSnafu {
373 expected: "{FROM | IN} table",
374 actual: self.peek_token_as_string(),
375 }
376 .fail();
377 }
378 };
379
380 let database = match self.parser.peek_token().token {
381 Token::EOF | Token::SemiColon => {
382 return Ok(Statement::ShowIndex(ShowIndex {
383 kind: ShowKind::All,
384 table,
385 database: None,
386 }));
387 }
388
389 Token::Word(w) => match w.keyword {
391 Keyword::IN | Keyword::FROM => self.parse_db_name()?,
392
393 _ => None,
394 },
395 _ => None,
396 };
397
398 let kind = match self.parser.peek_token().token {
399 Token::EOF | Token::SemiColon => ShowKind::All,
400 Token::Word(w) => match w.keyword {
402 Keyword::WHERE => {
403 self.parser.next_token();
404 ShowKind::Where(self.parser.parse_expr().with_context(|_| {
405 error::UnexpectedSnafu {
406 expected: "some valid expression",
407 actual: self.peek_token_as_string(),
408 }
409 })?)
410 }
411 _ => return self.unsupported(self.peek_token_as_string()),
412 },
413 _ => return self.unsupported(self.peek_token_as_string()),
414 };
415
416 Ok(Statement::ShowIndex(ShowIndex {
417 kind,
418 database,
419 table,
420 }))
421 }
422
423 fn parse_show_regions(&mut self) -> Result<Statement> {
424 let table = match self.parser.peek_token().token {
425 Token::Word(w) if matches!(w.keyword, Keyword::IN | Keyword::FROM) => {
427 self.parse_show_table_name()?
428 }
429 _ => {
430 return error::UnexpectedTokenSnafu {
431 expected: "{FROM | IN} table",
432 actual: self.peek_token_as_string(),
433 }
434 .fail();
435 }
436 };
437
438 let database = match self.parser.peek_token().token {
439 Token::EOF | Token::SemiColon => {
440 return Ok(Statement::ShowRegion(ShowRegion {
441 kind: ShowKind::All,
442 table,
443 database: None,
444 }));
445 }
446
447 Token::Word(w) => match w.keyword {
449 Keyword::IN | Keyword::FROM => self.parse_db_name()?,
450
451 _ => None,
452 },
453 _ => None,
454 };
455
456 let kind = match self.parser.peek_token().token {
457 Token::EOF | Token::SemiColon => ShowKind::All,
458 Token::Word(w) => match w.keyword {
460 Keyword::WHERE => {
461 self.parser.next_token();
462 ShowKind::Where(self.parser.parse_expr().with_context(|_| {
463 error::UnexpectedSnafu {
464 expected: "some valid expression",
465 actual: self.peek_token_as_string(),
466 }
467 })?)
468 }
469 _ => return self.unsupported(self.peek_token_as_string()),
470 },
471 _ => return self.unsupported(self.peek_token_as_string()),
472 };
473
474 Ok(Statement::ShowRegion(ShowRegion {
475 kind,
476 database,
477 table,
478 }))
479 }
480
481 fn parse_show_tables(&mut self, full: bool) -> Result<Statement> {
482 let database = match self.parser.peek_token().token {
483 Token::EOF | Token::SemiColon => {
484 return Ok(Statement::ShowTables(ShowTables {
485 kind: ShowKind::All,
486 database: None,
487 full,
488 }));
489 }
490
491 Token::Word(w) => match w.keyword {
493 Keyword::IN | Keyword::FROM => self.parse_db_name()?,
494
495 _ => None,
496 },
497 _ => None,
498 };
499
500 let kind = self.parse_show_kind()?;
501
502 Ok(Statement::ShowTables(ShowTables {
503 kind,
504 database,
505 full,
506 }))
507 }
508
509 fn parse_show_table_status(&mut self) -> Result<Statement> {
510 let database = match self.parser.peek_token().token {
511 Token::EOF | Token::SemiColon => {
512 return Ok(Statement::ShowTableStatus(ShowTableStatus {
513 kind: ShowKind::All,
514 database: None,
515 }));
516 }
517
518 Token::Word(w) => match w.keyword {
520 Keyword::IN | Keyword::FROM => self.parse_db_name()?,
521
522 _ => None,
523 },
524 _ => None,
525 };
526
527 let kind = self.parse_show_kind()?;
528
529 Ok(Statement::ShowTableStatus(ShowTableStatus {
530 kind,
531 database,
532 }))
533 }
534
535 pub fn parse_show_databases(&mut self, full: bool) -> Result<Statement> {
537 let tok = self.parser.next_token().token;
538 match &tok {
539 Token::EOF | Token::SemiColon => Ok(Statement::ShowDatabases(ShowDatabases::new(
540 ShowKind::All,
541 full,
542 ))),
543 Token::Word(w) => match w.keyword {
544 Keyword::LIKE => Ok(Statement::ShowDatabases(ShowDatabases::new(
545 ShowKind::Like(self.parser.parse_identifier().with_context(|_| {
546 error::UnexpectedSnafu {
547 expected: "LIKE",
548 actual: tok.to_string(),
549 }
550 })?),
551 full,
552 ))),
553 Keyword::WHERE => Ok(Statement::ShowDatabases(ShowDatabases::new(
554 ShowKind::Where(self.parser.parse_expr().with_context(|_| {
555 error::UnexpectedSnafu {
556 expected: "some valid expression",
557 actual: self.peek_token_as_string(),
558 }
559 })?),
560 full,
561 ))),
562 _ => self.unsupported(self.peek_token_as_string()),
563 },
564 _ => self.unsupported(self.peek_token_as_string()),
565 }
566 }
567
568 fn parse_show_views(&mut self) -> Result<Statement> {
569 let database = match self.parser.peek_token().token {
570 Token::EOF | Token::SemiColon => {
571 return Ok(Statement::ShowViews(ShowViews {
572 kind: ShowKind::All,
573 database: None,
574 }));
575 }
576
577 Token::Word(w) => match w.keyword {
579 Keyword::IN | Keyword::FROM => self.parse_db_name()?,
580 _ => None,
581 },
582 _ => None,
583 };
584
585 let kind = self.parse_show_kind()?;
586
587 Ok(Statement::ShowViews(ShowViews { kind, database }))
588 }
589
590 fn parse_show_flows(&mut self) -> Result<Statement> {
591 let database = match self.parser.peek_token().token {
592 Token::EOF | Token::SemiColon => {
593 return Ok(Statement::ShowFlows(ShowFlows {
594 kind: ShowKind::All,
595 database: None,
596 }));
597 }
598
599 Token::Word(w) => match w.keyword {
601 Keyword::IN | Keyword::FROM => self.parse_db_name()?,
602 _ => None,
603 },
604 _ => None,
605 };
606
607 let kind = self.parse_show_kind()?;
608
609 Ok(Statement::ShowFlows(ShowFlows { kind, database }))
610 }
611
612 fn parse_show_flow_status(&mut self) -> Result<Statement> {
613 let kind = self.parse_show_kind()?;
614
615 Ok(Statement::ShowFlowStatus(ShowFlowStatus { kind }))
616 }
617
618 fn parse_show_processlist(&mut self, full: bool) -> Result<Statement> {
619 match self.parser.next_token().token {
620 Token::EOF | Token::SemiColon => {
621 Ok(Statement::ShowProcesslist(ShowProcessList { full }))
622 }
623 _ => self.unsupported(self.peek_token_as_string()),
624 }
625 }
626}
627
628#[cfg(test)]
629mod tests {
630 use std::assert_matches;
631
632 use sqlparser::ast::{Ident, ObjectName};
633
634 use super::*;
635 use crate::dialect::GreptimeDbDialect;
636 use crate::parser::ParseOptions;
637 use crate::statements::show::ShowDatabases;
638 #[cfg(feature = "enterprise")]
639 use crate::statements::show::trigger::ShowCreateTrigger;
640 #[cfg(feature = "enterprise")]
641 use crate::statements::show::trigger::ShowTriggers;
642
643 #[test]
644 pub fn test_show_database_all() {
645 let sql = "SHOW DATABASES";
646 let result =
647 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
648 let stmts = result.unwrap();
649 assert_eq!(1, stmts.len());
650
651 assert_matches!(
652 &stmts[0],
653 Statement::ShowDatabases(ShowDatabases {
654 kind: ShowKind::All,
655 full: false,
656 })
657 );
658 }
659
660 #[test]
661 pub fn test_show_full_databases() {
662 let sql = "SHOW FULL DATABASES";
663 let result =
664 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
665 let stmts = result.unwrap();
666 assert_eq!(1, stmts.len());
667
668 assert_matches!(
669 &stmts[0],
670 Statement::ShowDatabases(ShowDatabases {
671 kind: ShowKind::All,
672 full: true,
673 })
674 );
675
676 let sql = "SHOW FULL DATABASES LIKE 'test%'";
677 let result =
678 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
679 let stmts = result.unwrap();
680 assert_eq!(1, stmts.len());
681
682 assert_matches!(
683 &stmts[0],
684 Statement::ShowDatabases(ShowDatabases {
685 kind: ShowKind::Like(_),
686 full: true,
687 })
688 );
689 }
690
691 #[test]
692 pub fn test_show_database_like() {
693 let sql = "SHOW DATABASES LIKE test_database";
694 let result =
695 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
696 let stmts = result.unwrap();
697 assert_eq!(1, stmts.len());
698
699 assert_matches!(
700 &stmts[0],
701 Statement::ShowDatabases(ShowDatabases {
702 kind: ShowKind::Like(sqlparser::ast::Ident {
703 value: _,
704 quote_style: None,
705 span: _,
706 }),
707 ..
708 })
709 );
710 }
711
712 #[test]
713 pub fn test_show_database_where() {
714 let sql = "SHOW DATABASES WHERE Database LIKE '%whatever1%' OR Database LIKE '%whatever2%'";
715 let result =
716 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
717 let stmts = result.unwrap();
718 assert_eq!(1, stmts.len());
719
720 assert_matches!(
721 &stmts[0],
722 Statement::ShowDatabases(ShowDatabases {
723 kind: ShowKind::Where(sqlparser::ast::Expr::BinaryOp {
724 left: _,
725 right: _,
726 op: sqlparser::ast::BinaryOperator::Or,
727 }),
728 ..
729 })
730 );
731 }
732
733 #[test]
734 pub fn test_show_tables_all() {
735 let sql = "SHOW TABLES";
736 let result =
737 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
738 let stmts = result.unwrap();
739 assert_eq!(1, stmts.len());
740
741 assert_matches!(
742 &stmts[0],
743 Statement::ShowTables(ShowTables {
744 kind: ShowKind::All,
745 database: None,
746 full: false
747 })
748 );
749 }
750
751 #[test]
752 pub fn test_show_tables_like() {
753 let sql = "SHOW TABLES LIKE test_table";
754 let result =
755 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
756 let stmts = result.unwrap();
757 assert_eq!(1, stmts.len());
758
759 assert_matches!(
760 &stmts[0],
761 Statement::ShowTables(ShowTables {
762 kind: ShowKind::Like(sqlparser::ast::Ident {
763 value: _,
764 quote_style: None,
765 span: _,
766 }),
767 database: None,
768 full: false
769 })
770 );
771
772 let sql = "SHOW TABLES in test_db LIKE test_table";
773 let result =
774 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
775 let stmts = result.unwrap();
776 assert_eq!(1, stmts.len());
777
778 assert_matches!(
779 &stmts[0],
780 Statement::ShowTables(ShowTables {
781 kind: ShowKind::Like(sqlparser::ast::Ident {
782 value: _,
783 quote_style: None,
784 span: _,
785 }),
786 database: Some(_),
787 full: false
788 })
789 );
790 }
791
792 #[test]
793 pub fn test_show_tables_where() {
794 let sql = "SHOW TABLES where name like test_table";
795 let result =
796 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
797 let stmts = result.unwrap();
798 assert_eq!(1, stmts.len());
799
800 assert_matches!(
801 &stmts[0],
802 Statement::ShowTables(ShowTables {
803 kind: ShowKind::Where(sqlparser::ast::Expr::Like { .. }),
804 database: None,
805 full: false
806 })
807 );
808
809 let sql = "SHOW TABLES in test_db where name LIKE test_table";
810 let result =
811 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
812 let stmts = result.unwrap();
813 assert_eq!(1, stmts.len());
814
815 assert_matches!(
816 &stmts[0],
817 Statement::ShowTables(ShowTables {
818 kind: ShowKind::Where(sqlparser::ast::Expr::Like { .. }),
819 database: Some(_),
820 full: false
821 })
822 );
823 }
824
825 #[test]
826 pub fn test_show_full_tables() {
827 let sql = "SHOW FULL TABLES";
828 let stmts =
829 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
830 .unwrap();
831 assert_eq!(1, stmts.len());
832 assert_matches!(&stmts[0], Statement::ShowTables { .. });
833 match &stmts[0] {
834 Statement::ShowTables(show) => {
835 assert!(show.full);
836 }
837 _ => {
838 unreachable!();
839 }
840 }
841 }
842
843 #[test]
844 pub fn test_show_full_tables_where() {
845 let sql = "SHOW FULL TABLES IN test_db WHERE Tables LIKE test_table";
846 let stmts =
847 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
848 .unwrap();
849 assert_eq!(1, stmts.len());
850
851 assert_matches!(
852 &stmts[0],
853 Statement::ShowTables(ShowTables {
854 kind: ShowKind::Where(sqlparser::ast::Expr::Like { .. }),
855 database: Some(_),
856 full: true
857 })
858 );
859 }
860
861 #[test]
862 pub fn test_show_full_tables_like() {
863 let sql = "SHOW FULL TABLES LIKE test_table";
864 let result =
865 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
866 let stmts = result.unwrap();
867 assert_eq!(1, stmts.len());
868
869 assert_matches!(
870 &stmts[0],
871 Statement::ShowTables(ShowTables {
872 kind: ShowKind::Like(sqlparser::ast::Ident {
873 value: _,
874 quote_style: None,
875 span: _,
876 }),
877 database: None,
878 full: true
879 })
880 );
881
882 let sql = "SHOW FULL TABLES in test_db LIKE test_table";
883 let result =
884 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
885 let stmts = result.unwrap();
886 assert_eq!(1, stmts.len());
887
888 assert_matches!(
889 &stmts[0],
890 Statement::ShowTables(ShowTables {
891 kind: ShowKind::Like(sqlparser::ast::Ident {
892 value: _,
893 quote_style: None,
894 span: _,
895 }),
896 database: Some(_),
897 full: true
898 })
899 );
900 }
901
902 #[test]
903 pub fn test_show_variables() {
904 let sql = "SHOW VARIABLES system_time_zone";
905 let result =
906 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
907 let stmts = result.unwrap();
908 assert_eq!(1, stmts.len());
909 assert_eq!(
910 stmts[0],
911 Statement::ShowVariables(ShowVariables {
912 variable: ObjectName::from(vec![Ident::new("system_time_zone")]),
913 })
914 );
915 }
916
917 #[test]
918 pub fn test_show_columns() {
919 let sql = "SHOW COLUMNS";
920 let result =
921 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
922 let error = result.unwrap_err();
923 assert_eq!(
924 "Unexpected token while parsing SQL statement, expected: '{FROM | IN} table', found: EOF",
925 error.to_string()
926 );
927
928 let sql = "SHOW COLUMNS from test";
929 let result =
930 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
931 let stmts = result.unwrap();
932 assert_eq!(1, stmts.len());
933 assert!(matches!(&stmts[0],
934 Statement::ShowColumns(ShowColumns {
935 table,
936 database,
937 full,
938 ..
939
940 }) if table == "test" && database.is_none() && !full));
941
942 let sql = "SHOW FULL COLUMNS from test from public";
943 let result =
944 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
945 let stmts = result.unwrap();
946 assert_eq!(1, stmts.len());
947 assert!(matches!(&stmts[0],
948 Statement::ShowColumns(ShowColumns {
949 table,
950 database: Some(database),
951 full,
952 ..
953 }) if table == "test" && database == "public" && *full));
954
955 let sql = "SHOW COLUMNS from test like 'disk%'";
956 let result =
957 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
958 let stmts = result.unwrap();
959 assert_eq!(1, stmts.len());
960 assert!(matches!(&stmts[0],
961 Statement::ShowColumns(ShowColumns {
962 table,
963 kind: ShowKind::Like(ident),
964 ..
965 }) if table == "test" && ident.to_string() == "'disk%'"));
966
967 let sql = "SHOW COLUMNS from test where Field = 'disk'";
968 let result =
969 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
970 let stmts = result.unwrap();
971 assert_eq!(1, stmts.len());
972 assert!(matches!(&stmts[0],
973 Statement::ShowColumns(ShowColumns {
974 table,
975 kind: ShowKind::Where(expr),
976 ..
977 }) if table == "test" && expr.to_string() == "Field = 'disk'"));
978 }
979
980 #[test]
981 pub fn test_show_index() {
982 let sql = "SHOW INDEX";
983 let result =
984 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
985 let error = result.unwrap_err();
986 assert_eq!(
987 "Unexpected token while parsing SQL statement, expected: '{FROM | IN} table', found: EOF",
988 error.to_string()
989 );
990
991 let sql = "SHOW INDEX from test";
992 let result =
993 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
994 let stmts = result.unwrap();
995 assert_eq!(1, stmts.len());
996 assert!(matches!(&stmts[0],
997 Statement::ShowIndex(ShowIndex {
998 table,
999 database,
1000 ..
1001
1002 }) if table == "test" && database.is_none()));
1003
1004 let sql = "SHOW INDEX from test from public";
1005 let result =
1006 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1007 let stmts = result.unwrap();
1008 assert_eq!(1, stmts.len());
1009 assert!(matches!(&stmts[0],
1010 Statement::ShowIndex(ShowIndex {
1011 table,
1012 database: Some(database),
1013 ..
1014 }) if table == "test" && database == "public"));
1015
1016 let sql = "SHOW INDEX from test like 'disk%'";
1018 let result =
1019 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1020 let error = result.unwrap_err();
1021 assert_eq!(
1022 "SQL statement is not supported, keyword: like",
1023 error.to_string()
1024 );
1025
1026 let sql = "SHOW INDEX from test where Field = 'disk'";
1027 let result =
1028 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1029 let stmts = result.unwrap();
1030 assert_eq!(1, stmts.len());
1031 assert!(matches!(&stmts[0],
1032 Statement::ShowIndex(ShowIndex {
1033 table,
1034 kind: ShowKind::Where(expr),
1035 ..
1036 }) if table == "test" && expr.to_string() == "Field = 'disk'"));
1037 }
1038
1039 #[test]
1040 fn test_show_region() {
1041 let sql = "SHOW REGION";
1042 let result =
1043 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1044 let error = result.unwrap_err();
1045 assert_eq!(
1046 "Unexpected token while parsing SQL statement, expected: '{FROM | IN} table', found: EOF",
1047 error.to_string()
1048 );
1049
1050 let sql = "SHOW REGION from test";
1051 let result =
1052 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1053 let stmts = result.unwrap();
1054 assert_eq!(1, stmts.len());
1055 assert!(matches!(&stmts[0],
1056 Statement::ShowRegion(ShowRegion {
1057 table,
1058 database,
1059 ..
1060
1061 }) if table == "test" && database.is_none()));
1062
1063 let sql = "SHOW REGION from test from public";
1064 let result =
1065 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1066 let stmts = result.unwrap();
1067 assert_eq!(1, stmts.len());
1068 assert!(matches!(&stmts[0],
1069 Statement::ShowRegion(ShowRegion {
1070 table,
1071 database: Some(database),
1072 ..
1073 }) if table == "test" && database == "public"));
1074
1075 let sql = "SHOW REGION from test like 'disk%'";
1077 let result =
1078 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1079 let error = result.unwrap_err();
1080 assert_eq!(
1081 "SQL statement is not supported, keyword: like",
1082 error.to_string()
1083 );
1084
1085 let sql = "SHOW REGION from test where Field = 'disk'";
1086 let result =
1087 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1088 let stmts = result.unwrap();
1089 assert_eq!(1, stmts.len());
1090 assert!(matches!(&stmts[0],
1091 Statement::ShowRegion(ShowRegion {
1092 table,
1093 kind: ShowKind::Where(expr),
1094 ..
1095 }) if table == "test" && expr.to_string() == "Field = 'disk'"));
1096 }
1097
1098 #[test]
1099 fn parse_show_collation() {
1100 let sql = "SHOW COLLATION";
1101 let result =
1102 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1103 assert!(matches!(
1104 result.unwrap()[0],
1105 Statement::ShowCollation(ShowKind::All)
1106 ));
1107
1108 let sql = "SHOW COLLATION WHERE Charset = 'latin1'";
1109 let result =
1110 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1111 assert!(matches!(
1112 result.unwrap()[0],
1113 Statement::ShowCollation(ShowKind::Where(_))
1114 ));
1115
1116 let sql = "SHOW COLLATION LIKE 'latin1'";
1117 let result =
1118 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1119 assert!(matches!(
1120 result.unwrap()[0],
1121 Statement::ShowCollation(ShowKind::Like(_))
1122 ));
1123 }
1124
1125 #[test]
1126 fn parse_show_charset() {
1127 let sql = "SHOW CHARSET";
1128 let result =
1129 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1130 assert!(matches!(
1131 result.unwrap()[0],
1132 Statement::ShowCharset(ShowKind::All)
1133 ));
1134
1135 let sql = "SHOW CHARACTER SET";
1136 let result =
1137 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1138 assert!(matches!(
1139 result.unwrap()[0],
1140 Statement::ShowCharset(ShowKind::All)
1141 ));
1142
1143 let sql = "SHOW CHARSET WHERE Charset = 'latin1'";
1144 let result =
1145 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1146 assert!(matches!(
1147 result.unwrap()[0],
1148 Statement::ShowCharset(ShowKind::Where(_))
1149 ));
1150
1151 let sql = "SHOW CHARACTER SET LIKE 'latin1'";
1152 let result =
1153 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1154 assert!(matches!(
1155 result.unwrap()[0],
1156 Statement::ShowCharset(ShowKind::Like(_))
1157 ));
1158 }
1159
1160 #[test]
1161 fn test_show_variables_scope() {
1162 for sql in [
1163 "SHOW STATUS",
1164 "SHOW GLOBAL STATUS",
1165 "SHOW SESSION STATUS",
1166 "SHOW LOCAL STATUS",
1167 ] {
1168 let result = ParserContext::create_with_dialect(
1169 sql,
1170 &GreptimeDbDialect {},
1171 ParseOptions::default(),
1172 );
1173 assert!(
1174 matches!(result.unwrap()[0], Statement::ShowStatus(_)),
1175 "{sql}"
1176 );
1177 }
1178
1179 let result = ParserContext::create_with_dialect(
1181 "SHOW GLOBAL TABLES",
1182 &GreptimeDbDialect {},
1183 ParseOptions::default(),
1184 );
1185 assert!(result.is_err());
1186 }
1187
1188 fn parse_show_table_status(sql: &str) -> ShowTableStatus {
1189 let result =
1190 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1191 let mut stmts = result.unwrap();
1192 assert_eq!(1, stmts.len());
1193
1194 match stmts.remove(0) {
1195 Statement::ShowTableStatus(stmt) => stmt,
1196 _ => panic!("Failed to parse show table status"),
1197 }
1198 }
1199
1200 #[test]
1201 pub fn test_show_table_status() {
1202 let sql = "SHOW TABLE STATUS";
1203 let stmt = parse_show_table_status(sql);
1204 assert!(stmt.database.is_none());
1205 assert_eq!(sql, stmt.to_string());
1206
1207 let sql = "SHOW TABLE STATUS IN test";
1208 let stmt = parse_show_table_status(sql);
1209 assert_eq!("test", stmt.database.as_ref().unwrap());
1210 assert_eq!(sql, stmt.to_string());
1211
1212 let sql = "SHOW TABLE STATUS LIKE '%monitor'";
1213 let stmt = parse_show_table_status(sql);
1214 assert!(stmt.database.is_none());
1215 assert!(matches!(stmt.kind, ShowKind::Like(_)));
1216 assert_eq!(sql, stmt.to_string());
1217
1218 let sql = "SHOW TABLE STATUS IN test WHERE Name = 'monitor'";
1219 let stmt = parse_show_table_status(sql);
1220 assert_eq!("test", stmt.database.as_ref().unwrap());
1221 assert!(matches!(stmt.kind, ShowKind::Where(_)));
1222 assert_eq!(sql, stmt.to_string());
1223 }
1224
1225 #[test]
1226 pub fn test_show_create_view() {
1227 let sql = "SHOW CREATE VIEW test";
1228 let result =
1229 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1230 let stmts = result.unwrap();
1231 assert_eq!(1, stmts.len());
1232 assert_eq!(
1233 stmts[0],
1234 Statement::ShowCreateView(ShowCreateView {
1235 view_name: ObjectName::from(vec![Ident::new("test")]),
1236 })
1237 );
1238 assert_eq!(sql, stmts[0].to_string());
1239 }
1240
1241 #[test]
1242 pub fn test_show_views() {
1243 let sql = "SHOW VIEWS";
1244 let result =
1245 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1246 let stmts = result.unwrap();
1247 assert_eq!(1, stmts.len());
1248 assert_eq!(
1249 stmts[0],
1250 Statement::ShowViews(ShowViews {
1251 kind: ShowKind::All,
1252 database: None,
1253 })
1254 );
1255 assert_eq!(sql, stmts[0].to_string());
1256 }
1257
1258 #[test]
1259 pub fn test_show_views_in_db() {
1260 let sql = "SHOW VIEWS IN d1";
1261 let result =
1262 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1263 let stmts = result.unwrap();
1264 assert_eq!(1, stmts.len());
1265 assert_eq!(
1266 stmts[0],
1267 Statement::ShowViews(ShowViews {
1268 kind: ShowKind::All,
1269 database: Some("d1".to_string()),
1270 })
1271 );
1272 assert_eq!(sql, stmts[0].to_string());
1273 }
1274
1275 #[test]
1276 pub fn test_show_flows() {
1277 let sql = "SHOW FLOWS";
1278 let result =
1279 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1280 let stmts = result.unwrap();
1281 assert_eq!(1, stmts.len());
1282 assert_eq!(
1283 stmts[0],
1284 Statement::ShowFlows(ShowFlows {
1285 kind: ShowKind::All,
1286 database: None,
1287 })
1288 );
1289 assert_eq!(sql, stmts[0].to_string());
1290 }
1291
1292 #[test]
1293 pub fn test_show_flows_in_db() {
1294 let sql = "SHOW FLOWS IN d1";
1295 let result =
1296 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1297 let stmts = result.unwrap();
1298 assert_eq!(1, stmts.len());
1299 assert_eq!(
1300 stmts[0],
1301 Statement::ShowFlows(ShowFlows {
1302 kind: ShowKind::All,
1303 database: Some("d1".to_string()),
1304 })
1305 );
1306 assert_eq!(sql, stmts[0].to_string());
1307 }
1308
1309 #[test]
1310 pub fn test_show_flow_status() {
1311 let sql = "SHOW FLOW STATUS";
1312 let result =
1313 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1314 let stmts = result.unwrap();
1315 assert_eq!(1, stmts.len());
1316 assert_eq!(
1317 stmts[0],
1318 Statement::ShowFlowStatus(ShowFlowStatus {
1319 kind: ShowKind::All,
1320 })
1321 );
1322 assert_eq!(sql, stmts[0].to_string());
1323 }
1324
1325 #[test]
1326 pub fn test_show_processlist() {
1327 let sql = "SHOW PROCESSLIST";
1328 let result =
1329 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1330 let stmts = result.unwrap();
1331 assert_eq!(1, stmts.len());
1332 assert_eq!(
1333 stmts[0],
1334 Statement::ShowProcesslist(ShowProcessList { full: false })
1335 );
1336 assert_eq!(sql, stmts[0].to_string());
1337
1338 let sql = "SHOW FULL PROCESSLIST";
1339 let result =
1340 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1341 let stmts = result.unwrap();
1342 assert_eq!(1, stmts.len());
1343 assert_eq!(
1344 stmts[0],
1345 Statement::ShowProcesslist(ShowProcessList { full: true })
1346 );
1347 assert_eq!(sql, stmts[0].to_string());
1348 }
1349
1350 #[cfg(feature = "enterprise")]
1351 #[test]
1352 pub fn test_parse_show_create_trigger() {
1353 let sql = "SHOW CREATE TRIGGER test_trigger";
1354 let result =
1355 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1356 let stmts = result.unwrap();
1357 assert_eq!(1, stmts.len());
1358 assert_eq!(
1359 stmts[0],
1360 Statement::ShowCreateTrigger(ShowCreateTrigger {
1361 trigger_name: ObjectName::from(vec![Ident::new("test_trigger")]),
1362 })
1363 );
1364 assert_eq!(sql, stmts[0].to_string());
1365 }
1366
1367 #[cfg(feature = "enterprise")]
1368 #[test]
1369 pub fn test_parse_show_triggers() {
1370 let sql = "SHOW TRIGGERS";
1371 let result =
1372 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1373 let stmts = result.unwrap();
1374 assert_eq!(1, stmts.len());
1375 assert_eq!(
1376 stmts[0],
1377 Statement::ShowTriggers(ShowTriggers {
1378 kind: ShowKind::All,
1379 })
1380 );
1381 assert_eq!(sql, stmts[0].to_string());
1382 }
1383
1384 #[cfg(feature = "enterprise")]
1385 #[test]
1386 pub fn test_parse_show_triggers_like() {
1387 let sql = "SHOW TRIGGERS LIKE 'test_trigger'";
1388 let result =
1389 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1390 let stmts = result.unwrap();
1391 assert_eq!(1, stmts.len());
1392 assert_eq!(
1393 stmts[0],
1394 Statement::ShowTriggers(ShowTriggers {
1395 kind: ShowKind::Like(Ident::with_quote('\'', "test_trigger")),
1396 })
1397 );
1398 assert_eq!(sql, stmts[0].to_string());
1399 }
1400
1401 #[cfg(feature = "enterprise")]
1402 #[test]
1403 pub fn test_parse_show_triggers_where() {
1404 let sql = "SHOW TRIGGERS WHERE name = 'test_trigger'";
1405 let result =
1406 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1407 let stmts = result.unwrap();
1408 assert_eq!(1, stmts.len());
1409 assert!(matches!(
1410 &stmts[0],
1411 Statement::ShowTriggers(ShowTriggers {
1412 kind: ShowKind::Where(_)
1413 })
1414 ));
1415 assert_eq!(sql, stmts[0].to_string());
1416 }
1417}