diff --git a/.unreleased/PR_6491_now_between b/.unreleased/PR_6491_now_between new file mode 100644 index 00000000000..34ccac5061f --- /dev/null +++ b/.unreleased/PR_6491_now_between @@ -0,0 +1 @@ +Fixes: #6491 Enable now() plantime constification with BETWEEN diff --git a/sql/debug_build_utils.sql b/sql/debug_build_utils.sql index 30f3f3019be..ac31226d2bf 100644 --- a/sql/debug_build_utils.sql +++ b/sql/debug_build_utils.sql @@ -13,3 +13,6 @@ AS '@MODULE_PATHNAME@', 'ts_debug_point_release'; CREATE OR REPLACE FUNCTION debug_waitpoint_id(TEXT) RETURNS BIGINT LANGUAGE C VOLATILE STRICT AS '@MODULE_PATHNAME@', 'ts_debug_point_id'; + +CREATE OR REPLACE FUNCTION ts_now_mock() +RETURNS TIMESTAMPTZ AS '@MODULE_PATHNAME@', 'ts_now_mock' LANGUAGE C STABLE STRICT PARALLEL SAFE; diff --git a/src/planner/constify_now.c b/src/planner/constify_now.c index ce263d03bcd..1dfcb1f7afe 100644 --- a/src/planner/constify_now.c +++ b/src/planner/constify_now.c @@ -44,7 +44,7 @@ get_hypertable_dimension(Oid relid, int flags) return hyperspace_get_open_dimension(ht->space, 0); } -static bool +bool is_valid_now_func(Node *node) { if (IsA(node, FuncExpr) && castNode(FuncExpr, node)->funcid == F_NOW) @@ -249,17 +249,11 @@ ts_constify_now(PlannerInfo *root, List *rtable, Node *node) foreach (lc, be->args) { - if (IsA(lfirst(lc), OpExpr) && is_valid_now_expr(lfirst_node(OpExpr, lc), rtable)) - { - OpExpr *op = lfirst_node(OpExpr, lc); - additions = lappend(additions, constify_now_expr(root, op)); - } + additions = lappend(additions, ts_constify_now(root, rtable, (Node *) lfirst(lc))); } if (additions) - { - be->args = list_concat(be->args, additions); - } + be->args = additions; break; } diff --git a/src/planner/planner.c b/src/planner/planner.c index 1c84e8a40f1..c94132d1bc0 100644 --- a/src/planner/planner.c +++ b/src/planner/planner.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "compat/compat-msvc-exit.h" #include @@ -279,6 +280,47 @@ typedef struct PlannerInfo *root; } PreprocessQueryContext; +void +replace_now_mock_walker(PlannerInfo *root, Node *clause, Oid funcid) +{ + /* whenever we encounter a FuncExpr with now(), replace it with the supplied funcid */ + switch (nodeTag(clause)) + { + case T_FuncExpr: + { + if (is_valid_now_func(clause)) + { + FuncExpr *fe = castNode(FuncExpr, clause); + fe->funcid = funcid; + return; + } + break; + } + case T_OpExpr: + { + ListCell *lc; + OpExpr *oe = castNode(OpExpr, clause); + foreach (lc, oe->args) + { + replace_now_mock_walker(root, (Node *) lfirst(lc), funcid); + } + break; + } + case T_BoolExpr: + { + ListCell *lc; + BoolExpr *be = castNode(BoolExpr, clause); + foreach (lc, be->args) + { + replace_now_mock_walker(root, (Node *) lfirst(lc), funcid); + } + break; + } + default: + return; + } +} + /* * Preprocess the query tree, including, e.g., subqueries. * @@ -310,6 +352,20 @@ preprocess_query(Node *node, PreprocessQueryContext *context) { from->quals = ts_constify_now(context->root, context->current_query->rtable, from->quals); +#ifdef TS_DEBUG + /* + * only replace if GUC is also set. This is used for testing purposes only, + * so no need to change the output for other tests in DEBUG builds + */ + if (ts_current_timestamp_mock != NULL && strlen(ts_current_timestamp_mock) != 0) + { + Oid funcid_mock; + const char *funcname = "ts_now_mock()"; + funcid_mock = DatumGetObjectId( + DirectFunctionCall1(regprocedurein, CStringGetDatum(funcname))); + replace_now_mock_walker(context->root, from->quals, funcid_mock); + } +#endif } /* * We only amend space constraints for UPDATE/DELETE and SELECT FOR UPDATE diff --git a/src/time_utils.c b/src/time_utils.c index acf84fa6f69..9b7b0af646f 100644 --- a/src/time_utils.c +++ b/src/time_utils.c @@ -567,3 +567,24 @@ ts_get_mock_time_or_current_time(void) return res; } #endif + +TS_FUNCTION_INFO_V1(ts_now_mock); + +/* return mock time for testing */ +Datum +ts_now_mock(PG_FUNCTION_ARGS) +{ + Datum res; +#ifdef TS_DEBUG + if (ts_current_timestamp_mock != NULL && strlen(ts_current_timestamp_mock) != 0) + { + res = DirectFunctionCall3(timestamptz_in, + CStringGetDatum(ts_current_timestamp_mock), + 0, + Int32GetDatum(-1)); + return res; + } +#endif + res = TimestampTzGetDatum(GetCurrentTimestamp()); + return res; +} diff --git a/src/time_utils.h b/src/time_utils.h index 12dc291c0b0..98b971555e2 100644 --- a/src/time_utils.h +++ b/src/time_utils.h @@ -91,3 +91,5 @@ extern TSDLLEXPORT int64 ts_subtract_integer_from_now_saturating(Oid now_func, i #ifdef TS_DEBUG extern TSDLLEXPORT Datum ts_get_mock_time_or_current_time(void); #endif + +bool is_valid_now_func(Node *node); diff --git a/src/utils.h b/src/utils.h index 0c38d1f013d..9b3285a55c6 100644 --- a/src/utils.h +++ b/src/utils.h @@ -246,3 +246,5 @@ ts_get_relation_relid(char const *schema_name, char const *relation_name, bool r return InvalidOid; } } + +void replace_now_mock_walker(PlannerInfo *root, Node *clause, Oid funcid); diff --git a/tsl/test/shared/expected/constify_now-13.out b/tsl/test/shared/expected/constify_now-13.out index c95386da2b1..9e96b777752 100644 --- a/tsl/test/shared/expected/constify_now-13.out +++ b/tsl/test/shared/expected/constify_now-13.out @@ -27,61 +27,61 @@ INSERT INTO const_now SELECT '3000-01-01','3000-01-01',2,0.5; :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) :PREFIX SELECT FROM const_now WHERE time >= now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= now()) + Index Cond: ("time" >= ts_now_mock()) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() - '24h'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 24 hours'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 24 hours'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() + '10m'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() + '@ 10 mins'::interval)) + Index Cond: ("time" > (ts_now_mock() + '@ 10 mins'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time >= now() - '10m'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= (now() - '@ 10 mins'::interval)) + Index Cond: ("time" >= (ts_now_mock() - '@ 10 mins'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= (now() + '@ 10 mins'::interval)) + Index Cond: ("time" >= (ts_now_mock() + '@ 10 mins'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() - '2d'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 2 days'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 2 days'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() + '3d'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() + '@ 3 days'::interval)) + Index Cond: ("time" > (ts_now_mock() + '@ 3 days'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() - '1week'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 7 days'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 7 days'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() - '1month'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > CURRENT_TIMESTAMP; @@ -179,9 +179,9 @@ SET enable_indexscan TO false; :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Bitmap Heap Scan on _hyper_X_X_chunk - Recheck Cond: ("time" > now()) + Recheck Cond: ("time" > ts_now_mock()) -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (4 rows) RESET enable_indexscan; @@ -189,21 +189,21 @@ RESET enable_indexscan; :PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND device_id = 2; QUERY PLAN Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= (now() + '@ 10 mins'::interval)) + Index Cond: ("time" >= (ts_now_mock() + '@ 10 mins'::interval)) Filter: (device_id = 2) (3 rows) :PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND (device_id = 2 OR device_id = 3); QUERY PLAN Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= (now() + '@ 10 mins'::interval)) + Index Cond: ("time" >= (ts_now_mock() + '@ 10 mins'::interval)) Filter: ((device_id = 2) OR (device_id = 3)) (3 rows) :PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND time >= now() - '10m'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: (("time" >= (now() + '@ 10 mins'::interval)) AND ("time" >= (now() - '@ 10 mins'::interval))) + Index Cond: (("time" >= (ts_now_mock() + '@ 10 mins'::interval)) AND ("time" >= (ts_now_mock() - '@ 10 mins'::interval))) (2 rows) -- variants we don't optimize @@ -232,28 +232,28 @@ QUERY PLAN QUERY PLAN Append -> Bitmap Heap Scan on _hyper_X_X_chunk - Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval))) + Recheck Cond: (("time" > (ts_now_mock() - '@ 1 min'::interval)) OR ("time" > (ts_now_mock() + '@ 1 min'::interval))) -> BitmapOr -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > (now() - '@ 1 min'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 min'::interval)) -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > (now() + '@ 1 min'::interval)) + Index Cond: ("time" > (ts_now_mock() + '@ 1 min'::interval)) -> Bitmap Heap Scan on _hyper_X_X_chunk - Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval))) + Recheck Cond: (("time" > (ts_now_mock() - '@ 1 min'::interval)) OR ("time" > (ts_now_mock() + '@ 1 min'::interval))) -> BitmapOr -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > (now() - '@ 1 min'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 min'::interval)) -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > (now() + '@ 1 min'::interval)) + Index Cond: ("time" > (ts_now_mock() + '@ 1 min'::interval)) (15 rows) :PREFIX SELECT FROM const_now WHERE device_id = 2 OR (time > now() - '1m'::interval AND time > now() + '1m'::interval); QUERY PLAN Append -> Seq Scan on _hyper_X_X_chunk - Filter: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval)))) + Filter: ((device_id = 2) OR (("time" > (ts_now_mock() - '@ 1 min'::interval)) AND ("time" > (ts_now_mock() + '@ 1 min'::interval)))) -> Seq Scan on _hyper_X_X_chunk - Filter: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval)))) + Filter: ((device_id = 2) OR (("time" > (ts_now_mock() - '@ 1 min'::interval)) AND ("time" > (ts_now_mock() + '@ 1 min'::interval)))) (5 rows) -- CTE @@ -262,7 +262,7 @@ QUERY PLAN ) SELECT FROM q1; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) :PREFIX WITH q1 AS ( @@ -271,9 +271,9 @@ QUERY PLAN QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (5 rows) -- JOIN @@ -285,7 +285,7 @@ QUERY PLAN -> Seq Scan on _hyper_X_X_chunk m2_2 -> Materialize -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (7 rows) :PREFIX SELECT FROM const_now m1, const_now m2 WHERE m2.time > now(); @@ -296,17 +296,17 @@ QUERY PLAN -> Seq Scan on _hyper_X_X_chunk m1_2 -> Materialize -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (7 rows) :PREFIX SELECT FROM const_now m1, const_now m2 WHERE m1.time > now() AND m2.time > now(); QUERY PLAN Nested Loop -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Materialize -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (6 rows) -- only top-level constraints in WHERE clause are constified @@ -334,7 +334,7 @@ QUERY PLAN Index Cond: ("time" > now()) -> Materialize -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (9 rows) -- test UPDATE @@ -344,9 +344,9 @@ QUERY PLAN Update on const_now Update on _hyper_X_X_chunk const_now_1 -> Seq Scan on const_now - Filter: ("time" > now()) + Filter: ("time" > ts_now_mock()) -> Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk const_now_1 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (7 rows) -- test DELETE @@ -356,9 +356,9 @@ QUERY PLAN Delete on const_now Delete on _hyper_X_X_chunk const_now_1 -> Seq Scan on const_now - Filter: ("time" > now()) + Filter: ("time" > ts_now_mock()) -> Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk const_now_1 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (7 rows) -- test chunks actually get excluded @@ -367,7 +367,7 @@ SET timescaledb.current_timestamp_mock TO '2010-01-01'; :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) -- should exclude all but 1 chunk @@ -375,14 +375,14 @@ SET timescaledb.current_timestamp_mock TO '2000-01-14'; :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) -- should have one time filter false :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) -- no constification because it's not partitioning column @@ -390,9 +390,9 @@ QUERY PLAN QUERY PLAN Append -> Seq Scan on _hyper_X_X_chunk - Filter: (time2 > now()) + Filter: (time2 > ts_now_mock()) -> Seq Scan on _hyper_X_X_chunk - Filter: (time2 > now()) + Filter: (time2 > ts_now_mock()) (5 rows) DROP TABLE const_now; @@ -413,9 +413,9 @@ PREPARE p1 AS SELECT FROM prep_const_now WHERE time > now(); QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (5 rows) EXECUTE p1; @@ -427,14 +427,48 @@ SET timescaledb.current_timestamp_mock TO '3002-01-01'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (5 rows) +EXECUTE p1; +(1 row) + +-- same test with ChunkAppend enabled +set timescaledb.enable_chunk_append = on; +set timescaledb.enable_constraint_aware_append = on; +DEALLOCATE p1; +PREPARE p1 AS SELECT FROM prep_const_now WHERE time > now(); +set timescaledb.current_timestamp_mock TO '3001-01-01'; +:PREFIX EXECUTE p1; +QUERY PLAN + Custom Scan (ChunkAppend) on prep_const_now + Chunks excluded during startup: 0 + -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk + Index Cond: ("time" > ts_now_mock()) + -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk + Index Cond: ("time" > ts_now_mock()) +(6 rows) + EXECUTE p1; (2 rows) +SET timescaledb.current_timestamp_mock TO '3002-01-01'; +-- plan won't change cause the query didnt get replanned +:PREFIX EXECUTE p1; +QUERY PLAN + Custom Scan (ChunkAppend) on prep_const_now + Chunks excluded during startup: 1 + -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk + Index Cond: ("time" > ts_now_mock()) +(4 rows) + +EXECUTE p1; +(1 row) + +set timescaledb.enable_chunk_append = off; +set timescaledb.enable_constraint_aware_append = off; DROP TABLE prep_const_now; -- test outer var references dont trip up constify_now -- no optimization is done in this case @@ -449,7 +483,7 @@ QUERY PLAN -> Materialize -> Nested Loop Semi Join -> Index Scan using _hyper_X_X_chunk_metrics_tstz_time_idx on _hyper_X_X_chunk m2 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Materialize -> Seq Scan on _hyper_X_X_chunk m3 (8 rows) @@ -482,9 +516,9 @@ SET timescaledb.current_timestamp_mock TO '2022-03-28 0:45+0'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 day'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 day'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 day'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 day'::interval)) (5 rows) SET timescaledb.current_timestamp_mock TO '2022-03-28 1:15+0'; @@ -493,9 +527,9 @@ SET timescaledb.current_timestamp_mock TO '2022-03-28 1:15+0'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 day'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 day'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 day'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 day'::interval)) (5 rows) TRUNCATE const_now_dst; @@ -513,15 +547,15 @@ set timezone to 'utc+1'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) (11 rows) set timezone to 'utc-1'; @@ -530,15 +564,15 @@ set timezone to 'utc-1'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) (11 rows) DROP TABLE const_now_dst; @@ -586,11 +620,11 @@ QUERY PLAN -> Partial HashAggregate Group Key: _hyper_X_X_chunk."time", _hyper_X_X_chunk.device -> Index Scan Backward using _hyper_X_X_chunk_now_view_test_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 168 hours'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 168 hours'::interval)) -> Partial HashAggregate Group Key: _hyper_X_X_chunk."time", _hyper_X_X_chunk.device -> Index Scan Backward using _hyper_X_X_chunk_now_view_test_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 168 hours'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 168 hours'::interval)) (11 rows) DROP TABLE now_view_test CASCADE; @@ -606,3 +640,203 @@ WHERE subq_1.time > m1.time; ------+-----------+----+----+----+----+------+-----------+----+----+----+----+------ (0 rows) +CREATE TABLE logged_data ( + rawtag_id INTEGER, + timestamp TIMESTAMP WITH TIME ZONE NOT NULL, + value REAL, + site_id INTEGER +); +SELECT table_name FROM create_hypertable('logged_data', 'timestamp'); + table_name + logged_data +(1 row) + +INSERT INTO logged_data (rawtag_id, timestamp, value, site_id) +VALUES +(1, '2023-01-01'::timestamptz, 13, 1), +(1, '2023-01-07'::timestamptz, 13, 1), +(1, '2023-01-10'::timestamptz, 13, 1), +(1, '2023-01-15'::timestamptz, 13, 1), +(1, '2023-01-20'::timestamptz, 15, 1), +(2, '2023-01-01'::timestamptz, 90, 1), +(3, '2023-01-07'::timestamptz, 2, 1), +(4, '2023-01-10'::timestamptz, 13, 3), +(2, '2023-01-15'::timestamptz, 13, 4), +(5, '2023-01-20'::timestamptz, 13, 1); +-- four chunks, all of them should be excluded at plantime +SELECT COUNT(*) FROM show_chunks('logged_data'); + count + 4 +(1 row) + +SET timescaledb.current_timestamp_mock TO '2024-01-01 0:30:00+00'; +SET timescaledb.enable_chunk_append TO true; +SET timescaledb.enable_constraint_aware_append TO true; +-- for all the queries below, exclusion should be happening at plantime +EXPLAIN (ANALYZE, SUMMARY OFF, TIMING OFF) SELECT * FROM logged_data WHERE +timestamp BETWEEN now() - interval '1 day' AND now() +AND rawtag_id = 1 ORDER BY "timestamp" ASC; +QUERY PLAN + Sort (cost=0.01..0.02 rows=0 width=20) (actual rows=0 loops=1) + Sort Key: "timestamp" + Sort Method: quicksort + -> Result (cost=0.00..0.00 rows=0 width=0) (actual rows=0 loops=1) + One-Time Filter: false +(5 rows) + +EXPLAIN (ANALYZE, SUMMARY OFF, TIMING OFF) SELECT * FROM logged_data WHERE +timestamp <= now() AND timestamp >= now() - interval '1 day' +AND rawtag_id = 1 ORDER BY "timestamp" ASC; +QUERY PLAN + Sort (cost=0.01..0.02 rows=0 width=20) (actual rows=0 loops=1) + Sort Key: "timestamp" + Sort Method: quicksort + -> Result (cost=0.00..0.00 rows=0 width=0) (actual rows=0 loops=1) + One-Time Filter: false +(5 rows) + +EXPLAIN (ANALYZE, SUMMARY OFF, TIMING OFF) SELECT * FROM logged_data WHERE +timestamp <= now() AND timestamp >= now() - interval '1 day' +ORDER BY "timestamp" ASC; +QUERY PLAN + Sort (cost=0.01..0.02 rows=0 width=20) (actual rows=0 loops=1) + Sort Key: "timestamp" + Sort Method: quicksort + -> Result (cost=0.00..0.00 rows=0 width=0) (actual rows=0 loops=1) + One-Time Filter: false +(5 rows) + +-- mock_now() in the middle of the table +SET timescaledb.current_timestamp_mock TO '2023-01-11'; +PREPARE pbtw AS SELECT * FROM logged_data WHERE +timestamp BETWEEN now() - interval '5 day' AND now() AND rawtag_id = 1 +ORDER BY "timestamp" ASC; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Custom Scan (ChunkAppend) on logged_data (cost=0.16..22.08 rows=3 width=20) + Order: logged_data."timestamp" + Chunks excluded during startup: 2 + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(6 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+------------------------------+-------+--------- + 1 | Sat Jan 07 00:00:00 2023 UTC | 13 | 1 + 1 | Tue Jan 10 00:00:00 2023 UTC | 13 | 1 +(2 rows) + +-- now move mock_now() to the future +SET timescaledb.current_timestamp_mock TO '2023-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Custom Scan (ChunkAppend) on logged_data (cost=0.16..22.08 rows=3 width=20) + Order: logged_data."timestamp" + Chunks excluded during startup: 1 + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(9 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+------------------------------+-------+--------- + 1 | Fri Jan 20 00:00:00 2023 UTC | 15 | 1 +(1 row) + +-- much further into the future, no rows should be returned +SET timescaledb.current_timestamp_mock TO '2024-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Custom Scan (ChunkAppend) on logged_data (cost=0.16..22.08 rows=3 width=20) + Order: logged_data."timestamp" + Chunks excluded during startup: 3 +(3 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+-----------+-------+--------- +(0 rows) + +DEALLOCATE pbtw; +-- repeat without ChunkAppend +set timescaledb.enable_chunk_append = off; +set timescaledb.enable_constraint_aware_append = off; +SET timescaledb.current_timestamp_mock TO '2023-01-11'; +PREPARE pbtw AS SELECT * FROM logged_data WHERE +timestamp BETWEEN now() - interval '5 day' AND now() AND rawtag_id = 1 +ORDER BY "timestamp" ASC; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Merge Append (cost=0.50..22.14 rows=3 width=20) + Sort Key: _hyper_X_X_chunk."timestamp" + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(11 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+------------------------------+-------+--------- + 1 | Sat Jan 07 00:00:00 2023 UTC | 13 | 1 + 1 | Tue Jan 10 00:00:00 2023 UTC | 13 | 1 +(2 rows) + +-- now move mock_now() to the future +SET timescaledb.current_timestamp_mock TO '2023-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Merge Append (cost=0.50..22.14 rows=3 width=20) + Sort Key: _hyper_X_X_chunk."timestamp" + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(11 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+------------------------------+-------+--------- + 1 | Fri Jan 20 00:00:00 2023 UTC | 15 | 1 +(1 row) + +-- much further into the future, no rows should be returned +SET timescaledb.current_timestamp_mock TO '2024-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Merge Append (cost=0.50..22.14 rows=3 width=20) + Sort Key: _hyper_X_X_chunk."timestamp" + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(11 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+-----------+-------+--------- +(0 rows) + +DEALLOCATE pbtw; +DROP TABLE logged_data; diff --git a/tsl/test/shared/expected/constify_now-14.out b/tsl/test/shared/expected/constify_now-14.out index c529cf1e310..a6f69f95a38 100644 --- a/tsl/test/shared/expected/constify_now-14.out +++ b/tsl/test/shared/expected/constify_now-14.out @@ -27,61 +27,61 @@ INSERT INTO const_now SELECT '3000-01-01','3000-01-01',2,0.5; :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) :PREFIX SELECT FROM const_now WHERE time >= now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= now()) + Index Cond: ("time" >= ts_now_mock()) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() - '24h'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 24 hours'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 24 hours'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() + '10m'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() + '@ 10 mins'::interval)) + Index Cond: ("time" > (ts_now_mock() + '@ 10 mins'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time >= now() - '10m'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= (now() - '@ 10 mins'::interval)) + Index Cond: ("time" >= (ts_now_mock() - '@ 10 mins'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= (now() + '@ 10 mins'::interval)) + Index Cond: ("time" >= (ts_now_mock() + '@ 10 mins'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() - '2d'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 2 days'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 2 days'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() + '3d'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() + '@ 3 days'::interval)) + Index Cond: ("time" > (ts_now_mock() + '@ 3 days'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() - '1week'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 7 days'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 7 days'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() - '1month'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > CURRENT_TIMESTAMP; @@ -179,9 +179,9 @@ SET enable_indexscan TO false; :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Bitmap Heap Scan on _hyper_X_X_chunk - Recheck Cond: ("time" > now()) + Recheck Cond: ("time" > ts_now_mock()) -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (4 rows) RESET enable_indexscan; @@ -189,21 +189,21 @@ RESET enable_indexscan; :PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND device_id = 2; QUERY PLAN Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= (now() + '@ 10 mins'::interval)) + Index Cond: ("time" >= (ts_now_mock() + '@ 10 mins'::interval)) Filter: (device_id = 2) (3 rows) :PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND (device_id = 2 OR device_id = 3); QUERY PLAN Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= (now() + '@ 10 mins'::interval)) + Index Cond: ("time" >= (ts_now_mock() + '@ 10 mins'::interval)) Filter: ((device_id = 2) OR (device_id = 3)) (3 rows) :PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND time >= now() - '10m'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: (("time" >= (now() + '@ 10 mins'::interval)) AND ("time" >= (now() - '@ 10 mins'::interval))) + Index Cond: (("time" >= (ts_now_mock() + '@ 10 mins'::interval)) AND ("time" >= (ts_now_mock() - '@ 10 mins'::interval))) (2 rows) -- variants we don't optimize @@ -232,28 +232,28 @@ QUERY PLAN QUERY PLAN Append -> Bitmap Heap Scan on _hyper_X_X_chunk - Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval))) + Recheck Cond: (("time" > (ts_now_mock() - '@ 1 min'::interval)) OR ("time" > (ts_now_mock() + '@ 1 min'::interval))) -> BitmapOr -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > (now() - '@ 1 min'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 min'::interval)) -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > (now() + '@ 1 min'::interval)) + Index Cond: ("time" > (ts_now_mock() + '@ 1 min'::interval)) -> Bitmap Heap Scan on _hyper_X_X_chunk - Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval))) + Recheck Cond: (("time" > (ts_now_mock() - '@ 1 min'::interval)) OR ("time" > (ts_now_mock() + '@ 1 min'::interval))) -> BitmapOr -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > (now() - '@ 1 min'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 min'::interval)) -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > (now() + '@ 1 min'::interval)) + Index Cond: ("time" > (ts_now_mock() + '@ 1 min'::interval)) (15 rows) :PREFIX SELECT FROM const_now WHERE device_id = 2 OR (time > now() - '1m'::interval AND time > now() + '1m'::interval); QUERY PLAN Append -> Seq Scan on _hyper_X_X_chunk - Filter: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval)))) + Filter: ((device_id = 2) OR (("time" > (ts_now_mock() - '@ 1 min'::interval)) AND ("time" > (ts_now_mock() + '@ 1 min'::interval)))) -> Seq Scan on _hyper_X_X_chunk - Filter: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval)))) + Filter: ((device_id = 2) OR (("time" > (ts_now_mock() - '@ 1 min'::interval)) AND ("time" > (ts_now_mock() + '@ 1 min'::interval)))) (5 rows) -- CTE @@ -262,7 +262,7 @@ QUERY PLAN ) SELECT FROM q1; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) :PREFIX WITH q1 AS ( @@ -271,9 +271,9 @@ QUERY PLAN QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (5 rows) -- JOIN @@ -285,7 +285,7 @@ QUERY PLAN -> Seq Scan on _hyper_X_X_chunk m2_2 -> Materialize -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (7 rows) :PREFIX SELECT FROM const_now m1, const_now m2 WHERE m2.time > now(); @@ -296,17 +296,17 @@ QUERY PLAN -> Seq Scan on _hyper_X_X_chunk m1_2 -> Materialize -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (7 rows) :PREFIX SELECT FROM const_now m1, const_now m2 WHERE m1.time > now() AND m2.time > now(); QUERY PLAN Nested Loop -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Materialize -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (6 rows) -- only top-level constraints in WHERE clause are constified @@ -334,7 +334,7 @@ QUERY PLAN Index Cond: ("time" > now()) -> Materialize -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (9 rows) -- test UPDATE @@ -345,7 +345,7 @@ QUERY PLAN Update on _hyper_X_X_chunk const_now_1 -> Result -> Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk const_now_1 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (6 rows) -- test DELETE @@ -355,7 +355,7 @@ QUERY PLAN -> Delete on const_now Delete on _hyper_X_X_chunk const_now_1 -> Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk const_now_1 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (5 rows) -- test chunks actually get excluded @@ -364,7 +364,7 @@ SET timescaledb.current_timestamp_mock TO '2010-01-01'; :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) -- should exclude all but 1 chunk @@ -372,14 +372,14 @@ SET timescaledb.current_timestamp_mock TO '2000-01-14'; :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) -- should have one time filter false :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) -- no constification because it's not partitioning column @@ -387,9 +387,9 @@ QUERY PLAN QUERY PLAN Append -> Seq Scan on _hyper_X_X_chunk - Filter: (time2 > now()) + Filter: (time2 > ts_now_mock()) -> Seq Scan on _hyper_X_X_chunk - Filter: (time2 > now()) + Filter: (time2 > ts_now_mock()) (5 rows) DROP TABLE const_now; @@ -410,9 +410,9 @@ PREPARE p1 AS SELECT FROM prep_const_now WHERE time > now(); QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (5 rows) EXECUTE p1; @@ -424,14 +424,48 @@ SET timescaledb.current_timestamp_mock TO '3002-01-01'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (5 rows) +EXECUTE p1; +(1 row) + +-- same test with ChunkAppend enabled +set timescaledb.enable_chunk_append = on; +set timescaledb.enable_constraint_aware_append = on; +DEALLOCATE p1; +PREPARE p1 AS SELECT FROM prep_const_now WHERE time > now(); +set timescaledb.current_timestamp_mock TO '3001-01-01'; +:PREFIX EXECUTE p1; +QUERY PLAN + Custom Scan (ChunkAppend) on prep_const_now + Chunks excluded during startup: 0 + -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk + Index Cond: ("time" > ts_now_mock()) + -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk + Index Cond: ("time" > ts_now_mock()) +(6 rows) + EXECUTE p1; (2 rows) +SET timescaledb.current_timestamp_mock TO '3002-01-01'; +-- plan won't change cause the query didnt get replanned +:PREFIX EXECUTE p1; +QUERY PLAN + Custom Scan (ChunkAppend) on prep_const_now + Chunks excluded during startup: 1 + -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk + Index Cond: ("time" > ts_now_mock()) +(4 rows) + +EXECUTE p1; +(1 row) + +set timescaledb.enable_chunk_append = off; +set timescaledb.enable_constraint_aware_append = off; DROP TABLE prep_const_now; -- test outer var references dont trip up constify_now -- no optimization is done in this case @@ -446,7 +480,7 @@ QUERY PLAN -> Materialize -> Nested Loop Semi Join -> Index Scan using _hyper_X_X_chunk_metrics_tstz_time_idx on _hyper_X_X_chunk m2 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Materialize -> Seq Scan on _hyper_X_X_chunk m3 (8 rows) @@ -479,9 +513,9 @@ SET timescaledb.current_timestamp_mock TO '2022-03-28 0:45+0'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 day'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 day'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 day'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 day'::interval)) (5 rows) SET timescaledb.current_timestamp_mock TO '2022-03-28 1:15+0'; @@ -490,9 +524,9 @@ SET timescaledb.current_timestamp_mock TO '2022-03-28 1:15+0'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 day'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 day'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 day'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 day'::interval)) (5 rows) TRUNCATE const_now_dst; @@ -510,15 +544,15 @@ set timezone to 'utc+1'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) (11 rows) set timezone to 'utc-1'; @@ -527,15 +561,15 @@ set timezone to 'utc-1'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) (11 rows) DROP TABLE const_now_dst; @@ -583,11 +617,11 @@ QUERY PLAN -> Partial HashAggregate Group Key: _hyper_X_X_chunk."time", _hyper_X_X_chunk.device -> Index Scan Backward using _hyper_X_X_chunk_now_view_test_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 168 hours'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 168 hours'::interval)) -> Partial HashAggregate Group Key: _hyper_X_X_chunk."time", _hyper_X_X_chunk.device -> Index Scan Backward using _hyper_X_X_chunk_now_view_test_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 168 hours'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 168 hours'::interval)) (11 rows) DROP TABLE now_view_test CASCADE; @@ -603,3 +637,203 @@ WHERE subq_1.time > m1.time; ------+-----------+----+----+----+----+------+-----------+----+----+----+----+------ (0 rows) +CREATE TABLE logged_data ( + rawtag_id INTEGER, + timestamp TIMESTAMP WITH TIME ZONE NOT NULL, + value REAL, + site_id INTEGER +); +SELECT table_name FROM create_hypertable('logged_data', 'timestamp'); + table_name + logged_data +(1 row) + +INSERT INTO logged_data (rawtag_id, timestamp, value, site_id) +VALUES +(1, '2023-01-01'::timestamptz, 13, 1), +(1, '2023-01-07'::timestamptz, 13, 1), +(1, '2023-01-10'::timestamptz, 13, 1), +(1, '2023-01-15'::timestamptz, 13, 1), +(1, '2023-01-20'::timestamptz, 15, 1), +(2, '2023-01-01'::timestamptz, 90, 1), +(3, '2023-01-07'::timestamptz, 2, 1), +(4, '2023-01-10'::timestamptz, 13, 3), +(2, '2023-01-15'::timestamptz, 13, 4), +(5, '2023-01-20'::timestamptz, 13, 1); +-- four chunks, all of them should be excluded at plantime +SELECT COUNT(*) FROM show_chunks('logged_data'); + count + 4 +(1 row) + +SET timescaledb.current_timestamp_mock TO '2024-01-01 0:30:00+00'; +SET timescaledb.enable_chunk_append TO true; +SET timescaledb.enable_constraint_aware_append TO true; +-- for all the queries below, exclusion should be happening at plantime +EXPLAIN (ANALYZE, SUMMARY OFF, TIMING OFF) SELECT * FROM logged_data WHERE +timestamp BETWEEN now() - interval '1 day' AND now() +AND rawtag_id = 1 ORDER BY "timestamp" ASC; +QUERY PLAN + Sort (cost=0.01..0.02 rows=0 width=20) (actual rows=0 loops=1) + Sort Key: "timestamp" + Sort Method: quicksort + -> Result (cost=0.00..0.00 rows=0 width=0) (actual rows=0 loops=1) + One-Time Filter: false +(5 rows) + +EXPLAIN (ANALYZE, SUMMARY OFF, TIMING OFF) SELECT * FROM logged_data WHERE +timestamp <= now() AND timestamp >= now() - interval '1 day' +AND rawtag_id = 1 ORDER BY "timestamp" ASC; +QUERY PLAN + Sort (cost=0.01..0.02 rows=0 width=20) (actual rows=0 loops=1) + Sort Key: "timestamp" + Sort Method: quicksort + -> Result (cost=0.00..0.00 rows=0 width=0) (actual rows=0 loops=1) + One-Time Filter: false +(5 rows) + +EXPLAIN (ANALYZE, SUMMARY OFF, TIMING OFF) SELECT * FROM logged_data WHERE +timestamp <= now() AND timestamp >= now() - interval '1 day' +ORDER BY "timestamp" ASC; +QUERY PLAN + Sort (cost=0.01..0.02 rows=0 width=20) (actual rows=0 loops=1) + Sort Key: "timestamp" + Sort Method: quicksort + -> Result (cost=0.00..0.00 rows=0 width=0) (actual rows=0 loops=1) + One-Time Filter: false +(5 rows) + +-- mock_now() in the middle of the table +SET timescaledb.current_timestamp_mock TO '2023-01-11'; +PREPARE pbtw AS SELECT * FROM logged_data WHERE +timestamp BETWEEN now() - interval '5 day' AND now() AND rawtag_id = 1 +ORDER BY "timestamp" ASC; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Custom Scan (ChunkAppend) on logged_data (cost=0.16..22.08 rows=3 width=20) + Order: logged_data."timestamp" + Chunks excluded during startup: 2 + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(6 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+------------------------------+-------+--------- + 1 | Sat Jan 07 00:00:00 2023 UTC | 13 | 1 + 1 | Tue Jan 10 00:00:00 2023 UTC | 13 | 1 +(2 rows) + +-- now move mock_now() to the future +SET timescaledb.current_timestamp_mock TO '2023-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Custom Scan (ChunkAppend) on logged_data (cost=0.16..22.08 rows=3 width=20) + Order: logged_data."timestamp" + Chunks excluded during startup: 1 + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(9 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+------------------------------+-------+--------- + 1 | Fri Jan 20 00:00:00 2023 UTC | 15 | 1 +(1 row) + +-- much further into the future, no rows should be returned +SET timescaledb.current_timestamp_mock TO '2024-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Custom Scan (ChunkAppend) on logged_data (cost=0.16..22.08 rows=3 width=20) + Order: logged_data."timestamp" + Chunks excluded during startup: 3 +(3 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+-----------+-------+--------- +(0 rows) + +DEALLOCATE pbtw; +-- repeat without ChunkAppend +set timescaledb.enable_chunk_append = off; +set timescaledb.enable_constraint_aware_append = off; +SET timescaledb.current_timestamp_mock TO '2023-01-11'; +PREPARE pbtw AS SELECT * FROM logged_data WHERE +timestamp BETWEEN now() - interval '5 day' AND now() AND rawtag_id = 1 +ORDER BY "timestamp" ASC; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Merge Append (cost=0.50..22.14 rows=3 width=20) + Sort Key: _hyper_X_X_chunk."timestamp" + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(11 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+------------------------------+-------+--------- + 1 | Sat Jan 07 00:00:00 2023 UTC | 13 | 1 + 1 | Tue Jan 10 00:00:00 2023 UTC | 13 | 1 +(2 rows) + +-- now move mock_now() to the future +SET timescaledb.current_timestamp_mock TO '2023-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Merge Append (cost=0.50..22.14 rows=3 width=20) + Sort Key: _hyper_X_X_chunk."timestamp" + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(11 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+------------------------------+-------+--------- + 1 | Fri Jan 20 00:00:00 2023 UTC | 15 | 1 +(1 row) + +-- much further into the future, no rows should be returned +SET timescaledb.current_timestamp_mock TO '2024-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Merge Append (cost=0.50..22.14 rows=3 width=20) + Sort Key: _hyper_X_X_chunk."timestamp" + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(11 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+-----------+-------+--------- +(0 rows) + +DEALLOCATE pbtw; +DROP TABLE logged_data; diff --git a/tsl/test/shared/expected/constify_now-15.out b/tsl/test/shared/expected/constify_now-15.out index c529cf1e310..a6f69f95a38 100644 --- a/tsl/test/shared/expected/constify_now-15.out +++ b/tsl/test/shared/expected/constify_now-15.out @@ -27,61 +27,61 @@ INSERT INTO const_now SELECT '3000-01-01','3000-01-01',2,0.5; :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) :PREFIX SELECT FROM const_now WHERE time >= now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= now()) + Index Cond: ("time" >= ts_now_mock()) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() - '24h'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 24 hours'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 24 hours'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() + '10m'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() + '@ 10 mins'::interval)) + Index Cond: ("time" > (ts_now_mock() + '@ 10 mins'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time >= now() - '10m'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= (now() - '@ 10 mins'::interval)) + Index Cond: ("time" >= (ts_now_mock() - '@ 10 mins'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= (now() + '@ 10 mins'::interval)) + Index Cond: ("time" >= (ts_now_mock() + '@ 10 mins'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() - '2d'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 2 days'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 2 days'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() + '3d'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() + '@ 3 days'::interval)) + Index Cond: ("time" > (ts_now_mock() + '@ 3 days'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() - '1week'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 7 days'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 7 days'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() - '1month'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > CURRENT_TIMESTAMP; @@ -179,9 +179,9 @@ SET enable_indexscan TO false; :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Bitmap Heap Scan on _hyper_X_X_chunk - Recheck Cond: ("time" > now()) + Recheck Cond: ("time" > ts_now_mock()) -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (4 rows) RESET enable_indexscan; @@ -189,21 +189,21 @@ RESET enable_indexscan; :PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND device_id = 2; QUERY PLAN Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= (now() + '@ 10 mins'::interval)) + Index Cond: ("time" >= (ts_now_mock() + '@ 10 mins'::interval)) Filter: (device_id = 2) (3 rows) :PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND (device_id = 2 OR device_id = 3); QUERY PLAN Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= (now() + '@ 10 mins'::interval)) + Index Cond: ("time" >= (ts_now_mock() + '@ 10 mins'::interval)) Filter: ((device_id = 2) OR (device_id = 3)) (3 rows) :PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND time >= now() - '10m'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: (("time" >= (now() + '@ 10 mins'::interval)) AND ("time" >= (now() - '@ 10 mins'::interval))) + Index Cond: (("time" >= (ts_now_mock() + '@ 10 mins'::interval)) AND ("time" >= (ts_now_mock() - '@ 10 mins'::interval))) (2 rows) -- variants we don't optimize @@ -232,28 +232,28 @@ QUERY PLAN QUERY PLAN Append -> Bitmap Heap Scan on _hyper_X_X_chunk - Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval))) + Recheck Cond: (("time" > (ts_now_mock() - '@ 1 min'::interval)) OR ("time" > (ts_now_mock() + '@ 1 min'::interval))) -> BitmapOr -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > (now() - '@ 1 min'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 min'::interval)) -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > (now() + '@ 1 min'::interval)) + Index Cond: ("time" > (ts_now_mock() + '@ 1 min'::interval)) -> Bitmap Heap Scan on _hyper_X_X_chunk - Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval))) + Recheck Cond: (("time" > (ts_now_mock() - '@ 1 min'::interval)) OR ("time" > (ts_now_mock() + '@ 1 min'::interval))) -> BitmapOr -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > (now() - '@ 1 min'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 min'::interval)) -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > (now() + '@ 1 min'::interval)) + Index Cond: ("time" > (ts_now_mock() + '@ 1 min'::interval)) (15 rows) :PREFIX SELECT FROM const_now WHERE device_id = 2 OR (time > now() - '1m'::interval AND time > now() + '1m'::interval); QUERY PLAN Append -> Seq Scan on _hyper_X_X_chunk - Filter: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval)))) + Filter: ((device_id = 2) OR (("time" > (ts_now_mock() - '@ 1 min'::interval)) AND ("time" > (ts_now_mock() + '@ 1 min'::interval)))) -> Seq Scan on _hyper_X_X_chunk - Filter: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval)))) + Filter: ((device_id = 2) OR (("time" > (ts_now_mock() - '@ 1 min'::interval)) AND ("time" > (ts_now_mock() + '@ 1 min'::interval)))) (5 rows) -- CTE @@ -262,7 +262,7 @@ QUERY PLAN ) SELECT FROM q1; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) :PREFIX WITH q1 AS ( @@ -271,9 +271,9 @@ QUERY PLAN QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (5 rows) -- JOIN @@ -285,7 +285,7 @@ QUERY PLAN -> Seq Scan on _hyper_X_X_chunk m2_2 -> Materialize -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (7 rows) :PREFIX SELECT FROM const_now m1, const_now m2 WHERE m2.time > now(); @@ -296,17 +296,17 @@ QUERY PLAN -> Seq Scan on _hyper_X_X_chunk m1_2 -> Materialize -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (7 rows) :PREFIX SELECT FROM const_now m1, const_now m2 WHERE m1.time > now() AND m2.time > now(); QUERY PLAN Nested Loop -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Materialize -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (6 rows) -- only top-level constraints in WHERE clause are constified @@ -334,7 +334,7 @@ QUERY PLAN Index Cond: ("time" > now()) -> Materialize -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (9 rows) -- test UPDATE @@ -345,7 +345,7 @@ QUERY PLAN Update on _hyper_X_X_chunk const_now_1 -> Result -> Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk const_now_1 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (6 rows) -- test DELETE @@ -355,7 +355,7 @@ QUERY PLAN -> Delete on const_now Delete on _hyper_X_X_chunk const_now_1 -> Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk const_now_1 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (5 rows) -- test chunks actually get excluded @@ -364,7 +364,7 @@ SET timescaledb.current_timestamp_mock TO '2010-01-01'; :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) -- should exclude all but 1 chunk @@ -372,14 +372,14 @@ SET timescaledb.current_timestamp_mock TO '2000-01-14'; :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) -- should have one time filter false :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) -- no constification because it's not partitioning column @@ -387,9 +387,9 @@ QUERY PLAN QUERY PLAN Append -> Seq Scan on _hyper_X_X_chunk - Filter: (time2 > now()) + Filter: (time2 > ts_now_mock()) -> Seq Scan on _hyper_X_X_chunk - Filter: (time2 > now()) + Filter: (time2 > ts_now_mock()) (5 rows) DROP TABLE const_now; @@ -410,9 +410,9 @@ PREPARE p1 AS SELECT FROM prep_const_now WHERE time > now(); QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (5 rows) EXECUTE p1; @@ -424,14 +424,48 @@ SET timescaledb.current_timestamp_mock TO '3002-01-01'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (5 rows) +EXECUTE p1; +(1 row) + +-- same test with ChunkAppend enabled +set timescaledb.enable_chunk_append = on; +set timescaledb.enable_constraint_aware_append = on; +DEALLOCATE p1; +PREPARE p1 AS SELECT FROM prep_const_now WHERE time > now(); +set timescaledb.current_timestamp_mock TO '3001-01-01'; +:PREFIX EXECUTE p1; +QUERY PLAN + Custom Scan (ChunkAppend) on prep_const_now + Chunks excluded during startup: 0 + -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk + Index Cond: ("time" > ts_now_mock()) + -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk + Index Cond: ("time" > ts_now_mock()) +(6 rows) + EXECUTE p1; (2 rows) +SET timescaledb.current_timestamp_mock TO '3002-01-01'; +-- plan won't change cause the query didnt get replanned +:PREFIX EXECUTE p1; +QUERY PLAN + Custom Scan (ChunkAppend) on prep_const_now + Chunks excluded during startup: 1 + -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk + Index Cond: ("time" > ts_now_mock()) +(4 rows) + +EXECUTE p1; +(1 row) + +set timescaledb.enable_chunk_append = off; +set timescaledb.enable_constraint_aware_append = off; DROP TABLE prep_const_now; -- test outer var references dont trip up constify_now -- no optimization is done in this case @@ -446,7 +480,7 @@ QUERY PLAN -> Materialize -> Nested Loop Semi Join -> Index Scan using _hyper_X_X_chunk_metrics_tstz_time_idx on _hyper_X_X_chunk m2 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Materialize -> Seq Scan on _hyper_X_X_chunk m3 (8 rows) @@ -479,9 +513,9 @@ SET timescaledb.current_timestamp_mock TO '2022-03-28 0:45+0'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 day'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 day'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 day'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 day'::interval)) (5 rows) SET timescaledb.current_timestamp_mock TO '2022-03-28 1:15+0'; @@ -490,9 +524,9 @@ SET timescaledb.current_timestamp_mock TO '2022-03-28 1:15+0'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 day'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 day'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 day'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 day'::interval)) (5 rows) TRUNCATE const_now_dst; @@ -510,15 +544,15 @@ set timezone to 'utc+1'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) (11 rows) set timezone to 'utc-1'; @@ -527,15 +561,15 @@ set timezone to 'utc-1'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) (11 rows) DROP TABLE const_now_dst; @@ -583,11 +617,11 @@ QUERY PLAN -> Partial HashAggregate Group Key: _hyper_X_X_chunk."time", _hyper_X_X_chunk.device -> Index Scan Backward using _hyper_X_X_chunk_now_view_test_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 168 hours'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 168 hours'::interval)) -> Partial HashAggregate Group Key: _hyper_X_X_chunk."time", _hyper_X_X_chunk.device -> Index Scan Backward using _hyper_X_X_chunk_now_view_test_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 168 hours'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 168 hours'::interval)) (11 rows) DROP TABLE now_view_test CASCADE; @@ -603,3 +637,203 @@ WHERE subq_1.time > m1.time; ------+-----------+----+----+----+----+------+-----------+----+----+----+----+------ (0 rows) +CREATE TABLE logged_data ( + rawtag_id INTEGER, + timestamp TIMESTAMP WITH TIME ZONE NOT NULL, + value REAL, + site_id INTEGER +); +SELECT table_name FROM create_hypertable('logged_data', 'timestamp'); + table_name + logged_data +(1 row) + +INSERT INTO logged_data (rawtag_id, timestamp, value, site_id) +VALUES +(1, '2023-01-01'::timestamptz, 13, 1), +(1, '2023-01-07'::timestamptz, 13, 1), +(1, '2023-01-10'::timestamptz, 13, 1), +(1, '2023-01-15'::timestamptz, 13, 1), +(1, '2023-01-20'::timestamptz, 15, 1), +(2, '2023-01-01'::timestamptz, 90, 1), +(3, '2023-01-07'::timestamptz, 2, 1), +(4, '2023-01-10'::timestamptz, 13, 3), +(2, '2023-01-15'::timestamptz, 13, 4), +(5, '2023-01-20'::timestamptz, 13, 1); +-- four chunks, all of them should be excluded at plantime +SELECT COUNT(*) FROM show_chunks('logged_data'); + count + 4 +(1 row) + +SET timescaledb.current_timestamp_mock TO '2024-01-01 0:30:00+00'; +SET timescaledb.enable_chunk_append TO true; +SET timescaledb.enable_constraint_aware_append TO true; +-- for all the queries below, exclusion should be happening at plantime +EXPLAIN (ANALYZE, SUMMARY OFF, TIMING OFF) SELECT * FROM logged_data WHERE +timestamp BETWEEN now() - interval '1 day' AND now() +AND rawtag_id = 1 ORDER BY "timestamp" ASC; +QUERY PLAN + Sort (cost=0.01..0.02 rows=0 width=20) (actual rows=0 loops=1) + Sort Key: "timestamp" + Sort Method: quicksort + -> Result (cost=0.00..0.00 rows=0 width=0) (actual rows=0 loops=1) + One-Time Filter: false +(5 rows) + +EXPLAIN (ANALYZE, SUMMARY OFF, TIMING OFF) SELECT * FROM logged_data WHERE +timestamp <= now() AND timestamp >= now() - interval '1 day' +AND rawtag_id = 1 ORDER BY "timestamp" ASC; +QUERY PLAN + Sort (cost=0.01..0.02 rows=0 width=20) (actual rows=0 loops=1) + Sort Key: "timestamp" + Sort Method: quicksort + -> Result (cost=0.00..0.00 rows=0 width=0) (actual rows=0 loops=1) + One-Time Filter: false +(5 rows) + +EXPLAIN (ANALYZE, SUMMARY OFF, TIMING OFF) SELECT * FROM logged_data WHERE +timestamp <= now() AND timestamp >= now() - interval '1 day' +ORDER BY "timestamp" ASC; +QUERY PLAN + Sort (cost=0.01..0.02 rows=0 width=20) (actual rows=0 loops=1) + Sort Key: "timestamp" + Sort Method: quicksort + -> Result (cost=0.00..0.00 rows=0 width=0) (actual rows=0 loops=1) + One-Time Filter: false +(5 rows) + +-- mock_now() in the middle of the table +SET timescaledb.current_timestamp_mock TO '2023-01-11'; +PREPARE pbtw AS SELECT * FROM logged_data WHERE +timestamp BETWEEN now() - interval '5 day' AND now() AND rawtag_id = 1 +ORDER BY "timestamp" ASC; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Custom Scan (ChunkAppend) on logged_data (cost=0.16..22.08 rows=3 width=20) + Order: logged_data."timestamp" + Chunks excluded during startup: 2 + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(6 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+------------------------------+-------+--------- + 1 | Sat Jan 07 00:00:00 2023 UTC | 13 | 1 + 1 | Tue Jan 10 00:00:00 2023 UTC | 13 | 1 +(2 rows) + +-- now move mock_now() to the future +SET timescaledb.current_timestamp_mock TO '2023-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Custom Scan (ChunkAppend) on logged_data (cost=0.16..22.08 rows=3 width=20) + Order: logged_data."timestamp" + Chunks excluded during startup: 1 + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(9 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+------------------------------+-------+--------- + 1 | Fri Jan 20 00:00:00 2023 UTC | 15 | 1 +(1 row) + +-- much further into the future, no rows should be returned +SET timescaledb.current_timestamp_mock TO '2024-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Custom Scan (ChunkAppend) on logged_data (cost=0.16..22.08 rows=3 width=20) + Order: logged_data."timestamp" + Chunks excluded during startup: 3 +(3 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+-----------+-------+--------- +(0 rows) + +DEALLOCATE pbtw; +-- repeat without ChunkAppend +set timescaledb.enable_chunk_append = off; +set timescaledb.enable_constraint_aware_append = off; +SET timescaledb.current_timestamp_mock TO '2023-01-11'; +PREPARE pbtw AS SELECT * FROM logged_data WHERE +timestamp BETWEEN now() - interval '5 day' AND now() AND rawtag_id = 1 +ORDER BY "timestamp" ASC; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Merge Append (cost=0.50..22.14 rows=3 width=20) + Sort Key: _hyper_X_X_chunk."timestamp" + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(11 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+------------------------------+-------+--------- + 1 | Sat Jan 07 00:00:00 2023 UTC | 13 | 1 + 1 | Tue Jan 10 00:00:00 2023 UTC | 13 | 1 +(2 rows) + +-- now move mock_now() to the future +SET timescaledb.current_timestamp_mock TO '2023-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Merge Append (cost=0.50..22.14 rows=3 width=20) + Sort Key: _hyper_X_X_chunk."timestamp" + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(11 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+------------------------------+-------+--------- + 1 | Fri Jan 20 00:00:00 2023 UTC | 15 | 1 +(1 row) + +-- much further into the future, no rows should be returned +SET timescaledb.current_timestamp_mock TO '2024-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Merge Append (cost=0.50..22.14 rows=3 width=20) + Sort Key: _hyper_X_X_chunk."timestamp" + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(11 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+-----------+-------+--------- +(0 rows) + +DEALLOCATE pbtw; +DROP TABLE logged_data; diff --git a/tsl/test/shared/expected/constify_now-16.out b/tsl/test/shared/expected/constify_now-16.out index c529cf1e310..a6f69f95a38 100644 --- a/tsl/test/shared/expected/constify_now-16.out +++ b/tsl/test/shared/expected/constify_now-16.out @@ -27,61 +27,61 @@ INSERT INTO const_now SELECT '3000-01-01','3000-01-01',2,0.5; :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) :PREFIX SELECT FROM const_now WHERE time >= now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= now()) + Index Cond: ("time" >= ts_now_mock()) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() - '24h'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 24 hours'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 24 hours'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() + '10m'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() + '@ 10 mins'::interval)) + Index Cond: ("time" > (ts_now_mock() + '@ 10 mins'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time >= now() - '10m'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= (now() - '@ 10 mins'::interval)) + Index Cond: ("time" >= (ts_now_mock() - '@ 10 mins'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= (now() + '@ 10 mins'::interval)) + Index Cond: ("time" >= (ts_now_mock() + '@ 10 mins'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() - '2d'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 2 days'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 2 days'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() + '3d'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() + '@ 3 days'::interval)) + Index Cond: ("time" > (ts_now_mock() + '@ 3 days'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() - '1week'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 7 days'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 7 days'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > now() - '1month'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) (2 rows) :PREFIX SELECT FROM const_now WHERE time > CURRENT_TIMESTAMP; @@ -179,9 +179,9 @@ SET enable_indexscan TO false; :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Bitmap Heap Scan on _hyper_X_X_chunk - Recheck Cond: ("time" > now()) + Recheck Cond: ("time" > ts_now_mock()) -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (4 rows) RESET enable_indexscan; @@ -189,21 +189,21 @@ RESET enable_indexscan; :PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND device_id = 2; QUERY PLAN Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= (now() + '@ 10 mins'::interval)) + Index Cond: ("time" >= (ts_now_mock() + '@ 10 mins'::interval)) Filter: (device_id = 2) (3 rows) :PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND (device_id = 2 OR device_id = 3); QUERY PLAN Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" >= (now() + '@ 10 mins'::interval)) + Index Cond: ("time" >= (ts_now_mock() + '@ 10 mins'::interval)) Filter: ((device_id = 2) OR (device_id = 3)) (3 rows) :PREFIX SELECT FROM const_now WHERE time >= now() + '10m'::interval AND time >= now() - '10m'::interval; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: (("time" >= (now() + '@ 10 mins'::interval)) AND ("time" >= (now() - '@ 10 mins'::interval))) + Index Cond: (("time" >= (ts_now_mock() + '@ 10 mins'::interval)) AND ("time" >= (ts_now_mock() - '@ 10 mins'::interval))) (2 rows) -- variants we don't optimize @@ -232,28 +232,28 @@ QUERY PLAN QUERY PLAN Append -> Bitmap Heap Scan on _hyper_X_X_chunk - Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval))) + Recheck Cond: (("time" > (ts_now_mock() - '@ 1 min'::interval)) OR ("time" > (ts_now_mock() + '@ 1 min'::interval))) -> BitmapOr -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > (now() - '@ 1 min'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 min'::interval)) -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > (now() + '@ 1 min'::interval)) + Index Cond: ("time" > (ts_now_mock() + '@ 1 min'::interval)) -> Bitmap Heap Scan on _hyper_X_X_chunk - Recheck Cond: (("time" > (now() - '@ 1 min'::interval)) OR ("time" > (now() + '@ 1 min'::interval))) + Recheck Cond: (("time" > (ts_now_mock() - '@ 1 min'::interval)) OR ("time" > (ts_now_mock() + '@ 1 min'::interval))) -> BitmapOr -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > (now() - '@ 1 min'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 min'::interval)) -> Bitmap Index Scan on _hyper_X_X_chunk_const_now_time_idx - Index Cond: ("time" > (now() + '@ 1 min'::interval)) + Index Cond: ("time" > (ts_now_mock() + '@ 1 min'::interval)) (15 rows) :PREFIX SELECT FROM const_now WHERE device_id = 2 OR (time > now() - '1m'::interval AND time > now() + '1m'::interval); QUERY PLAN Append -> Seq Scan on _hyper_X_X_chunk - Filter: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval)))) + Filter: ((device_id = 2) OR (("time" > (ts_now_mock() - '@ 1 min'::interval)) AND ("time" > (ts_now_mock() + '@ 1 min'::interval)))) -> Seq Scan on _hyper_X_X_chunk - Filter: ((device_id = 2) OR (("time" > (now() - '@ 1 min'::interval)) AND ("time" > (now() + '@ 1 min'::interval)))) + Filter: ((device_id = 2) OR (("time" > (ts_now_mock() - '@ 1 min'::interval)) AND ("time" > (ts_now_mock() + '@ 1 min'::interval)))) (5 rows) -- CTE @@ -262,7 +262,7 @@ QUERY PLAN ) SELECT FROM q1; QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) :PREFIX WITH q1 AS ( @@ -271,9 +271,9 @@ QUERY PLAN QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (5 rows) -- JOIN @@ -285,7 +285,7 @@ QUERY PLAN -> Seq Scan on _hyper_X_X_chunk m2_2 -> Materialize -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (7 rows) :PREFIX SELECT FROM const_now m1, const_now m2 WHERE m2.time > now(); @@ -296,17 +296,17 @@ QUERY PLAN -> Seq Scan on _hyper_X_X_chunk m1_2 -> Materialize -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (7 rows) :PREFIX SELECT FROM const_now m1, const_now m2 WHERE m1.time > now() AND m2.time > now(); QUERY PLAN Nested Loop -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m1 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Materialize -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (6 rows) -- only top-level constraints in WHERE clause are constified @@ -334,7 +334,7 @@ QUERY PLAN Index Cond: ("time" > now()) -> Materialize -> Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk m2 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (9 rows) -- test UPDATE @@ -345,7 +345,7 @@ QUERY PLAN Update on _hyper_X_X_chunk const_now_1 -> Result -> Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk const_now_1 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (6 rows) -- test DELETE @@ -355,7 +355,7 @@ QUERY PLAN -> Delete on const_now Delete on _hyper_X_X_chunk const_now_1 -> Index Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk const_now_1 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (5 rows) -- test chunks actually get excluded @@ -364,7 +364,7 @@ SET timescaledb.current_timestamp_mock TO '2010-01-01'; :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) -- should exclude all but 1 chunk @@ -372,14 +372,14 @@ SET timescaledb.current_timestamp_mock TO '2000-01-14'; :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) -- should have one time filter false :PREFIX SELECT FROM const_now WHERE time > now(); QUERY PLAN Index Only Scan using _hyper_X_X_chunk_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (2 rows) -- no constification because it's not partitioning column @@ -387,9 +387,9 @@ QUERY PLAN QUERY PLAN Append -> Seq Scan on _hyper_X_X_chunk - Filter: (time2 > now()) + Filter: (time2 > ts_now_mock()) -> Seq Scan on _hyper_X_X_chunk - Filter: (time2 > now()) + Filter: (time2 > ts_now_mock()) (5 rows) DROP TABLE const_now; @@ -410,9 +410,9 @@ PREPARE p1 AS SELECT FROM prep_const_now WHERE time > now(); QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (5 rows) EXECUTE p1; @@ -424,14 +424,48 @@ SET timescaledb.current_timestamp_mock TO '3002-01-01'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) (5 rows) +EXECUTE p1; +(1 row) + +-- same test with ChunkAppend enabled +set timescaledb.enable_chunk_append = on; +set timescaledb.enable_constraint_aware_append = on; +DEALLOCATE p1; +PREPARE p1 AS SELECT FROM prep_const_now WHERE time > now(); +set timescaledb.current_timestamp_mock TO '3001-01-01'; +:PREFIX EXECUTE p1; +QUERY PLAN + Custom Scan (ChunkAppend) on prep_const_now + Chunks excluded during startup: 0 + -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk + Index Cond: ("time" > ts_now_mock()) + -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk + Index Cond: ("time" > ts_now_mock()) +(6 rows) + EXECUTE p1; (2 rows) +SET timescaledb.current_timestamp_mock TO '3002-01-01'; +-- plan won't change cause the query didnt get replanned +:PREFIX EXECUTE p1; +QUERY PLAN + Custom Scan (ChunkAppend) on prep_const_now + Chunks excluded during startup: 1 + -> Index Only Scan using _hyper_X_X_chunk_prep_const_now_time_idx on _hyper_X_X_chunk + Index Cond: ("time" > ts_now_mock()) +(4 rows) + +EXECUTE p1; +(1 row) + +set timescaledb.enable_chunk_append = off; +set timescaledb.enable_constraint_aware_append = off; DROP TABLE prep_const_now; -- test outer var references dont trip up constify_now -- no optimization is done in this case @@ -446,7 +480,7 @@ QUERY PLAN -> Materialize -> Nested Loop Semi Join -> Index Scan using _hyper_X_X_chunk_metrics_tstz_time_idx on _hyper_X_X_chunk m2 - Index Cond: ("time" > now()) + Index Cond: ("time" > ts_now_mock()) -> Materialize -> Seq Scan on _hyper_X_X_chunk m3 (8 rows) @@ -479,9 +513,9 @@ SET timescaledb.current_timestamp_mock TO '2022-03-28 0:45+0'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 day'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 day'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 day'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 day'::interval)) (5 rows) SET timescaledb.current_timestamp_mock TO '2022-03-28 1:15+0'; @@ -490,9 +524,9 @@ SET timescaledb.current_timestamp_mock TO '2022-03-28 1:15+0'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 day'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 day'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 day'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 day'::interval)) (5 rows) TRUNCATE const_now_dst; @@ -510,15 +544,15 @@ set timezone to 'utc+1'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) (11 rows) set timezone to 'utc-1'; @@ -527,15 +561,15 @@ set timezone to 'utc-1'; QUERY PLAN Append -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) -> Index Only Scan using _hyper_X_X_chunk_const_now_dst_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 1 mon'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 1 mon'::interval)) (11 rows) DROP TABLE const_now_dst; @@ -583,11 +617,11 @@ QUERY PLAN -> Partial HashAggregate Group Key: _hyper_X_X_chunk."time", _hyper_X_X_chunk.device -> Index Scan Backward using _hyper_X_X_chunk_now_view_test_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 168 hours'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 168 hours'::interval)) -> Partial HashAggregate Group Key: _hyper_X_X_chunk."time", _hyper_X_X_chunk.device -> Index Scan Backward using _hyper_X_X_chunk_now_view_test_time_idx on _hyper_X_X_chunk - Index Cond: ("time" > (now() - '@ 168 hours'::interval)) + Index Cond: ("time" > (ts_now_mock() - '@ 168 hours'::interval)) (11 rows) DROP TABLE now_view_test CASCADE; @@ -603,3 +637,203 @@ WHERE subq_1.time > m1.time; ------+-----------+----+----+----+----+------+-----------+----+----+----+----+------ (0 rows) +CREATE TABLE logged_data ( + rawtag_id INTEGER, + timestamp TIMESTAMP WITH TIME ZONE NOT NULL, + value REAL, + site_id INTEGER +); +SELECT table_name FROM create_hypertable('logged_data', 'timestamp'); + table_name + logged_data +(1 row) + +INSERT INTO logged_data (rawtag_id, timestamp, value, site_id) +VALUES +(1, '2023-01-01'::timestamptz, 13, 1), +(1, '2023-01-07'::timestamptz, 13, 1), +(1, '2023-01-10'::timestamptz, 13, 1), +(1, '2023-01-15'::timestamptz, 13, 1), +(1, '2023-01-20'::timestamptz, 15, 1), +(2, '2023-01-01'::timestamptz, 90, 1), +(3, '2023-01-07'::timestamptz, 2, 1), +(4, '2023-01-10'::timestamptz, 13, 3), +(2, '2023-01-15'::timestamptz, 13, 4), +(5, '2023-01-20'::timestamptz, 13, 1); +-- four chunks, all of them should be excluded at plantime +SELECT COUNT(*) FROM show_chunks('logged_data'); + count + 4 +(1 row) + +SET timescaledb.current_timestamp_mock TO '2024-01-01 0:30:00+00'; +SET timescaledb.enable_chunk_append TO true; +SET timescaledb.enable_constraint_aware_append TO true; +-- for all the queries below, exclusion should be happening at plantime +EXPLAIN (ANALYZE, SUMMARY OFF, TIMING OFF) SELECT * FROM logged_data WHERE +timestamp BETWEEN now() - interval '1 day' AND now() +AND rawtag_id = 1 ORDER BY "timestamp" ASC; +QUERY PLAN + Sort (cost=0.01..0.02 rows=0 width=20) (actual rows=0 loops=1) + Sort Key: "timestamp" + Sort Method: quicksort + -> Result (cost=0.00..0.00 rows=0 width=0) (actual rows=0 loops=1) + One-Time Filter: false +(5 rows) + +EXPLAIN (ANALYZE, SUMMARY OFF, TIMING OFF) SELECT * FROM logged_data WHERE +timestamp <= now() AND timestamp >= now() - interval '1 day' +AND rawtag_id = 1 ORDER BY "timestamp" ASC; +QUERY PLAN + Sort (cost=0.01..0.02 rows=0 width=20) (actual rows=0 loops=1) + Sort Key: "timestamp" + Sort Method: quicksort + -> Result (cost=0.00..0.00 rows=0 width=0) (actual rows=0 loops=1) + One-Time Filter: false +(5 rows) + +EXPLAIN (ANALYZE, SUMMARY OFF, TIMING OFF) SELECT * FROM logged_data WHERE +timestamp <= now() AND timestamp >= now() - interval '1 day' +ORDER BY "timestamp" ASC; +QUERY PLAN + Sort (cost=0.01..0.02 rows=0 width=20) (actual rows=0 loops=1) + Sort Key: "timestamp" + Sort Method: quicksort + -> Result (cost=0.00..0.00 rows=0 width=0) (actual rows=0 loops=1) + One-Time Filter: false +(5 rows) + +-- mock_now() in the middle of the table +SET timescaledb.current_timestamp_mock TO '2023-01-11'; +PREPARE pbtw AS SELECT * FROM logged_data WHERE +timestamp BETWEEN now() - interval '5 day' AND now() AND rawtag_id = 1 +ORDER BY "timestamp" ASC; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Custom Scan (ChunkAppend) on logged_data (cost=0.16..22.08 rows=3 width=20) + Order: logged_data."timestamp" + Chunks excluded during startup: 2 + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(6 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+------------------------------+-------+--------- + 1 | Sat Jan 07 00:00:00 2023 UTC | 13 | 1 + 1 | Tue Jan 10 00:00:00 2023 UTC | 13 | 1 +(2 rows) + +-- now move mock_now() to the future +SET timescaledb.current_timestamp_mock TO '2023-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Custom Scan (ChunkAppend) on logged_data (cost=0.16..22.08 rows=3 width=20) + Order: logged_data."timestamp" + Chunks excluded during startup: 1 + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(9 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+------------------------------+-------+--------- + 1 | Fri Jan 20 00:00:00 2023 UTC | 15 | 1 +(1 row) + +-- much further into the future, no rows should be returned +SET timescaledb.current_timestamp_mock TO '2024-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Custom Scan (ChunkAppend) on logged_data (cost=0.16..22.08 rows=3 width=20) + Order: logged_data."timestamp" + Chunks excluded during startup: 3 +(3 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+-----------+-------+--------- +(0 rows) + +DEALLOCATE pbtw; +-- repeat without ChunkAppend +set timescaledb.enable_chunk_append = off; +set timescaledb.enable_constraint_aware_append = off; +SET timescaledb.current_timestamp_mock TO '2023-01-11'; +PREPARE pbtw AS SELECT * FROM logged_data WHERE +timestamp BETWEEN now() - interval '5 day' AND now() AND rawtag_id = 1 +ORDER BY "timestamp" ASC; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Merge Append (cost=0.50..22.14 rows=3 width=20) + Sort Key: _hyper_X_X_chunk."timestamp" + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(11 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+------------------------------+-------+--------- + 1 | Sat Jan 07 00:00:00 2023 UTC | 13 | 1 + 1 | Tue Jan 10 00:00:00 2023 UTC | 13 | 1 +(2 rows) + +-- now move mock_now() to the future +SET timescaledb.current_timestamp_mock TO '2023-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Merge Append (cost=0.50..22.14 rows=3 width=20) + Sort Key: _hyper_X_X_chunk."timestamp" + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(11 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+------------------------------+-------+--------- + 1 | Fri Jan 20 00:00:00 2023 UTC | 15 | 1 +(1 row) + +-- much further into the future, no rows should be returned +SET timescaledb.current_timestamp_mock TO '2024-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +QUERY PLAN + Merge Append (cost=0.50..22.14 rows=3 width=20) + Sort Key: _hyper_X_X_chunk."timestamp" + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) + -> Index Scan Backward using _hyper_X_X_chunk_logged_data_timestamp_idx on _hyper_X_X_chunk (cost=0.16..7.36 rows=1 width=20) + Index Cond: (("timestamp" >= (ts_now_mock() - '@ 5 days'::interval)) AND ("timestamp" <= ts_now_mock())) + Filter: (rawtag_id = 1) +(11 rows) + +EXECUTE pbtw; + rawtag_id | timestamp | value | site_id +-----------+-----------+-------+--------- +(0 rows) + +DEALLOCATE pbtw; +DROP TABLE logged_data; diff --git a/tsl/test/shared/expected/extension.out b/tsl/test/shared/expected/extension.out index e94971884e3..fa6b8e1fa03 100644 --- a/tsl/test/shared/expected/extension.out +++ b/tsl/test/shared/expected/extension.out @@ -220,6 +220,7 @@ ORDER BY pronamespace::regnamespace::text COLLATE "C", p.oid::regprocedure::text debug_waitpoint_enable(text) debug_waitpoint_id(text) debug_waitpoint_release(text) + ts_now_mock() add_compression_policy(regclass,"any",boolean,interval,timestamp with time zone,text,interval) add_continuous_aggregate_policy(regclass,"any","any",interval,boolean,timestamp with time zone,text) add_dimension(regclass,_timescaledb_internal.dimension_info,boolean) diff --git a/tsl/test/shared/sql/constify_now.sql.in b/tsl/test/shared/sql/constify_now.sql.in index fe076604c83..cef2b6432da 100644 --- a/tsl/test/shared/sql/constify_now.sql.in +++ b/tsl/test/shared/sql/constify_now.sql.in @@ -121,6 +121,21 @@ SET timescaledb.current_timestamp_mock TO '3002-01-01'; :PREFIX EXECUTE p1; EXECUTE p1; +-- same test with ChunkAppend enabled +set timescaledb.enable_chunk_append = on; +set timescaledb.enable_constraint_aware_append = on; +DEALLOCATE p1; +PREPARE p1 AS SELECT FROM prep_const_now WHERE time > now(); +set timescaledb.current_timestamp_mock TO '3001-01-01'; +:PREFIX EXECUTE p1; +EXECUTE p1; +SET timescaledb.current_timestamp_mock TO '3002-01-01'; +-- plan won't change cause the query didnt get replanned +:PREFIX EXECUTE p1; +EXECUTE p1; +set timescaledb.enable_chunk_append = off; +set timescaledb.enable_constraint_aware_append = off; + DROP TABLE prep_const_now; -- test outer var references dont trip up constify_now @@ -189,3 +204,85 @@ SELECT * FROM LATERAL (SELECT m2.time FROM devices LIMIT 1) as subq_1 WHERE subq_1.time > m1.time; +CREATE TABLE logged_data ( + rawtag_id INTEGER, + timestamp TIMESTAMP WITH TIME ZONE NOT NULL, + value REAL, + site_id INTEGER +); + +SELECT table_name FROM create_hypertable('logged_data', 'timestamp'); + +INSERT INTO logged_data (rawtag_id, timestamp, value, site_id) +VALUES +(1, '2023-01-01'::timestamptz, 13, 1), +(1, '2023-01-07'::timestamptz, 13, 1), +(1, '2023-01-10'::timestamptz, 13, 1), +(1, '2023-01-15'::timestamptz, 13, 1), +(1, '2023-01-20'::timestamptz, 15, 1), +(2, '2023-01-01'::timestamptz, 90, 1), +(3, '2023-01-07'::timestamptz, 2, 1), +(4, '2023-01-10'::timestamptz, 13, 3), +(2, '2023-01-15'::timestamptz, 13, 4), +(5, '2023-01-20'::timestamptz, 13, 1); + +-- four chunks, all of them should be excluded at plantime +SELECT COUNT(*) FROM show_chunks('logged_data'); + +SET timescaledb.current_timestamp_mock TO '2024-01-01 0:30:00+00'; + +SET timescaledb.enable_chunk_append TO true; +SET timescaledb.enable_constraint_aware_append TO true; + +-- for all the queries below, exclusion should be happening at plantime +EXPLAIN (ANALYZE, SUMMARY OFF, TIMING OFF) SELECT * FROM logged_data WHERE +timestamp BETWEEN now() - interval '1 day' AND now() +AND rawtag_id = 1 ORDER BY "timestamp" ASC; + +EXPLAIN (ANALYZE, SUMMARY OFF, TIMING OFF) SELECT * FROM logged_data WHERE +timestamp <= now() AND timestamp >= now() - interval '1 day' +AND rawtag_id = 1 ORDER BY "timestamp" ASC; + +EXPLAIN (ANALYZE, SUMMARY OFF, TIMING OFF) SELECT * FROM logged_data WHERE +timestamp <= now() AND timestamp >= now() - interval '1 day' +ORDER BY "timestamp" ASC; + +-- mock_now() in the middle of the table +SET timescaledb.current_timestamp_mock TO '2023-01-11'; +PREPARE pbtw AS SELECT * FROM logged_data WHERE +timestamp BETWEEN now() - interval '5 day' AND now() AND rawtag_id = 1 +ORDER BY "timestamp" ASC; + +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +EXECUTE pbtw; +-- now move mock_now() to the future +SET timescaledb.current_timestamp_mock TO '2023-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +EXECUTE pbtw; +-- much further into the future, no rows should be returned +SET timescaledb.current_timestamp_mock TO '2024-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +EXECUTE pbtw; +DEALLOCATE pbtw; + +-- repeat without ChunkAppend +set timescaledb.enable_chunk_append = off; +set timescaledb.enable_constraint_aware_append = off; +SET timescaledb.current_timestamp_mock TO '2023-01-11'; +PREPARE pbtw AS SELECT * FROM logged_data WHERE +timestamp BETWEEN now() - interval '5 day' AND now() AND rawtag_id = 1 +ORDER BY "timestamp" ASC; + +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +EXECUTE pbtw; +-- now move mock_now() to the future +SET timescaledb.current_timestamp_mock TO '2023-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +EXECUTE pbtw; +-- much further into the future, no rows should be returned +SET timescaledb.current_timestamp_mock TO '2024-01-21 0:30:00+00'; +EXPLAIN (SUMMARY OFF, TIMING OFF) EXECUTE pbtw; +EXECUTE pbtw; +DEALLOCATE pbtw; + +DROP TABLE logged_data;