Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit be634f0

Browse files
improved support for rowmarks (select for share; update; delete; etc)
1 parent 62e4952 commit be634f0

File tree

7 files changed

+234
-185
lines changed

7 files changed

+234
-185
lines changed

‎expected/pathman_rowmarks.out‎

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,148 @@ FOR SHARE;
168168
6
169169
(1 row)
170170

171+
/* Check updates (plan) */
172+
EXPLAIN (COSTS OFF)
173+
UPDATE rowmarks.second SET id = 2
174+
WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id = 1);
175+
QUERY PLAN
176+
---------------------------------------------
177+
Update on second
178+
-> Nested Loop Semi Join
179+
-> Seq Scan on second
180+
Filter: (id = 1)
181+
-> Materialize
182+
-> Append
183+
-> Seq Scan on first_0
184+
Filter: (id = 1)
185+
(8 rows)
186+
187+
EXPLAIN (COSTS OFF)
188+
UPDATE rowmarks.second SET id = 2
189+
WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id < 1);
190+
QUERY PLAN
191+
---------------------------------------------------
192+
Update on second
193+
-> Hash Join
194+
Hash Cond: (second.id = first_0.id)
195+
-> Seq Scan on second
196+
-> Hash
197+
-> HashAggregate
198+
Group Key: first_0.id
199+
-> Append
200+
-> Seq Scan on first_0
201+
Filter: (id < 1)
202+
-> Seq Scan on first_1
203+
Filter: (id < 1)
204+
-> Seq Scan on first_2
205+
Filter: (id < 1)
206+
-> Seq Scan on first_3
207+
Filter: (id < 1)
208+
-> Seq Scan on first_4
209+
Filter: (id < 1)
210+
(18 rows)
211+
212+
EXPLAIN (COSTS OFF)
213+
UPDATE rowmarks.second SET id = 2
214+
WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id = 1 OR id = 2);
215+
QUERY PLAN
216+
---------------------------------------------
217+
Update on second
218+
-> Hash Semi Join
219+
Hash Cond: (second.id = first_0.id)
220+
-> Seq Scan on second
221+
-> Hash
222+
-> Append
223+
-> Seq Scan on first_0
224+
Filter: (id = 1)
225+
-> Seq Scan on first_1
226+
Filter: (id = 2)
227+
(10 rows)
228+
229+
EXPLAIN (COSTS OFF)
230+
UPDATE rowmarks.second SET id = 2
231+
WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id = 1)
232+
RETURNING *, tableoid::regclass;
233+
QUERY PLAN
234+
---------------------------------------------
235+
Update on second
236+
-> Nested Loop Semi Join
237+
-> Seq Scan on second
238+
Filter: (id = 1)
239+
-> Materialize
240+
-> Append
241+
-> Seq Scan on first_0
242+
Filter: (id = 1)
243+
(8 rows)
244+
245+
/* Check updates (execution) */
246+
UPDATE rowmarks.second SET id = 1
247+
WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id = 1 OR id = 2)
248+
RETURNING *, tableoid::regclass;
249+
id | tableoid
250+
----+-----------------
251+
1 | rowmarks.second
252+
1 | rowmarks.second
253+
(2 rows)
254+
255+
/* Check deletes (plan) */
256+
EXPLAIN (COSTS OFF)
257+
DELETE FROM rowmarks.second
258+
WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id = 1);
259+
QUERY PLAN
260+
---------------------------------------------
261+
Delete on second
262+
-> Nested Loop Semi Join
263+
-> Seq Scan on second
264+
Filter: (id = 1)
265+
-> Materialize
266+
-> Append
267+
-> Seq Scan on first_0
268+
Filter: (id = 1)
269+
(8 rows)
270+
271+
EXPLAIN (COSTS OFF)
272+
DELETE FROM rowmarks.second
273+
WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id < 1);
274+
QUERY PLAN
275+
---------------------------------------------------
276+
Delete on second
277+
-> Hash Join
278+
Hash Cond: (second.id = first_0.id)
279+
-> Seq Scan on second
280+
-> Hash
281+
-> HashAggregate
282+
Group Key: first_0.id
283+
-> Append
284+
-> Seq Scan on first_0
285+
Filter: (id < 1)
286+
-> Seq Scan on first_1
287+
Filter: (id < 1)
288+
-> Seq Scan on first_2
289+
Filter: (id < 1)
290+
-> Seq Scan on first_3
291+
Filter: (id < 1)
292+
-> Seq Scan on first_4
293+
Filter: (id < 1)
294+
(18 rows)
295+
296+
EXPLAIN (COSTS OFF)
297+
DELETE FROM rowmarks.second
298+
WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id = 1 OR id = 2);
299+
QUERY PLAN
300+
---------------------------------------------
301+
Delete on second
302+
-> Hash Semi Join
303+
Hash Cond: (second.id = first_0.id)
304+
-> Seq Scan on second
305+
-> Hash
306+
-> Append
307+
-> Seq Scan on first_0
308+
Filter: (id = 1)
309+
-> Seq Scan on first_1
310+
Filter: (id = 2)
311+
(10 rows)
312+
171313
DROP SCHEMA rowmarks CASCADE;
172314
NOTICE: drop cascades to 7 other objects
173315
DETAIL: drop cascades to table rowmarks.first

‎sql/pathman_rowmarks.sql‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
CREATE EXTENSION pg_pathman;
22
CREATE SCHEMA rowmarks;
33

4+
5+
46
CREATE TABLE rowmarks.first(id int NOT NULL);
57
CREATE TABLE rowmarks.second(id int NOT NULL);
68

@@ -56,6 +58,38 @@ WHERE id = (SELECT id FROM rowmarks.second
5658
FOR UPDATE)
5759
FOR SHARE;
5860

61+
/* Check updates (plan) */
62+
EXPLAIN (COSTS OFF)
63+
UPDATE rowmarks.second SET id = 2
64+
WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id = 1);
65+
EXPLAIN (COSTS OFF)
66+
UPDATE rowmarks.second SET id = 2
67+
WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id < 1);
68+
EXPLAIN (COSTS OFF)
69+
UPDATE rowmarks.second SET id = 2
70+
WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id = 1 OR id = 2);
71+
EXPLAIN (COSTS OFF)
72+
UPDATE rowmarks.second SET id = 2
73+
WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id = 1)
74+
RETURNING *, tableoid::regclass;
75+
76+
/* Check updates (execution) */
77+
UPDATE rowmarks.second SET id = 1
78+
WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id = 1 OR id = 2)
79+
RETURNING *, tableoid::regclass;
80+
81+
/* Check deletes (plan) */
82+
EXPLAIN (COSTS OFF)
83+
DELETE FROM rowmarks.second
84+
WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id = 1);
85+
EXPLAIN (COSTS OFF)
86+
DELETE FROM rowmarks.second
87+
WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id < 1);
88+
EXPLAIN (COSTS OFF)
89+
DELETE FROM rowmarks.second
90+
WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id = 1 OR id = 2);
91+
92+
5993

6094
DROP SCHEMA rowmarks CASCADE;
6195
DROP EXTENSION pg_pathman;

‎src/compat/rowmarks_fix.c‎

Lines changed: 18 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -14,165 +14,39 @@
1414

1515
#include "access/sysattr.h"
1616
#include "catalog/pg_type.h"
17-
#include "nodes/relation.h"
1817
#include "nodes/nodeFuncs.h"
18+
#include "optimizer/planmain.h"
1919
#include "utils/builtins.h"
2020
#include "utils/rel.h"
2121

2222

2323
#ifndef NATIVE_PARTITIONING_ROWMARKS
2424

25-
/* Special column name for rowmarks */
26-
#define TABLEOID_STR(subst) ( "pathman_tableoid" subst )
27-
#define TABLEOID_STR_BASE_LEN ( sizeof(TABLEOID_STR("")) - 1 )
2825

29-
30-
static void lock_rows_visitor(Plan *plan, void *context);
31-
static List *get_tableoids_list(List *tlist);
32-
33-
34-
/* Final rowmark processing for partitioned tables */
3526
void
36-
postprocess_lock_rows(List *rtable, Plan *plan)
37-
{
38-
plan_tree_walker(plan, lock_rows_visitor, rtable);
39-
}
40-
41-
/*
42-
* Add missing 'TABLEOID_STR%u' junk attributes for inherited partitions
43-
*
44-
* This is necessary since preprocess_targetlist() heavily
45-
* depends on the 'inh' flag which we have to unset.
46-
*
47-
* postprocess_lock_rows() will later transform 'TABLEOID_STR:Oid'
48-
* relnames into 'tableoid:rowmarkId'.
49-
*/
50-
void
51-
rowmark_add_tableoids(Query *parse)
52-
{
53-
ListCell *lc;
54-
55-
/* Generate 'tableoid' for partitioned table rowmark */
56-
foreach (lc, parse->rowMarks)
57-
{
58-
RowMarkClause *rc = (RowMarkClause *) lfirst(lc);
59-
Oid parent = getrelid(rc->rti, parse->rtable);
60-
Var *var;
61-
TargetEntry *tle;
62-
char resname[64];
63-
64-
/* Check that table is partitioned */
65-
if (!get_pathman_relation_info(parent))
66-
continue;
67-
68-
var = makeVar(rc->rti,
69-
TableOidAttributeNumber,
70-
OIDOID,
71-
-1,
72-
InvalidOid,
73-
0);
74-
75-
/* Use parent's Oid as TABLEOID_STR's key (%u) */
76-
snprintf(resname, sizeof(resname), TABLEOID_STR("%u"), parent);
77-
78-
tle = makeTargetEntry((Expr *) var,
79-
list_length(parse->targetList) + 1,
80-
pstrdup(resname),
81-
true);
82-
83-
/* There's no problem here since new attribute is junk */
84-
parse->targetList = lappend(parse->targetList, tle);
85-
}
86-
}
87-
88-
/*
89-
* Extract target entries with resnames beginning with TABLEOID_STR
90-
* and var->varoattno == TableOidAttributeNumber
91-
*/
92-
static List *
93-
get_tableoids_list(List *tlist)
27+
append_tle_for_rowmark(PlannerInfo *root, PlanRowMark *rc)
9428
{
95-
List *result = NIL;
96-
ListCell *lc;
97-
98-
foreach (lc, tlist)
99-
{
100-
TargetEntry *te = (TargetEntry *) lfirst(lc);
101-
Var *var = (Var *) te->expr;
102-
103-
if (!IsA(var, Var))
104-
continue;
105-
106-
/* Check that column name begins with TABLEOID_STR & it's tableoid */
107-
if (var->varoattno == TableOidAttributeNumber &&
108-
(te->resname && strlen(te->resname) > TABLEOID_STR_BASE_LEN) &&
109-
0 == strncmp(te->resname, TABLEOID_STR(""), TABLEOID_STR_BASE_LEN))
110-
{
111-
result = lappend(result, te);
112-
}
113-
}
114-
115-
return result;
116-
}
117-
118-
/*
119-
* Find 'TABLEOID_STR%u' attributes that were manually
120-
* created for partitioned tables and replace Oids
121-
* (used for '%u') with expected rc->rowmarkIds
122-
*/
123-
static void
124-
lock_rows_visitor(Plan *plan, void *context)
125-
{
126-
List *rtable = (List *) context;
127-
LockRows *lock_rows = (LockRows *) plan;
128-
Plan *lock_child = outerPlan(plan);
129-
List *tableoids;
130-
ListCell *lc;
131-
132-
if (!IsA(lock_rows, LockRows))
133-
return;
134-
135-
Assert(rtable && IsA(rtable, List) && lock_child);
136-
137-
/* Select tableoid attributes that must be renamed */
138-
tableoids = get_tableoids_list(lock_child->targetlist);
139-
if (!tableoids)
140-
return; /* this LockRows has nothing to do with partitioned table */
141-
142-
foreach (lc, lock_rows->rowMarks)
143-
{
144-
PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
145-
Oid parent_oid = getrelid(rc->rti, rtable);
146-
ListCell *mark_lc;
147-
List *finished_tes = NIL; /* postprocessed target entries */
148-
149-
foreach (mark_lc, tableoids)
150-
{
151-
TargetEntry *te = (TargetEntry *) lfirst(mark_lc);
152-
const char *cur_oid_str = &(te->resname[TABLEOID_STR_BASE_LEN]);
153-
Datum cur_oid_datum;
154-
155-
cur_oid_datum = DirectFunctionCall1(oidin, CStringGetDatum(cur_oid_str));
29+
Var *var;
30+
char resname[32];
31+
TargetEntry *tle;
15632

157-
if (DatumGetObjectId(cur_oid_datum) == parent_oid)
158-
{
159-
char resname[64];
33+
var = makeVar(rc->rti,
34+
TableOidAttributeNumber,
35+
OIDOID,
36+
-1,
37+
InvalidOid,
38+
0);
16039

161-
/* Replace 'TABLEOID_STR:Oid' with 'tableoid:rowmarkId' */
162-
snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
163-
te->resname = pstrdup(resname);
40+
snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
16441

165-
finished_tes = lappend(finished_tes, te);
166-
}
167-
}
42+
tle = makeTargetEntry((Expr *) var,
43+
list_length(root->processed_tlist) + 1,
44+
pstrdup(resname),
45+
true);
16846

169-
/* Remove target entries that have been processed in this step */
170-
foreach (mark_lc, finished_tes)
171-
tableoids = list_delete_ptr(tableoids, lfirst(mark_lc));
47+
root->processed_tlist = lappend(root->processed_tlist, tle);
17248

173-
if (list_length(tableoids) == 0)
174-
break; /* nothing to do */
175-
}
49+
add_vars_to_targetlist(root, list_make1(var), bms_make_singleton(0), true);
17650
}
17751

17852
#endif /* NATIVE_PARTITIONING_ROWMARKS */

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /