8000 Make viewquery a copy in rewriteTargetView() · home201448/postgres@4271ed3 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4271ed3

Browse files
committed
Make viewquery a copy in rewriteTargetView()
Rather than expect the Query returned by get_view_query() to be read-only and then copy bits and pieces of it out, simply copy the entire structure when we get it. This addresses an issue where AcquireRewriteLocks, which is called by acquireLocksOnSubLinks(), scribbles on the parsetree passed in, which was actually an entry in relcache, leading to segfaults with certain view definitions. This also future-proofs us a bit for anyone adding more code to this path. The acquireLocksOnSubLinks() was added in commit c3e0ddd. Back-patch to 9.3 as that commit was.
1 parent 06d4fab commit 4271ed3

File tree

3 files changed

+130
-10
lines changed

3 files changed

+130
-10
lines changed

src/backend/rewrite/rewriteHandler.c

Lines changed: 19 additions & 10 deletions
10000
Original file line numberDiff line numberDiff line change
@@ -1893,6 +1893,9 @@ fireRules(Query *parsetree,
18931893
*
18941894
* Caller should have verified that the relation is a view, and therefore
18951895
* we should find an ON SELECT action.
1896+
*
1897+
* Note that the pointer returned is into the relcache and therefore must
1898+
* be treated as read-only to the caller and not modified or scribbled on.
18961899
*/
18971900
static Query *
18981901
get_view_query(Relation view)
@@ -2377,8 +2380,14 @@ rewriteTargetView(Query *parsetree, Relation view)
23772380
/*
23782381
* If we get here, view_is_auto_updatable() has verified that the view
23792382
* contains a single base relation.
2383+
*
2384+
* Get the Query from the view's ON SELECT rule. We're going to munge the
2385+
* Query to change the view's base relation into the target relation,
2386+
* along with various other changes along the way, so we need to make a
2387+
* copy of it (get_view_query() returns a pointer into the relcache, so we
2388+
* have to treat it as read-only).
23802389
*/
2381-
viewquery = get_view_query(view);
2390+
viewquery = copyObject(get_view_query(view));
23822391

23832392
Assert(list_length(viewquery->jointree->fromlist) == 1);
23842393
rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
@@ -2427,7 +2436,7 @@ rewriteTargetView(Query *parsetree, Relation view)
24272436
* outer query. Perhaps someday we should refactor things enough so that
24282437
* we can share code with the planner.)
24292438
*/
2430-
new_rte = (RangeTblEntry *) copyObject(base_rte);
2439+
new_rte = (RangeTblEntry *) base_rte;
24312440
parsetree->rtable = lappend(parsetree->rtable, new_rte);
24322441
new_rt_index = list_length(parsetree->rtable);
24332442

@@ -2439,14 +2448,14 @@ rewriteTargetView(Query *parsetree, Relation view)
24392448
new_rte->inh = false;
24402449

24412450
/*
2442-
* Make a copy of the view's targetlist, adjusting its Vars to reference
2443-
* the new target RTE, ie make their varnos be new_rt_index instead of
2444-
* base_rt_index. There can be no Vars for other rels in the tlist, so
2445-
* this is sufficient to pull up the tlist expressions for use in the
2446-
* outer query. The tlist will provide the replacement expressions used
2447-
* by ReplaceVarsFromTargetList below.
2451+
* Adjust the view's targetlist Vars to reference the new target RTE, ie
2452+
* make their varnos be new_rt_index instead of base_rt_index. There can
2453+
* be no Vars for other rels in the tlist, so this is sufficient to pull
2454+
* up the tlist expressions for use in the outer query. The tlist will
2455+
* provide the replacement expressions used by ReplaceVarsFromTargetList
2456+
* below.
24482457
*/
2449-
view_targetlist = copyObject(viewquery->targetList);
2458+
view_targetlist = viewquery->targetList;
24502459

24512460
ChangeVarNodes((Node *) view_targetlist,
24522461
base_rt_index,
@@ -2581,7 +2590,7 @@ rewriteTargetView(Query *parsetree, Relation view)
25812590
if (parsetree->commandType != CMD_INSERT &&
25822591
viewquery->jointree->quals != NULL)
25832592
{
2584-
Node *viewqual = (Node *) copyObject(viewquery->jointree->quals);
2593+
Node *viewqual = (Node *) viewquery->jointree->quals;
25852594

25862595
ChangeVarNodes(viewqual, base_rt_index, new_rt_index, 0);
25872596
AddQual(parsetree, (Node *) viewqual);

src/test/regress/expected/updatable_views.out

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,3 +1163,70 @@ DROP TABLE base_tbl_parent, base_tbl_child CASCADE;
11631163
NOTICE: drop cascades to 2 other objects
11641164
DETAIL: drop cascades to view rw_view1
11651165
drop cascades to view rw_view2
1166+
CREATE TABLE tx1 (a integer);
1167+
CREATE TABLE tx2 (b integer);
1168+
CREATE TABLE tx3 (c integer);
1169+
CREATE VIEW vx1 AS SELECT a FROM tx1 WHERE EXISTS(SELECT 1 FROM tx2 JOIN tx3 ON b=c);
1170+
INSERT INTO vx1 values (1);
1171+
SELECT * FROM tx1;
1172+
a
1173+
---
1174+
1
1175+
(1 row)
1176+
1177+
SELECT * FROM vx1;
1178+
a
1179+
---
1180+
(0 rows)
1181+
1182+
DROP VIEW vx1;
1183+
DROP TABLE tx1;
1184+
DROP TABLE tx2;
1185+
DROP TABLE tx3;
1186+
CREATE TABLE tx1 (a integer);
1187+
CREATE TABLE tx2 (b integer);
1188+
CREATE TABLE tx3 (c integer);
1189+
CREATE VIEW vx1 AS SELECT a FROM tx1 WHERE EXISTS(SELECT 1 FROM tx2 JOIN tx3 ON b=c);
1190+
INSERT INTO vx1 VALUES (1);
1191+
INSERT INTO vx1 VALUES (1);
1192+
SELECT * FROM tx1;
1193+
a
1194+
---
1195+
1
1196+
1
1197+
(2 rows)
1198+
1199+
SELECT * FROM vx1;
1200+
a
1201+
---
1202+
(0 rows)
1203+
1204+
DROP VIEW vx1;
1205+
DROP TABLE tx1;
1206+
DROP TABLE tx2;
1207+
DROP TABLE tx3;
1208+
CREATE TABLE tx1 (a integer, b integer);
1209+
CREATE TABLE tx2 (b integer, c integer);
1210+
CREATE TABLE tx3 (c integer, d integer);
1211+
ALTER TABLE tx1 DROP COLUMN b;
1212+
ALTER TABLE tx2 DROP COLUMN c;
1213+
ALTER TABLE tx3 DROP COLUMN d;
1214+
CREATE VIEW vx1 AS SELECT a FROM tx1 WHERE EXISTS(SELECT 1 FROM tx2 JOIN tx3 ON b=c);
1215+
INSERT INTO vx1 VALUES (1);
1216+
INSERT INTO vx1 VALUES (1);
1217+
SELECT * FROM tx1;
1218+
a
1219+
---
1220+
1
1221+
1
1222+
(2 rows)
1223+
1224+
SELECT * FROM vx1;
1225+
a
1226+
---
1227+
(0 rows)
1228+
1229+
DROP VIEW vx1;
1230+
DROP TABLE tx1;
1231+
DROP TABLE tx2;
1232+
DROP TABLE tx3;

src/test/regress/sql/updatable_views.sql

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,3 +541,47 @@ SELECT * FROM ONLY base_tbl_parent ORDER BY a;
541541
SELECT * FROM base_tbl_child ORDER BY a;
542542

543543
DROP TABLE base_tbl_parent, base_tbl_child CASCADE;
544+
545+
CREATE TABLE tx1 (a integer);
546+
CREATE TABLE tx2 (b integer);
547+
CREATE TABLE tx3 (c integer);
548+
CREATE VIEW vx1 AS SELECT a FROM tx1 WHERE EXISTS(SELECT 1 FROM tx2 JOIN tx3 ON b=c);
549+
INSERT INTO vx1 values (1);
550+
SELECT * FROM tx1;
551+
SELECT * FROM vx1;
552+
553+
DROP VIEW vx1;
554+
DROP TABLE tx1;
555+
DROP TABLE tx2;
556+
DROP TABLE tx3;
557+
558+
CREATE TABLE tx1 (a integer);
559+
CREATE TABLE tx2 (b integer);
560+
CREATE TABLE tx3 (c integer);
561+
CREATE VIEW vx1 AS SELECT a FROM tx1 WHERE EXISTS(SELECT 1 FROM tx2 JOIN tx3 ON b=c);
562+
INSERT INTO vx1 VALUES (1);
563+
INSERT INTO vx1 VALUES (1);
564+
SELECT * FROM tx1;
565+
SELECT * FROM vx1;
566+
567+
DROP VIEW vx1;
568+
DROP TABLE tx1;
569+
DROP TABLE tx2;
570+
DROP TABLE tx3;
571+
572+
CREATE TABLE tx1 (a integer, b integer);
573+
CREATE TABLE tx2 (b integer, c integer);
574+
CREATE TABLE tx3 (c integer, d integer);
575+
ALTER TABLE tx1 DROP COLUMN b;
576+
ALTER TABLE tx2 DROP COLUMN c;
577+
ALTER TABLE tx3 DROP COLUMN d;
578+
CREATE VIEW vx1 AS SELECT a FROM tx1 WHERE EXISTS(SELECT 1 FROM tx2 JOIN tx3 ON b=c);
579+
INSERT INTO vx1 VALUES (1);
580+
INSERT INTO vx1 VALUES (1);
581+
SELECT * FROM tx1;
582+
SELECT * FROM vx1;
583+
584+
DROP VIEW vx1;
585+
DROP TABLE tx1;
586+
DROP TABLE tx2;
587+
DROP TABLE tx3;

0 commit comments

Comments
 (0)
0