diff --git a/src/query/src/promql/planner.rs b/src/query/src/promql/planner.rs index 49c6051454..51c836bd54 100644 --- a/src/query/src/promql/planner.rs +++ b/src/query/src/promql/planner.rs @@ -99,6 +99,7 @@ const FIELD_COLUMN_MATCHER: &str = "__field__"; /// Special modifier for cross schema query const SCHEMA_COLUMN_MATCHER: &str = "__schema__"; +const DB_COLUMN_MATCHER: &str = "__database__"; /// Threshold for scatter scan mode const MAX_SCATTER_POINTS: i64 = 400; @@ -724,7 +725,7 @@ impl PromPlanner { .field_column_matcher .get_or_insert_default() .push(matcher.clone()); - } else if matcher.name == SCHEMA_COLUMN_MATCHER { + } else if matcher.name == SCHEMA_COLUMN_MATCHER || matcher.name == DB_COLUMN_MATCHER { ensure!( matcher.op == MatchOp::Equal, UnsupportedMatcherOpSnafu { @@ -3323,6 +3324,13 @@ mod test { indie_query_plan_compare(query, expected).await; + let query = "some_alt_metric{__database__=\"greptime_private\"}"; + let expected = String::from( + "PromInstantManipulate: range=[0..100000000], lookback=[1000], interval=[5000], time index=[timestamp] [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n PromSeriesNormalize: offset=[0], time index=[timestamp], filter NaN: [false] [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n PromSeriesDivide: tags=[\"tag_0\"] [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n Sort: greptime_private.some_alt_metric.tag_0 DESC NULLS LAST, greptime_private.some_alt_metric.timestamp DESC NULLS LAST [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n Filter: greptime_private.some_alt_metric.timestamp >= TimestampMillisecond(-1000, None) AND greptime_private.some_alt_metric.timestamp <= TimestampMillisecond(100001000, None) [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n TableScan: greptime_private.some_alt_metric [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]" + ); + + indie_query_plan_compare(query, expected).await; + let query = "some_alt_metric{__schema__=\"greptime_private\"} / some_metric"; let expected = String::from("Projection: some_metric.tag_0, some_metric.timestamp, greptime_private.some_alt_metric.field_0 / some_metric.field_0 AS greptime_private.some_alt_metric.field_0 / some_metric.field_0 [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), greptime_private.some_alt_metric.field_0 / some_metric.field_0:Float64;N]\n Inner Join: greptime_private.some_alt_metric.tag_0 = some_metric.tag_0, greptime_private.some_alt_metric.timestamp = some_metric.timestamp [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N, tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n SubqueryAlias: greptime_private.some_alt_metric [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n PromInstantManipulate: range=[0..100000000], lookback=[1000], interval=[5000], time index=[timestamp] [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n PromSeriesNormalize: offset=[0], time index=[timestamp], filter NaN: [false] [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n PromSeriesDivide: tags=[\"tag_0\"] [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n Sort: greptime_private.some_alt_metric.tag_0 DESC NULLS LAST, greptime_private.some_alt_metric.timestamp DESC NULLS LAST [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n Filter: greptime_private.some_alt_metric.timestamp >= TimestampMillisecond(-1000, None) AND greptime_private.some_alt_metric.timestamp <= TimestampMillisecond(100001000, None) [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n TableScan: greptime_private.some_alt_metric [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n SubqueryAlias: some_metric [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n PromInstantManipulate: range=[0..100000000], lookback=[1000], interval=[5000], time index=[timestamp] [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n PromSeriesNormalize: offset=[0], time index=[timestamp], filter NaN: [false] [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n PromSeriesDivide: tags=[\"tag_0\"] [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n Sort: some_metric.tag_0 DESC NULLS LAST, some_metric.timestamp DESC NULLS LAST [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n Filter: some_metric.timestamp >= TimestampMillisecond(-1000, None) AND some_metric.timestamp <= TimestampMillisecond(100001000, None) [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n TableScan: some_metric [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]"); @@ -3334,6 +3342,8 @@ mod test { let queries = &[ "some_alt_metric{__schema__!=\"greptime_private\"}", "some_alt_metric{__schema__=~\"lalala\"}", + "some_alt_metric{__database__!=\"greptime_private\"}", + "some_alt_metric{__database__=~\"lalala\"}", ]; for query in queries { diff --git a/tests-integration/src/tests/promql_test.rs b/tests-integration/src/tests/promql_test.rs index 1352531119..4b8ac8a691 100644 --- a/tests-integration/src/tests/promql_test.rs +++ b/tests-integration/src/tests/promql_test.rs @@ -602,6 +602,33 @@ async fn cross_schema_query(instance: Arc) { check_unordered_output_stream(query_output, expected).await; + let query_output = promql_query( + ins.clone(), + r#"http_requests{__database__="greptime_private"}"#, + QueryContext::arc(), + start, + end, + interval, + lookback_delta, + ) + .await + .unwrap(); + + let expected = r#"+------------+----------+------------+-------+---------------------+ +| job | instance | group | value | ts | ++------------+----------+------------+-------+---------------------+ +| api-server | 0 | production | 100.0 | 1970-01-01T00:00:00 | +| api-server | 0 | canary | 300.0 | 1970-01-01T00:00:00 | +| api-server | 1 | production | 200.0 | 1970-01-01T00:00:00 | +| api-server | 1 | canary | 400.0 | 1970-01-01T00:00:00 | +| app-server | 0 | canary | 700.0 | 1970-01-01T00:00:00 | +| app-server | 0 | production | 500.0 | 1970-01-01T00:00:00 | +| app-server | 1 | canary | 800.0 | 1970-01-01T00:00:00 | +| app-server | 1 | production | 600.0 | 1970-01-01T00:00:00 | ++------------+----------+------------+-------+---------------------+"#; + + check_unordered_output_stream(query_output, expected).await; + let query_output = promql_query( ins.clone(), r#"http_requests"#, diff --git a/tests/cases/standalone/common/tql/basic.result b/tests/cases/standalone/common/tql/basic.result index 3015101a55..ca0c7c9252 100644 --- a/tests/cases/standalone/common/tql/basic.result +++ b/tests/cases/standalone/common/tql/basic.result @@ -49,6 +49,23 @@ TQL EVAL (0, 10, '5s') test{__schema__="greptime_private"}; Error: 4001(TableNotFound), Table not found: greptime.greptime_private.test +-- SQLNESS SORT_RESULT 2 1 +TQL EVAL (0, 10, '5s') test{__database__="public"}; + ++-----+---------------------+---+ +| i | j | k | ++-----+---------------------+---+ +| 1.0 | 1970-01-01T00:00:05 | b | +| 1.0 | 1970-01-01T00:00:10 | b | +| 2.0 | 1970-01-01T00:00:05 | a | +| 2.0 | 1970-01-01T00:00:10 | a | ++-----+---------------------+---+ + +-- SQLNESS SORT_RESULT 2 1 +TQL EVAL (0, 10, '5s') test{__database__="greptime_private"}; + +Error: 4001(TableNotFound), Table not found: greptime.greptime_private.test + -- SQLNESS SORT_RESULT 2 1 TQL EVAL (0, 10, '5s') {__name__="test", __field__="i"}; diff --git a/tests/cases/standalone/common/tql/basic.sql b/tests/cases/standalone/common/tql/basic.sql index afca586ed8..e31206f02b 100644 --- a/tests/cases/standalone/common/tql/basic.sql +++ b/tests/cases/standalone/common/tql/basic.sql @@ -16,6 +16,12 @@ TQL EVAL (0, 10, '5s') test{__schema__="public"}; -- SQLNESS SORT_RESULT 2 1 TQL EVAL (0, 10, '5s') test{__schema__="greptime_private"}; +-- SQLNESS SORT_RESULT 2 1 +TQL EVAL (0, 10, '5s') test{__database__="public"}; + +-- SQLNESS SORT_RESULT 2 1 +TQL EVAL (0, 10, '5s') test{__database__="greptime_private"}; + -- SQLNESS SORT_RESULT 2 1 TQL EVAL (0, 10, '5s') {__name__="test", __field__="i"};