Route UPDATE through HypertableModify

Route UPDATE on Hypertables through our custom HypertableModify
node. This patch by itself does not make any other changes to
UPDATE but is the foundation for other features regarding UPDATE
on hypertables.
This commit is contained in:
Sven Klemm 2022-03-18 05:33:35 +01:00 committed by Sven Klemm
parent 846878c6bb
commit 566a4ff104
5 changed files with 72 additions and 66 deletions

View File

@ -480,12 +480,12 @@ hypertable_modify_plan_create(PlannerInfo *root, RelOptInfo *rel, CustomPath *be
cscan->scan.plan.targetlist = copyObject(root->processed_tlist); cscan->scan.plan.targetlist = copyObject(root->processed_tlist);
/* /*
* For DELETE processed_tlist will have ROWID_VAR. We need to remove * For UPDATE/DELETE processed_tlist will have ROWID_VAR. We need to remove
* those because set_customscan_references will bail if it sees * those because set_customscan_references will bail if it sees
* ROWID_VAR entries in the targetlist. * ROWID_VAR entries in the targetlist.
*/ */
#if PG14_GE #if PG14_GE
if (mt->operation == CMD_DELETE) if (mt->operation == CMD_UPDATE || mt->operation == CMD_DELETE)
{ {
ListCell *lc; ListCell *lc;
foreach (lc, cscan->scan.plan.targetlist) foreach (lc, cscan->scan.plan.targetlist)
@ -500,8 +500,9 @@ hypertable_modify_plan_create(PlannerInfo *root, RelOptInfo *rel, CustomPath *be
} }
} }
#else #else
/* We only route DELETEs through our CustomNode for PG 14+ because /*
* the codepath for earlier versions is different. */ * For postgres versions < PG14 we only route INSERT through our custom node.
*/
Assert(mt->operation == CMD_INSERT); Assert(mt->operation == CMD_INSERT);
#endif #endif
cscan->custom_scan_tlist = cscan->scan.plan.targetlist; cscan->custom_scan_tlist = cscan->scan.plan.targetlist;

View File

@ -1137,9 +1137,10 @@ replace_hypertable_modify_paths(PlannerInfo *root, List *pathlist)
ModifyTablePath *mt = castNode(ModifyTablePath, path); ModifyTablePath *mt = castNode(ModifyTablePath, path);
#if PG14_GE #if PG14_GE
/* We only route DELETEs through our CustomNode for PG 14+ because /* We only route UPDATE/DELETE through our CustomNode for PG 14+ because
* the codepath for earlier versions is different. */ * the codepath for earlier versions is different. */
if (mt->operation == CMD_INSERT || mt->operation == CMD_DELETE) if (mt->operation == CMD_INSERT || mt->operation == CMD_UPDATE ||
mt->operation == CMD_DELETE)
#else #else
if (mt->operation == CMD_INSERT) if (mt->operation == CMD_INSERT)
#endif #endif

View File

@ -2265,19 +2265,20 @@ INSERT INTO bv1 VALUES (11, 'xxx'); -- should fail RLS check
ERROR: new row violates row-level security policy for table "b1" ERROR: new row violates row-level security policy for table "b1"
INSERT INTO bv1 VALUES (12, 'xxx'); -- ok INSERT INTO bv1 VALUES (12, 'xxx'); -- ok
EXPLAIN (COSTS OFF) UPDATE bv1 SET b = 'yyy' WHERE a = 4 AND f_leak(b); EXPLAIN (COSTS OFF) UPDATE bv1 SET b = 'yyy' WHERE a = 4 AND f_leak(b);
QUERY PLAN QUERY PLAN
----------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------------
Update on b1 Custom Scan (HypertableModify)
Update on b1 b1_1 -> Update on b1
Update on _hyper_8_41_chunk b1_2 Update on b1 b1_1
-> Result Update on _hyper_8_41_chunk b1_2
-> Append -> Result
-> Seq Scan on b1 b1_1 -> Append
Filter: ((a > 0) AND (a = 4) AND ((a % 2) = 0) AND f_leak(b)) -> Seq Scan on b1 b1_1
-> Index Scan using _hyper_8_41_chunk_b1_a_idx on _hyper_8_41_chunk b1_2 Filter: ((a > 0) AND (a = 4) AND ((a % 2) = 0) AND f_leak(b))
Index Cond: ((a > 0) AND (a = 4)) -> Index Scan using _hyper_8_41_chunk_b1_a_idx on _hyper_8_41_chunk b1_2
Filter: (((a % 2) = 0) AND f_leak(b)) Index Cond: ((a > 0) AND (a = 4))
(10 rows) Filter: (((a % 2) = 0) AND f_leak(b))
(11 rows)
UPDATE bv1 SET b = 'yyy' WHERE a = 4 AND f_leak(b); UPDATE bv1 SET b = 'yyy' WHERE a = 4 AND f_leak(b);
NOTICE: f_leak => a87ff679a2f3e71d9181a67b7542122c NOTICE: f_leak => a87ff679a2f3e71d9181a67b7542122c
@ -4354,19 +4355,20 @@ SELECT * FROM current_check;
-- Plan should be a subquery TID scan -- Plan should be a subquery TID scan
EXPLAIN (COSTS OFF) UPDATE current_check SET payload = payload WHERE CURRENT OF current_check_cursor; EXPLAIN (COSTS OFF) UPDATE current_check SET payload = payload WHERE CURRENT OF current_check_cursor;
QUERY PLAN QUERY PLAN
------------------------------------------------------------------- -------------------------------------------------------------------------
Update on current_check Custom Scan (HypertableModify)
Update on current_check current_check_1 -> Update on current_check
Update on _hyper_21_104_chunk current_check_2 Update on current_check current_check_1
-> Append Update on _hyper_21_104_chunk current_check_2
-> Tid Scan on current_check current_check_1 -> Append
TID Cond: CURRENT OF current_check_cursor -> Tid Scan on current_check current_check_1
Filter: ((currentid = 4) AND ((currentid % 2) = 0)) TID Cond: CURRENT OF current_check_cursor
-> Tid Scan on _hyper_21_104_chunk current_check_2 Filter: ((currentid = 4) AND ((currentid % 2) = 0))
TID Cond: CURRENT OF current_check_cursor -> Tid Scan on _hyper_21_104_chunk current_check_2
Filter: ((currentid = 4) AND ((currentid % 2) = 0)) TID Cond: CURRENT OF current_check_cursor
(10 rows) Filter: ((currentid = 4) AND ((currentid % 2) = 0))
(11 rows)
-- Similarly can only delete row 4 -- Similarly can only delete row 4
FETCH ABSOLUTE 1 FROM current_check_cursor; FETCH ABSOLUTE 1 FROM current_check_cursor;

View File

@ -81,33 +81,34 @@ EXPLAIN (costs off)
UPDATE "one_Partition" UPDATE "one_Partition"
SET series_1 = 8 SET series_1 = 8
WHERE series_1 IN (SELECT series_1 FROM "one_Partition" WHERE series_1 > series_val()); WHERE series_1 IN (SELECT series_1 FROM "one_Partition" WHERE series_1 > series_val());
QUERY PLAN QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------------------------------------------------------------------
Update on "one_Partition" Custom Scan (HypertableModify)
Update on "one_Partition" "one_Partition_2" -> Update on "one_Partition"
Update on _hyper_1_1_chunk "one_Partition_3" Update on "one_Partition" "one_Partition_2"
Update on _hyper_1_2_chunk "one_Partition_4" Update on _hyper_1_1_chunk "one_Partition_3"
Update on _hyper_1_3_chunk "one_Partition_5" Update on _hyper_1_2_chunk "one_Partition_4"
-> Hash Join Update on _hyper_1_3_chunk "one_Partition_5"
Hash Cond: ("one_Partition".series_1 = "one_Partition_1".series_1) -> Hash Join
-> Append Hash Cond: ("one_Partition".series_1 = "one_Partition_1".series_1)
-> Seq Scan on "one_Partition" "one_Partition_2" -> Append
-> Seq Scan on _hyper_1_1_chunk "one_Partition_3" -> Seq Scan on "one_Partition" "one_Partition_2"
-> Seq Scan on _hyper_1_2_chunk "one_Partition_4" -> Seq Scan on _hyper_1_1_chunk "one_Partition_3"
-> Seq Scan on _hyper_1_3_chunk "one_Partition_5" -> Seq Scan on _hyper_1_2_chunk "one_Partition_4"
-> Hash -> Seq Scan on _hyper_1_3_chunk "one_Partition_5"
-> HashAggregate -> Hash
Group Key: "one_Partition_1".series_1 -> HashAggregate
-> Append Group Key: "one_Partition_1".series_1
-> Seq Scan on "one_Partition" "one_Partition_6" -> Append
Filter: (series_1 > (series_val())::double precision) -> Seq Scan on "one_Partition" "one_Partition_6"
-> Index Scan using "_hyper_1_1_chunk_one_Partition_timeCustom_series_1_idx" on _hyper_1_1_chunk "one_Partition_7" Filter: (series_1 > (series_val())::double precision)
Index Cond: (series_1 > (series_val())::double precision) -> Index Scan using "_hyper_1_1_chunk_one_Partition_timeCustom_series_1_idx" on _hyper_1_1_chunk "one_Partition_7"
-> Index Scan using "_hyper_1_2_chunk_one_Partition_timeCustom_series_1_idx" on _hyper_1_2_chunk "one_Partition_8" Index Cond: (series_1 > (series_val())::double precision)
Index Cond: (series_1 > (series_val())::double precision) -> Index Scan using "_hyper_1_2_chunk_one_Partition_timeCustom_series_1_idx" on _hyper_1_2_chunk "one_Partition_8"
-> Index Scan using "_hyper_1_3_chunk_one_Partition_timeCustom_series_1_idx" on _hyper_1_3_chunk "one_Partition_9" Index Cond: (series_1 > (series_val())::double precision)
Index Cond: (series_1 > (series_val())::double precision) -> Index Scan using "_hyper_1_3_chunk_one_Partition_timeCustom_series_1_idx" on _hyper_1_3_chunk "one_Partition_9"
(24 rows) Index Cond: (series_1 > (series_val())::double precision)
(25 rows)
SELECT * FROM "one_Partition" ORDER BY "timeCustom", device_id, series_0, series_1, series_2; SELECT * FROM "one_Partition" ORDER BY "timeCustom", device_id, series_0, series_1, series_2;
timeCustom | device_id | series_0 | series_1 | series_2 | series_bool timeCustom | device_id | series_0 | series_1 | series_2 | series_bool

View File

@ -141,13 +141,14 @@ SELECT * FROM jit_test_interval WHERE id >= 23 and id < 73 ORDER BY id;
:PREFIX :PREFIX
UPDATE jit_test_interval SET temp = temp * 2.3 WHERE id >= 23 and id < 73; UPDATE jit_test_interval SET temp = temp * 2.3 WHERE id >= 23 and id < 73;
QUERY PLAN QUERY PLAN
------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------
Update on public.jit_test_interval Custom Scan (HypertableModify)
-> Index Scan using jit_test_interval_id_idx on public.jit_test_interval -> Update on public.jit_test_interval
Output: (temp * '2.3'::double precision), ctid -> Index Scan using jit_test_interval_id_idx on public.jit_test_interval
Index Cond: ((jit_test_interval.id >= 23) AND (jit_test_interval.id < 73)) Output: (temp * '2.3'::double precision), ctid
(4 rows) Index Cond: ((jit_test_interval.id >= 23) AND (jit_test_interval.id < 73))
(5 rows)
:PREFIX :PREFIX
SELECT * FROM jit_test_interval ORDER BY id; SELECT * FROM jit_test_interval ORDER BY id;