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            select_modifiers: None,
73            top: None,
74            projection: vec![sqlparser::ast::SelectItem::Wildcard(
75                WildcardAdditionalOptions::default(),
76            )],
77            exclude: None,
78            into: None,
79            from: vec![sqlparser::ast::TableWithJoins {
80                relation: sqlparser::ast::TableFactor::Table {
81                    name: sqlparser::ast::ObjectName::from(vec![sqlparser::ast::Ident::new("foo")]),
82                    alias: None,
83                    args: None,
84                    with_hints: vec![],
85                    partitions: vec![],
86                    version: None,
87                    with_ordinality: false,
88                    json_path: None,
89                    sample: None,
90                    index_hints: vec![],
91                },
92                joins: vec![],
93            }],
94            lateral_views: vec![],
95            selection: None,
96            group_by: GroupByExpr::Expressions(vec![], vec![]),
97            cluster_by: vec![],
98            distribute_by: vec![],
99            sort_by: vec![],
100            having: None,
101            qualify: None,
102            named_window: vec![],
103            value_table_mode: None,
104            top_before_distinct: false,
105            prewhere: None,
106            window_before_qualify: false,
107            connect_by: vec![],
108            select_token: AttachedToken::empty(),
109            flavor: SelectFlavor::Standard,
110            optimizer_hint: None,
111        };
112
113        let sp_query = Box::new(
114            SpQuery {
115                with: None,
116                body: Box::new(sqlparser::ast::SetExpr::Select(Box::new(select))),
117                order_by: None,
118                limit_clause: None,
119                pipe_operators: vec![],
120                fetch: None,
121                locks: vec![],
122                for_clause: None,
123                settings: None,
124                format_clause: None,
125            }
126            .try_into()
127            .unwrap(),
128        );
129
130        let explain = ExplainStatement {
131            analyze: false,
132            verbose: false,
133            format: None,
134            statement: Box::new(Statement::Query(sp_query)),
135        };
136
137        assert_eq!(stmts[0], Statement::Explain(Box::new(explain)))
138    }
139}