sql/parsers/
explain_parser.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use snafu::ResultExt;
16use sqlparser::keywords::Keyword;
17
18use crate::error::{self, Result};
19use crate::parser::ParserContext;
20use crate::statements::explain::ExplainStatement;
21use crate::statements::statement::Statement;
22
23/// EXPLAIN statement parser implementation
24impl ParserContext<'_> {
25    /// explain that support use our own parser to parse the inner statement
26    pub(crate) fn parse_explain(&mut self) -> Result<Statement> {
27        let analyze = self.parser.parse_keyword(Keyword::ANALYZE);
28        let verbose = self.parser.parse_keyword(Keyword::VERBOSE);
29        let format =
30            if self.parser.parse_keyword(Keyword::FORMAT) {
31                Some(self.parser.parse_analyze_format().with_context(|_| {
32                    error::UnexpectedSnafu {
33                        expected: "analyze format",
34                        actual: self.peek_token_as_string(),
35                    }
36                })?)
37            } else {
38                None
39            };
40
41        let statement = self.parse_statement()?;
42
43        let explain = ExplainStatement {
44            analyze,
45            verbose,
46            format,
47            statement: Box::new(statement),
48        };
49        Ok(Statement::Explain(Box::new(explain)))
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use sqlparser::ast::helpers::attached_token::AttachedToken;
56    use sqlparser::ast::{GroupByExpr, Query as SpQuery, SelectFlavor, WildcardAdditionalOptions};
57
58    use super::*;
59    use crate::dialect::GreptimeDbDialect;
60    use crate::parser::ParseOptions;
61
62    #[test]
63    pub fn test_explain() {
64        let sql = "EXPLAIN select * from foo";
65        let result =
66            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
67        let stmts = result.unwrap();
68        assert_eq!(1, stmts.len());
69
70        let select = sqlparser::ast::Select {
71            distinct: None,
72            top: None,
73            projection: vec![sqlparser::ast::SelectItem::Wildcard(
74                WildcardAdditionalOptions::default(),
75            )],
76            into: None,
77            from: vec![sqlparser::ast::TableWithJoins {
78                relation: sqlparser::ast::TableFactor::Table {
79                    name: sqlparser::ast::ObjectName::from(vec![sqlparser::ast::Ident::new("foo")]),
80                    alias: None,
81                    args: None,
82                    with_hints: vec![],
83                    partitions: vec![],
84                    version: None,
85                    with_ordinality: false,
86                    json_path: None,
87                    sample: None,
88                    index_hints: vec![],
89                },
90                joins: vec![],
91            }],
92            lateral_views: vec![],
93            selection: None,
94            group_by: GroupByExpr::Expressions(vec![], vec![]),
95            cluster_by: vec![],
96            distribute_by: vec![],
97            sort_by: vec![],
98            having: None,
99            qualify: None,
100            named_window: vec![],
101            value_table_mode: None,
102            top_before_distinct: false,
103            prewhere: None,
104            window_before_qualify: false,
105            connect_by: None,
106            select_token: AttachedToken::empty(),
107            flavor: SelectFlavor::Standard,
108        };
109
110        let sp_query = Box::new(
111            SpQuery {
112                with: None,
113                body: Box::new(sqlparser::ast::SetExpr::Select(Box::new(select))),
114                order_by: None,
115                limit: None,
116                limit_by: vec![],
117                offset: None,
118                fetch: None,
119                locks: vec![],
120                for_clause: None,
121                settings: None,
122                format_clause: None,
123            }
124            .try_into()
125            .unwrap(),
126        );
127
128        let explain = ExplainStatement {
129            analyze: false,
130            verbose: false,
131            format: None,
132            statement: Box::new(Statement::Query(sp_query)),
133        };
134
135        assert_eq!(stmts[0], Statement::Explain(Box::new(explain)))
136    }
137}