Files
greptimedb/tests/cases/standalone/common/promql/functions.result
dennis zhuang f3a0841f4f fix(promql): follow IEEE 754 float semantics in comparisons and aggregations (#9479)
* fix(promql): follow IEEE 754 float semantics in operators and aggregations

- Comparisons: Arrow orders floats totally (NaN == NaN, NaN > +Inf); PromQL
  comparisons with NaN are false except !=.
- min/max: skip NaN unless the whole group is NaN. DataFusion's grouped
  min/max let NaN replace and be replaced by neighbours, so the result
  depended on input order.
- topk/bottomk rank NaN last.
- round() rounds ties up and returns NaN for a zero step, like Prometheus.
- sqrt() of a negative number is NaN instead of an error.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix(promql): round() without a step rounds to integers

The planner passed a zero step for single-argument round(), which now
yields NaN like Prometheus; pass 1 instead. Found by the compatibility harness.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix(promql): apply the sqrt guard to builtin functions and register min/max for plan decoding

sqrt resolves through the session's builtin functions, not the UDF branch.
Distributed plans are decoded with the serializer's session, which did not
know prom_min/prom_max.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* test(promql): cover NaN and rounding semantics

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix(promql): keep the nested count rewrite for PromQL min/max

count(min(x) by (l)) was rewritten by count_nest_aggr only for the builtin
min/max names. prom_min/prom_max return NULL for the same groups, so the
rewrite stays valid. Update plan snapshots for the IEEE comparison, sqrt,
topk and min/max changes.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix(promql): register prom_min/prom_max in the function registry

Distributed plans split an aggregation into state and merge steps only for
functions whose state function exists in FUNCTION_REGISTRY; prom_min and
prom_max lived in the promql crate, so min/max stopped being pushed down to
datanodes. Move them to common-function and register them before the state
functions are derived.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* test: update sqlness results for PromQL float semantics

Plans and column names now show prom_min/prom_max, the NaN guards of
comparisons and sqrt, and the NaN sort key of topk. round() results follow
Prometheus' formula. Distributed min/max keep the state/merge split.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix(promql): keep column names and NULLs in IEEE comparisons and sqrt

Rewriting comparisons as `a op b AND NOT (isnan(a) OR isnan(b))` changed
TQL output column names and turned NULL operands into true for `!=` and
false for the bool forms. Implement comparisons and sqrt as PromQL UDFs
that propagate NULL and report the column name of the expression they
replace; prom_min/prom_max report min/max column names the same way.

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* test: restore column names in sqlness results for PromQL float semantics

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* test(promql): share the prom_min/prom_max groups accumulator with tests

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* fix(promql): keep distinct names for prom_min/prom_max

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

---------

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>
2026-10-12 05:10:18 +00:00

181 lines
7.8 KiB
Plaintext

CREATE TABLE
prom_series (
ts TIMESTAMP TIME INDEX,
val DOUBLE,
host STRING PRIMARY KEY
);
Affected Rows: 0
INSERT INTO
prom_series (ts, val, host)
VALUES
(0, 0.0, 'p'),
(300, 10.0, 'p'),
(600, 20.0, 'p'),
(900, 30.0, 'p'),
(1200, 40.0, 'p'),
(1500, 0.0, 'p'),
(1800, 10.0, 'p'),
(2100, 20.0, 'p'),
(2400, 30.0, 'p'),
(2700, 40.0, 'p'),
(3000, 50.0, 'p');
Affected Rows: 11
-- predict_linear
-- SQLNESS SORT_RESULT 3 1
tql eval (3, 3, '1s') predict_linear(prom_series[3s], 0);
+---------------------+----------------------------------------------+------+
| ts | prom_predict_linear(ts_range,val,Float64(0)) | host |
+---------------------+----------------------------------------------+------+
| 1970-01-01T00:00:03 | 37.27272727272727 | p |
+---------------------+----------------------------------------------+------+
-- SQLNESS SORT_RESULT 3 1
tql eval (3, 3, '1s') predict_linear(prom_series[3s], 3);
+---------------------+----------------------------------------------+------+
| ts | prom_predict_linear(ts_range,val,Float64(3)) | host |
+---------------------+----------------------------------------------+------+
| 1970-01-01T00:00:03 | 64.54545454545455 | p |
+---------------------+----------------------------------------------+------+
-- SQLNESS SORT_RESULT 3 1
tql eval (3, 3, '1s') predict_linear(prom_series[3s], 40 + 2);
+---------------------+------------------------------------------------------------+------+
| ts | prom_predict_linear(ts_range,val,Float64(40) + Float64(2)) | host |
+---------------------+------------------------------------------------------------+------+
| 1970-01-01T00:00:03 | 419.090909090909 | p |
+---------------------+------------------------------------------------------------+------+
-- double_exponential_smoothing
-- SQLNESS SORT_RESULT 3 1
tql eval (10, 10, '1s') double_exponential_smoothing(prom_series[10s], 0.4 + 0.1, 0.1);
+---------------------+------------------------------------------------------------------------------------------+------+
| ts | prom_double_exponential_smoothing(ts_range,val,Float64(0.4) + Float64(0.1),Float64(0.1)) | host |
+---------------------+------------------------------------------------------------------------------------------+------+
| 1970-01-01T00:00:10 | 47.0806953125 | p |
+---------------------+------------------------------------------------------------------------------------------+------+
DROP TABLE prom_series;
Affected Rows: 0
CREATE TABLE
prom_series_q (
ts TIMESTAMP TIME INDEX,
val DOUBLE,
host STRING PRIMARY KEY
);
Affected Rows: 0
INSERT INTO
prom_series_q (ts, val, host)
VALUES
(1000, 123.45, 'q'),
(2000, 234.567, 'q'),
(3000, 345.678, 'q'),
(4000, 456.789, 'q');
Affected Rows: 4
-- quantile_over_time
-- SQLNESS SORT_RESULT 3 1
tql eval (4, 4, '1s') quantile_over_time(0.2 + 0.05, prom_series_q[4s]);
+---------------------+--------------------------------------------------------------------+------+
| ts | prom_quantile_over_time(ts_range,val,Float64(0.2) + Float64(0.05)) | host |
+---------------------+--------------------------------------------------------------------+------+
| 1970-01-01T00:00:04 | 206.78775000000002 | q |
+---------------------+--------------------------------------------------------------------+------+
-- SQLNESS SORT_RESULT 3 1
tql eval (4, 4, '1s') quantile_over_time(0.4 + 0.1, prom_series_q[4s]);
+---------------------+-------------------------------------------------------------------+------+
| ts | prom_quantile_over_time(ts_range,val,Float64(0.4) + Float64(0.1)) | host |
+---------------------+-------------------------------------------------------------------+------+
| 1970-01-01T00:00:04 | 290.1225 | q |
+---------------------+-------------------------------------------------------------------+------+
-- round
-- SQLNESS SORT_RESULT 3 1
tql eval (3, 3, '1s') round(prom_series_q);
+---------------------+----------------------------+------+
| ts | prom_round(val,Float64(1)) | host |
+---------------------+----------------------------+------+
| 1970-01-01T00:00:03 | 346.0 | q |
+---------------------+----------------------------+------+
-- SQLNESS SORT_RESULT 3 1
tql eval (1, 4, '1s') round(prom_series_q, 0.01);
+---------------------+-------------------------------+------+
| ts | prom_round(val,Float64(0.01)) | host |
+---------------------+-------------------------------+------+
| 1970-01-01T00:00:01 | 123.45 | q |
| 1970-01-01T00:00:02 | 234.57 | q |
| 1970-01-01T00:00:03 | 345.68 | q |
| 1970-01-01T00:00:04 | 456.79 | q |
+---------------------+-------------------------------+------+
-- SQLNESS SORT_RESULT 3 1
tql eval (1, 4, '1s') round(prom_series_q, 0.05 + 0.05);
+---------------------+-----------------------------------------------+------+
| ts | prom_round(val,Float64(0.05) + Float64(0.05)) | host |
+---------------------+-----------------------------------------------+------+
| 1970-01-01T00:00:01 | 123.5 | q |
| 1970-01-01T00:00:02 | 234.6 | q |
| 1970-01-01T00:00:03 | 345.7 | q |
| 1970-01-01T00:00:04 | 456.8 | q |
+---------------------+-----------------------------------------------+------+
-- SQLNESS SORT_RESULT 3 1
tql eval (1, 4, '1s') round(prom_series_q, 10.0);
+---------------------+-----------------------------+------+
| ts | prom_round(val,Float64(10)) | host |
+---------------------+-----------------------------+------+
| 1970-01-01T00:00:01 | 120.0 | q |
| 1970-01-01T00:00:02 | 230.0 | q |
| 1970-01-01T00:00:03 | 350.0 | q |
| 1970-01-01T00:00:04 | 460.0 | q |
+---------------------+-----------------------------+------+
-- SQLNESS SORT_RESULT 3 1
tql eval (1, 4, '1s') round(prom_series_q, 100.0 + 3.0);
+---------------------+-------------------------------------------+------+
| ts | prom_round(val,Float64(100) + Float64(3)) | host |
+---------------------+-------------------------------------------+------+
| 1970-01-01T00:00:01 | 103.00000000000001 | q |
| 1970-01-01T00:00:02 | 206.00000000000003 | q |
| 1970-01-01T00:00:03 | 309.0 | q |
| 1970-01-01T00:00:04 | 412.00000000000006 | q |
+---------------------+-------------------------------------------+------+
-- SQLNESS SORT_RESULT 3 1
tql eval (1, 4, '1s') round(prom_series_q, - 3.0 + 13.0);
+---------------------+-------------------------------------------+------+
| ts | prom_round(val,Float64(-3) + Float64(13)) | host |
+---------------------+-------------------------------------------+------+
| 1970-01-01T00:00:01 | 120.0 | q |
| 1970-01-01T00:00:02 | 230.0 | q |
| 1970-01-01T00:00:03 | 350.0 | q |
| 1970-01-01T00:00:04 | 460.0 | q |
+---------------------+-------------------------------------------+------+
DROP TABLE prom_series_q;
Affected Rows: 0