mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-01-04 20:32:56 +00:00
fix(promql): handle field column projection with correct qualifier (#6183)
* fix(promql): handle field column projection with correct qualifier * test: add sqlness tests
This commit is contained in:
@@ -2722,12 +2722,26 @@ impl PromPlanner {
|
||||
right_time_index_column,
|
||||
))
|
||||
.alias(left_time_index_column.clone());
|
||||
// The field column in right side may not have qualifier (it may be removed by join operation),
|
||||
// so we need to find it from the schema.
|
||||
let right_qualifier_for_field = right
|
||||
.schema()
|
||||
.iter()
|
||||
.find(|(_, f)| f.name() == right_field_col)
|
||||
.map(|(q, _)| q)
|
||||
.context(ColumnNotFoundSnafu {
|
||||
col: right_field_col.to_string(),
|
||||
})?
|
||||
.cloned();
|
||||
// `skip(1)` to skip the time index column
|
||||
let right_proj_exprs_without_time_index = all_columns.iter().skip(1).map(|col| {
|
||||
// expr
|
||||
if col == left_field_col && left_field_col != right_field_col {
|
||||
// alias field in right side if necessary to handle different field name
|
||||
DfExpr::Column(Column::new(right_qualifier.clone(), right_field_col))
|
||||
DfExpr::Column(Column::new(
|
||||
right_qualifier_for_field.clone(),
|
||||
right_field_col,
|
||||
))
|
||||
} else if tags_not_in_right.contains(col) {
|
||||
DfExpr::Literal(ScalarValue::Utf8(None)).alias(col.to_string())
|
||||
} else {
|
||||
@@ -3767,6 +3781,100 @@ mod test {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_parse_or_operator() {
|
||||
let mut eval_stmt = EvalStmt {
|
||||
expr: PromExpr::NumberLiteral(NumberLiteral { val: 1.0 }),
|
||||
start: UNIX_EPOCH,
|
||||
end: UNIX_EPOCH
|
||||
.checked_add(Duration::from_secs(100_000))
|
||||
.unwrap(),
|
||||
interval: Duration::from_secs(5),
|
||||
lookback_delta: Duration::from_secs(1),
|
||||
};
|
||||
|
||||
let case = r#"
|
||||
sum(rate(sysstat{tenant_name=~"tenant1",cluster_name=~"cluster1"}[120s])) by (cluster_name,tenant_name) /
|
||||
(sum(sysstat{tenant_name=~"tenant1",cluster_name=~"cluster1"}) by (cluster_name,tenant_name) * 100)
|
||||
or
|
||||
200 * sum(sysstat{tenant_name=~"tenant1",cluster_name=~"cluster1"}) by (cluster_name,tenant_name) /
|
||||
sum(sysstat{tenant_name=~"tenant1",cluster_name=~"cluster1"}) by (cluster_name,tenant_name)"#;
|
||||
|
||||
let table_provider = build_test_table_provider_with_fields(
|
||||
&[(DEFAULT_SCHEMA_NAME.to_string(), "sysstat".to_string())],
|
||||
&["tenant_name", "cluster_name"],
|
||||
)
|
||||
.await;
|
||||
eval_stmt.expr = parser::parse(case).unwrap();
|
||||
let _ = PromPlanner::stmt_to_plan(table_provider, &eval_stmt, &build_session_state())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let case = r#"sum(delta(sysstat{tenant_name=~"sys",cluster_name=~"cluster1"}[2m])/120) by (cluster_name,tenant_name) /
|
||||
(sum(delta(sysstat{tenant_name=~"sys",cluster_name=~"cluster1"}[2m])/120) by (cluster_name,tenant_name) *1000) +
|
||||
sum(delta(sysstat{tenant_name=~"sys",cluster_name=~"cluster1"}[2m])/120) by (cluster_name,tenant_name) /
|
||||
(sum(delta(sysstat{tenant_name=~"sys",cluster_name=~"cluster1"}[2m])/120) by (cluster_name,tenant_name) *1000) >= 0
|
||||
or
|
||||
sum(delta(sysstat{tenant_name=~"sys",cluster_name=~"cluster1"}[2m])/120) by (cluster_name,tenant_name) /
|
||||
(sum(delta(sysstat{tenant_name=~"sys",cluster_name=~"cluster1"}[2m])/120) by (cluster_name,tenant_name) *1000) >= 0
|
||||
or
|
||||
sum(delta(sysstat{tenant_name=~"sys",cluster_name=~"cluster1"}[2m])/120) by (cluster_name,tenant_name) /
|
||||
(sum(delta(sysstat{tenant_name=~"sys",cluster_name=~"cluster1"}[2m])/120) by (cluster_name,tenant_name) *1000) >= 0"#;
|
||||
let table_provider = build_test_table_provider_with_fields(
|
||||
&[(DEFAULT_SCHEMA_NAME.to_string(), "sysstat".to_string())],
|
||||
&["tenant_name", "cluster_name"],
|
||||
)
|
||||
.await;
|
||||
eval_stmt.expr = parser::parse(case).unwrap();
|
||||
let _ = PromPlanner::stmt_to_plan(table_provider, &eval_stmt, &build_session_state())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let case = r#"(sum(background_waitevent_cnt{tenant_name=~"sys",cluster_name=~"cluster1"}) by (cluster_name,tenant_name) +
|
||||
sum(foreground_waitevent_cnt{tenant_name=~"sys",cluster_name=~"cluster1"}) by (cluster_name,tenant_name)) or
|
||||
(sum(background_waitevent_cnt{tenant_name=~"sys",cluster_name=~"cluster1"}) by (cluster_name,tenant_name)) or
|
||||
(sum(foreground_waitevent_cnt{tenant_name=~"sys",cluster_name=~"cluster1"}) by (cluster_name,tenant_name))"#;
|
||||
let table_provider = build_test_table_provider_with_fields(
|
||||
&[
|
||||
(
|
||||
DEFAULT_SCHEMA_NAME.to_string(),
|
||||
"background_waitevent_cnt".to_string(),
|
||||
),
|
||||
(
|
||||
DEFAULT_SCHEMA_NAME.to_string(),
|
||||
"foreground_waitevent_cnt".to_string(),
|
||||
),
|
||||
],
|
||||
&["tenant_name", "cluster_name"],
|
||||
)
|
||||
.await;
|
||||
eval_stmt.expr = parser::parse(case).unwrap();
|
||||
let _ = PromPlanner::stmt_to_plan(table_provider, &eval_stmt, &build_session_state())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let case = r#"avg(node_load1{cluster_name=~"cluster1"}) by (cluster_name,host_name) or max(container_cpu_load_average_10s{cluster_name=~"cluster1"}) by (cluster_name,host_name) * 100 / max(container_spec_cpu_quota{cluster_name=~"cluster1"}) by (cluster_name,host_name)"#;
|
||||
let table_provider = build_test_table_provider_with_fields(
|
||||
&[
|
||||
(DEFAULT_SCHEMA_NAME.to_string(), "node_load1".to_string()),
|
||||
(
|
||||
DEFAULT_SCHEMA_NAME.to_string(),
|
||||
"container_cpu_load_average_10s".to_string(),
|
||||
),
|
||||
(
|
||||
DEFAULT_SCHEMA_NAME.to_string(),
|
||||
"container_spec_cpu_quota".to_string(),
|
||||
),
|
||||
],
|
||||
&["cluster_name", "host_name"],
|
||||
)
|
||||
.await;
|
||||
eval_stmt.expr = parser::parse(case).unwrap();
|
||||
let _ = PromPlanner::stmt_to_plan(table_provider, &eval_stmt, &build_session_state())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn value_matcher() {
|
||||
// template
|
||||
|
||||
64
tests/cases/standalone/common/promql/or_operation.result
Normal file
64
tests/cases/standalone/common/promql/or_operation.result
Normal file
@@ -0,0 +1,64 @@
|
||||
create table http_requests (
|
||||
ts timestamp time index,
|
||||
job string,
|
||||
instance string,
|
||||
env string,
|
||||
greptime_value double,
|
||||
primary key (job, instance, env)
|
||||
);
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
insert into http_requests values
|
||||
(3000000, "api", "0", "production", 100),
|
||||
(3000000, "api", "0", "production", 200),
|
||||
(3000000, "api", "0", "canary", 300),
|
||||
(3000000, "api", "0", "canary", 400),
|
||||
(3000000, "app", "2", "production", 500),
|
||||
(3000000, "app", "2", "production", 600),
|
||||
(3000000, "app", "2", "canary", 700),
|
||||
(3000000, "app", "2", "canary", 800);
|
||||
|
||||
Affected Rows: 8
|
||||
|
||||
tql eval (3000, 3000, '1s') http_requests{job="api",instance="0",env="production"} + 5;
|
||||
|
||||
+-----+----------+------------+---------------------+-----------------------------+
|
||||
| job | instance | env | ts | greptime_value + Float64(5) |
|
||||
+-----+----------+------------+---------------------+-----------------------------+
|
||||
| api | 0 | production | 1970-01-01T00:50:00 | 205.0 |
|
||||
+-----+----------+------------+---------------------+-----------------------------+
|
||||
|
||||
tql eval (3000, 3000, '1s') http_requests{job="web",instance="1",env="production"} * 5;
|
||||
|
||||
++
|
||||
++
|
||||
|
||||
tql eval (3000, 3000, '1s') http_requests{job="web",instance="1",env="production"} * 5 or http_requests{job="api",instance="0",env="production"} + 5;
|
||||
|
||||
+---------------------+------------+-----------------------------+----------+-----+
|
||||
| ts | env | greptime_value * Float64(5) | instance | job |
|
||||
+---------------------+------------+-----------------------------+----------+-----+
|
||||
| 1970-01-01T00:50:00 | production | 205.0 | 0 | api |
|
||||
+---------------------+------------+-----------------------------+----------+-----+
|
||||
|
||||
tql eval (3000, 3000, '1s') http_requests{job="api",instance="0",env="production"} + 5 or http_requests{job="web",instance="1",env="production"} * 5;
|
||||
|
||||
+---------------------+------------+-----------------------------+----------+-----+
|
||||
| ts | env | greptime_value + Float64(5) | instance | job |
|
||||
+---------------------+------------+-----------------------------+----------+-----+
|
||||
| 1970-01-01T00:50:00 | production | 205.0 | 0 | api |
|
||||
+---------------------+------------+-----------------------------+----------+-----+
|
||||
|
||||
tql eval (3000, 3000, '1s') http_requests{job="web",instance="1",env="production"} * 5 or http_requests{job="web",instance="2",env="production"} * 3 or http_requests{job="api",instance="0",env="production"} + 5;
|
||||
|
||||
+---------------------+------------+-----------------------------+----------+-----+
|
||||
| ts | env | greptime_value * Float64(5) | instance | job |
|
||||
+---------------------+------------+-----------------------------+----------+-----+
|
||||
| 1970-01-01T00:50:00 | production | 205.0 | 0 | api |
|
||||
+---------------------+------------+-----------------------------+----------+-----+
|
||||
|
||||
drop table http_requests;
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
30
tests/cases/standalone/common/promql/or_operation.sql
Normal file
30
tests/cases/standalone/common/promql/or_operation.sql
Normal file
@@ -0,0 +1,30 @@
|
||||
create table http_requests (
|
||||
ts timestamp time index,
|
||||
job string,
|
||||
instance string,
|
||||
env string,
|
||||
greptime_value double,
|
||||
primary key (job, instance, env)
|
||||
);
|
||||
|
||||
insert into http_requests values
|
||||
(3000000, "api", "0", "production", 100),
|
||||
(3000000, "api", "0", "production", 200),
|
||||
(3000000, "api", "0", "canary", 300),
|
||||
(3000000, "api", "0", "canary", 400),
|
||||
(3000000, "app", "2", "production", 500),
|
||||
(3000000, "app", "2", "production", 600),
|
||||
(3000000, "app", "2", "canary", 700),
|
||||
(3000000, "app", "2", "canary", 800);
|
||||
|
||||
tql eval (3000, 3000, '1s') http_requests{job="api",instance="0",env="production"} + 5;
|
||||
|
||||
tql eval (3000, 3000, '1s') http_requests{job="web",instance="1",env="production"} * 5;
|
||||
|
||||
tql eval (3000, 3000, '1s') http_requests{job="web",instance="1",env="production"} * 5 or http_requests{job="api",instance="0",env="production"} + 5;
|
||||
|
||||
tql eval (3000, 3000, '1s') http_requests{job="api",instance="0",env="production"} + 5 or http_requests{job="web",instance="1",env="production"} * 5;
|
||||
|
||||
tql eval (3000, 3000, '1s') http_requests{job="web",instance="1",env="production"} * 5 or http_requests{job="web",instance="2",env="production"} * 3 or http_requests{job="api",instance="0",env="production"} + 5;
|
||||
|
||||
drop table http_requests;
|
||||
Reference in New Issue
Block a user