Files
greptimedb/tests/cases/standalone/common/promql/timestamp_fn.sql
T
dennis zhuang cedd078440 fix(promql): align timestamp(), label_join and label_replace with Prometheus semantics (#9385)
* fix(promql): align timestamp() and label_join with Prometheus semantics

- timestamp() over a selector reports the selected sample's timestamp, without adding the offset.
- timestamp() over any other expression reports the evaluation time instead of the input value.
- label_join that overwrites an existing label rejects duplicate label sets at runtime.

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

* fix(promql): align label_replace and label_join edge cases with Prometheus

- label_replace leaves non-matching series unchanged instead of copying the source value into the destination label.
- label_replace may overwrite an existing label; duplicate label sets are rejected at runtime like label_join.
- label_join with no source labels removes the destination label, and an empty source label name is rejected.
- Empty label values produced by these functions are NULL, the same as an absent label.

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

* fix(promql): join absent labels as empty strings in label_join

concat_ws skips NULL arguments together with their separator, so a label that is absent (NULL) dropped its separator, e.g. label_join(label_join(vector(1), "a", "", "missing"), "b", "-", "a", "a") lost b="-". Read every source label as coalesce(label, '') like label_replace does.

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

* fix(promql): skip rows without a sample in timestamp()

timestamp() replaced the input fields with the timestamp before the empty-value filter ran, so a row whose fields were all NULL got a timestamp, e.g. timestamp(-m) for a NULL sample. Filter such rows before the projection, for both the selector and the evaluation-time paths.

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

---------

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>
(cherry picked from commit 78a7b93292)
Signed-off-by: WenyXu <wenymedia@gmail.com>
2026-10-12 12:49:20 +00:00

91 lines
2.7 KiB
SQL

-- Test `timestamp()` function
-- timestamp() returns the timestamp of each sample as seconds since Unix epoch
create table timestamp_test (ts timestamp time index, val double);
insert into timestamp_test values
(0, 1.0),
(1000, 2.0),
(60000, 3.0),
(3600000, 4.0),
-- 2021-01-01 00:00:00
(1609459200000, 5.0),
-- 2021-01-01 00:01:00
(1609459260000, 6.0);
-- Test timestamp() with time series
tql eval (0, 3600, '30s') timestamp(timestamp_test);
-- Test timestamp() with specific time range
tql eval (0, 60, '30s') timestamp(timestamp_test);
tql eval (0, 60, '30s') -timestamp(timestamp_test);
-- Test timestamp() with 2021 data
tql eval (1609459200, 1609459260, '30s') timestamp(timestamp_test);
-- Test timestamp() with arithmetic operations
tql eval (0, 60, '30s') timestamp(timestamp_test) + 1;
-- Test timestamp() with boolean operations
tql eval (0, 60, '30s') timestamp(timestamp_test) > bool 30;
-- Test timestamp() with time functions
tql eval (0, 60, '30s') timestamp(timestamp_test) - time();
-- Test timestamp() with other functions
tql eval (0, 60, '30s') abs(timestamp(timestamp_test) - avg(timestamp(timestamp_test))) > 20;
-- Test Issue 6707
tql eval timestamp(demo_memory_usage_bytes * 1);
tql eval timestamp(-demo_memory_usage_bytes);
tql eval (0, 60, '30s') timestamp(timestamp_test) == 60;
-- timestamp() reports the timestamp of the selected sample, not the evaluation time
tql eval (60, 60, '1s') timestamp(timestamp_test offset 30s);
tql eval (60, 60, '1s') timestamp((timestamp_test offset 30s));
-- The result of a function is sampled at the evaluation time
tql eval (90, 90, '1s') timestamp(abs(timestamp_test));
-- A row whose fields are all NULL holds no sample and gets no timestamp; a row with any
-- non-NULL field does.
create table timestamp_null (ts timestamp time index, host string primary key, a double, b double);
insert into timestamp_null values
(0, 'none', NULL, NULL),
(0, 'only_a', 1.0, NULL),
(0, 'only_b', NULL, 2.0);
-- SQLNESS SORT_RESULT 3 1
tql eval (60, 60, '1s') timestamp(timestamp_null);
-- SQLNESS SORT_RESULT 3 1
tql eval (60, 60, '1s') timestamp(-timestamp_null);
-- SQLNESS SORT_RESULT 3 1
tql eval (60, 60, '1s') timestamp(abs(timestamp_null));
drop table timestamp_null;
-- Test timestamp() with multiple metrics
create table timestamp_test2 (ts timestamp time index, val double);
insert into timestamp_test2 values
(0, 10.0),
(1000, 20.0),
(60000, 30.0);
-- SQLNESS SORT_RESULT 3 1
tql eval (0, 60, '30s') timestamp(timestamp_test) + timestamp(timestamp_test2);
-- SQLNESS SORT_RESULT 3 1
tql eval (0, 60, '30s') timestamp(timestamp_test) == timestamp(timestamp_test2);
drop table timestamp_test;
drop table timestamp_test2;