Skip to content

Commit f0e6d6d

Browse files
committed
Revert "Get rid of the "new" and "old" entries in a view's rangetable."
This reverts commit 1b4d280. It's broken the buildfarm members that run cross-version-upgrade tests, because they're not prepared to deal with cosmetic differences between CREATE VIEW commands emitted by older servers and HEAD. Even if we had a solution to that, which we don't, it'd take some time to roll it out to the affected animals. This improvement isn't valuable enough to justify addressing that problem on an emergency basis, so revert it for now.
1 parent 5a26c7b commit f0e6d6d

34 files changed

+890
-774
lines changed

contrib/postgres_fdw/expected/postgres_fdw.out

+8-8
Original file line numberDiff line numberDiff line change
@@ -2606,7 +2606,7 @@ SELECT t1.c1, t2.c2 FROM v4 t1 LEFT JOIN v5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1
26062606
Foreign Scan
26072607
Output: ft4.c1, ft5.c2, ft5.c1
26082608
Relations: (public.ft4) LEFT JOIN (public.ft5)
2609-
Remote SQL: SELECT r4.c1, r5.c2, r5.c1 FROM ("S 1"."T 3" r4 LEFT JOIN "S 1"."T 4" r5 ON (((r4.c1 = r5.c1)))) ORDER BY r4.c1 ASC NULLS LAST, r5.c1 ASC NULLS LAST LIMIT 10::bigint OFFSET 10::bigint
2609+
Remote SQL: SELECT r6.c1, r9.c2, r9.c1 FROM ("S 1"."T 3" r6 LEFT JOIN "S 1"."T 4" r9 ON (((r6.c1 = r9.c1)))) ORDER BY r6.c1 ASC NULLS LAST, r9.c1 ASC NULLS LAST LIMIT 10::bigint OFFSET 10::bigint
26102610
(4 rows)
26112611

26122612
SELECT t1.c1, t2.c2 FROM v4 t1 LEFT JOIN v5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10;
@@ -2669,7 +2669,7 @@ SELECT t1.c1, t2.c2 FROM v4 t1 LEFT JOIN ft5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c
26692669
Foreign Scan
26702670
Output: ft4.c1, t2.c2, t2.c1
26712671
Relations: (public.ft4) LEFT JOIN (public.ft5 t2)
2672-
Remote SQL: SELECT r4.c1, r2.c2, r2.c1 FROM ("S 1"."T 3" r4 LEFT JOIN "S 1"."T 4" r2 ON (((r4.c1 = r2.c1)))) ORDER BY r4.c1 ASC NULLS LAST, r2.c1 ASC NULLS LAST LIMIT 10::bigint OFFSET 10::bigint
2672+
Remote SQL: SELECT r6.c1, r2.c2, r2.c1 FROM ("S 1"."T 3" r6 LEFT JOIN "S 1"."T 4" r2 ON (((r6.c1 = r2.c1)))) ORDER BY r6.c1 ASC NULLS LAST, r2.c1 ASC NULLS LAST LIMIT 10::bigint OFFSET 10::bigint
26732673
(4 rows)
26742674

26752675
SELECT t1.c1, t2.c2 FROM v4 t1 LEFT JOIN ft5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10;
@@ -6557,10 +6557,10 @@ CREATE VIEW rw_view AS SELECT * FROM foreign_tbl
65576557
a | integer | | | | plain |
65586558
b | integer | | | | plain |
65596559
View definition:
6560-
SELECT a,
6561-
b
6560+
SELECT foreign_tbl.a,
6561+
foreign_tbl.b
65626562
FROM foreign_tbl
6563-
WHERE a < b;
6563+
WHERE foreign_tbl.a < foreign_tbl.b;
65646564
Options: check_option=cascaded
65656565

65666566
EXPLAIN (VERBOSE, COSTS OFF)
@@ -6674,10 +6674,10 @@ CREATE VIEW rw_view AS SELECT * FROM parent_tbl
66746674
a | integer | | | | plain |
66756675
b | integer | | | | plain |
66766676
View definition:
6677-
SELECT a,
6678-
b
6677+
SELECT parent_tbl.a,
6678+
parent_tbl.b
66796679
FROM parent_tbl
6680-
WHERE a < b;
6680+
WHERE parent_tbl.a < parent_tbl.b;
66816681
Options: check_option=cascaded
66826682

66836683
EXPLAIN (VERBOSE, COSTS OFF)

src/backend/commands/lockcmds.c

+9
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,15 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
194194
char relkind = rte->relkind;
195195
char *relname = get_rel_name(relid);
196196

197+
/*
198+
* The OLD and NEW placeholder entries in the view's rtable are
199+
* skipped.
200+
*/
201+
if (relid == context->viewoid &&
202+
(strcmp(rte->eref->aliasname, "old") == 0 ||
203+
strcmp(rte->eref->aliasname, "new") == 0))
204+
continue;
205+
197206
/* Currently, we only allow plain tables or views to be locked. */
198207
if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
199208
relkind != RELKIND_VIEW)

src/backend/commands/view.c

+107
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,107 @@ DefineViewRules(Oid viewOid, Query *viewParse, bool replace)
353353
*/
354354
}
355355

356+
/*---------------------------------------------------------------
357+
* UpdateRangeTableOfViewParse
358+
*
359+
* Update the range table of the given parsetree.
360+
* This update consists of adding two new entries IN THE BEGINNING
361+
* of the range table (otherwise the rule system will die a slow,
362+
* horrible and painful death, and we do not want that now, do we?)
363+
* one for the OLD relation and one for the NEW one (both of
364+
* them refer in fact to the "view" relation).
365+
*
366+
* Of course we must also increase the 'varnos' of all the Var nodes
367+
* by 2...
368+
*
369+
* These extra RT entries are not actually used in the query,
370+
* except for run-time locking.
371+
*---------------------------------------------------------------
372+
*/
373+
static Query *
374+
UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
375+
{
376+
Relation viewRel;
377+
List *new_rt;
378+
ParseNamespaceItem *nsitem;
379+
RangeTblEntry *rt_entry1,
380+
*rt_entry2;
381+
RTEPermissionInfo *rte_perminfo1;
382+
ParseState *pstate;
383+
ListCell *lc;
384+
385+
/*
386+
* Make a copy of the given parsetree. It's not so much that we don't
387+
* want to scribble on our input, it's that the parser has a bad habit of
388+
* outputting multiple links to the same subtree for constructs like
389+
* BETWEEN, and we mustn't have OffsetVarNodes increment the varno of a
390+
* Var node twice. copyObject will expand any multiply-referenced subtree
391+
* into multiple copies.
392+
*/
393+
viewParse = copyObject(viewParse);
394+
395+
/* Create a dummy ParseState for addRangeTableEntryForRelation */
396+
pstate = make_parsestate(NULL);
397+
398+
/* need to open the rel for addRangeTableEntryForRelation */
399+
viewRel = relation_open(viewOid, AccessShareLock);
400+
401+
/*
402+
* Create the 2 new range table entries and form the new range table...
403+
* OLD first, then NEW....
404+
*/
405+
nsitem = addRangeTableEntryForRelation(pstate, viewRel,
406+
AccessShareLock,
407+
makeAlias("old", NIL),
408+
false, false);
409+
rt_entry1 = nsitem->p_rte;
410+
rte_perminfo1 = nsitem->p_perminfo;
411+
nsitem = addRangeTableEntryForRelation(pstate, viewRel,
412+
AccessShareLock,
413+
makeAlias("new", NIL),
414+
false, false);
415+
rt_entry2 = nsitem->p_rte;
416+
417+
/*
418+
* Add only the "old" RTEPermissionInfo at the head of view query's list
419+
* and update the other RTEs' perminfoindex accordingly. When rewriting a
420+
* query on the view, ApplyRetrieveRule() will transfer the view
421+
* relation's permission details into this RTEPermissionInfo. That's
422+
* needed because the view's RTE itself will be transposed into a subquery
423+
* RTE that can't carry the permission details; see the code stanza toward
424+
* the end of ApplyRetrieveRule() for how that's done.
425+
*/
426+
viewParse->rteperminfos = lcons(rte_perminfo1, viewParse->rteperminfos);
427+
foreach(lc, viewParse->rtable)
428+
{
429+
RangeTblEntry *rte = lfirst(lc);
430+
431+
if (rte->perminfoindex > 0)
432+
rte->perminfoindex += 1;
433+
}
434+
435+
/*
436+
* Also make the "new" RTE's RTEPermissionInfo undiscoverable. This is a
437+
* bit of a hack given that all the non-child RTE_RELATION entries really
438+
* should have a RTEPermissionInfo, but this dummy "new" RTE is going to
439+
* go away anyway in the very near future.
440+
*/
441+
rt_entry2->perminfoindex = 0;
442+
443+
new_rt = lcons(rt_entry1, lcons(rt_entry2, viewParse->rtable));
444+
445+
viewParse->rtable = new_rt;
446+
447+
/*
448+
* Now offset all var nodes by 2, and jointree RT indexes too.
449+
*/
450+
OffsetVarNodes((Node *) viewParse, 2, 0);
451+
452+
relation_close(viewRel, AccessShareLock);
453+
454+
return viewParse;
455+
}
456+
356457
/*
357458
* DefineView
358459
* Execute a CREATE VIEW command.
@@ -515,6 +616,12 @@ DefineView(ViewStmt *stmt, const char *queryString,
515616
void
516617
StoreViewQuery(Oid viewOid, Query *viewParse, bool replace)
517618
{
619+
/*
620+
* The range table of 'viewParse' does not contain entries for the "OLD"
621+
* and "NEW" relations. So... add them!
622+
*/
623+
viewParse = UpdateRangeTableOfViewParse(viewOid, viewParse);
624+
518625
/*
519626
* Now create the rules associated with the view.
520627
*/

src/backend/nodes/outfuncs.c

+1-6
Original file line numberDiff line numberDiff line change
@@ -512,10 +512,6 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
512512
case RTE_SUBQUERY:
513513
WRITE_NODE_FIELD(subquery);
514514
WRITE_BOOL_FIELD(security_barrier);
515-
/* we re-use these RELATION fields, too: */
516-
WRITE_OID_FIELD(relid);
517-
WRITE_INT_FIELD(rellockmode);
518-
WRITE_UINT_FIELD(perminfoindex);
519515
break;
520516
case RTE_JOIN:
521517
WRITE_ENUM_FIELD(jointype, JoinType);
@@ -549,11 +545,10 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
549545
case RTE_NAMEDTUPLESTORE:
550546
WRITE_STRING_FIELD(enrname);
551547
WRITE_FLOAT_FIELD(enrtuples);
548+
WRITE_OID_FIELD(relid);
552549
WRITE_NODE_FIELD(coltypes);
553550
WRITE_NODE_FIELD(coltypmods);
554551
WRITE_NODE_FIELD(colcollations);
555-
/* we re-use these RELATION fields, too: */
556-
WRITE_OID_FIELD(relid);
557552
break;
558553
case RTE_RESULT:
559554
/* no extra fields */

src/backend/nodes/readfuncs.c

+1-6
Original file line numberDiff line numberDiff line change
@@ -478,10 +478,6 @@ _readRangeTblEntry(void)
478478
case RTE_SUBQUERY:
479479
READ_NODE_FIELD(subquery);
480480
READ_BOOL_FIELD(security_barrier);
481-
/* we re-use these RELATION fields, too: */
482-
READ_OID_FIELD(relid);
483-
READ_INT_FIELD(rellockmode);
484-
READ_UINT_FIELD(perminfoindex);
485481
break;
486482
case RTE_JOIN:
487483
READ_ENUM_FIELD(jointype, JoinType);
@@ -524,11 +520,10 @@ _readRangeTblEntry(void)
524520
case RTE_NAMEDTUPLESTORE:
525521
READ_STRING_FIELD(enrname);
526522
READ_FLOAT_FIELD(enrtuples);
523+
READ_OID_FIELD(relid);
527524
READ_NODE_FIELD(coltypes);
528525
READ_NODE_FIELD(coltypmods);
529526
READ_NODE_FIELD(colcollations);
530-
/* we re-use these RELATION fields, too: */
531-
READ_OID_FIELD(relid);
532527
break;
533528
case RTE_RESULT:
534529
/* no extra fields */

src/backend/optimizer/plan/setrefs.c

+12-14
Original file line numberDiff line numberDiff line change
@@ -405,15 +405,13 @@ add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing)
405405
*
406406
* At top level, we must add all RTEs so that their indexes in the
407407
* flattened rangetable match up with their original indexes. When
408-
* recursing, we only care about extracting relation RTEs (and subquery
409-
* RTEs that were once relation RTEs).
408+
* recursing, we only care about extracting relation RTEs.
410409
*/
411410
foreach(lc, root->parse->rtable)
412411
{
413412
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
414413

415-
if (!recursing || rte->rtekind == RTE_RELATION ||
416-
(rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)))
414+
if (!recursing || rte->rtekind == RTE_RELATION)
417415
add_rte_to_flat_rtable(glob, root->parse->rteperminfos, rte);
418416
}
419417

@@ -503,9 +501,8 @@ flatten_rtes_walker(Node *node, flatten_rtes_walker_context *cxt)
503501
{
504502
RangeTblEntry *rte = (RangeTblEntry *) node;
505503

506-
/* As above, we need only save relation RTEs and former relations */
507-
if (rte->rtekind == RTE_RELATION ||
508-
(rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)))
504+
/* As above, we need only save relation RTEs */
505+
if (rte->rtekind == RTE_RELATION)
509506
add_rte_to_flat_rtable(cxt->glob, cxt->query->rteperminfos, rte);
510507
return false;
511508
}
@@ -563,8 +560,7 @@ add_rte_to_flat_rtable(PlannerGlobal *glob, List *rteperminfos,
563560
glob->finalrtable = lappend(glob->finalrtable, newrte);
564561

565562
/*
566-
* If it's a plain relation RTE (or a subquery that was once a view
567-
* reference), add the relation OID to relationOids.
563+
* If it's a plain relation RTE, add the table to relationOids.
568564
*
569565
* We do this even though the RTE might be unreferenced in the plan tree;
570566
* this would correspond to cases such as views that were expanded, child
@@ -574,8 +570,7 @@ add_rte_to_flat_rtable(PlannerGlobal *glob, List *rteperminfos,
574570
* Note we don't bother to avoid making duplicate list entries. We could,
575571
* but it would probably cost more cycles than it would save.
576572
*/
577-
if (newrte->rtekind == RTE_RELATION ||
578-
(newrte->rtekind == RTE_SUBQUERY && OidIsValid(newrte->relid)))
573+
if (newrte->rtekind == RTE_RELATION)
579574
glob->relationOids = lappend_oid(glob->relationOids, newrte->relid);
580575

581576
/*
@@ -3408,11 +3403,14 @@ extract_query_dependencies_walker(Node *node, PlannerInfo *context)
34083403
{
34093404
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
34103405

3411-
if (rte->rtekind == RTE_RELATION ||
3412-
(rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)) ||
3413-
(rte->rtekind == RTE_NAMEDTUPLESTORE && OidIsValid(rte->relid)))
3406+
if (rte->rtekind == RTE_RELATION)
34143407
context->glob->relationOids =
34153408
lappend_oid(context->glob->relationOids, rte->relid);
3409+
else if (rte->rtekind == RTE_NAMEDTUPLESTORE &&
3410+
OidIsValid(rte->relid))
3411+
context->glob->relationOids =
3412+
lappend_oid(context->glob->relationOids,
3413+
rte->relid);
34163414
}
34173415

34183416
/* And recurse into the query's subexpressions */

src/backend/parser/parse_relation.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -3834,7 +3834,7 @@ addRTEPermissionInfo(List **rteperminfos, RangeTblEntry *rte)
38343834
{
38353835
RTEPermissionInfo *perminfo;
38363836

3837-
Assert(OidIsValid(rte->relid));
3837+
Assert(rte->rtekind == RTE_RELATION);
38383838
Assert(rte->perminfoindex == 0);
38393839

38403840
/* Nope, so make one and add to the list. */

src/backend/rewrite/rewriteDefine.c

+7
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,13 @@ checkRuleResultList(List *targetList, TupleDesc resultDesc, bool isSelect,
633633
* setRuleCheckAsUser
634634
* Recursively scan a query or expression tree and set the checkAsUser
635635
* field to the given userid in all RTEPermissionInfos of the query.
636+
*
637+
* Note: for a view (ON SELECT rule), the checkAsUser field of the OLD
638+
* RTE entry's RTEPermissionInfo will be overridden when the view rule is
639+
* expanded, and the checkAsUser for the NEW RTE entry's RTEPermissionInfo is
640+
* irrelevant because its requiredPerms bits will always be zero. However, for
641+
* other types of rules it's important to set these fields to match the rule
642+
* owner. So we just set them always.
636643
*/
637644
void
638645
setRuleCheckAsUser(Node *node, Oid userid)

src/backend/rewrite/rewriteHandler.c

+26-12
Original file line numberDiff line numberDiff line change
@@ -1715,7 +1715,10 @@ ApplyRetrieveRule(Query *parsetree,
17151715
List *activeRIRs)
17161716
{
17171717
Query *rule_action;
1718-
RangeTblEntry *rte;
1718+
RangeTblEntry *rte,
1719+
*subrte;
1720+
RTEPermissionInfo *perminfo,
1721+
*sub_perminfo;
17191722
RowMarkClause *rc;
17201723

17211724
if (list_length(rule->actions) != 1)
@@ -1827,21 +1830,33 @@ ApplyRetrieveRule(Query *parsetree,
18271830
* original RTE to a subquery RTE.
18281831
*/
18291832
rte = rt_fetch(rt_index, parsetree->rtable);
1833+
perminfo = getRTEPermissionInfo(parsetree->rteperminfos, rte);
18301834

18311835
rte->rtekind = RTE_SUBQUERY;
18321836
rte->subquery = rule_action;
18331837
rte->security_barrier = RelationIsSecurityView(relation);
1834-
1835-
/*
1836-
* Clear fields that should not be set in a subquery RTE. Note that we
1837-
* leave the relid, rellockmode, and perminfoindex fields set, so that the
1838-
* view relation can be appropriately locked before execution and its
1839-
* permissions checked.
1840-
*/
1838+
/* Clear fields that should not be set in a subquery RTE */
1839+
rte->relid = InvalidOid;
18411840
rte->relkind = 0;
1841+
rte->rellockmode = 0;
18421842
rte->tablesample = NULL;
1843+
rte->perminfoindex = 0; /* no permission checking for this RTE */
18431844
rte->inh = false; /* must not be set for a subquery */
18441845

1846+
/*
1847+
* We move the view's permission check data down to its RTEPermissionInfo
1848+
* contained in the view query, which the OLD entry in its range table
1849+
* points to.
1850+
*/
1851+
subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable);
1852+
Assert(subrte->relid == relation->rd_id);
1853+
sub_perminfo = getRTEPermissionInfo(rule_action->rteperminfos, subrte);
1854+
sub_perminfo->requiredPerms = perminfo->requiredPerms;
1855+
sub_perminfo->checkAsUser = perminfo->checkAsUser;
1856+
sub_perminfo->selectedCols = perminfo->selectedCols;
1857+
sub_perminfo->insertedCols = perminfo->insertedCols;
1858+
sub_perminfo->updatedCols = perminfo->updatedCols;
1859+
18451860
return parsetree;
18461861
}
18471862

@@ -1852,10 +1867,9 @@ ApplyRetrieveRule(Query *parsetree,
18521867
* aggregate. We leave it to the planner to detect that.
18531868
*
18541869
* NB: this must agree with the parser's transformLockingClause() routine.
1855-
* However, we used to have to avoid marking a view's OLD and NEW rels for
1856-
* updating, which motivated scanning the jointree to determine which rels
1857-
* are used. Possibly that could now be simplified into just scanning the
1858-
* rangetable as the parser does.
1870+
* However, unlike the parser we have to be careful not to mark a view's
1871+
* OLD and NEW rels for updating. The best way to handle that seems to be
1872+
* to scan the jointree to determine which rels are used.
18591873
*/
18601874
static void
18611875
markQueryForLocking(Query *qry, Node *jtnode,

src/backend/utils/cache/plancache.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -1769,8 +1769,7 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
17691769
{
17701770
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
17711771

1772-
if (!(rte->rtekind == RTE_RELATION ||
1773-
(rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid))))
1772+
if (rte->rtekind != RTE_RELATION)
17741773
continue;
17751774

17761775
/*

0 commit comments

Comments
 (0)