Skip to main content

query/
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 std::any::Any;
16use std::collections::HashMap;
17use std::sync::Arc;
18use std::time::{Duration, SystemTime};
19
20use chrono::DateTime;
21use common_error::ext::{BoxedError, PlainError};
22use common_error::status_code::StatusCode;
23use common_telemetry::tracing;
24use promql_parser::parser::Expr::Extension;
25use promql_parser::parser::ast::{Extension as NodeExtension, ExtensionExpr};
26use promql_parser::parser::value::ValueType;
27use promql_parser::parser::{EvalStmt, Expr};
28use session::context::QueryContextRef;
29use snafu::{OptionExt, ResultExt};
30use sql::dialect::GreptimeDbDialect;
31use sql::parser::{ParseOptions, ParserContext};
32use sql::statements::statement::Statement;
33
34use crate::error::{
35    AddSystemTimeOverflowSnafu, MultipleStatementsSnafu, ParseFloatSnafu, ParseTimestampSnafu,
36    QueryParseSnafu, Result, TryIntoDurationSnafu, UnimplementedSnafu,
37};
38use crate::metrics::{PARSE_PROMQL_ELAPSED, PARSE_SQL_ELAPSED};
39
40pub const DEFAULT_LOOKBACK_STRING: &str = "5m";
41pub const EXPLAIN_NODE_NAME: &str = "EXPLAIN";
42pub const EXPLAIN_VERBOSE_NODE_NAME: &str = "EXPLAIN VERBOSE";
43pub const ANALYZE_NODE_NAME: &str = "ANALYZE";
44pub const ANALYZE_VERBOSE_NODE_NAME: &str = "ANALYZE VERBOSE";
45pub const ALIAS_NODE_NAME: &str = "ALIAS";
46
47#[derive(Debug, Clone)]
48pub enum QueryStatement {
49    Sql(Statement),
50    // The optional String is the alias name
51    Promql(EvalStmt, Option<String>),
52}
53
54impl QueryStatement {
55    pub fn post_process(self, params: HashMap<String, String>) -> Result<QueryStatement> {
56        match self {
57            QueryStatement::Sql(_) => UnimplementedSnafu {
58                operation: "sql post process",
59            }
60            .fail(),
61            QueryStatement::Promql(mut eval_stmt, alias) => {
62                let node_name = match params.get("name") {
63                    Some(name) => name.as_str(),
64                    None => "",
65                };
66                let extension_node = Self::create_extension_node(node_name, eval_stmt.expr);
67                eval_stmt.expr = Extension(extension_node.unwrap());
68                Ok(QueryStatement::Promql(eval_stmt, alias))
69            }
70        }
71    }
72
73    fn create_extension_node(node_name: &str, expr: Expr) -> Option<NodeExtension> {
74        match node_name {
75            ANALYZE_NODE_NAME => Some(NodeExtension {
76                expr: Arc::new(AnalyzeExpr { expr }),
77            }),
78            ANALYZE_VERBOSE_NODE_NAME => Some(NodeExtension {
79                expr: Arc::new(AnalyzeVerboseExpr { expr }),
80            }),
81            EXPLAIN_NODE_NAME => Some(NodeExtension {
82                expr: Arc::new(ExplainExpr { expr }),
83            }),
84            EXPLAIN_VERBOSE_NODE_NAME => Some(NodeExtension {
85                expr: Arc::new(ExplainVerboseExpr { expr }),
86            }),
87            _ => None,
88        }
89    }
90}
91
92#[derive(Debug, Clone, PartialEq, Eq)]
93pub struct PromQuery {
94    pub query: String,
95    pub start: String,
96    pub end: String,
97    pub step: String,
98    pub lookback: String,
99    pub alias: Option<String>,
100}
101
102impl Default for PromQuery {
103    fn default() -> Self {
104        PromQuery {
105            query: String::new(),
106            start: String::from("0"),
107            end: String::from("0"),
108            step: String::from("5m"),
109            lookback: String::from(DEFAULT_LOOKBACK_STRING),
110            alias: None,
111        }
112    }
113}
114
115/// Query language parser, supports parsing SQL and PromQL
116pub struct QueryLanguageParser {}
117
118impl QueryLanguageParser {
119    /// Try to parse SQL with GreptimeDB dialect, return the statement when success.
120    pub fn parse_sql(sql: &str, query_ctx: &QueryContextRef) -> Result<QueryStatement> {
121        let _timer = PARSE_SQL_ELAPSED.start_timer();
122        let scheduled_time =
123            crate::options::parse_scheduled_time_datetime(&query_ctx.extensions())?;
124        let mut statement = ParserContext::create_with_dialect(
125            sql,
126            &GreptimeDbDialect {},
127            ParseOptions { scheduled_time },
128        )
129        .map_err(BoxedError::new)
130        .context(QueryParseSnafu { query: sql })?;
131        if statement.len() != 1 {
132            MultipleStatementsSnafu {
133                query: sql.to_string(),
134            }
135            .fail()
136        } else {
137            Ok(QueryStatement::Sql(statement.pop().unwrap()))
138        }
139    }
140
141    /// Try to parse PromQL, return the statement when success.
142    #[tracing::instrument(skip_all)]
143    pub fn parse_promql(query: &PromQuery, _query_ctx: &QueryContextRef) -> Result<QueryStatement> {
144        let _timer = PARSE_PROMQL_ELAPSED.start_timer();
145
146        let expr = promql_parser::parser::parse(&query.query)
147            .map_err(|msg| BoxedError::new(PlainError::new(msg, StatusCode::InvalidArguments)))
148            .context(QueryParseSnafu {
149                query: &query.query,
150            })?;
151
152        let start = Self::parse_promql_timestamp(&query.start)
153            .map_err(BoxedError::new)
154            .context(QueryParseSnafu {
155                query: &query.query,
156            })?;
157
158        let end = Self::parse_promql_timestamp(&query.end)
159            .map_err(BoxedError::new)
160            .context(QueryParseSnafu {
161                query: &query.query,
162            })?;
163
164        let step = query
165            .step
166            .parse::<u64>()
167            .map(Duration::from_secs)
168            .or_else(|_| promql_parser::util::parse_duration(&query.step))
169            .map_err(|msg| BoxedError::new(PlainError::new(msg, StatusCode::InvalidArguments)))
170            .context(QueryParseSnafu {
171                query: &query.query,
172            })?;
173
174        let lookback_delta = query
175            .lookback
176            .parse::<u64>()
177            .map(Duration::from_secs)
178            .or_else(|_| promql_parser::util::parse_duration(&query.lookback))
179            .map_err(|msg| BoxedError::new(PlainError::new(msg, StatusCode::InvalidArguments)))
180            .context(QueryParseSnafu {
181                query: &query.query,
182            })?;
183
184        let eval_stmt = EvalStmt {
185            expr,
186            start,
187            end,
188            interval: step,
189            lookback_delta,
190        };
191        if let Some(alias) = &query.alias {
192            let eval_stmt = Self::apply_alias_extension(eval_stmt, alias);
193            return Ok(QueryStatement::Promql(eval_stmt, query.alias.clone()));
194        }
195        Ok(QueryStatement::Promql(eval_stmt, None))
196    }
197
198    pub(crate) fn apply_alias_extension(mut eval_stmt: EvalStmt, alias: &str) -> EvalStmt {
199        let expr = eval_stmt.expr;
200        eval_stmt.expr = Extension(NodeExtension {
201            expr: Arc::new(AliasExpr {
202                expr,
203                alias: alias.to_string(),
204            }),
205        });
206        eval_stmt
207    }
208
209    pub fn parse_promql_timestamp(timestamp: &str) -> Result<SystemTime> {
210        // try rfc3339 format
211        let rfc3339_result = DateTime::parse_from_rfc3339(timestamp)
212            .context(ParseTimestampSnafu { raw: timestamp })
213            .map(Into::<SystemTime>::into);
214
215        // shorthand
216        if rfc3339_result.is_ok() {
217            return rfc3339_result;
218        }
219
220        // try float format
221        let secs = timestamp
222            .parse::<f64>()
223            .context(ParseFloatSnafu { raw: timestamp })
224            // also report rfc3339 error if float parsing fails
225            .map_err(|_| rfc3339_result.unwrap_err())?;
226
227        // Prometheus accepts timestamps before the Unix epoch. Follow the arithmetic of its
228        // `parseTime` and `timestamp.FromTime` step by step: the float fraction is rounded to
229        // milliseconds before any conversion to nanoseconds, which decides boundary values
230        // like 1.0005, whose fraction is just below 0.0005.
231        let magnitude = Duration::try_from_secs_f64(secs.abs())
232            .context(TryIntoDurationSnafu { raw: timestamp })?;
233        let whole = secs.trunc();
234        let fraction = ((secs - whole) * 1000.0).round() / 1000.0;
235        let nanos = whole as i128 * 1_000_000_000 + (fraction * 1e9) as i128;
236        let millis = nanos.div_euclid(1_000_000);
237        let duration = u64::try_from(millis.unsigned_abs())
238            .ok()
239            .map(Duration::from_millis)
240            .context(AddSystemTimeOverflowSnafu {
241                duration: magnitude,
242            })?;
243        if millis < 0 {
244            SystemTime::UNIX_EPOCH
245                .checked_sub(duration)
246                .context(AddSystemTimeOverflowSnafu { duration })
247        } else {
248            SystemTime::UNIX_EPOCH
249                .checked_add(duration)
250                .context(AddSystemTimeOverflowSnafu { duration })
251        }
252    }
253}
254
255macro_rules! define_node_ast_extension {
256    ($name:ident, $name_expr:ident, $expr_type:ty, $extension_name:expr) => {
257        /// The implementation of the `$name_expr` extension AST node
258        #[derive(Debug, Clone)]
259        pub struct $name_expr {
260            pub expr: $expr_type,
261        }
262
263        impl ExtensionExpr for $name_expr {
264            fn as_any(&self) -> &dyn Any {
265                self
266            }
267
268            fn name(&self) -> &str {
269                $extension_name
270            }
271
272            fn value_type(&self) -> ValueType {
273                self.expr.value_type()
274            }
275
276            fn children(&self) -> &[Expr] {
277                std::slice::from_ref(&self.expr)
278            }
279
280            fn with_new_children(&self, children: Vec<Expr>) -> Arc<dyn ExtensionExpr> {
281                let mut iter = children.into_iter();
282                match (iter.next(), iter.next()) {
283                    (Some(expr), None) => Arc::new($name_expr { expr }),
284                    _ => Arc::new(self.clone()),
285                }
286            }
287        }
288
289        #[allow(rustdoc::broken_intra_doc_links)]
290        #[derive(Debug, Clone)]
291        pub struct $name {
292            pub expr: Arc<$name_expr>,
293        }
294
295        impl $name {
296            pub fn new(expr: $expr_type) -> Self {
297                Self {
298                    expr: Arc::new($name_expr { expr }),
299                }
300            }
301        }
302    };
303}
304
305define_node_ast_extension!(Analyze, AnalyzeExpr, Expr, ANALYZE_NODE_NAME);
306define_node_ast_extension!(
307    AnalyzeVerbose,
308    AnalyzeVerboseExpr,
309    Expr,
310    ANALYZE_VERBOSE_NODE_NAME
311);
312define_node_ast_extension!(Explain, ExplainExpr, Expr, EXPLAIN_NODE_NAME);
313define_node_ast_extension!(
314    ExplainVerbose,
315    ExplainVerboseExpr,
316    Expr,
317    EXPLAIN_VERBOSE_NODE_NAME
318);
319#[derive(Debug, Clone)]
320pub struct AliasExpr {
321    pub expr: Expr,
322    pub alias: String,
323}
324impl ExtensionExpr for AliasExpr {
325    fn as_any(&self) -> &dyn Any {
326        self
327    }
328    fn name(&self) -> &str {
329        ALIAS_NODE_NAME
330    }
331    fn value_type(&self) -> ValueType {
332        self.expr.value_type()
333    }
334    fn children(&self) -> &[Expr] {
335        std::slice::from_ref(&self.expr)
336    }
337    fn with_new_children(&self, children: Vec<Expr>) -> Arc<dyn ExtensionExpr> {
338        let mut iter = children.into_iter();
339        match (iter.next(), iter.next()) {
340            (Some(expr), None) => Arc::new(Self {
341                expr,
342                alias: self.alias.clone(),
343            }),
344            _ => Arc::new(self.clone()),
345        }
346    }
347}
348#[derive(Debug, Clone)]
349pub struct Alias {
350    pub expr: Arc<AliasExpr>,
351}
352impl Alias {
353    pub fn new(expr: Expr, alias: String) -> Self {
354        Self {
355            expr: Arc::new(AliasExpr { expr, alias }),
356        }
357    }
358}
359
360#[cfg(test)]
361mod test {
362    use session::context::{QueryContext, QueryContextBuilder};
363
364    use super::*;
365
366    // Detailed logic tests are covered in the parser crate.
367    #[test]
368    fn parse_sql_simple() {
369        let sql = "select * from t1";
370        let stmt = QueryLanguageParser::parse_sql(sql, &QueryContext::arc()).unwrap();
371        let QueryStatement::Sql(sql_stmt) = stmt else {
372            panic!("Expected SQL statement, got {:?}", stmt);
373        };
374        assert_eq!("SELECT * FROM t1", sql_stmt.to_string());
375    }
376
377    #[test]
378    fn parse_sql_tql_uses_scheduled_time_extension() {
379        let ctx = Arc::new(
380            QueryContextBuilder::default()
381                .set_extension(
382                    crate::options::FLOW_SCHEDULED_TIME_MILLIS.to_string(),
383                    "1700000000000".to_string(),
384                )
385                .build(),
386        );
387        let query = "TQL EVAL (now() - '10 minutes'::interval, now(), '1m') http_requests_total";
388        let stmt = QueryLanguageParser::parse_sql(query, &ctx).unwrap();
389
390        match stmt {
391            QueryStatement::Sql(sql::statements::statement::Statement::Tql(
392                sql::statements::tql::Tql::Eval(eval),
393            )) => {
394                assert_eq!(eval.start, "1699999400");
395                assert_eq!(eval.end, "1700000000");
396                assert_eq!(eval.step, "1m");
397                assert_eq!(eval.query, "http_requests_total");
398            }
399            _ => panic!("Expected TQL eval statement, got {stmt:?}"),
400        }
401    }
402
403    #[test]
404    fn parse_promql_timestamp_matches_prometheus_millis() {
405        // Expected values are Prometheus' `timestamp.FromTime(parseTime(input))`.
406        for (input, millis) in [
407            ("-30000.5", -30_000_500),
408            ("-0.001", -1),
409            ("-0.0006", -1),
410            ("-1.2346", -1235),
411            ("1.2346", 1235),
412            ("0.0004", 0),
413            ("1.0005", 1000),
414            ("-1.0005", -1000),
415            ("0.0004999999", 0),
416            ("1969-12-31T23:59:59.9999Z", -1),
417            ("1970-01-01T00:00:00.0009Z", 0),
418        ] {
419            let result = QueryLanguageParser::parse_promql_timestamp(input).unwrap();
420            assert_eq!(
421                crate::promql::label_values::signed_millis_since_epoch(result).unwrap(),
422                millis,
423                "{input}"
424            );
425        }
426    }
427
428    #[test]
429    fn parse_promql_timestamp() {
430        let cases = vec![
431            (
432                "1435781451.781",
433                SystemTime::UNIX_EPOCH
434                    .checked_add(Duration::from_secs_f64(1435781451.781))
435                    .unwrap(),
436            ),
437            ("0.000", SystemTime::UNIX_EPOCH),
438            ("00", SystemTime::UNIX_EPOCH),
439            (
440                "2015-07-01T20:10:51.781Z",
441                SystemTime::UNIX_EPOCH
442                    .checked_add(Duration::from_secs_f64(1435781451.781))
443                    .unwrap(),
444            ),
445            ("1970-01-01T00:00:00.000Z", SystemTime::UNIX_EPOCH),
446        ];
447
448        for (input, expected) in cases {
449            let result = QueryLanguageParser::parse_promql_timestamp(input).unwrap();
450
451            let result = result
452                .duration_since(SystemTime::UNIX_EPOCH)
453                .unwrap()
454                .as_millis();
455            let expected = expected
456                .duration_since(SystemTime::UNIX_EPOCH)
457                .unwrap()
458                .as_millis();
459
460            // assert difference < 0.1 second
461            assert!(result.abs_diff(expected) < 100);
462        }
463
464        // i64::MAX + 1
465        let timestamp = "9223372036854775808.000";
466        let result = QueryLanguageParser::parse_promql_timestamp(timestamp);
467        assert_eq!(
468            result.unwrap_err().to_string(),
469            "Failed to add duration '9223372036854775808s' to SystemTime, overflowed"
470        );
471    }
472
473    #[test]
474    fn parse_promql_simple() {
475        let promql = PromQuery {
476            query: "http_request".to_string(),
477            start: "2022-02-13T17:14:00Z".to_string(),
478            end: "2023-02-13T17:14:00Z".to_string(),
479            step: "1d".to_string(),
480            lookback: "5m".to_string(),
481            alias: Some("my_query".to_string()),
482        };
483
484        #[cfg(not(windows))]
485        let expected = String::from(
486            "\
487            Promql(EvalStmt { \
488                expr: Extension(Extension { \
489                    expr: AliasExpr { \
490                        expr: VectorSelector(VectorSelector { \
491                            name: Some(\"http_request\"), \
492                            matchers: Matchers { matchers: [], or_matchers: [] }, \
493                            offset: None, at: None \
494                        }), \
495                        alias: \"my_query\" \
496                    } \
497                }), \
498                start: SystemTime { tv_sec: 1644772440, tv_nsec: 0 }, \
499                end: SystemTime { tv_sec: 1676308440, tv_nsec: 0 }, \
500                interval: 86400s, \
501                lookback_delta: 300s \
502            }, Some(\"my_query\"))",
503        );
504
505        // Windows has different debug output for SystemTime.
506        #[cfg(windows)]
507        let expected = String::from(
508            "\
509            Promql(EvalStmt { \
510                expr: Extension(Extension { \
511                    expr: AliasExpr { \
512                        expr: VectorSelector(VectorSelector { \
513                            name: Some(\"http_request\"), \
514                            matchers: Matchers { matchers: [], or_matchers: [] }, \
515                            offset: None, at: None \
516                        }), \
517                        alias: \"my_query\" \
518                    } \
519                }), \
520                start: SystemTime { intervals: 132892460400000000 }, \
521                end: SystemTime { intervals: 133207820400000000 }, \
522                interval: 86400s, \
523                lookback_delta: 300s \
524            }, Some(\"my_query\"))",
525        );
526
527        let result = QueryLanguageParser::parse_promql(&promql, &QueryContext::arc()).unwrap();
528        assert_eq!(format!("{result:?}"), expected);
529    }
530}