1use std::str::FromStr;
16
17use chrono::{DateTime, Utc};
18use snafu::{OptionExt, ResultExt};
19use sqlparser::ast::{Ident, Query, Value};
20use sqlparser::dialect::Dialect;
21use sqlparser::keywords::Keyword;
22use sqlparser::parser::{Parser, ParserError, ParserOptions};
23use sqlparser::tokenizer::{Token, TokenWithSpan};
24
25use crate::ast::{Expr, ObjectName};
26use crate::error::{self, InvalidSqlSnafu, Result, SyntaxSnafu};
27use crate::parsers::tql_parser;
28use crate::statements::kill::Kill;
29use crate::statements::statement::Statement;
30use crate::statements::transform_statements;
31
32pub const FLOW: &str = "FLOW";
33
34#[derive(Clone, Debug, Default)]
36pub struct ParseOptions {
37 pub scheduled_time: Option<DateTime<Utc>>,
40}
41
42pub struct ParserContext<'a> {
44 pub(crate) parser: Parser<'a>,
45 pub(crate) sql: &'a str,
46 pub(crate) scheduled_time: Option<DateTime<Utc>>,
48}
49
50impl ParserContext<'_> {
51 pub fn new<'a>(dialect: &'a dyn Dialect, sql: &'a str) -> Result<ParserContext<'a>> {
53 let parser = Parser::new(dialect)
54 .with_options(ParserOptions::new().with_trailing_commas(true))
55 .try_with_sql(sql)
56 .context(SyntaxSnafu)?;
57
58 Ok(ParserContext {
59 parser,
60 sql,
61 scheduled_time: None,
62 })
63 }
64
65 pub fn parser_query(&mut self) -> Result<Box<Query>> {
67 self.parser.parse_query().context(SyntaxSnafu)
68 }
69
70 pub fn create_with_dialect(
72 sql: &str,
73 dialect: &dyn Dialect,
74 opts: ParseOptions,
75 ) -> Result<Vec<Statement>> {
76 let mut stmts: Vec<Statement> = Vec::new();
77
78 let mut parser_ctx = ParserContext::new(dialect, sql)?;
79 parser_ctx.scheduled_time = opts.scheduled_time;
80
81 let mut expecting_statement_delimiter = false;
82 loop {
83 while parser_ctx.parser.consume_token(&Token::SemiColon) {
85 expecting_statement_delimiter = false;
86 }
87
88 if parser_ctx.parser.peek_token() == Token::EOF {
89 break;
90 }
91 if expecting_statement_delimiter {
92 return parser_ctx.unsupported(parser_ctx.peek_token_as_string());
93 }
94
95 let statement = parser_ctx.parse_statement()?;
96 stmts.push(statement);
97 expecting_statement_delimiter = true;
98 }
99
100 transform_statements(&mut stmts)?;
101
102 Ok(stmts)
103 }
104
105 pub fn parse_table_name(sql: &str, dialect: &dyn Dialect) -> Result<ObjectName> {
106 let parser = Parser::new(dialect)
107 .with_options(ParserOptions::new().with_trailing_commas(true))
108 .try_with_sql(sql)
109 .context(SyntaxSnafu)?;
110 ParserContext {
111 parser,
112 sql,
113 scheduled_time: None,
114 }
115 .intern_parse_table_name()
116 }
117
118 pub(crate) fn intern_parse_table_name(&mut self) -> Result<ObjectName> {
119 let raw_table_name =
120 self.parser
121 .parse_object_name(false)
122 .context(error::UnexpectedSnafu {
123 expected: "a table name",
124 actual: self.parser.peek_token().to_string(),
125 })?;
126 Self::canonicalize_object_name(raw_table_name)
127 }
128
129 pub fn parse_function(sql: &str, dialect: &dyn Dialect) -> Result<Expr> {
130 let mut parser = Parser::new(dialect)
131 .with_options(ParserOptions::new().with_trailing_commas(true))
132 .try_with_sql(sql)
133 .context(SyntaxSnafu)?;
134
135 let function_name = parser.parse_identifier().context(SyntaxSnafu)?;
136 parser
137 .parse_function(vec![function_name].into())
138 .context(SyntaxSnafu)
139 }
140
141 pub fn parse_statement(&mut self) -> Result<Statement> {
143 match self.parser.peek_token().token {
144 Token::Word(w) => match w.keyword {
145 Keyword::CREATE => {
146 let _ = self.parser.next_token();
147 self.parse_create()
148 }
149
150 Keyword::EXPLAIN => {
151 let _ = self.parser.next_token();
152 self.parse_explain()
153 }
154
155 Keyword::SHOW => {
156 let _ = self.parser.next_token();
157 self.parse_show()
158 }
159
160 Keyword::DELETE => self.parse_delete(),
161
162 Keyword::DESCRIBE | Keyword::DESC => {
163 let _ = self.parser.next_token();
164 self.parse_describe()
165 }
166
167 Keyword::INSERT => self.parse_insert(),
168
169 Keyword::REPLACE => self.parse_replace(),
170
171 Keyword::SELECT | Keyword::VALUES => self.parse_query(),
172
173 Keyword::WITH => self.parse_with_tql(),
174
175 Keyword::ALTER => self.parse_alter(),
176
177 Keyword::DROP => self.parse_drop(),
178
179 Keyword::COPY => self.parse_copy(),
180
181 Keyword::TRUNCATE => self.parse_truncate(),
182
183 Keyword::COMMENT => self.parse_comment(),
184
185 Keyword::SET => self.parse_set_variables(),
186
187 Keyword::ADMIN => self.parse_admin_command(),
188
189 Keyword::NoKeyword
190 if w.quote_style.is_none() && w.value.to_uppercase() == tql_parser::TQL =>
191 {
192 self.parse_tql(false)
193 }
194
195 #[cfg(feature = "enterprise")]
196 Keyword::NoKeyword
197 if w.quote_style.is_none() && w.value.eq_ignore_ascii_case("UNDROP") =>
198 {
199 self.parse_undrop_table()
200 }
201
202 Keyword::DECLARE => self.parse_declare_cursor(),
203
204 Keyword::FETCH => self.parse_fetch_cursor(),
205
206 Keyword::CLOSE => self.parse_close_cursor(),
207
208 Keyword::USE => {
209 let _ = self.parser.next_token();
210
211 let database_name = self.parser.parse_identifier().with_context(|_| {
212 error::UnexpectedSnafu {
213 expected: "a database name",
214 actual: self.peek_token_as_string(),
215 }
216 })?;
217 Ok(Statement::Use(
218 Self::canonicalize_identifier(database_name).value,
219 ))
220 }
221
222 Keyword::KILL => {
223 let _ = self.parser.next_token();
224 let kill = if self.parser.parse_keyword(Keyword::QUERY) {
225 let connection_id_exp =
227 self.parser.parse_number_value().with_context(|_| {
228 error::UnexpectedSnafu {
229 expected: "MySQL numeric connection id",
230 actual: self.peek_token_as_string(),
231 }
232 })?;
233 let Value::Number(s, _) = connection_id_exp.value else {
234 return error::UnexpectedTokenSnafu {
235 expected: "MySQL numeric connection id",
236 actual: connection_id_exp.to_string(),
237 }
238 .fail();
239 };
240
241 let connection_id = u32::from_str(&s).map_err(|_| {
242 error::UnexpectedTokenSnafu {
243 expected: "MySQL numeric connection id",
244 actual: s,
245 }
246 .build()
247 })?;
248 Kill::ConnectionId(connection_id)
249 } else {
250 let process_id_ident =
251 self.parser.parse_literal_string().with_context(|_| {
252 error::UnexpectedSnafu {
253 expected: "process id string literal",
254 actual: self.peek_token_as_string(),
255 }
256 })?;
257 Kill::ProcessId(process_id_ident)
258 };
259
260 Ok(Statement::Kill(kill))
261 }
262
263 _ => self.unsupported(self.peek_token_as_string()),
264 },
265 Token::LParen => self.parse_query(),
266 unexpected => self.unsupported(unexpected.to_string()),
267 }
268 }
269
270 pub fn parse_mysql_prepare_stmt(sql: &str, dialect: &dyn Dialect) -> Result<(String, String)> {
272 ParserContext::new(dialect, sql)?.parse_mysql_prepare()
273 }
274
275 pub fn parse_mysql_execute_stmt(
277 sql: &str,
278 dialect: &dyn Dialect,
279 ) -> Result<(String, Vec<Expr>)> {
280 ParserContext::new(dialect, sql)?.parse_mysql_execute()
281 }
282
283 pub fn parse_mysql_deallocate_stmt(sql: &str, dialect: &dyn Dialect) -> Result<String> {
285 ParserContext::new(dialect, sql)?.parse_deallocate()
286 }
287
288 pub fn unsupported<T>(&self, keyword: String) -> Result<T> {
290 error::UnsupportedSnafu { keyword }.fail()
291 }
292
293 pub(crate) fn expected<T>(&self, expected: &str, found: TokenWithSpan) -> Result<T> {
295 Err(ParserError::ParserError(format!(
296 "Expected {expected}, found: {found}",
297 )))
298 .context(SyntaxSnafu)
299 }
300
301 pub fn matches_keyword(&mut self, expected: Keyword) -> bool {
302 match self.parser.peek_token().token {
303 Token::Word(w) => w.keyword == expected,
304 _ => false,
305 }
306 }
307
308 pub fn consume_token(&mut self, expected: &str) -> bool {
309 if self.peek_token_as_string().to_uppercase() == *expected.to_uppercase() {
310 let _ = self.parser.next_token();
311 true
312 } else {
313 false
314 }
315 }
316
317 #[inline]
318 pub(crate) fn peek_token_as_string(&self) -> String {
319 self.parser.peek_token().to_string()
320 }
321
322 pub fn canonicalize_identifier(ident: Ident) -> Ident {
324 if ident.quote_style.is_some() {
325 ident
326 } else {
327 Ident::new(ident.value.to_lowercase())
328 }
329 }
330
331 pub(crate) fn canonicalize_object_name(object_name: ObjectName) -> Result<ObjectName> {
333 object_name
334 .0
335 .into_iter()
336 .map(|x| {
337 x.as_ident()
338 .cloned()
339 .map(Self::canonicalize_identifier)
340 .with_context(|| InvalidSqlSnafu {
341 msg: format!("not an ident: '{x}'"),
342 })
343 })
344 .collect::<Result<Vec<_>>>()
345 .map(Into::into)
346 }
347
348 pub(crate) fn parse_object_name(&mut self) -> std::result::Result<ObjectName, ParserError> {
353 self.parser.parse_object_name(false)
354 }
355}
356
357#[cfg(test)]
358mod tests {
359
360 use datatypes::prelude::ConcreteDataType;
361 use sqlparser::dialect::MySqlDialect;
362
363 use super::*;
364 use crate::dialect::GreptimeDbDialect;
365 use crate::statements::create::CreateTable;
366 use crate::statements::sql_data_type_to_concrete_data_type;
367
368 fn test_timestamp_precision(sql: &str, expected_type: ConcreteDataType) {
369 match ParserContext::create_with_dialect(
370 sql,
371 &GreptimeDbDialect {},
372 ParseOptions::default(),
373 )
374 .unwrap()
375 .pop()
376 .unwrap()
377 {
378 Statement::CreateTable(CreateTable { columns, .. }) => {
379 let ts_col = columns.first().unwrap();
380 assert_eq!(
381 expected_type,
382 sql_data_type_to_concrete_data_type(ts_col.data_type()).unwrap()
383 );
384 }
385 _ => unreachable!(),
386 }
387 }
388
389 #[test]
390 pub fn test_create_table_with_precision() {
391 test_timestamp_precision(
392 "create table demo (ts timestamp time index, cnt int);",
393 ConcreteDataType::timestamp_millisecond_datatype(),
394 );
395 test_timestamp_precision(
396 "create table demo (ts timestamp(0) time index, cnt int);",
397 ConcreteDataType::timestamp_second_datatype(),
398 );
399 test_timestamp_precision(
400 "create table demo (ts timestamp(3) time index, cnt int);",
401 ConcreteDataType::timestamp_millisecond_datatype(),
402 );
403 test_timestamp_precision(
404 "create table demo (ts timestamp(6) time index, cnt int);",
405 ConcreteDataType::timestamp_microsecond_datatype(),
406 );
407 test_timestamp_precision(
408 "create table demo (ts timestamp(9) time index, cnt int);",
409 ConcreteDataType::timestamp_nanosecond_datatype(),
410 );
411 }
412
413 #[test]
414 #[should_panic]
415 pub fn test_create_table_with_invalid_precision() {
416 test_timestamp_precision(
417 "create table demo (ts timestamp(1) time index, cnt int);",
418 ConcreteDataType::timestamp_millisecond_datatype(),
419 );
420 }
421
422 #[test]
423 pub fn test_parse_table_name() {
424 let table_name = "a.b.c";
425
426 let object_name =
427 ParserContext::parse_table_name(table_name, &GreptimeDbDialect {}).unwrap();
428
429 assert_eq!(object_name.0.len(), 3);
430 assert_eq!(object_name.to_string(), table_name);
431
432 let table_name = "a.b";
433
434 let object_name =
435 ParserContext::parse_table_name(table_name, &GreptimeDbDialect {}).unwrap();
436
437 assert_eq!(object_name.0.len(), 2);
438 assert_eq!(object_name.to_string(), table_name);
439
440 let table_name = "Test.\"public-test\"";
441
442 let object_name =
443 ParserContext::parse_table_name(table_name, &GreptimeDbDialect {}).unwrap();
444
445 assert_eq!(object_name.0.len(), 2);
446 assert_eq!(object_name.to_string(), table_name.to_ascii_lowercase());
447
448 let table_name = "HelloWorld";
449
450 let object_name =
451 ParserContext::parse_table_name(table_name, &GreptimeDbDialect {}).unwrap();
452
453 assert_eq!(object_name.0.len(), 1);
454 assert_eq!(object_name.to_string(), table_name.to_ascii_lowercase());
455 }
456
457 #[test]
458 pub fn test_parse_mysql_prepare_stmt() {
459 let sql = "PREPARE stmt1 FROM 'SELECT * FROM t1 WHERE id = ?';";
460 let (stmt_name, stmt) =
461 ParserContext::parse_mysql_prepare_stmt(sql, &MySqlDialect {}).unwrap();
462 assert_eq!(stmt_name, "stmt1");
463 assert_eq!(stmt, "SELECT * FROM t1 WHERE id = ?");
464
465 let sql = "PREPARE stmt2 FROM \"SELECT * FROM t1 WHERE id = ?\"";
466 let (stmt_name, stmt) =
467 ParserContext::parse_mysql_prepare_stmt(sql, &MySqlDialect {}).unwrap();
468 assert_eq!(stmt_name, "stmt2");
469 assert_eq!(stmt, "SELECT * FROM t1 WHERE id = ?");
470 }
471
472 #[test]
473 pub fn test_parse_mysql_execute_stmt() {
474 let sql = "EXECUTE stmt1 USING 1, 'hello';";
475 let (stmt_name, params) =
476 ParserContext::parse_mysql_execute_stmt(sql, &GreptimeDbDialect {}).unwrap();
477 assert_eq!(stmt_name, "stmt1");
478 assert_eq!(params.len(), 2);
479 assert_eq!(params[0].to_string(), "1");
480 assert_eq!(params[1].to_string(), "'hello'");
481
482 let sql = "EXECUTE stmt2;";
483 let (stmt_name, params) =
484 ParserContext::parse_mysql_execute_stmt(sql, &GreptimeDbDialect {}).unwrap();
485 assert_eq!(stmt_name, "stmt2");
486 assert_eq!(params.len(), 0);
487
488 let sql = "EXECUTE stmt3 USING 231, 'hello', \"2003-03-1\", NULL, ;";
489 let (stmt_name, params) =
490 ParserContext::parse_mysql_execute_stmt(sql, &GreptimeDbDialect {}).unwrap();
491 assert_eq!(stmt_name, "stmt3");
492 assert_eq!(params.len(), 4);
493 assert_eq!(params[0].to_string(), "231");
494 assert_eq!(params[1].to_string(), "'hello'");
495 assert_eq!(params[2].to_string(), "\"2003-03-1\"");
496 assert_eq!(params[3].to_string(), "NULL");
497 }
498
499 #[test]
500 pub fn test_parse_mysql_deallocate_stmt() {
501 let sql = "DEALLOCATE stmt1;";
502 let stmt_name = ParserContext::parse_mysql_deallocate_stmt(sql, &MySqlDialect {}).unwrap();
503 assert_eq!(stmt_name, "stmt1");
504
505 let sql = "DEALLOCATE stmt2";
506 let stmt_name = ParserContext::parse_mysql_deallocate_stmt(sql, &MySqlDialect {}).unwrap();
507 assert_eq!(stmt_name, "stmt2");
508 }
509
510 #[test]
511 pub fn test_parse_kill_query_statement() {
512 use crate::statements::kill::Kill;
513
514 let sql = "KILL QUERY 123";
516 let statements =
517 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
518 .unwrap();
519
520 assert_eq!(statements.len(), 1);
521 match &statements[0] {
522 Statement::Kill(Kill::ConnectionId(connection_id)) => {
523 assert_eq!(*connection_id, 123);
524 }
525 _ => panic!("Expected Kill::ConnectionId statement"),
526 }
527
528 let sql = "KILL QUERY 999999";
530 let statements =
531 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
532 .unwrap();
533
534 assert_eq!(statements.len(), 1);
535 match &statements[0] {
536 Statement::Kill(Kill::ConnectionId(connection_id)) => {
537 assert_eq!(*connection_id, 999999);
538 }
539 _ => panic!("Expected Kill::ConnectionId statement"),
540 }
541 }
542
543 #[test]
544 pub fn test_parse_kill_process_statement() {
545 use crate::statements::kill::Kill;
546
547 let sql = "KILL 'process-123'";
549 let statements =
550 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
551 .unwrap();
552
553 assert_eq!(statements.len(), 1);
554 match &statements[0] {
555 Statement::Kill(Kill::ProcessId(process_id)) => {
556 assert_eq!(process_id, "process-123");
557 }
558 _ => panic!("Expected Kill::ProcessId statement"),
559 }
560
561 let sql = "KILL \"process-456\"";
563 let statements =
564 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
565 .unwrap();
566
567 assert_eq!(statements.len(), 1);
568 match &statements[0] {
569 Statement::Kill(Kill::ProcessId(process_id)) => {
570 assert_eq!(process_id, "process-456");
571 }
572 _ => panic!("Expected Kill::ProcessId statement"),
573 }
574
575 let sql = "KILL 'f47ac10b-58cc-4372-a567-0e02b2c3d479'";
577 let statements =
578 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
579 .unwrap();
580
581 assert_eq!(statements.len(), 1);
582 match &statements[0] {
583 Statement::Kill(Kill::ProcessId(process_id)) => {
584 assert_eq!(process_id, "f47ac10b-58cc-4372-a567-0e02b2c3d479");
585 }
586 _ => panic!("Expected Kill::ProcessId statement"),
587 }
588 }
589
590 #[test]
591 pub fn test_parse_kill_statement_errors() {
592 let sql = "KILL QUERY";
594 let result =
595 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
596 assert!(result.is_err());
597
598 let sql = "KILL QUERY 'not-a-number'";
600 let result =
601 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
602 assert!(result.is_err());
603
604 let sql = "KILL";
606 let result =
607 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
608 assert!(result.is_err());
609
610 let sql = "KILL QUERY 4294967296"; let result =
613 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
614 assert!(result.is_err());
615 }
616
617 #[test]
618 pub fn test_parse_kill_statement_edge_cases() {
619 use crate::statements::kill::Kill;
620
621 let sql = "KILL QUERY 0";
623 let statements =
624 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
625 .unwrap();
626
627 assert_eq!(statements.len(), 1);
628 match &statements[0] {
629 Statement::Kill(Kill::ConnectionId(connection_id)) => {
630 assert_eq!(*connection_id, 0);
631 }
632 _ => panic!("Expected Kill::ConnectionId statement"),
633 }
634
635 let sql = "KILL QUERY 4294967295"; let statements =
638 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
639 .unwrap();
640
641 assert_eq!(statements.len(), 1);
642 match &statements[0] {
643 Statement::Kill(Kill::ConnectionId(connection_id)) => {
644 assert_eq!(*connection_id, 4294967295);
645 }
646 _ => panic!("Expected Kill::ConnectionId statement"),
647 }
648
649 let sql = "KILL ''";
651 let statements =
652 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
653 .unwrap();
654
655 assert_eq!(statements.len(), 1);
656 match &statements[0] {
657 Statement::Kill(Kill::ProcessId(process_id)) => {
658 assert_eq!(process_id, "");
659 }
660 _ => panic!("Expected Kill::ProcessId statement"),
661 }
662 }
663
664 #[test]
665 pub fn test_parse_kill_statement_case_insensitive() {
666 use crate::statements::kill::Kill;
667
668 let sql = "kill query 123";
670 let statements =
671 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
672 .unwrap();
673
674 assert_eq!(statements.len(), 1);
675 match &statements[0] {
676 Statement::Kill(Kill::ConnectionId(connection_id)) => {
677 assert_eq!(*connection_id, 123);
678 }
679 _ => panic!("Expected Kill::ConnectionId statement"),
680 }
681
682 let sql = "Kill Query 456";
684 let statements =
685 ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
686 .unwrap();
687
688 assert_eq!(statements.len(), 1);
689 match &statements[0] {
690 Statement::Kill(Kill::ConnectionId(connection_id)) => {
691 assert_eq!(*connection_id, 456);
692 }
693 _ => panic!("Expected Kill::ConnectionId statement"),
694 }
695 }
696}