diff --git a/src/nodes/hypertable_modify.c b/src/nodes/hypertable_modify.c index 9d32e10dba6..ad716036199 100644 --- a/src/nodes/hypertable_modify.c +++ b/src/nodes/hypertable_modify.c @@ -539,6 +539,12 @@ hypertable_modify_plan_create(PlannerInfo *root, RelOptInfo *rel, CustomPath *be { cscan->scan.plan.targetlist = ts_replace_rowid_vars(root, cscan->scan.plan.targetlist, mt->nominalRelation); + + if (mt->operation == CMD_UPDATE && ts_is_chunk_append_plan(mt->plan.lefttree)) + { + mt->plan.lefttree->targetlist = + ts_replace_rowid_vars(root, mt->plan.lefttree->targetlist, mt->nominalRelation); + } } #else /* diff --git a/src/planner.c b/src/planner.c index 6879e81bb06..a22c57a6547 100644 --- a/src/planner.c +++ b/src/planner.c @@ -679,18 +679,19 @@ static inline bool should_chunk_append(Hypertable *ht, PlannerInfo *root, RelOptInfo *rel, Path *path, bool ordered, int order_attno) { - if (!(root->parse->commandType == CMD_SELECT || root->parse->commandType == CMD_DELETE) || + if ( +#if PG14_LT + root->parse->commandType != CMD_SELECT || +#else + /* + * We only support chunk exclusion on UPDATE/DELETE when no JOIN is involved on PG14+. + */ + ((root->parse->commandType == CMD_DELETE || root->parse->commandType == CMD_UPDATE) && + bms_num_members(root->all_baserels) > 1) || +#endif !ts_guc_enable_chunk_append || hypertable_is_distributed(ht)) return false; -#if PG14_GE - /* - * We only support chunk exclusion on DELETE when no JOIN is involved on PG14+. - */ - if (root->parse->commandType == CMD_DELETE && bms_num_members(root->all_baserels) > 1) - return false; -#endif - switch (nodeTag(path)) { case T_AppendPath: @@ -932,7 +933,8 @@ apply_optimizations(PlannerInfo *root, TsRelType reltype, RelOptInfo *rel, Range if (reltype == TS_REL_HYPERTABLE && #if PG14_GE - (root->parse->commandType == CMD_SELECT || root->parse->commandType == CMD_DELETE) + (root->parse->commandType == CMD_SELECT || root->parse->commandType == CMD_DELETE || + root->parse->commandType == CMD_UPDATE) #else /* * For PG < 14 commandType will be CMD_SELECT even when planning DELETE so we diff --git a/test/expected/rowsecurity-14.out b/test/expected/rowsecurity-14.out index 9a0d0e79406..b32e09eecd1 100644 --- a/test/expected/rowsecurity-14.out +++ b/test/expected/rowsecurity-14.out @@ -2265,19 +2265,19 @@ INSERT INTO bv1 VALUES (11, 'xxx'); -- should fail RLS check ERROR: new row violates row-level security policy for table "b1" INSERT INTO bv1 VALUES (12, 'xxx'); -- ok EXPLAIN (COSTS OFF) UPDATE bv1 SET b = 'yyy' WHERE a = 4 AND f_leak(b); - QUERY PLAN ------------------------------------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------------------------------------------- Custom Scan (HypertableModify) -> Update on b1 Update on b1 b1_1 Update on _hyper_8_41_chunk b1_2 - -> Result - -> Append - -> Seq Scan on b1 b1_1 - Filter: ((a > 0) AND (a = 4) AND ((a % 2) = 0) AND f_leak(b)) - -> Index Scan using _hyper_8_41_chunk_b1_a_idx on _hyper_8_41_chunk b1_2 - Index Cond: ((a > 0) AND (a = 4)) - Filter: (((a % 2) = 0) AND f_leak(b)) + -> Custom Scan (ChunkAppend) on b1 + Chunks excluded during startup: 0 + -> Seq Scan on b1 b1_1 + Filter: ((a > 0) AND (a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Index Scan using _hyper_8_41_chunk_b1_a_idx on _hyper_8_41_chunk b1_2 + Index Cond: ((a > 0) AND (a = 4)) + Filter: (((a % 2) = 0) AND f_leak(b)) (11 rows) UPDATE bv1 SET b = 'yyy' WHERE a = 4 AND f_leak(b); diff --git a/tsl/test/expected/update_exclusion.out b/tsl/test/expected/update_exclusion.out new file mode 100644 index 00000000000..c6538cdbb45 --- /dev/null +++ b/tsl/test/expected/update_exclusion.out @@ -0,0 +1,1013 @@ +-- This file and its contents are licensed under the Timescale License. +-- Please see the included NOTICE for copyright information and +-- LICENSE-TIMESCALE for a copy of the license. +\set PREFIX 'EXPLAIN (ANALYZE,VERBOSE,SUMMARY OFF,TIMING OFF,COSTS OFF)' +CREATE TABLE metrics_int2(c1 int,c2 int, c3 int, c4 int, c5 int, time int2 NOT NULL, value float); +CREATE TABLE metrics_int4(c1 int,c2 int, c3 int, c4 int, c5 int, time int4 NOT NULL, value float); +CREATE TABLE metrics_int8(c1 int,c2 int, c3 int, c4 int, c5 int, time int8 NOT NULL, value float); +CREATE TABLE metrics_date(c1 int,c2 int, c3 int, c4 int, c5 int, time date NOT NULL, value float); +CREATE TABLE metrics_timestamp(c1 int,c2 int, c3 int, c4 int, c5 int, time timestamp NOT NULL, value float); +CREATE TABLE metrics_timestamptz(c1 int,c2 int, c3 int, c4 int, c5 int, time timestamptz NOT NULL, value float); +CREATE TABLE metrics_space(c1 int,c2 int, c3 int, c4 int, c5 int, time timestamp NOT NULL, device text, value float); +SELECT table_name FROM create_hypertable('metrics_int2','time',chunk_time_interval:=10); + table_name +-------------- + metrics_int2 +(1 row) + +SELECT table_name FROM create_hypertable('metrics_int4','time',chunk_time_interval:=10); + table_name +-------------- + metrics_int4 +(1 row) + +SELECT table_name FROM create_hypertable('metrics_int8','time',chunk_time_interval:=10); + table_name +-------------- + metrics_int8 +(1 row) + +SELECT table_name FROM create_hypertable('metrics_date','time'); + table_name +-------------- + metrics_date +(1 row) + +SELECT table_name FROM create_hypertable('metrics_timestamp','time'); + table_name +------------------- + metrics_timestamp +(1 row) + +SELECT table_name FROM create_hypertable('metrics_timestamptz','time'); + table_name +--------------------- + metrics_timestamptz +(1 row) + +SELECT table_name FROM create_hypertable('metrics_space','time','device',4); + table_name +--------------- + metrics_space +(1 row) + +CREATE FUNCTION drop_column(text) RETURNS VOID LANGUAGE PLPGSQL AS $$ +DECLARE + tbl name; +BEGIN + FOR tbl IN SELECT 'metrics_' || unnest(ARRAY['int2','int4','int8','date','timestamp','timestamptz','space']) + LOOP + EXECUTE format('ALTER TABLE %I DROP COLUMN %I;', tbl, $1); + END LOOP; +END; +$$; +-- create 4 chunks each with different physical layout +SELECT drop_column('c1'); + drop_column +------------- + +(1 row) + +INSERT INTO metrics_int2(time) VALUES (0); +INSERT INTO metrics_int4(time) VALUES (0); +INSERT INTO metrics_int8(time) VALUES (0); +INSERT INTO metrics_date(time) VALUES ('2000-01-01'); +INSERT INTO metrics_timestamp(time) VALUES ('2000-01-01'); +INSERT INTO metrics_timestamptz(time) VALUES ('2000-01-01'); +INSERT INTO metrics_space(time,device) VALUES ('2000-01-01','1'),('2000-01-01','2'); +SELECT drop_column('c2'); + drop_column +------------- + +(1 row) + +INSERT INTO metrics_int2(time) VALUES (10); +INSERT INTO metrics_int4(time) VALUES (10); +INSERT INTO metrics_int8(time) VALUES (10); +INSERT INTO metrics_date(time) VALUES ('2001-01-01'); +INSERT INTO metrics_timestamp(time) VALUES ('2001-01-01'); +INSERT INTO metrics_timestamptz(time) VALUES ('2001-01-01'); +INSERT INTO metrics_space(time,device) VALUES ('2001-01-01','1'),('2001-01-01','2'); +SELECT drop_column('c3'); + drop_column +------------- + +(1 row) + +INSERT INTO metrics_int2(time) VALUES (20); +INSERT INTO metrics_int4(time) VALUES (20); +INSERT INTO metrics_int8(time) VALUES (20); +INSERT INTO metrics_date(time) VALUES ('2002-01-01'); +INSERT INTO metrics_timestamp(time) VALUES ('2002-01-01'); +INSERT INTO metrics_timestamptz(time) VALUES ('2002-01-01'); +INSERT INTO metrics_space(time,device) VALUES ('2002-01-01','1'),('2002-01-01','2'); +SELECT drop_column('c4'); + drop_column +------------- + +(1 row) + +INSERT INTO metrics_int2(time) VALUES (30); +INSERT INTO metrics_int4(time) VALUES (30); +INSERT INTO metrics_int8(time) VALUES (30); +INSERT INTO metrics_date(time) VALUES ('2003-01-01'); +INSERT INTO metrics_timestamp(time) VALUES ('2003-01-01'); +INSERT INTO metrics_timestamptz(time) VALUES ('2003-01-01'); +INSERT INTO metrics_space(time,device) VALUES ('2003-01-01','1'),('2003-01-01','2'); +SELECT drop_column('c5'); + drop_column +------------- + +(1 row) + +-- immutable constraints +-- should not have ChunkAppend since constraint is immutable and postgres already does the exclusion +-- should only hit 1 chunk and base table +BEGIN; +:PREFIX UPDATE metrics_int2 SET value = 0.5 WHERE time = 15; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------ + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_int2 (actual rows=0 loops=1) + Update on public.metrics_int2 metrics_int2_1 + Update on _timescaledb_internal._hyper_1_9_chunk metrics_int2_2 + -> Result (actual rows=0 loops=1) + Output: '0.5'::double precision, metrics_int2.tableoid, metrics_int2.ctid + -> Append (actual rows=0 loops=1) + -> Seq Scan on public.metrics_int2 metrics_int2_1 (actual rows=0 loops=1) + Output: metrics_int2_1.tableoid, metrics_int2_1.ctid + Filter: (metrics_int2_1."time" = 15) + -> Index Scan using _hyper_1_9_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_9_chunk metrics_int2_2 (actual rows=0 loops=1) + Output: metrics_int2_2.tableoid, metrics_int2_2.ctid + Index Cond: (metrics_int2_2."time" = 15) +(13 rows) + +:PREFIX UPDATE metrics_int4 SET value = 0.5 WHERE time = 15; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_int4 (actual rows=0 loops=1) + Update on public.metrics_int4 metrics_int4_1 + Update on _timescaledb_internal._hyper_2_10_chunk metrics_int4_2 + -> Result (actual rows=0 loops=1) + Output: '0.5'::double precision, metrics_int4.tableoid, metrics_int4.ctid + -> Append (actual rows=0 loops=1) + -> Seq Scan on public.metrics_int4 metrics_int4_1 (actual rows=0 loops=1) + Output: metrics_int4_1.tableoid, metrics_int4_1.ctid + Filter: (metrics_int4_1."time" = 15) + -> Index Scan using _hyper_2_10_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_10_chunk metrics_int4_2 (actual rows=0 loops=1) + Output: metrics_int4_2.tableoid, metrics_int4_2.ctid + Index Cond: (metrics_int4_2."time" = 15) +(13 rows) + +:PREFIX UPDATE metrics_int8 SET value = 0.5 WHERE time = 15; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_int8 (actual rows=0 loops=1) + Update on public.metrics_int8 metrics_int8_1 + Update on _timescaledb_internal._hyper_3_11_chunk metrics_int8_2 + -> Result (actual rows=0 loops=1) + Output: '0.5'::double precision, metrics_int8.tableoid, metrics_int8.ctid + -> Append (actual rows=0 loops=1) + -> Seq Scan on public.metrics_int8 metrics_int8_1 (actual rows=0 loops=1) + Output: metrics_int8_1.tableoid, metrics_int8_1.ctid + Filter: (metrics_int8_1."time" = 15) + -> Index Scan using _hyper_3_11_chunk_metrics_int8_time_idx on _timescaledb_internal._hyper_3_11_chunk metrics_int8_2 (actual rows=0 loops=1) + Output: metrics_int8_2.tableoid, metrics_int8_2.ctid + Index Cond: (metrics_int8_2."time" = 15) +(13 rows) + +ROLLBACK; +-- stable constraints +-- should have ChunkAppend since constraint is stable +-- should only hit 1 chunk and base table +BEGIN; +:PREFIX UPDATE metrics_int2 SET value = 0.3 WHERE time = length(substring(version(),1,23)); + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_int2 (actual rows=0 loops=1) + Update on public.metrics_int2 metrics_int2_1 + Update on _timescaledb_internal._hyper_1_1_chunk metrics_int2 + Update on _timescaledb_internal._hyper_1_9_chunk metrics_int2 + Update on _timescaledb_internal._hyper_1_17_chunk metrics_int2_2 + Update on _timescaledb_internal._hyper_1_25_chunk metrics_int2 + -> Custom Scan (ChunkAppend) on public.metrics_int2 (actual rows=0 loops=1) + Output: '0.3'::double precision, metrics_int2.tableoid, metrics_int2.ctid + Startup Exclusion: true + Runtime Exclusion: false + Chunks excluded during startup: 3 + -> Seq Scan on public.metrics_int2 metrics_int2_1 (actual rows=0 loops=1) + Output: metrics_int2_1.tableoid, metrics_int2_1.ctid + Filter: (metrics_int2_1."time" = length("substring"(version(), 1, 23))) + -> Index Scan using _hyper_1_17_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_17_chunk metrics_int2_2 (actual rows=0 loops=1) + Output: metrics_int2_2.tableoid, metrics_int2_2.ctid + Index Cond: (metrics_int2_2."time" = length("substring"(version(), 1, 23))) +(18 rows) + +:PREFIX UPDATE metrics_int4 SET value = 0.3 WHERE time = length(substring(version(),1,23)); + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_int4 (actual rows=0 loops=1) + Update on public.metrics_int4 metrics_int4_1 + Update on _timescaledb_internal._hyper_2_2_chunk metrics_int4 + Update on _timescaledb_internal._hyper_2_10_chunk metrics_int4 + Update on _timescaledb_internal._hyper_2_18_chunk metrics_int4_2 + Update on _timescaledb_internal._hyper_2_26_chunk metrics_int4 + -> Custom Scan (ChunkAppend) on public.metrics_int4 (actual rows=0 loops=1) + Output: '0.3'::double precision, metrics_int4.tableoid, metrics_int4.ctid + Startup Exclusion: true + Runtime Exclusion: false + Chunks excluded during startup: 3 + -> Seq Scan on public.metrics_int4 metrics_int4_1 (actual rows=0 loops=1) + Output: metrics_int4_1.tableoid, metrics_int4_1.ctid + Filter: (metrics_int4_1."time" = length("substring"(version(), 1, 23))) + -> Index Scan using _hyper_2_18_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_18_chunk metrics_int4_2 (actual rows=0 loops=1) + Output: metrics_int4_2.tableoid, metrics_int4_2.ctid + Index Cond: (metrics_int4_2."time" = length("substring"(version(), 1, 23))) +(18 rows) + +:PREFIX UPDATE metrics_int8 SET value = 0.3 WHERE time = length(substring(version(),1,23)); + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_int8 (actual rows=0 loops=1) + Update on public.metrics_int8 metrics_int8_1 + Update on _timescaledb_internal._hyper_3_3_chunk metrics_int8 + Update on _timescaledb_internal._hyper_3_11_chunk metrics_int8 + Update on _timescaledb_internal._hyper_3_19_chunk metrics_int8_2 + Update on _timescaledb_internal._hyper_3_27_chunk metrics_int8 + -> Custom Scan (ChunkAppend) on public.metrics_int8 (actual rows=0 loops=1) + Output: '0.3'::double precision, metrics_int8.tableoid, metrics_int8.ctid + Startup Exclusion: true + Runtime Exclusion: false + Chunks excluded during startup: 3 + -> Seq Scan on public.metrics_int8 metrics_int8_1 (actual rows=0 loops=1) + Output: metrics_int8_1.tableoid, metrics_int8_1.ctid + Filter: (metrics_int8_1."time" = length("substring"(version(), 1, 23))) + -> Index Scan using _hyper_3_19_chunk_metrics_int8_time_idx on _timescaledb_internal._hyper_3_19_chunk metrics_int8_2 (actual rows=0 loops=1) + Output: metrics_int8_2.tableoid, metrics_int8_2.ctid + Index Cond: (metrics_int8_2."time" = length("substring"(version(), 1, 23))) +(18 rows) + +ROLLBACK; +-- should have ChunkAppend since constraint is stable +-- should only hit 1 chunk and base table, toplevel rows should be 1 +BEGIN; +:PREFIX UPDATE metrics_int2 SET value = 0.4 WHERE time = length(substring(version(),1,20)) RETURNING 'returning', time; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=1 loops=1) + Output: ('returning'::text), metrics_int2_1."time" + -> Update on public.metrics_int2 (actual rows=1 loops=1) + Output: 'returning'::text, metrics_int2_1."time" + Update on public.metrics_int2 metrics_int2_1 + Update on _timescaledb_internal._hyper_1_1_chunk metrics_int2 + Update on _timescaledb_internal._hyper_1_9_chunk metrics_int2 + Update on _timescaledb_internal._hyper_1_17_chunk metrics_int2_2 + Update on _timescaledb_internal._hyper_1_25_chunk metrics_int2 + -> Custom Scan (ChunkAppend) on public.metrics_int2 (actual rows=1 loops=1) + Output: '0.4'::double precision, metrics_int2.tableoid, metrics_int2.ctid + Startup Exclusion: true + Runtime Exclusion: false + Chunks excluded during startup: 3 + -> Seq Scan on public.metrics_int2 metrics_int2_1 (actual rows=0 loops=1) + Output: metrics_int2_1.tableoid, metrics_int2_1.ctid + Filter: (metrics_int2_1."time" = length("substring"(version(), 1, 20))) + -> Index Scan using _hyper_1_17_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_17_chunk metrics_int2_2 (actual rows=1 loops=1) + Output: metrics_int2_2.tableoid, metrics_int2_2.ctid + Index Cond: (metrics_int2_2."time" = length("substring"(version(), 1, 20))) +(20 rows) + +:PREFIX UPDATE metrics_int4 SET value = 0.4 WHERE time = length(substring(version(),1,20)) RETURNING 'returning', time; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=1 loops=1) + Output: ('returning'::text), metrics_int4_1."time" + -> Update on public.metrics_int4 (actual rows=1 loops=1) + Output: 'returning'::text, metrics_int4_1."time" + Update on public.metrics_int4 metrics_int4_1 + Update on _timescaledb_internal._hyper_2_2_chunk metrics_int4 + Update on _timescaledb_internal._hyper_2_10_chunk metrics_int4 + Update on _timescaledb_internal._hyper_2_18_chunk metrics_int4_2 + Update on _timescaledb_internal._hyper_2_26_chunk metrics_int4 + -> Custom Scan (ChunkAppend) on public.metrics_int4 (actual rows=1 loops=1) + Output: '0.4'::double precision, metrics_int4.tableoid, metrics_int4.ctid + Startup Exclusion: true + Runtime Exclusion: false + Chunks excluded during startup: 3 + -> Seq Scan on public.metrics_int4 metrics_int4_1 (actual rows=0 loops=1) + Output: metrics_int4_1.tableoid, metrics_int4_1.ctid + Filter: (metrics_int4_1."time" = length("substring"(version(), 1, 20))) + -> Index Scan using _hyper_2_18_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_18_chunk metrics_int4_2 (actual rows=1 loops=1) + Output: metrics_int4_2.tableoid, metrics_int4_2.ctid + Index Cond: (metrics_int4_2."time" = length("substring"(version(), 1, 20))) +(20 rows) + +:PREFIX UPDATE metrics_int8 SET value = 0.4 WHERE time = length(substring(version(),1,20)) RETURNING 'returning', time; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=1 loops=1) + Output: ('returning'::text), metrics_int8_1."time" + -> Update on public.metrics_int8 (actual rows=1 loops=1) + Output: 'returning'::text, metrics_int8_1."time" + Update on public.metrics_int8 metrics_int8_1 + Update on _timescaledb_internal._hyper_3_3_chunk metrics_int8 + Update on _timescaledb_internal._hyper_3_11_chunk metrics_int8 + Update on _timescaledb_internal._hyper_3_19_chunk metrics_int8_2 + Update on _timescaledb_internal._hyper_3_27_chunk metrics_int8 + -> Custom Scan (ChunkAppend) on public.metrics_int8 (actual rows=1 loops=1) + Output: '0.4'::double precision, metrics_int8.tableoid, metrics_int8.ctid + Startup Exclusion: true + Runtime Exclusion: false + Chunks excluded during startup: 3 + -> Seq Scan on public.metrics_int8 metrics_int8_1 (actual rows=0 loops=1) + Output: metrics_int8_1.tableoid, metrics_int8_1.ctid + Filter: (metrics_int8_1."time" = length("substring"(version(), 1, 20))) + -> Index Scan using _hyper_3_19_chunk_metrics_int8_time_idx on _timescaledb_internal._hyper_3_19_chunk metrics_int8_2 (actual rows=1 loops=1) + Output: metrics_int8_2.tableoid, metrics_int8_2.ctid + Index Cond: (metrics_int8_2."time" = length("substring"(version(), 1, 20))) +(20 rows) + +ROLLBACK; +-- immutable constraints +-- should not have ChunkAppend since constraint is immutable and postgres already does the exclusion +-- should only hit 1 chunk and base table +BEGIN; +:PREFIX UPDATE metrics_date SET value = 0.6 WHERE time = '2000-01-01'; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------ + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_date (actual rows=0 loops=1) + Update on public.metrics_date metrics_date_1 + Update on _timescaledb_internal._hyper_4_4_chunk metrics_date_2 + -> Result (actual rows=1 loops=1) + Output: '0.6'::double precision, metrics_date.tableoid, metrics_date.ctid + -> Append (actual rows=1 loops=1) + -> Seq Scan on public.metrics_date metrics_date_1 (actual rows=0 loops=1) + Output: metrics_date_1.tableoid, metrics_date_1.ctid + Filter: (metrics_date_1."time" = '01-01-2000'::date) + -> Index Scan using _hyper_4_4_chunk_metrics_date_time_idx on _timescaledb_internal._hyper_4_4_chunk metrics_date_2 (actual rows=1 loops=1) + Output: metrics_date_2.tableoid, metrics_date_2.ctid + Index Cond: (metrics_date_2."time" = '01-01-2000'::date) +(13 rows) + +:PREFIX UPDATE metrics_timestamp SET value = 0.6 WHERE time = '2000-01-01'; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_timestamp (actual rows=0 loops=1) + Update on public.metrics_timestamp metrics_timestamp_1 + Update on _timescaledb_internal._hyper_5_5_chunk metrics_timestamp_2 + -> Result (actual rows=1 loops=1) + Output: '0.6'::double precision, metrics_timestamp.tableoid, metrics_timestamp.ctid + -> Append (actual rows=1 loops=1) + -> Seq Scan on public.metrics_timestamp metrics_timestamp_1 (actual rows=0 loops=1) + Output: metrics_timestamp_1.tableoid, metrics_timestamp_1.ctid + Filter: (metrics_timestamp_1."time" = 'Sat Jan 01 00:00:00 2000'::timestamp without time zone) + -> Index Scan using _hyper_5_5_chunk_metrics_timestamp_time_idx on _timescaledb_internal._hyper_5_5_chunk metrics_timestamp_2 (actual rows=1 loops=1) + Output: metrics_timestamp_2.tableoid, metrics_timestamp_2.ctid + Index Cond: (metrics_timestamp_2."time" = 'Sat Jan 01 00:00:00 2000'::timestamp without time zone) +(13 rows) + +:PREFIX UPDATE metrics_timestamptz SET value = 0.6 WHERE time = '2000-01-01'; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_timestamptz (actual rows=0 loops=1) + Update on public.metrics_timestamptz metrics_timestamptz_1 + Update on _timescaledb_internal._hyper_6_6_chunk metrics_timestamptz_2 + -> Result (actual rows=1 loops=1) + Output: '0.6'::double precision, metrics_timestamptz.tableoid, metrics_timestamptz.ctid + -> Append (actual rows=1 loops=1) + -> Seq Scan on public.metrics_timestamptz metrics_timestamptz_1 (actual rows=0 loops=1) + Output: metrics_timestamptz_1.tableoid, metrics_timestamptz_1.ctid + Filter: (metrics_timestamptz_1."time" = 'Sat Jan 01 00:00:00 2000 PST'::timestamp with time zone) + -> Index Scan using _hyper_6_6_chunk_metrics_timestamptz_time_idx on _timescaledb_internal._hyper_6_6_chunk metrics_timestamptz_2 (actual rows=1 loops=1) + Output: metrics_timestamptz_2.tableoid, metrics_timestamptz_2.ctid + Index Cond: (metrics_timestamptz_2."time" = 'Sat Jan 01 00:00:00 2000 PST'::timestamp with time zone) +(13 rows) + +:PREFIX UPDATE metrics_space SET value = 0.6 WHERE time = '2000-01-01' AND device = '1'; + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_space (actual rows=0 loops=1) + Update on public.metrics_space metrics_space_1 + Update on _timescaledb_internal._hyper_7_7_chunk metrics_space_2 + Update on _timescaledb_internal._hyper_7_8_chunk metrics_space_3 + -> Result (actual rows=1 loops=1) + Output: '0.6'::double precision, metrics_space.tableoid, metrics_space.ctid + -> Append (actual rows=1 loops=1) + -> Seq Scan on public.metrics_space metrics_space_1 (actual rows=0 loops=1) + Output: metrics_space_1.tableoid, metrics_space_1.ctid + Filter: ((metrics_space_1."time" = 'Sat Jan 01 00:00:00 2000'::timestamp without time zone) AND (metrics_space_1.device = '1'::text)) + -> Index Scan using _hyper_7_7_chunk_metrics_space_device_time_idx on _timescaledb_internal._hyper_7_7_chunk metrics_space_2 (actual rows=1 loops=1) + Output: metrics_space_2.tableoid, metrics_space_2.ctid + Index Cond: ((metrics_space_2.device = '1'::text) AND (metrics_space_2."time" = 'Sat Jan 01 00:00:00 2000'::timestamp without time zone)) + -> Index Scan using _hyper_7_8_chunk_metrics_space_device_time_idx on _timescaledb_internal._hyper_7_8_chunk metrics_space_3 (actual rows=0 loops=1) + Output: metrics_space_3.tableoid, metrics_space_3.ctid + Index Cond: ((metrics_space_3.device = '1'::text) AND (metrics_space_3."time" = 'Sat Jan 01 00:00:00 2000'::timestamp without time zone)) +(17 rows) + +:PREFIX UPDATE metrics_space SET value = 0.6 WHERE time = '2000-01-01'; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_space (actual rows=0 loops=1) + Update on public.metrics_space metrics_space_1 + Update on _timescaledb_internal._hyper_7_7_chunk metrics_space_2 + Update on _timescaledb_internal._hyper_7_8_chunk metrics_space_3 + -> Result (actual rows=2 loops=1) + Output: '0.6'::double precision, metrics_space.tableoid, metrics_space.ctid + -> Append (actual rows=2 loops=1) + -> Seq Scan on public.metrics_space metrics_space_1 (actual rows=0 loops=1) + Output: metrics_space_1.tableoid, metrics_space_1.ctid + Filter: (metrics_space_1."time" = 'Sat Jan 01 00:00:00 2000'::timestamp without time zone) + -> Index Scan using _hyper_7_7_chunk_metrics_space_time_idx on _timescaledb_internal._hyper_7_7_chunk metrics_space_2 (actual rows=1 loops=1) + Output: metrics_space_2.tableoid, metrics_space_2.ctid + Index Cond: (metrics_space_2."time" = 'Sat Jan 01 00:00:00 2000'::timestamp without time zone) + -> Index Scan using _hyper_7_8_chunk_metrics_space_time_idx on _timescaledb_internal._hyper_7_8_chunk metrics_space_3 (actual rows=1 loops=1) + Output: metrics_space_3.tableoid, metrics_space_3.ctid + Index Cond: (metrics_space_3."time" = 'Sat Jan 01 00:00:00 2000'::timestamp without time zone) +(17 rows) + +ROLLBACK; +-- stable constraints +-- should have ChunkAppend since constraint is stable +-- should only hit 1 chunk and base table +BEGIN; +:PREFIX UPDATE metrics_date SET value = 0.9 WHERE time = '2000-01-01'::text::date; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------ + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_date (actual rows=0 loops=1) + Update on public.metrics_date metrics_date_1 + Update on _timescaledb_internal._hyper_4_4_chunk metrics_date_2 + Update on _timescaledb_internal._hyper_4_12_chunk metrics_date + Update on _timescaledb_internal._hyper_4_20_chunk metrics_date + Update on _timescaledb_internal._hyper_4_28_chunk metrics_date + -> Custom Scan (ChunkAppend) on public.metrics_date (actual rows=1 loops=1) + Output: '0.9'::double precision, metrics_date.tableoid, metrics_date.ctid + Startup Exclusion: true + Runtime Exclusion: false + Chunks excluded during startup: 3 + -> Seq Scan on public.metrics_date metrics_date_1 (actual rows=0 loops=1) + Output: metrics_date_1.tableoid, metrics_date_1.ctid + Filter: (metrics_date_1."time" = ('2000-01-01'::cstring)::date) + -> Index Scan using _hyper_4_4_chunk_metrics_date_time_idx on _timescaledb_internal._hyper_4_4_chunk metrics_date_2 (actual rows=1 loops=1) + Output: metrics_date_2.tableoid, metrics_date_2.ctid + Index Cond: (metrics_date_2."time" = ('2000-01-01'::cstring)::date) +(18 rows) + +:PREFIX UPDATE metrics_timestamp SET value = 0.9 WHERE time = '2000-01-01'::text::timestamp; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_timestamp (actual rows=0 loops=1) + Update on public.metrics_timestamp metrics_timestamp_1 + Update on _timescaledb_internal._hyper_5_5_chunk metrics_timestamp_2 + Update on _timescaledb_internal._hyper_5_13_chunk metrics_timestamp + Update on _timescaledb_internal._hyper_5_21_chunk metrics_timestamp + Update on _timescaledb_internal._hyper_5_29_chunk metrics_timestamp + -> Custom Scan (ChunkAppend) on public.metrics_timestamp (actual rows=1 loops=1) + Output: '0.9'::double precision, metrics_timestamp.tableoid, metrics_timestamp.ctid + Startup Exclusion: true + Runtime Exclusion: false + Chunks excluded during startup: 3 + -> Seq Scan on public.metrics_timestamp metrics_timestamp_1 (actual rows=0 loops=1) + Output: metrics_timestamp_1.tableoid, metrics_timestamp_1.ctid + Filter: (metrics_timestamp_1."time" = ('2000-01-01'::cstring)::timestamp without time zone) + -> Index Scan using _hyper_5_5_chunk_metrics_timestamp_time_idx on _timescaledb_internal._hyper_5_5_chunk metrics_timestamp_2 (actual rows=1 loops=1) + Output: metrics_timestamp_2.tableoid, metrics_timestamp_2.ctid + Index Cond: (metrics_timestamp_2."time" = ('2000-01-01'::cstring)::timestamp without time zone) +(18 rows) + +:PREFIX UPDATE metrics_timestamptz SET value = 0.9 WHERE time = '2000-01-01'::text::timestamptz; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_timestamptz (actual rows=0 loops=1) + Update on public.metrics_timestamptz metrics_timestamptz_1 + Update on _timescaledb_internal._hyper_6_6_chunk metrics_timestamptz_2 + Update on _timescaledb_internal._hyper_6_14_chunk metrics_timestamptz + Update on _timescaledb_internal._hyper_6_22_chunk metrics_timestamptz + Update on _timescaledb_internal._hyper_6_30_chunk metrics_timestamptz + -> Custom Scan (ChunkAppend) on public.metrics_timestamptz (actual rows=1 loops=1) + Output: '0.9'::double precision, metrics_timestamptz.tableoid, metrics_timestamptz.ctid + Startup Exclusion: true + Runtime Exclusion: false + Chunks excluded during startup: 3 + -> Seq Scan on public.metrics_timestamptz metrics_timestamptz_1 (actual rows=0 loops=1) + Output: metrics_timestamptz_1.tableoid, metrics_timestamptz_1.ctid + Filter: (metrics_timestamptz_1."time" = ('2000-01-01'::cstring)::timestamp with time zone) + -> Index Scan using _hyper_6_6_chunk_metrics_timestamptz_time_idx on _timescaledb_internal._hyper_6_6_chunk metrics_timestamptz_2 (actual rows=1 loops=1) + Output: metrics_timestamptz_2.tableoid, metrics_timestamptz_2.ctid + Index Cond: (metrics_timestamptz_2."time" = ('2000-01-01'::cstring)::timestamp with time zone) +(18 rows) + +ROLLBACK; +-- space partitioning +-- should have ChunkAppend since constraint is stable +-- should only hit 1 chunk and base table +BEGIN; +:PREFIX UPDATE metrics_space SET value = 0.1 WHERE time = '2000-01-01'::text::timestamptz AND device = format('1'); + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_space (actual rows=0 loops=1) + Update on public.metrics_space metrics_space_1 + Update on _timescaledb_internal._hyper_7_7_chunk metrics_space_2 + Update on _timescaledb_internal._hyper_7_8_chunk metrics_space_3 + Update on _timescaledb_internal._hyper_7_15_chunk metrics_space + Update on _timescaledb_internal._hyper_7_16_chunk metrics_space + Update on _timescaledb_internal._hyper_7_23_chunk metrics_space + Update on _timescaledb_internal._hyper_7_24_chunk metrics_space + Update on _timescaledb_internal._hyper_7_31_chunk metrics_space + Update on _timescaledb_internal._hyper_7_32_chunk metrics_space + -> Custom Scan (ChunkAppend) on public.metrics_space (actual rows=1 loops=1) + Output: '0.1'::double precision, metrics_space.tableoid, metrics_space.ctid + Startup Exclusion: true + Runtime Exclusion: false + Chunks excluded during startup: 6 + -> Seq Scan on public.metrics_space metrics_space_1 (actual rows=0 loops=1) + Output: metrics_space_1.tableoid, metrics_space_1.ctid + Filter: ((metrics_space_1.device = format('1'::text)) AND (metrics_space_1."time" = ('2000-01-01'::cstring)::timestamp with time zone)) + -> Index Scan using _hyper_7_7_chunk_metrics_space_device_time_idx on _timescaledb_internal._hyper_7_7_chunk metrics_space_2 (actual rows=1 loops=1) + Output: metrics_space_2.tableoid, metrics_space_2.ctid + Index Cond: ((metrics_space_2.device = format('1'::text)) AND (metrics_space_2."time" = ('2000-01-01'::cstring)::timestamp with time zone)) + -> Index Scan using _hyper_7_8_chunk_metrics_space_device_time_idx on _timescaledb_internal._hyper_7_8_chunk metrics_space_3 (actual rows=0 loops=1) + Output: metrics_space_3.tableoid, metrics_space_3.ctid + Index Cond: ((metrics_space_3.device = format('1'::text)) AND (metrics_space_3."time" = ('2000-01-01'::cstring)::timestamp with time zone)) +(25 rows) + +ROLLBACK; +BEGIN; +:PREFIX UPDATE metrics_space SET value = 0.1 WHERE device = format('1'); + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_space (actual rows=0 loops=1) + Update on public.metrics_space metrics_space_1 + Update on _timescaledb_internal._hyper_7_7_chunk metrics_space_2 + Update on _timescaledb_internal._hyper_7_8_chunk metrics_space_3 + Update on _timescaledb_internal._hyper_7_15_chunk metrics_space_4 + Update on _timescaledb_internal._hyper_7_16_chunk metrics_space_5 + Update on _timescaledb_internal._hyper_7_23_chunk metrics_space_6 + Update on _timescaledb_internal._hyper_7_24_chunk metrics_space_7 + Update on _timescaledb_internal._hyper_7_31_chunk metrics_space_8 + Update on _timescaledb_internal._hyper_7_32_chunk metrics_space_9 + -> Custom Scan (ChunkAppend) on public.metrics_space (actual rows=4 loops=1) + Output: '0.1'::double precision, metrics_space.tableoid, metrics_space.ctid + Startup Exclusion: true + Runtime Exclusion: false + Chunks excluded during startup: 0 + -> Seq Scan on public.metrics_space metrics_space_1 (actual rows=0 loops=1) + Output: metrics_space_1.tableoid, metrics_space_1.ctid + Filter: (metrics_space_1.device = format('1'::text)) + -> Index Scan using _hyper_7_7_chunk_metrics_space_device_time_idx on _timescaledb_internal._hyper_7_7_chunk metrics_space_2 (actual rows=1 loops=1) + Output: metrics_space_2.tableoid, metrics_space_2.ctid + Index Cond: (metrics_space_2.device = format('1'::text)) + -> Index Scan using _hyper_7_8_chunk_metrics_space_device_time_idx on _timescaledb_internal._hyper_7_8_chunk metrics_space_3 (actual rows=0 loops=1) + Output: metrics_space_3.tableoid, metrics_space_3.ctid + Index Cond: (metrics_space_3.device = format('1'::text)) + -> Index Scan using _hyper_7_15_chunk_metrics_space_device_time_idx on _timescaledb_internal._hyper_7_15_chunk metrics_space_4 (actual rows=1 loops=1) + Output: metrics_space_4.tableoid, metrics_space_4.ctid + Index Cond: (metrics_space_4.device = format('1'::text)) + -> Index Scan using _hyper_7_16_chunk_metrics_space_device_time_idx on _timescaledb_internal._hyper_7_16_chunk metrics_space_5 (actual rows=0 loops=1) + Output: metrics_space_5.tableoid, metrics_space_5.ctid + Index Cond: (metrics_space_5.device = format('1'::text)) + -> Index Scan using _hyper_7_23_chunk_metrics_space_device_time_idx on _timescaledb_internal._hyper_7_23_chunk metrics_space_6 (actual rows=1 loops=1) + Output: metrics_space_6.tableoid, metrics_space_6.ctid + Index Cond: (metrics_space_6.device = format('1'::text)) + -> Index Scan using _hyper_7_24_chunk_metrics_space_device_time_idx on _timescaledb_internal._hyper_7_24_chunk metrics_space_7 (actual rows=0 loops=1) + Output: metrics_space_7.tableoid, metrics_space_7.ctid + Index Cond: (metrics_space_7.device = format('1'::text)) + -> Index Scan using _hyper_7_31_chunk_metrics_space_device_time_idx on _timescaledb_internal._hyper_7_31_chunk metrics_space_8 (actual rows=1 loops=1) + Output: metrics_space_8.tableoid, metrics_space_8.ctid + Index Cond: (metrics_space_8.device = format('1'::text)) + -> Index Scan using _hyper_7_32_chunk_metrics_space_device_time_idx on _timescaledb_internal._hyper_7_32_chunk metrics_space_9 (actual rows=0 loops=1) + Output: metrics_space_9.tableoid, metrics_space_9.ctid + Index Cond: (metrics_space_9.device = format('1'::text)) +(43 rows) + +ROLLBACK; +-- should have ChunkAppend since constraint is stable +-- should only hit 1 chunk and base table, toplevel rows should be 1 +BEGIN; +:PREFIX UPDATE metrics_date SET value = 0.2 WHERE time = '2000-01-01'::text::date RETURNING 'returning', time; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------ + Custom Scan (HypertableModify) (actual rows=1 loops=1) + Output: ('returning'::text), metrics_date_1."time" + -> Update on public.metrics_date (actual rows=1 loops=1) + Output: 'returning'::text, metrics_date_1."time" + Update on public.metrics_date metrics_date_1 + Update on _timescaledb_internal._hyper_4_4_chunk metrics_date_2 + Update on _timescaledb_internal._hyper_4_12_chunk metrics_date + Update on _timescaledb_internal._hyper_4_20_chunk metrics_date + Update on _timescaledb_internal._hyper_4_28_chunk metrics_date + -> Custom Scan (ChunkAppend) on public.metrics_date (actual rows=1 loops=1) + Output: '0.2'::double precision, metrics_date.tableoid, metrics_date.ctid + Startup Exclusion: true + Runtime Exclusion: false + Chunks excluded during startup: 3 + -> Seq Scan on public.metrics_date metrics_date_1 (actual rows=0 loops=1) + Output: metrics_date_1.tableoid, metrics_date_1.ctid + Filter: (metrics_date_1."time" = ('2000-01-01'::cstring)::date) + -> Index Scan using _hyper_4_4_chunk_metrics_date_time_idx on _timescaledb_internal._hyper_4_4_chunk metrics_date_2 (actual rows=1 loops=1) + Output: metrics_date_2.tableoid, metrics_date_2.ctid + Index Cond: (metrics_date_2."time" = ('2000-01-01'::cstring)::date) +(20 rows) + +:PREFIX UPDATE metrics_timestamp SET value = 0.2 WHERE time = '2000-01-01'::text::timestamp RETURNING 'returning', time; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=1 loops=1) + Output: ('returning'::text), metrics_timestamp_1."time" + -> Update on public.metrics_timestamp (actual rows=1 loops=1) + Output: 'returning'::text, metrics_timestamp_1."time" + Update on public.metrics_timestamp metrics_timestamp_1 + Update on _timescaledb_internal._hyper_5_5_chunk metrics_timestamp_2 + Update on _timescaledb_internal._hyper_5_13_chunk metrics_timestamp + Update on _timescaledb_internal._hyper_5_21_chunk metrics_timestamp + Update on _timescaledb_internal._hyper_5_29_chunk metrics_timestamp + -> Custom Scan (ChunkAppend) on public.metrics_timestamp (actual rows=1 loops=1) + Output: '0.2'::double precision, metrics_timestamp.tableoid, metrics_timestamp.ctid + Startup Exclusion: true + Runtime Exclusion: false + Chunks excluded during startup: 3 + -> Seq Scan on public.metrics_timestamp metrics_timestamp_1 (actual rows=0 loops=1) + Output: metrics_timestamp_1.tableoid, metrics_timestamp_1.ctid + Filter: (metrics_timestamp_1."time" = ('2000-01-01'::cstring)::timestamp without time zone) + -> Index Scan using _hyper_5_5_chunk_metrics_timestamp_time_idx on _timescaledb_internal._hyper_5_5_chunk metrics_timestamp_2 (actual rows=1 loops=1) + Output: metrics_timestamp_2.tableoid, metrics_timestamp_2.ctid + Index Cond: (metrics_timestamp_2."time" = ('2000-01-01'::cstring)::timestamp without time zone) +(20 rows) + +:PREFIX UPDATE metrics_timestamptz SET value = 0.2 WHERE time = '2000-01-01'::text::timestamptz RETURNING 'returning', time; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=1 loops=1) + Output: ('returning'::text), metrics_timestamptz_1."time" + -> Update on public.metrics_timestamptz (actual rows=1 loops=1) + Output: 'returning'::text, metrics_timestamptz_1."time" + Update on public.metrics_timestamptz metrics_timestamptz_1 + Update on _timescaledb_internal._hyper_6_6_chunk metrics_timestamptz_2 + Update on _timescaledb_internal._hyper_6_14_chunk metrics_timestamptz + Update on _timescaledb_internal._hyper_6_22_chunk metrics_timestamptz + Update on _timescaledb_internal._hyper_6_30_chunk metrics_timestamptz + -> Custom Scan (ChunkAppend) on public.metrics_timestamptz (actual rows=1 loops=1) + Output: '0.2'::double precision, metrics_timestamptz.tableoid, metrics_timestamptz.ctid + Startup Exclusion: true + Runtime Exclusion: false + Chunks excluded during startup: 3 + -> Seq Scan on public.metrics_timestamptz metrics_timestamptz_1 (actual rows=0 loops=1) + Output: metrics_timestamptz_1.tableoid, metrics_timestamptz_1.ctid + Filter: (metrics_timestamptz_1."time" = ('2000-01-01'::cstring)::timestamp with time zone) + -> Index Scan using _hyper_6_6_chunk_metrics_timestamptz_time_idx on _timescaledb_internal._hyper_6_6_chunk metrics_timestamptz_2 (actual rows=1 loops=1) + Output: metrics_timestamptz_2.tableoid, metrics_timestamptz_2.ctid + Index Cond: (metrics_timestamptz_2."time" = ('2000-01-01'::cstring)::timestamp with time zone) +(20 rows) + +ROLLBACK; +-- subselects +-- no chunk exclusion for subqueries joins atm +:PREFIX UPDATE metrics_int4 SET value = 0.1 WHERE time IN (SELECT time FROM metrics_int2) AND time < length(version()); + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_int4 (actual rows=0 loops=1) + Update on public.metrics_int4 metrics_int4_1 + Update on _timescaledb_internal._hyper_2_2_chunk metrics_int4_2 + Update on _timescaledb_internal._hyper_2_10_chunk metrics_int4_3 + Update on _timescaledb_internal._hyper_2_18_chunk metrics_int4_4 + Update on _timescaledb_internal._hyper_2_26_chunk metrics_int4_5 + -> Hash Join (actual rows=4 loops=1) + Output: '0.1'::double precision, metrics_int2.ctid, metrics_int4.tableoid, metrics_int4.ctid, metrics_int2.tableoid + Inner Unique: true + Hash Cond: (metrics_int4."time" = metrics_int2."time") + -> Append (actual rows=4 loops=1) + -> Seq Scan on public.metrics_int4 metrics_int4_1 (actual rows=0 loops=1) + Output: metrics_int4_1."time", metrics_int4_1.tableoid, metrics_int4_1.ctid + Filter: (metrics_int4_1."time" < length(version())) + -> Index Scan Backward using _hyper_2_2_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_2_chunk metrics_int4_2 (actual rows=1 loops=1) + Output: metrics_int4_2."time", metrics_int4_2.tableoid, metrics_int4_2.ctid + Index Cond: (metrics_int4_2."time" < length(version())) + -> Index Scan Backward using _hyper_2_10_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_10_chunk metrics_int4_3 (actual rows=1 loops=1) + Output: metrics_int4_3."time", metrics_int4_3.tableoid, metrics_int4_3.ctid + Index Cond: (metrics_int4_3."time" < length(version())) + -> Index Scan Backward using _hyper_2_18_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_18_chunk metrics_int4_4 (actual rows=1 loops=1) + Output: metrics_int4_4."time", metrics_int4_4.tableoid, metrics_int4_4.ctid + Index Cond: (metrics_int4_4."time" < length(version())) + -> Index Scan Backward using _hyper_2_26_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_26_chunk metrics_int4_5 (actual rows=1 loops=1) + Output: metrics_int4_5."time", metrics_int4_5.tableoid, metrics_int4_5.ctid + Index Cond: (metrics_int4_5."time" < length(version())) + -> Hash (actual rows=4 loops=1) + Output: metrics_int2.ctid, metrics_int2."time", metrics_int2.tableoid + Buckets: 1024 Batches: 1 + -> HashAggregate (actual rows=4 loops=1) + Output: metrics_int2.ctid, metrics_int2."time", metrics_int2.tableoid + Group Key: metrics_int2."time" + Batches: 1 + -> Append (actual rows=4 loops=1) + -> Seq Scan on public.metrics_int2 metrics_int2_1 (actual rows=0 loops=1) + Output: metrics_int2_1.ctid, metrics_int2_1."time", metrics_int2_1.tableoid + -> Seq Scan on _timescaledb_internal._hyper_1_1_chunk metrics_int2_2 (actual rows=1 loops=1) + Output: metrics_int2_2.ctid, metrics_int2_2."time", metrics_int2_2.tableoid + -> Seq Scan on _timescaledb_internal._hyper_1_9_chunk metrics_int2_3 (actual rows=1 loops=1) + Output: metrics_int2_3.ctid, metrics_int2_3."time", metrics_int2_3.tableoid + -> Seq Scan on _timescaledb_internal._hyper_1_17_chunk metrics_int2_4 (actual rows=1 loops=1) + Output: metrics_int2_4.ctid, metrics_int2_4."time", metrics_int2_4.tableoid + -> Seq Scan on _timescaledb_internal._hyper_1_25_chunk metrics_int2_5 (actual rows=1 loops=1) + Output: metrics_int2_5.ctid, metrics_int2_5."time", metrics_int2_5.tableoid +(45 rows) + +:PREFIX UPDATE metrics_int4 SET value = 0.1 WHERE time IN (SELECT time FROM metrics_int2 WHERE time < length(version())); + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_int4 (actual rows=0 loops=1) + Update on public.metrics_int4 metrics_int4_1 + Update on _timescaledb_internal._hyper_2_2_chunk metrics_int4_2 + Update on _timescaledb_internal._hyper_2_10_chunk metrics_int4_3 + Update on _timescaledb_internal._hyper_2_18_chunk metrics_int4_4 + Update on _timescaledb_internal._hyper_2_26_chunk metrics_int4_5 + -> Hash Join (actual rows=4 loops=1) + Output: '0.1'::double precision, metrics_int2.ctid, metrics_int4.tableoid, metrics_int4.ctid, metrics_int2.tableoid + Inner Unique: true + Hash Cond: (metrics_int4."time" = metrics_int2."time") + -> Append (actual rows=4 loops=1) + -> Seq Scan on public.metrics_int4 metrics_int4_1 (actual rows=0 loops=1) + Output: metrics_int4_1."time", metrics_int4_1.tableoid, metrics_int4_1.ctid + -> Seq Scan on _timescaledb_internal._hyper_2_2_chunk metrics_int4_2 (actual rows=1 loops=1) + Output: metrics_int4_2."time", metrics_int4_2.tableoid, metrics_int4_2.ctid + -> Seq Scan on _timescaledb_internal._hyper_2_10_chunk metrics_int4_3 (actual rows=1 loops=1) + Output: metrics_int4_3."time", metrics_int4_3.tableoid, metrics_int4_3.ctid + -> Seq Scan on _timescaledb_internal._hyper_2_18_chunk metrics_int4_4 (actual rows=1 loops=1) + Output: metrics_int4_4."time", metrics_int4_4.tableoid, metrics_int4_4.ctid + -> Seq Scan on _timescaledb_internal._hyper_2_26_chunk metrics_int4_5 (actual rows=1 loops=1) + Output: metrics_int4_5."time", metrics_int4_5.tableoid, metrics_int4_5.ctid + -> Hash (actual rows=4 loops=1) + Output: metrics_int2.ctid, metrics_int2."time", metrics_int2.tableoid + Buckets: 1024 Batches: 1 + -> HashAggregate (actual rows=4 loops=1) + Output: metrics_int2.ctid, metrics_int2."time", metrics_int2.tableoid + Group Key: metrics_int2."time" + Batches: 1 + -> Append (actual rows=4 loops=1) + -> Seq Scan on public.metrics_int2 metrics_int2_1 (actual rows=0 loops=1) + Output: metrics_int2_1.ctid, metrics_int2_1."time", metrics_int2_1.tableoid + Filter: (metrics_int2_1."time" < length(version())) + -> Index Scan Backward using _hyper_1_1_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_1_chunk metrics_int2_2 (actual rows=1 loops=1) + Output: metrics_int2_2.ctid, metrics_int2_2."time", metrics_int2_2.tableoid + Index Cond: (metrics_int2_2."time" < length(version())) + -> Index Scan Backward using _hyper_1_9_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_9_chunk metrics_int2_3 (actual rows=1 loops=1) + Output: metrics_int2_3.ctid, metrics_int2_3."time", metrics_int2_3.tableoid + Index Cond: (metrics_int2_3."time" < length(version())) + -> Index Scan Backward using _hyper_1_17_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_17_chunk metrics_int2_4 (actual rows=1 loops=1) + Output: metrics_int2_4.ctid, metrics_int2_4."time", metrics_int2_4.tableoid + Index Cond: (metrics_int2_4."time" < length(version())) + -> Index Scan Backward using _hyper_1_25_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_25_chunk metrics_int2_5 (actual rows=1 loops=1) + Output: metrics_int2_5.ctid, metrics_int2_5."time", metrics_int2_5.tableoid + Index Cond: (metrics_int2_5."time" < length(version())) +(45 rows) + +:PREFIX UPDATE metrics_int4 SET value = 0.1 WHERE time IN (SELECT time FROM metrics_int2 WHERE time < length(version())) AND time < length(version()); + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_int4 (actual rows=0 loops=1) + Update on public.metrics_int4 metrics_int4_1 + Update on _timescaledb_internal._hyper_2_2_chunk metrics_int4_2 + Update on _timescaledb_internal._hyper_2_10_chunk metrics_int4_3 + Update on _timescaledb_internal._hyper_2_18_chunk metrics_int4_4 + Update on _timescaledb_internal._hyper_2_26_chunk metrics_int4_5 + -> Hash Join (actual rows=4 loops=1) + Output: '0.1'::double precision, metrics_int2.ctid, metrics_int4.tableoid, metrics_int4.ctid, metrics_int2.tableoid + Inner Unique: true + Hash Cond: (metrics_int4."time" = metrics_int2."time") + -> Append (actual rows=4 loops=1) + -> Seq Scan on public.metrics_int4 metrics_int4_1 (actual rows=0 loops=1) + Output: metrics_int4_1."time", metrics_int4_1.tableoid, metrics_int4_1.ctid + Filter: (metrics_int4_1."time" < length(version())) + -> Index Scan Backward using _hyper_2_2_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_2_chunk metrics_int4_2 (actual rows=1 loops=1) + Output: metrics_int4_2."time", metrics_int4_2.tableoid, metrics_int4_2.ctid + Index Cond: (metrics_int4_2."time" < length(version())) + -> Index Scan Backward using _hyper_2_10_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_10_chunk metrics_int4_3 (actual rows=1 loops=1) + Output: metrics_int4_3."time", metrics_int4_3.tableoid, metrics_int4_3.ctid + Index Cond: (metrics_int4_3."time" < length(version())) + -> Index Scan Backward using _hyper_2_18_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_18_chunk metrics_int4_4 (actual rows=1 loops=1) + Output: metrics_int4_4."time", metrics_int4_4.tableoid, metrics_int4_4.ctid + Index Cond: (metrics_int4_4."time" < length(version())) + -> Index Scan Backward using _hyper_2_26_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_26_chunk metrics_int4_5 (actual rows=1 loops=1) + Output: metrics_int4_5."time", metrics_int4_5.tableoid, metrics_int4_5.ctid + Index Cond: (metrics_int4_5."time" < length(version())) + -> Hash (actual rows=4 loops=1) + Output: metrics_int2.ctid, metrics_int2."time", metrics_int2.tableoid + Buckets: 1024 Batches: 1 + -> HashAggregate (actual rows=4 loops=1) + Output: metrics_int2.ctid, metrics_int2."time", metrics_int2.tableoid + Group Key: metrics_int2."time" + Batches: 1 + -> Append (actual rows=4 loops=1) + -> Seq Scan on public.metrics_int2 metrics_int2_1 (actual rows=0 loops=1) + Output: metrics_int2_1.ctid, metrics_int2_1."time", metrics_int2_1.tableoid + Filter: (metrics_int2_1."time" < length(version())) + -> Index Scan Backward using _hyper_1_1_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_1_chunk metrics_int2_2 (actual rows=1 loops=1) + Output: metrics_int2_2.ctid, metrics_int2_2."time", metrics_int2_2.tableoid + Index Cond: (metrics_int2_2."time" < length(version())) + -> Index Scan Backward using _hyper_1_9_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_9_chunk metrics_int2_3 (actual rows=1 loops=1) + Output: metrics_int2_3.ctid, metrics_int2_3."time", metrics_int2_3.tableoid + Index Cond: (metrics_int2_3."time" < length(version())) + -> Index Scan Backward using _hyper_1_17_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_17_chunk metrics_int2_4 (actual rows=1 loops=1) + Output: metrics_int2_4.ctid, metrics_int2_4."time", metrics_int2_4.tableoid + Index Cond: (metrics_int2_4."time" < length(version())) + -> Index Scan Backward using _hyper_1_25_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_25_chunk metrics_int2_5 (actual rows=1 loops=1) + Output: metrics_int2_5.ctid, metrics_int2_5."time", metrics_int2_5.tableoid + Index Cond: (metrics_int2_5."time" < length(version())) +(50 rows) + +-- join +-- no chunk exclusion for subqueries joins atm +:PREFIX UPDATE metrics_int4 m4 SET value = 0.15 FROM metrics_int2 m2; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_int4 m4 (actual rows=0 loops=1) + Update on public.metrics_int4 m4_1 + Update on _timescaledb_internal._hyper_2_2_chunk m4_2 + Update on _timescaledb_internal._hyper_2_10_chunk m4_3 + Update on _timescaledb_internal._hyper_2_18_chunk m4_4 + Update on _timescaledb_internal._hyper_2_26_chunk m4_5 + -> Nested Loop (actual rows=16 loops=1) + Output: '0.15'::double precision, m2.ctid, m4.tableoid, m4.ctid, m2.tableoid + -> Append (actual rows=4 loops=1) + -> Seq Scan on public.metrics_int2 m2_1 (actual rows=0 loops=1) + Output: m2_1.ctid, m2_1.tableoid + -> Seq Scan on _timescaledb_internal._hyper_1_1_chunk m2_2 (actual rows=1 loops=1) + Output: m2_2.ctid, m2_2.tableoid + -> Seq Scan on _timescaledb_internal._hyper_1_9_chunk m2_3 (actual rows=1 loops=1) + Output: m2_3.ctid, m2_3.tableoid + -> Seq Scan on _timescaledb_internal._hyper_1_17_chunk m2_4 (actual rows=1 loops=1) + Output: m2_4.ctid, m2_4.tableoid + -> Seq Scan on _timescaledb_internal._hyper_1_25_chunk m2_5 (actual rows=1 loops=1) + Output: m2_5.ctid, m2_5.tableoid + -> Materialize (actual rows=4 loops=4) + Output: m4.tableoid, m4.ctid + -> Append (actual rows=4 loops=1) + -> Seq Scan on public.metrics_int4 m4_1 (actual rows=0 loops=1) + Output: m4_1.tableoid, m4_1.ctid + -> Seq Scan on _timescaledb_internal._hyper_2_2_chunk m4_2 (actual rows=1 loops=1) + Output: m4_2.tableoid, m4_2.ctid + -> Seq Scan on _timescaledb_internal._hyper_2_10_chunk m4_3 (actual rows=1 loops=1) + Output: m4_3.tableoid, m4_3.ctid + -> Seq Scan on _timescaledb_internal._hyper_2_18_chunk m4_4 (actual rows=1 loops=1) + Output: m4_4.tableoid, m4_4.ctid + -> Seq Scan on _timescaledb_internal._hyper_2_26_chunk m4_5 (actual rows=1 loops=1) + Output: m4_5.tableoid, m4_5.ctid +(33 rows) + +:PREFIX UPDATE metrics_int4 m4 SET value = 0.15 FROM metrics_int2 m2 WHERE m4.time = m2.time; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_int4 m4 (actual rows=0 loops=1) + Update on public.metrics_int4 m4_1 + Update on _timescaledb_internal._hyper_2_2_chunk m4_2 + Update on _timescaledb_internal._hyper_2_10_chunk m4_3 + Update on _timescaledb_internal._hyper_2_18_chunk m4_4 + Update on _timescaledb_internal._hyper_2_26_chunk m4_5 + -> Merge Join (actual rows=4 loops=1) + Output: '0.15'::double precision, m2.ctid, m4.tableoid, m4.ctid, m2.tableoid + Merge Cond: (m4."time" = m2."time") + -> Merge Append (actual rows=4 loops=1) + Sort Key: m4."time" + -> Index Scan Backward using metrics_int4_time_idx on public.metrics_int4 m4_1 (actual rows=0 loops=1) + Output: m4_1."time", m4_1.tableoid, m4_1.ctid + -> Index Scan Backward using _hyper_2_2_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_2_chunk m4_2 (actual rows=1 loops=1) + Output: m4_2."time", m4_2.tableoid, m4_2.ctid + -> Index Scan Backward using _hyper_2_10_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_10_chunk m4_3 (actual rows=1 loops=1) + Output: m4_3."time", m4_3.tableoid, m4_3.ctid + -> Index Scan Backward using _hyper_2_18_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_18_chunk m4_4 (actual rows=1 loops=1) + Output: m4_4."time", m4_4.tableoid, m4_4.ctid + -> Index Scan Backward using _hyper_2_26_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_26_chunk m4_5 (actual rows=1 loops=1) + Output: m4_5."time", m4_5.tableoid, m4_5.ctid + -> Materialize (actual rows=4 loops=1) + Output: m2.ctid, m2."time", m2.tableoid + -> Merge Append (actual rows=4 loops=1) + Sort Key: m2."time" + -> Index Scan Backward using metrics_int2_time_idx on public.metrics_int2 m2_1 (actual rows=0 loops=1) + Output: m2_1.ctid, m2_1."time", m2_1.tableoid + -> Index Scan Backward using _hyper_1_1_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_1_chunk m2_2 (actual rows=1 loops=1) + Output: m2_2.ctid, m2_2."time", m2_2.tableoid + -> Index Scan Backward using _hyper_1_9_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_9_chunk m2_3 (actual rows=1 loops=1) + Output: m2_3.ctid, m2_3."time", m2_3.tableoid + -> Index Scan Backward using _hyper_1_17_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_17_chunk m2_4 (actual rows=1 loops=1) + Output: m2_4.ctid, m2_4."time", m2_4.tableoid + -> Index Scan Backward using _hyper_1_25_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_25_chunk m2_5 (actual rows=1 loops=1) + Output: m2_5.ctid, m2_5."time", m2_5.tableoid +(36 rows) + +:PREFIX UPDATE metrics_int4 m4 SET value = 0.15 FROM metrics_int2 m2 WHERE m4.time = m2.time AND m4.time < length(version()); + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_int4 m4 (actual rows=0 loops=1) + Update on public.metrics_int4 m4_1 + Update on _timescaledb_internal._hyper_2_2_chunk m4_2 + Update on _timescaledb_internal._hyper_2_10_chunk m4_3 + Update on _timescaledb_internal._hyper_2_18_chunk m4_4 + Update on _timescaledb_internal._hyper_2_26_chunk m4_5 + -> Merge Join (actual rows=4 loops=1) + Output: '0.15'::double precision, m2.ctid, m4.tableoid, m4.ctid, m2.tableoid + Merge Cond: (m4."time" = m2."time") + -> Merge Append (actual rows=4 loops=1) + Sort Key: m4."time" + -> Index Scan Backward using metrics_int4_time_idx on public.metrics_int4 m4_1 (actual rows=0 loops=1) + Output: m4_1."time", m4_1.tableoid, m4_1.ctid + Index Cond: (m4_1."time" < length(version())) + -> Index Scan Backward using _hyper_2_2_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_2_chunk m4_2 (actual rows=1 loops=1) + Output: m4_2."time", m4_2.tableoid, m4_2.ctid + Index Cond: (m4_2."time" < length(version())) + -> Index Scan Backward using _hyper_2_10_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_10_chunk m4_3 (actual rows=1 loops=1) + Output: m4_3."time", m4_3.tableoid, m4_3.ctid + Index Cond: (m4_3."time" < length(version())) + -> Index Scan Backward using _hyper_2_18_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_18_chunk m4_4 (actual rows=1 loops=1) + Output: m4_4."time", m4_4.tableoid, m4_4.ctid + Index Cond: (m4_4."time" < length(version())) + -> Index Scan Backward using _hyper_2_26_chunk_metrics_int4_time_idx on _timescaledb_internal._hyper_2_26_chunk m4_5 (actual rows=1 loops=1) + Output: m4_5."time", m4_5.tableoid, m4_5.ctid + Index Cond: (m4_5."time" < length(version())) + -> Materialize (actual rows=4 loops=1) + Output: m2.ctid, m2."time", m2.tableoid + -> Merge Append (actual rows=4 loops=1) + Sort Key: m2."time" + -> Index Scan Backward using metrics_int2_time_idx on public.metrics_int2 m2_1 (actual rows=0 loops=1) + Output: m2_1.ctid, m2_1."time", m2_1.tableoid + -> Index Scan Backward using _hyper_1_1_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_1_chunk m2_2 (actual rows=1 loops=1) + Output: m2_2.ctid, m2_2."time", m2_2.tableoid + -> Index Scan Backward using _hyper_1_9_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_9_chunk m2_3 (actual rows=1 loops=1) + Output: m2_3.ctid, m2_3."time", m2_3.tableoid + -> Index Scan Backward using _hyper_1_17_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_17_chunk m2_4 (actual rows=1 loops=1) + Output: m2_4.ctid, m2_4."time", m2_4.tableoid + -> Index Scan Backward using _hyper_1_25_chunk_metrics_int2_time_idx on _timescaledb_internal._hyper_1_25_chunk m2_5 (actual rows=1 loops=1) + Output: m2_5.ctid, m2_5."time", m2_5.tableoid +(41 rows) + +-- test interaction with compression +-- with chunk exclusion for compressed chunks operations that would +-- error because they hit compressed chunks before can succeed now +-- if those chunks get excluded +CREATE TABLE metrics_compressed(time timestamptz NOT NULL, device int, value float); +SELECT table_name FROM create_hypertable('metrics_compressed','time'); + table_name +-------------------- + metrics_compressed +(1 row) + +ALTER TABLE metrics_compressed SET (timescaledb.compress); +-- create first chunk and compress +INSERT INTO metrics_compressed VALUES ('2000-01-01',1,0.5); +SELECT count(compress_chunk(chunk)) FROM show_chunks('metrics_compressed') chunk; + count +------- + 1 +(1 row) + +-- create more chunks +INSERT INTO metrics_compressed VALUES ('2010-01-01',1,0.5),('2011-01-01',1,0.5),('2012-01-01',1,0.5); +-- update uncompressed chunks with non-immutable constraints +BEGIN; +:PREFIX UPDATE metrics_compressed SET value = 2 * value WHERE time > '2005-01-01'::text::timestamptz; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Custom Scan (HypertableModify) (actual rows=0 loops=1) + -> Update on public.metrics_compressed (actual rows=0 loops=1) + Update on public.metrics_compressed metrics_compressed_1 + Update on _timescaledb_internal._hyper_8_33_chunk metrics_compressed + Update on _timescaledb_internal._hyper_8_35_chunk metrics_compressed_2 + Update on _timescaledb_internal._hyper_8_36_chunk metrics_compressed_3 + Update on _timescaledb_internal._hyper_8_37_chunk metrics_compressed_4 + -> Custom Scan (ChunkAppend) on public.metrics_compressed (actual rows=3 loops=1) + Output: ('2'::double precision * metrics_compressed.value), metrics_compressed.tableoid, metrics_compressed.ctid + Startup Exclusion: true + Runtime Exclusion: false + Chunks excluded during startup: 1 + -> Seq Scan on public.metrics_compressed metrics_compressed_1 (actual rows=0 loops=1) + Output: metrics_compressed_1.value, metrics_compressed_1.tableoid, metrics_compressed_1.ctid + Filter: (metrics_compressed_1."time" > ('2005-01-01'::cstring)::timestamp with time zone) + -> Index Scan using _hyper_8_35_chunk_metrics_compressed_time_idx on _timescaledb_internal._hyper_8_35_chunk metrics_compressed_2 (actual rows=1 loops=1) + Output: metrics_compressed_2.value, metrics_compressed_2.tableoid, metrics_compressed_2.ctid + Index Cond: (metrics_compressed_2."time" > ('2005-01-01'::cstring)::timestamp with time zone) + -> Index Scan using _hyper_8_36_chunk_metrics_compressed_time_idx on _timescaledb_internal._hyper_8_36_chunk metrics_compressed_3 (actual rows=1 loops=1) + Output: metrics_compressed_3.value, metrics_compressed_3.tableoid, metrics_compressed_3.ctid + Index Cond: (metrics_compressed_3."time" > ('2005-01-01'::cstring)::timestamp with time zone) + -> Index Scan using _hyper_8_37_chunk_metrics_compressed_time_idx on _timescaledb_internal._hyper_8_37_chunk metrics_compressed_4 (actual rows=1 loops=1) + Output: metrics_compressed_4.value, metrics_compressed_4.tableoid, metrics_compressed_4.ctid + Index Cond: (metrics_compressed_4."time" > ('2005-01-01'::cstring)::timestamp with time zone) +(24 rows) + +ROLLBACK; diff --git a/tsl/test/sql/CMakeLists.txt b/tsl/test/sql/CMakeLists.txt index f9023bf295e..c972c4a3dee 100644 --- a/tsl/test/sql/CMakeLists.txt +++ b/tsl/test/sql/CMakeLists.txt @@ -89,7 +89,7 @@ if(CMAKE_BUILD_TYPE MATCHES Debug) endif(CMAKE_BUILD_TYPE MATCHES Debug) if((${PG_VERSION_MAJOR} GREATER_EQUAL "14")) - list(APPEND TEST_FILES_postgresql delete_exclusion.sql) + list(APPEND TEST_FILES_postgresql delete_exclusion.sql update_exclusion.sql) endif() set(SOLO_TESTS_postgresql diff --git a/tsl/test/sql/update_exclusion.sql b/tsl/test/sql/update_exclusion.sql new file mode 100644 index 00000000000..70b5b569de6 --- /dev/null +++ b/tsl/test/sql/update_exclusion.sql @@ -0,0 +1,167 @@ +-- This file and its contents are licensed under the Timescale License. +-- Please see the included NOTICE for copyright information and +-- LICENSE-TIMESCALE for a copy of the license. + +\set PREFIX 'EXPLAIN (ANALYZE,VERBOSE,SUMMARY OFF,TIMING OFF,COSTS OFF)' + +CREATE TABLE metrics_int2(c1 int,c2 int, c3 int, c4 int, c5 int, time int2 NOT NULL, value float); +CREATE TABLE metrics_int4(c1 int,c2 int, c3 int, c4 int, c5 int, time int4 NOT NULL, value float); +CREATE TABLE metrics_int8(c1 int,c2 int, c3 int, c4 int, c5 int, time int8 NOT NULL, value float); +CREATE TABLE metrics_date(c1 int,c2 int, c3 int, c4 int, c5 int, time date NOT NULL, value float); +CREATE TABLE metrics_timestamp(c1 int,c2 int, c3 int, c4 int, c5 int, time timestamp NOT NULL, value float); +CREATE TABLE metrics_timestamptz(c1 int,c2 int, c3 int, c4 int, c5 int, time timestamptz NOT NULL, value float); +CREATE TABLE metrics_space(c1 int,c2 int, c3 int, c4 int, c5 int, time timestamp NOT NULL, device text, value float); + +SELECT table_name FROM create_hypertable('metrics_int2','time',chunk_time_interval:=10); +SELECT table_name FROM create_hypertable('metrics_int4','time',chunk_time_interval:=10); +SELECT table_name FROM create_hypertable('metrics_int8','time',chunk_time_interval:=10); +SELECT table_name FROM create_hypertable('metrics_date','time'); +SELECT table_name FROM create_hypertable('metrics_timestamp','time'); +SELECT table_name FROM create_hypertable('metrics_timestamptz','time'); +SELECT table_name FROM create_hypertable('metrics_space','time','device',4); + +CREATE FUNCTION drop_column(text) RETURNS VOID LANGUAGE PLPGSQL AS $$ +DECLARE + tbl name; +BEGIN + FOR tbl IN SELECT 'metrics_' || unnest(ARRAY['int2','int4','int8','date','timestamp','timestamptz','space']) + LOOP + EXECUTE format('ALTER TABLE %I DROP COLUMN %I;', tbl, $1); + END LOOP; +END; +$$; + +-- create 4 chunks each with different physical layout +SELECT drop_column('c1'); +INSERT INTO metrics_int2(time) VALUES (0); +INSERT INTO metrics_int4(time) VALUES (0); +INSERT INTO metrics_int8(time) VALUES (0); +INSERT INTO metrics_date(time) VALUES ('2000-01-01'); +INSERT INTO metrics_timestamp(time) VALUES ('2000-01-01'); +INSERT INTO metrics_timestamptz(time) VALUES ('2000-01-01'); +INSERT INTO metrics_space(time,device) VALUES ('2000-01-01','1'),('2000-01-01','2'); + +SELECT drop_column('c2'); +INSERT INTO metrics_int2(time) VALUES (10); +INSERT INTO metrics_int4(time) VALUES (10); +INSERT INTO metrics_int8(time) VALUES (10); +INSERT INTO metrics_date(time) VALUES ('2001-01-01'); +INSERT INTO metrics_timestamp(time) VALUES ('2001-01-01'); +INSERT INTO metrics_timestamptz(time) VALUES ('2001-01-01'); +INSERT INTO metrics_space(time,device) VALUES ('2001-01-01','1'),('2001-01-01','2'); + +SELECT drop_column('c3'); +INSERT INTO metrics_int2(time) VALUES (20); +INSERT INTO metrics_int4(time) VALUES (20); +INSERT INTO metrics_int8(time) VALUES (20); +INSERT INTO metrics_date(time) VALUES ('2002-01-01'); +INSERT INTO metrics_timestamp(time) VALUES ('2002-01-01'); +INSERT INTO metrics_timestamptz(time) VALUES ('2002-01-01'); +INSERT INTO metrics_space(time,device) VALUES ('2002-01-01','1'),('2002-01-01','2'); + +SELECT drop_column('c4'); +INSERT INTO metrics_int2(time) VALUES (30); +INSERT INTO metrics_int4(time) VALUES (30); +INSERT INTO metrics_int8(time) VALUES (30); +INSERT INTO metrics_date(time) VALUES ('2003-01-01'); +INSERT INTO metrics_timestamp(time) VALUES ('2003-01-01'); +INSERT INTO metrics_timestamptz(time) VALUES ('2003-01-01'); +INSERT INTO metrics_space(time,device) VALUES ('2003-01-01','1'),('2003-01-01','2'); + +SELECT drop_column('c5'); + +-- immutable constraints +-- should not have ChunkAppend since constraint is immutable and postgres already does the exclusion +-- should only hit 1 chunk and base table +BEGIN; +:PREFIX UPDATE metrics_int2 SET value = 0.5 WHERE time = 15; +:PREFIX UPDATE metrics_int4 SET value = 0.5 WHERE time = 15; +:PREFIX UPDATE metrics_int8 SET value = 0.5 WHERE time = 15; +ROLLBACK; + +-- stable constraints +-- should have ChunkAppend since constraint is stable +-- should only hit 1 chunk and base table +BEGIN; +:PREFIX UPDATE metrics_int2 SET value = 0.3 WHERE time = length(substring(version(),1,23)); +:PREFIX UPDATE metrics_int4 SET value = 0.3 WHERE time = length(substring(version(),1,23)); +:PREFIX UPDATE metrics_int8 SET value = 0.3 WHERE time = length(substring(version(),1,23)); +ROLLBACK; + +-- should have ChunkAppend since constraint is stable +-- should only hit 1 chunk and base table, toplevel rows should be 1 +BEGIN; +:PREFIX UPDATE metrics_int2 SET value = 0.4 WHERE time = length(substring(version(),1,20)) RETURNING 'returning', time; +:PREFIX UPDATE metrics_int4 SET value = 0.4 WHERE time = length(substring(version(),1,20)) RETURNING 'returning', time; +:PREFIX UPDATE metrics_int8 SET value = 0.4 WHERE time = length(substring(version(),1,20)) RETURNING 'returning', time; +ROLLBACK; + +-- immutable constraints +-- should not have ChunkAppend since constraint is immutable and postgres already does the exclusion +-- should only hit 1 chunk and base table +BEGIN; +:PREFIX UPDATE metrics_date SET value = 0.6 WHERE time = '2000-01-01'; +:PREFIX UPDATE metrics_timestamp SET value = 0.6 WHERE time = '2000-01-01'; +:PREFIX UPDATE metrics_timestamptz SET value = 0.6 WHERE time = '2000-01-01'; +:PREFIX UPDATE metrics_space SET value = 0.6 WHERE time = '2000-01-01' AND device = '1'; +:PREFIX UPDATE metrics_space SET value = 0.6 WHERE time = '2000-01-01'; +ROLLBACK; + +-- stable constraints +-- should have ChunkAppend since constraint is stable +-- should only hit 1 chunk and base table +BEGIN; +:PREFIX UPDATE metrics_date SET value = 0.9 WHERE time = '2000-01-01'::text::date; +:PREFIX UPDATE metrics_timestamp SET value = 0.9 WHERE time = '2000-01-01'::text::timestamp; +:PREFIX UPDATE metrics_timestamptz SET value = 0.9 WHERE time = '2000-01-01'::text::timestamptz; +ROLLBACK; + +-- space partitioning +-- should have ChunkAppend since constraint is stable +-- should only hit 1 chunk and base table +BEGIN; +:PREFIX UPDATE metrics_space SET value = 0.1 WHERE time = '2000-01-01'::text::timestamptz AND device = format('1'); +ROLLBACK; +BEGIN; +:PREFIX UPDATE metrics_space SET value = 0.1 WHERE device = format('1'); +ROLLBACK; + +-- should have ChunkAppend since constraint is stable +-- should only hit 1 chunk and base table, toplevel rows should be 1 +BEGIN; +:PREFIX UPDATE metrics_date SET value = 0.2 WHERE time = '2000-01-01'::text::date RETURNING 'returning', time; +:PREFIX UPDATE metrics_timestamp SET value = 0.2 WHERE time = '2000-01-01'::text::timestamp RETURNING 'returning', time; +:PREFIX UPDATE metrics_timestamptz SET value = 0.2 WHERE time = '2000-01-01'::text::timestamptz RETURNING 'returning', time; +ROLLBACK; + +-- subselects +-- no chunk exclusion for subqueries joins atm +:PREFIX UPDATE metrics_int4 SET value = 0.1 WHERE time IN (SELECT time FROM metrics_int2) AND time < length(version()); +:PREFIX UPDATE metrics_int4 SET value = 0.1 WHERE time IN (SELECT time FROM metrics_int2 WHERE time < length(version())); +:PREFIX UPDATE metrics_int4 SET value = 0.1 WHERE time IN (SELECT time FROM metrics_int2 WHERE time < length(version())) AND time < length(version()); + +-- join +-- no chunk exclusion for subqueries joins atm +:PREFIX UPDATE metrics_int4 m4 SET value = 0.15 FROM metrics_int2 m2; +:PREFIX UPDATE metrics_int4 m4 SET value = 0.15 FROM metrics_int2 m2 WHERE m4.time = m2.time; +:PREFIX UPDATE metrics_int4 m4 SET value = 0.15 FROM metrics_int2 m2 WHERE m4.time = m2.time AND m4.time < length(version()); + +-- test interaction with compression +-- with chunk exclusion for compressed chunks operations that would +-- error because they hit compressed chunks before can succeed now +-- if those chunks get excluded +CREATE TABLE metrics_compressed(time timestamptz NOT NULL, device int, value float); +SELECT table_name FROM create_hypertable('metrics_compressed','time'); +ALTER TABLE metrics_compressed SET (timescaledb.compress); + +-- create first chunk and compress +INSERT INTO metrics_compressed VALUES ('2000-01-01',1,0.5); +SELECT count(compress_chunk(chunk)) FROM show_chunks('metrics_compressed') chunk; + +-- create more chunks +INSERT INTO metrics_compressed VALUES ('2010-01-01',1,0.5),('2011-01-01',1,0.5),('2012-01-01',1,0.5); + +-- update uncompressed chunks with non-immutable constraints +BEGIN; +:PREFIX UPDATE metrics_compressed SET value = 2 * value WHERE time > '2005-01-01'::text::timestamptz; +ROLLBACK;