Skip to content

Commit f02137d

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 590d201 commit f02137d

File tree

3 files changed

+133
-12
lines changed

3 files changed

+133
-12
lines changed

src/backend/rewrite/rewriteHandler.c

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1908,6 +1908,9 @@ fireRules(Query *parsetree,
19081908
*
19091909
* Caller should have verified that the relation is a view, and therefore
19101910
* we should find an ON SELECT action.
1911+
*
1912+
* Note that the pointer returned is into the relcache and therefore must
1913+
* be treated as read-only to the caller and not modified or scribbled on.
19111914
*/
19121915
Query *
19131916
get_view_query(Relation view)
@@ -2494,9 +2497,16 @@ rewriteTargetView(Query *parsetree, Relation view)
24942497
List *view_targetlist;
24952498
ListCell *lc;
24962499

2497-
/* The view must be updatable, else fail */
2498-
viewquery = get_view_query(view);
2500+
/*
2501+
* Get the Query from the view's ON SELECT rule. We're going to munge the
2502+
* Query to change the view's base relation into the target relation,
2503+
* along with various other changes along the way, so we need to make a
2504+
* copy of it (get_view_query() returns a pointer into the relcache, so we
2505+
* have to treat it as read-only).
2506+
*/
2507+
viewquery = copyObject(get_view_query(view));
24992508

2509+
/* The view must be updatable, else fail */
25002510
auto_update_detail =
25012511
view_query_is_auto_updatable(viewquery,
25022512
parsetree->commandType != CMD_DELETE);
@@ -2648,7 +2658,7 @@ rewriteTargetView(Query *parsetree, Relation view)
26482658
* outer query. Perhaps someday we should refactor things enough so that
26492659
* we can share code with the planner.)
26502660
*/
2651-
new_rte = (RangeTblEntry *) copyObject(base_rte);
2661+
new_rte = (RangeTblEntry *) base_rte;
26522662
parsetree->rtable = lappend(parsetree->rtable, new_rte);
26532663
new_rt_index = list_length(parsetree->rtable);
26542664

@@ -2660,14 +2670,14 @@ rewriteTargetView(Query *parsetree, Relation view)
26602670
new_rte->inh = false;
26612671

26622672
/*
2663-
* Make a copy of the view's targetlist, adjusting its Vars to reference
2664-
* the new target RTE, ie make their varnos be new_rt_index instead of
2665-
* base_rt_index. There can be no Vars for other rels in the tlist, so
2666-
* this is sufficient to pull up the tlist expressions for use in the
2667-
* outer query. The tlist will provide the replacement expressions used
2668-
* by ReplaceVarsFromTargetList below.
2673+
* Adjust the view's targetlist Vars to reference the new target RTE, ie
2674+
* make their varnos be new_rt_index instead of base_rt_index. There can
2675+
* be no Vars for other rels in the tlist, so this is sufficient to pull
2676+
* up the tlist expressions for use in the outer query. The tlist will
2677+
* provide the replacement expressions used by ReplaceVarsFromTargetList
2678+
* below.
26692679
*/
2670-
view_targetlist = copyObject(viewquery->targetList);
2680+
view_targetlist = viewquery->targetList;
26712681

26722682
ChangeVarNodes((Node *) view_targetlist,
26732683
base_rt_index,
@@ -2813,7 +2823,7 @@ rewriteTargetView(Query *parsetree, Relation view)
28132823
if (parsetree->commandType != CMD_INSERT &&
28142824
viewquery->jointree->quals != NULL)
28152825
{
2816-
Node *viewqual = (Node *) copyObject(viewquery->jointree->quals);
2826+
Node *viewqual = (Node *) viewquery->jointree->quals;
28172827

28182828
ChangeVarNodes(viewqual, base_rt_index, new_rt_index, 0);
28192829

@@ -2890,7 +2900,7 @@ rewriteTargetView(Query *parsetree, Relation view)
28902900

28912901
if (viewquery->jointree->quals != NULL)
28922902
{
2893-
wco->qual = (Node *) copyObject(viewquery->jointree->quals);
2903+
wco->qual = (Node *) viewquery->jointree->quals;
28942904
ChangeVarNodes(wco->qual, base_rt_index, new_rt_index, 0);
28952905

28962906
/*

src/test/regress/expected/updatable_views.out

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2284,3 +2284,70 @@ DROP TABLE t1, t11, t12, t111 CASCADE;
22842284
NOTICE: drop cascades to view v1
22852285
DROP FUNCTION snoop(anyelement);
22862286
DROP FUNCTION leakproof(anyelement);
2287+
CREATE TABLE tx1 (a integer);
2288+
CREATE TABLE tx2 (b integer);
2289+
CREATE TABLE tx3 (c integer);
2290+
CREATE VIEW vx1 AS SELECT a FROM tx1 WHERE EXISTS(SELECT 1 FROM tx2 JOIN tx3 ON b=c);
2291+
INSERT INTO vx1 values (1);
2292+
SELECT * FROM tx1;
2293+
a
2294+
---
2295+
1
2296+
(1 row)
2297+
2298+
SELECT * FROM vx1;
2299+
a
2300+
---
2301+
(0 rows)
2302+
2303+
DROP VIEW vx1;
2304+
DROP TABLE tx1;
2305+
DROP TABLE tx2;
2306+
DROP TABLE tx3;
2307+
CREATE TABLE tx1 (a integer);
2308+
CREATE TABLE tx2 (b integer);
2309+
CREATE TABLE tx3 (c integer);
2310+
CREATE VIEW vx1 AS SELECT a FROM tx1 WHERE EXISTS(SELECT 1 FROM tx2 JOIN tx3 ON b=c);
2311+
INSERT INTO vx1 VALUES (1);
2312+
INSERT INTO vx1 VALUES (1);
2313+
SELECT * FROM tx1;
2314+
a
2315+
---
2316+
1
2317+
1
2318+
(2 rows)
2319+
2320+
SELECT * FROM vx1;
2321+
a
2322+
---
2323+
(0 rows)
2324+
2325+
DROP VIEW vx1;
2326+
DROP TABLE tx1;
2327+
DROP TABLE tx2;
2328+
DROP TABLE tx3;
2329+
CREATE TABLE tx1 (a integer, b integer);
2330+
CREATE TABLE tx2 (b integer, c integer);
2331+
CREATE TABLE tx3 (c integer, d integer);
2332+
ALTER TABLE tx1 DROP COLUMN b;
2333+
ALTER TABLE tx2 DROP COLUMN c;
2334+
ALTER TABLE tx3 DROP COLUMN d;
2335+
CREATE VIEW vx1 AS SELECT a FROM tx1 WHERE EXISTS(SELECT 1 FROM tx2 JOIN tx3 ON b=c);
2336+
INSERT INTO vx1 VALUES (1);
2337+
INSERT INTO vx1 VALUES (1);
2338+
SELECT * FROM tx1;
2339+
a
2340+
---
2341+
1
2342+
1
2343+
(2 rows)
2344+
2345+
SELECT * FROM vx1;
2346+
a
2347+
---
2348+
(0 rows)
2349+
2350+
DROP VIEW vx1;
2351+
DROP TABLE tx1;
2352+
DROP TABLE tx2;
2353+
DROP TABLE tx3;

src/test/regress/sql/updatable_views.sql

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,3 +1011,47 @@ TABLE t1; -- verify all a<=5 are intact
10111011
DROP TABLE t1, t11, t12, t111 CASCADE;
10121012
DROP FUNCTION snoop(anyelement);
10131013
DROP FUNCTION leakproof(anyelement);
1014+
1015+
CREATE TABLE tx1 (a integer);
1016+
CREATE TABLE tx2 (b integer);
1017+
CREATE TABLE tx3 (c integer);
1018+
CREATE VIEW vx1 AS SELECT a FROM tx1 WHERE EXISTS(SELECT 1 FROM tx2 JOIN tx3 ON b=c);
1019+
INSERT INTO vx1 values (1);
1020+
SELECT * FROM tx1;
1021+
SELECT * FROM vx1;
1022+
1023+
DROP VIEW vx1;
1024+
DROP TABLE tx1;
1025+
DROP TABLE tx2;
1026+
DROP TABLE tx3;
1027+
1028+
CREATE TABLE tx1 (a integer);
1029+
CREATE TABLE tx2 (b integer);
1030+
CREATE TABLE tx3 (c integer);
1031+
CREATE VIEW vx1 AS SELECT a FROM tx1 WHERE EXISTS(SELECT 1 FROM tx2 JOIN tx3 ON b=c);
1032+
INSERT INTO vx1 VALUES (1);
1033+
INSERT INTO vx1 VALUES (1);
1034+
SELECT * FROM tx1;
1035+
SELECT * FROM vx1;
1036+
1037+
DROP VIEW vx1;
1038+
DROP TABLE tx1;
1039+
DROP TABLE tx2;
1040+
DROP TABLE tx3;
1041+
1042+
CREATE TABLE tx1 (a integer, b integer);
1043+
CREATE TABLE tx2 (b integer, c integer);
1044+
CREATE TABLE tx3 (c integer, d integer);
1045+
ALTER TABLE tx1 DROP COLUMN b;
1046+
ALTER TABLE tx2 DROP COLUMN c;
1047+
ALTER TABLE tx3 DROP COLUMN d;
1048+
CREATE VIEW vx1 AS SELECT a FROM tx1 WHERE EXISTS(SELECT 1 FROM tx2 JOIN tx3 ON b=c);
1049+
INSERT INTO vx1 VALUES (1);
1050+
INSERT INTO vx1 VALUES (1);
1051+
SELECT * FROM tx1;
1052+
SELECT * FROM vx1;
1053+
1054+
DROP VIEW vx1;
1055+
DROP TABLE tx1;
1056+
DROP TABLE tx2;
1057+
DROP TABLE tx3;

0 commit comments

Comments
 (0)