Skip to content

Commit 496943e

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 0c28e76 commit 496943e

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
@@ -2026,6 +2026,9 @@ fireRules(Query *parsetree,
20262026
*
20272027
* Caller should have verified that the relation is a view, and therefore
20282028
* we should find an ON SELECT action.
2029+
*
2030+
* Note that the pointer returned is into the relcache and therefore must
2031+
* be treated as read-only to the caller and not modified or scribbled on.
20292032
*/
20302033
Query *
20312034
get_view_query(Relation view)
@@ -2613,9 +2616,16 @@ rewriteTargetView(Query *parsetree, Relation view)
26132616
List *view_targetlist;
26142617
ListCell *lc;
26152618

2616-
/* The view must be updatable, else fail */
2617-
viewquery = get_view_query(view);
2619+
/*
2620+
* Get the Query from the view's ON SELECT rule. We're going to munge the
2621+
* Query to change the view's base relation into the target relation,
2622+
* along with various other changes along the way, so we need to make a
2623+
* copy of it (get_view_query() returns a pointer into the relcache, so we
2624+
* have to treat it as read-only).
2625+
*/
2626+
viewquery = copyObject(get_view_query(view));
26182627

2628+
/* The view must be updatable, else fail */
26192629
auto_update_detail =
26202630
view_query_is_auto_updatable(viewquery,
26212631
parsetree->commandType != CMD_DELETE);
@@ -2779,7 +2789,7 @@ rewriteTargetView(Query *parsetree, Relation view)
27792789
* outer query. Perhaps someday we should refactor things enough so that
27802790
* we can share code with the planner.)
27812791
*/
2782-
new_rte = (RangeTblEntry *) copyObject(base_rte);
2792+
new_rte = (RangeTblEntry *) base_rte;
27832793
parsetree->rtable = lappend(parsetree->rtable, new_rte);
27842794
new_rt_index = list_length(parsetree->rtable);
27852795

@@ -2791,14 +2801,14 @@ rewriteTargetView(Query *parsetree, Relation view)
27912801
new_rte->inh = false;
27922802

27932803
/*
2794-
* Make a copy of the view's targetlist, adjusting its Vars to reference
2795-
* the new target RTE, ie make their varnos be new_rt_index instead of
2796-
* base_rt_index. There can be no Vars for other rels in the tlist, so
2797-
* this is sufficient to pull up the tlist expressions for use in the
2798-
* outer query. The tlist will provide the replacement expressions used
2799-
* by ReplaceVarsFromTargetList below.
2804+
* Adjust the view's targetlist Vars to reference the new target RTE, ie
2805+
* make their varnos be new_rt_index instead of base_rt_index. There can
2806+
* be no Vars for other rels in the tlist, so this is sufficient to pull
2807+
* up the tlist expressions for use in the outer query. The tlist will
2808+
* provide the replacement expressions used by ReplaceVarsFromTargetList
2809+
* below.
28002810
*/
2801-
view_targetlist = copyObject(viewquery->targetList);
2811+
view_targetlist = viewquery->targetList;
28022812

28032813
ChangeVarNodes((Node *) view_targetlist,
28042814
base_rt_index,
@@ -2949,7 +2959,7 @@ rewriteTargetView(Query *parsetree, Relation view)
29492959
if (parsetree->commandType != CMD_INSERT &&
29502960
viewquery->jointree->quals != NULL)
29512961
{
2952-
Node *viewqual = (Node *) copyObject(viewquery->jointree->quals);
2962+
Node *viewqual = (Node *) viewquery->jointree->quals;
29532963

29542964
ChangeVarNodes(viewqual, base_rt_index, new_rt_index, 0);
29552965

@@ -3028,7 +3038,7 @@ rewriteTargetView(Query *parsetree, Relation view)
30283038

30293039
if (viewquery->jointree->quals != NULL)
30303040
{
3031-
wco->qual = (Node *) copyObject(viewquery->jointree->quals);
3041+
wco->qual = (Node *) viewquery->jointree->quals;
30323042
ChangeVarNodes(wco->qual, base_rt_index, new_rt_index, 0);
30333043

30343044
/*

src/test/regress/expected/updatable_views.out

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2353,3 +2353,70 @@ DROP TABLE t1, t11, t12, t111 CASCADE;
23532353
NOTICE: drop cascades to view v1
23542354
DROP FUNCTION snoop(anyelement);
23552355
DROP FUNCTION leakproof(anyelement);
2356+
CREATE TABLE tx1 (a integer);
2357+
CREATE TABLE tx2 (b integer);
2358+
CREATE TABLE tx3 (c integer);
2359+
CREATE VIEW vx1 AS SELECT a FROM tx1 WHERE EXISTS(SELECT 1 FROM tx2 JOIN tx3 ON b=c);
2360+
INSERT INTO vx1 values (1);
2361+
SELECT * FROM tx1;
2362+
a
2363+
---
2364+
1
2365+
(1 row)
2366+
2367+
SELECT * FROM vx1;
2368+
a
2369+
---
2370+
(0 rows)
2371+
2372+
DROP VIEW vx1;
2373+
DROP TABLE tx1;
2374+
DROP TABLE tx2;
2375+
DROP TABLE tx3;
2376+
CREATE TABLE tx1 (a integer);
2377+
CREATE TABLE tx2 (b integer);
2378+
CREATE TABLE tx3 (c integer);
2379+
CREATE VIEW vx1 AS SELECT a FROM tx1 WHERE EXISTS(SELECT 1 FROM tx2 JOIN tx3 ON b=c);
2380+
INSERT INTO vx1 VALUES (1);
2381+
INSERT INTO vx1 VALUES (1);
2382+
SELECT * FROM tx1;
2383+
a
2384+
---
2385+
1
2386+
1
2387+
(2 rows)
2388+
2389+
SELECT * FROM vx1;
2390+
a
2391+
---
2392+
(0 rows)
2393+
2394+
DROP VIEW vx1;
2395+
DROP TABLE tx1;
2396+
DROP TABLE tx2;
2397+
DROP TABLE tx3;
2398+
CREATE TABLE tx1 (a integer, b integer);
2399+
CREATE TABLE tx2 (b integer, c integer);
2400+
CREATE TABLE tx3 (c integer, d integer);
2401+
ALTER TABLE tx1 DROP COLUMN b;
2402+
ALTER TABLE tx2 DROP COLUMN c;
2403+
ALTER TABLE tx3 DROP COLUMN d;
2404+
CREATE VIEW vx1 AS SELECT a FROM tx1 WHERE EXISTS(SELECT 1 FROM tx2 JOIN tx3 ON b=c);
2405+
INSERT INTO vx1 VALUES (1);
2406+
INSERT INTO vx1 VALUES (1);
2407+
SELECT * FROM tx1;
2408+
a
2409+
---
2410+
1
2411+
1
2412+
(2 rows)
2413+
2414+
SELECT * FROM vx1;
2415+
a
2416+
---
2417+
(0 rows)
2418+
2419+
DROP VIEW vx1;
2420+
DROP TABLE tx1;
2421+
DROP TABLE tx2;
2422+
DROP TABLE tx3;

src/test/regress/sql/updatable_views.sql

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

0 commit comments

Comments
 (0)