test(promql): exercise LastRow hints and filtered results

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>
This commit is contained in:
discord9
2026-09-09 17:25:39 +08:00
parent c38bd8e547
commit 12b2cc5ad3
3 changed files with 98 additions and 3 deletions
@@ -408,6 +408,69 @@ DROP TABLE instant_last_nano;
Affected Rows: 0
-- A field selector chooses the val column; it does not filter val. PromQL must
-- apply the comparison after selecting the latest eligible sample, rather than
-- falling back to an older sample that satisfies the comparison.
CREATE TABLE instant_last_field_filter (
ts TIMESTAMP TIME INDEX,
val DOUBLE,
host STRING,
instance STRING,
PRIMARY KEY (host, instance)
) ENGINE=mito;
Affected Rows: 0
-- Keep the older matching sample in an SST and the latest non-matching sample
-- in the memtable. Both timestamps are eligible at 1s.
INSERT INTO instant_last_field_filter VALUES (900, 10, 'host-a', 'instance-a');
Affected Rows: 1
ADMIN FLUSH_TABLE('instant_last_field_filter');
+------------------------------------------------+
| ADMIN FLUSH_TABLE('instant_last_field_filter') |
+------------------------------------------------+
| 0 |
+------------------------------------------------+
INSERT INTO instant_last_field_filter VALUES (1000, 1, 'host-a', 'instance-a');
Affected Rows: 1
-- Expected: no rows. The selected latest value is 1, so it must not fall back
-- to the older value 10 merely because that value is greater than 5.
-- SQLNESS SORT_RESULT 3 1
TQL EVAL (1, 1, '1s') instant_last_field_filter{__field__="val"} > 5;
++
++
-- A value matcher filters the scan before selecting a sample: the older 10
-- remains eligible, unlike the post-selection comparison above.
TQL EVAL (1, 1, '1s') instant_last_field_filter{val="10.0"};
+---------------------+------+--------+------------+
| ts | val | host | instance |
+---------------------+------+--------+------------+
| 1970-01-01T00:00:01 | 10.0 | host-a | instance-a |
+---------------------+------+--------+------------+
-- SQL filters rows before aggregation, so the older matching value remains.
-- Expected value: 10.
SELECT last_value(val ORDER BY ts) FROM instant_last_field_filter WHERE val > 5;
+--------------------------------------------------------------------------------------------------+
| last_value(instant_last_field_filter.val) ORDER BY [instant_last_field_filter.ts ASC NULLS LAST] |
+--------------------------------------------------------------------------------------------------+
| 10.0 |
+--------------------------------------------------------------------------------------------------+
DROP TABLE instant_last_field_filter;
Affected Rows: 0
-- Range evaluation is a control: range functions need their complete windows,
-- not a single last row. At 10s and 20s, [11s] contains two samples.
CREATE TABLE instant_last_range_control (
@@ -192,6 +192,38 @@ DROP TABLE instant_last_sec;
DROP TABLE instant_last_micro;
DROP TABLE instant_last_nano;
-- A field selector chooses the val column; it does not filter val. PromQL must
-- apply the comparison after selecting the latest eligible sample, rather than
-- falling back to an older sample that satisfies the comparison.
CREATE TABLE instant_last_field_filter (
ts TIMESTAMP TIME INDEX,
val DOUBLE,
host STRING,
instance STRING,
PRIMARY KEY (host, instance)
) ENGINE=mito;
-- Keep the older matching sample in an SST and the latest non-matching sample
-- in the memtable. Both timestamps are eligible at 1s.
INSERT INTO instant_last_field_filter VALUES (900, 10, 'host-a', 'instance-a');
ADMIN FLUSH_TABLE('instant_last_field_filter');
INSERT INTO instant_last_field_filter VALUES (1000, 1, 'host-a', 'instance-a');
-- Expected: no rows. The selected latest value is 1, so it must not fall back
-- to the older value 10 merely because that value is greater than 5.
-- SQLNESS SORT_RESULT 3 1
TQL EVAL (1, 1, '1s') instant_last_field_filter{__field__="val"} > 5;
-- A value matcher filters the scan before selecting a sample: the older 10
-- remains eligible, unlike the post-selection comparison above.
TQL EVAL (1, 1, '1s') instant_last_field_filter{val="10.0"};
-- SQL filters rows before aggregation, so the older matching value remains.
-- Expected value: 10.
SELECT last_value(val ORDER BY ts) FROM instant_last_field_filter WHERE val > 5;
DROP TABLE instant_last_field_filter;
-- Range evaluation is a control: range functions need their complete windows,
-- not a single last row. At 10s and 20s, [11s] contains two samples.
CREATE TABLE instant_last_range_control (
@@ -1,7 +1,7 @@
# PromQL instant-selector latency regression coverage for #9034.
#
# Instant, range, and aggregate controls cover LastRow latency behavior. The
# candidate instant query may enable the existing LastRow selector; the range
# candidate instant query must exercise the existing LastRow selector; the range
# query must not. This is latency regression coverage only: optimizer and
# sqlness tests own plan and correctness coverage. Evaluation is 0.7s after the
# final generated sample (last timestamp = start + 1023 * 0.1s =
@@ -44,7 +44,7 @@ distribution = { kind = "deterministic_wave", min = 0.0, max = 1000.0 }
[[scenario.tables.columns]]
name = "ts"
type = "TIMESTAMP(9)"
type = "TIMESTAMP(3)"
semantic = "timestamp"
[scenario.layout]
@@ -58,7 +58,7 @@ step_nanos = 100000000
time_range_layout = "non_overlapping_per_sst"
series_layout = "timestamp_major"
# Candidate instant query may enable the existing LastRow selector.
# Candidate instant query must exercise the existing LastRow selector.
[[scenario.queries]]
name = "instant_selector_last_row_candidate"
kind = "tql"