1use 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 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
115pub struct QueryLanguageParser {}
117
118impl QueryLanguageParser {
119 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 #[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 let rfc3339_result = DateTime::parse_from_rfc3339(timestamp)
212 .context(ParseTimestampSnafu { raw: timestamp })
213 .map(Into::<SystemTime>::into);
214
215 if rfc3339_result.is_ok() {
217 return rfc3339_result;
218 }
219
220 let secs = timestamp
222 .parse::<f64>()
223 .context(ParseFloatSnafu { raw: timestamp })
224 .map_err(|_| rfc3339_result.unwrap_err())?;
226
227 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 #[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 #[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 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!(result.abs_diff(expected) < 100);
462 }
463
464 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 #[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}