diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/commands/lockcmds.c | 9 | ||||
-rw-r--r-- | src/backend/commands/view.c | 107 | ||||
-rw-r--r-- | src/backend/nodes/outfuncs.c | 7 | ||||
-rw-r--r-- | src/backend/nodes/readfuncs.c | 7 | ||||
-rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 26 | ||||
-rw-r--r-- | src/backend/parser/parse_relation.c | 2 | ||||
-rw-r--r-- | src/backend/rewrite/rewriteDefine.c | 7 | ||||
-rw-r--r-- | src/backend/rewrite/rewriteHandler.c | 38 | ||||
-rw-r--r-- | src/backend/utils/cache/plancache.c | 3 |
9 files changed, 41 insertions, 165 deletions
diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c index 6bf1b815f01..43c7d7f4bb2 100644 --- a/src/backend/commands/lockcmds.c +++ b/src/backend/commands/lockcmds.c @@ -195,15 +195,6 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context) char relkind = rte->relkind; char *relname = get_rel_name(relid); - /* - * The OLD and NEW placeholder entries in the view's rtable are - * skipped. - */ - if (relid == context->viewoid && - (strcmp(rte->eref->aliasname, "old") == 0 || - strcmp(rte->eref->aliasname, "new") == 0)) - continue; - /* Currently, we only allow plain tables or views to be locked. */ if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE && relkind != RELKIND_VIEW) diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index 0bacb819e52..ff98c773f55 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -353,107 +353,6 @@ DefineViewRules(Oid viewOid, Query *viewParse, bool replace) */ } -/*--------------------------------------------------------------- - * UpdateRangeTableOfViewParse - * - * Update the range table of the given parsetree. - * This update consists of adding two new entries IN THE BEGINNING - * of the range table (otherwise the rule system will die a slow, - * horrible and painful death, and we do not want that now, do we?) - * one for the OLD relation and one for the NEW one (both of - * them refer in fact to the "view" relation). - * - * Of course we must also increase the 'varnos' of all the Var nodes - * by 2... - * - * These extra RT entries are not actually used in the query, - * except for run-time locking. - *--------------------------------------------------------------- - */ -static Query * -UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse) -{ - Relation viewRel; - List *new_rt; - ParseNamespaceItem *nsitem; - RangeTblEntry *rt_entry1, - *rt_entry2; - RTEPermissionInfo *rte_perminfo1; - ParseState *pstate; - ListCell *lc; - - /* - * Make a copy of the given parsetree. It's not so much that we don't - * want to scribble on our input, it's that the parser has a bad habit of - * outputting multiple links to the same subtree for constructs like - * BETWEEN, and we mustn't have OffsetVarNodes increment the varno of a - * Var node twice. copyObject will expand any multiply-referenced subtree - * into multiple copies. - */ - viewParse = copyObject(viewParse); - - /* Create a dummy ParseState for addRangeTableEntryForRelation */ - pstate = make_parsestate(NULL); - - /* need to open the rel for addRangeTableEntryForRelation */ - viewRel = relation_open(viewOid, AccessShareLock); - - /* - * Create the 2 new range table entries and form the new range table... - * OLD first, then NEW.... - */ - nsitem = addRangeTableEntryForRelation(pstate, viewRel, - AccessShareLock, - makeAlias("old", NIL), - false, false); - rt_entry1 = nsitem->p_rte; - rte_perminfo1 = nsitem->p_perminfo; - nsitem = addRangeTableEntryForRelation(pstate, viewRel, - AccessShareLock, - makeAlias("new", NIL), - false, false); - rt_entry2 = nsitem->p_rte; - - /* - * Add only the "old" RTEPermissionInfo at the head of view query's list - * and update the other RTEs' perminfoindex accordingly. When rewriting a - * query on the view, ApplyRetrieveRule() will transfer the view - * relation's permission details into this RTEPermissionInfo. That's - * needed because the view's RTE itself will be transposed into a subquery - * RTE that can't carry the permission details; see the code stanza toward - * the end of ApplyRetrieveRule() for how that's done. - */ - viewParse->rteperminfos = lcons(rte_perminfo1, viewParse->rteperminfos); - foreach(lc, viewParse->rtable) - { - RangeTblEntry *rte = lfirst(lc); - - if (rte->perminfoindex > 0) - rte->perminfoindex += 1; - } - - /* - * Also make the "new" RTE's RTEPermissionInfo undiscoverable. This is a - * bit of a hack given that all the non-child RTE_RELATION entries really - * should have a RTEPermissionInfo, but this dummy "new" RTE is going to - * go away anyway in the very near future. - */ - rt_entry2->perminfoindex = 0; - - new_rt = lcons(rt_entry1, lcons(rt_entry2, viewParse->rtable)); - - viewParse->rtable = new_rt; - - /* - * Now offset all var nodes by 2, and jointree RT indexes too. - */ - OffsetVarNodes((Node *) viewParse, 2, 0); - - relation_close(viewRel, AccessShareLock); - - return viewParse; -} - /* * DefineView * Execute a CREATE VIEW command. @@ -617,12 +516,6 @@ void StoreViewQuery(Oid viewOid, Query *viewParse, bool replace) { /* - * The range table of 'viewParse' does not contain entries for the "OLD" - * and "NEW" relations. So... add them! - */ - viewParse = UpdateRangeTableOfViewParse(viewOid, viewParse); - - /* * Now create the rules associated with the view. */ DefineViewRules(viewOid, viewParse, replace); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 69324d5a9aa..6b368b08b21 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -512,6 +512,10 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node) case RTE_SUBQUERY: WRITE_NODE_FIELD(subquery); WRITE_BOOL_FIELD(security_barrier); + /* we re-use these RELATION fields, too: */ + WRITE_OID_FIELD(relid); + WRITE_INT_FIELD(rellockmode); + WRITE_UINT_FIELD(perminfoindex); break; case RTE_JOIN: WRITE_ENUM_FIELD(jointype, JoinType); @@ -545,10 +549,11 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node) case RTE_NAMEDTUPLESTORE: WRITE_STRING_FIELD(enrname); WRITE_FLOAT_FIELD(enrtuples); - WRITE_OID_FIELD(relid); WRITE_NODE_FIELD(coltypes); WRITE_NODE_FIELD(coltypmods); WRITE_NODE_FIELD(colcollations); + /* we re-use these RELATION fields, too: */ + WRITE_OID_FIELD(relid); break; case RTE_RESULT: /* no extra fields */ diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 30cd7a0da6b..f3629cdfd14 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -478,6 +478,10 @@ _readRangeTblEntry(void) case RTE_SUBQUERY: READ_NODE_FIELD(subquery); READ_BOOL_FIELD(security_barrier); + /* we re-use these RELATION fields, too: */ + READ_OID_FIELD(relid); + READ_INT_FIELD(rellockmode); + READ_UINT_FIELD(perminfoindex); break; case RTE_JOIN: READ_ENUM_FIELD(jointype, JoinType); @@ -520,10 +524,11 @@ _readRangeTblEntry(void) case RTE_NAMEDTUPLESTORE: READ_STRING_FIELD(enrname); READ_FLOAT_FIELD(enrtuples); - READ_OID_FIELD(relid); READ_NODE_FIELD(coltypes); READ_NODE_FIELD(coltypmods); READ_NODE_FIELD(colcollations); + /* we re-use these RELATION fields, too: */ + READ_OID_FIELD(relid); break; case RTE_RESULT: /* no extra fields */ diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index ed9c1e61876..85ba9d1ca1e 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -405,13 +405,15 @@ add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing) * * At top level, we must add all RTEs so that their indexes in the * flattened rangetable match up with their original indexes. When - * recursing, we only care about extracting relation RTEs. + * recursing, we only care about extracting relation RTEs (and subquery + * RTEs that were once relation RTEs). */ foreach(lc, root->parse->rtable) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); - if (!recursing || rte->rtekind == RTE_RELATION) + if (!recursing || rte->rtekind == RTE_RELATION || + (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid))) add_rte_to_flat_rtable(glob, root->parse->rteperminfos, rte); } @@ -501,8 +503,9 @@ flatten_rtes_walker(Node *node, flatten_rtes_walker_context *cxt) { RangeTblEntry *rte = (RangeTblEntry *) node; - /* As above, we need only save relation RTEs */ - if (rte->rtekind == RTE_RELATION) + /* As above, we need only save relation RTEs and former relations */ + if (rte->rtekind == RTE_RELATION || + (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid))) add_rte_to_flat_rtable(cxt->glob, cxt->query->rteperminfos, rte); return false; } @@ -560,7 +563,8 @@ add_rte_to_flat_rtable(PlannerGlobal *glob, List *rteperminfos, glob->finalrtable = lappend(glob->finalrtable, newrte); /* - * If it's a plain relation RTE, add the table to relationOids. + * If it's a plain relation RTE (or a subquery that was once a view + * reference), add the relation OID to relationOids. * * We do this even though the RTE might be unreferenced in the plan tree; * this would correspond to cases such as views that were expanded, child @@ -570,7 +574,8 @@ add_rte_to_flat_rtable(PlannerGlobal *glob, List *rteperminfos, * Note we don't bother to avoid making duplicate list entries. We could, * but it would probably cost more cycles than it would save. */ - if (newrte->rtekind == RTE_RELATION) + if (newrte->rtekind == RTE_RELATION || + (newrte->rtekind == RTE_SUBQUERY && OidIsValid(newrte->relid))) glob->relationOids = lappend_oid(glob->relationOids, newrte->relid); /* @@ -3403,14 +3408,11 @@ extract_query_dependencies_walker(Node *node, PlannerInfo *context) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); - if (rte->rtekind == RTE_RELATION) + if (rte->rtekind == RTE_RELATION || + (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)) || + (rte->rtekind == RTE_NAMEDTUPLESTORE && OidIsValid(rte->relid))) context->glob->relationOids = lappend_oid(context->glob->relationOids, rte->relid); - else if (rte->rtekind == RTE_NAMEDTUPLESTORE && - OidIsValid(rte->relid)) - context->glob->relationOids = - lappend_oid(context->glob->relationOids, - rte->relid); } /* And recurse into the query's subexpressions */ diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 5389a0eddb6..b490541f03d 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -3834,7 +3834,7 @@ addRTEPermissionInfo(List **rteperminfos, RangeTblEntry *rte) { RTEPermissionInfo *perminfo; - Assert(rte->rtekind == RTE_RELATION); + Assert(OidIsValid(rte->relid)); Assert(rte->perminfoindex == 0); /* Nope, so make one and add to the list. */ diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index 52272202881..e36fc72e1ed 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -633,13 +633,6 @@ checkRuleResultList(List *targetList, TupleDesc resultDesc, bool isSelect, * setRuleCheckAsUser * Recursively scan a query or expression tree and set the checkAsUser * field to the given userid in all RTEPermissionInfos of the query. - * - * Note: for a view (ON SELECT rule), the checkAsUser field of the OLD - * RTE entry's RTEPermissionInfo will be overridden when the view rule is - * expanded, and the checkAsUser for the NEW RTE entry's RTEPermissionInfo is - * irrelevant because its requiredPerms bits will always be zero. However, for - * other types of rules it's important to set these fields to match the rule - * owner. So we just set them always. */ void setRuleCheckAsUser(Node *node, Oid userid) diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index 1960dad7013..c74bac20b13 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -1715,10 +1715,7 @@ ApplyRetrieveRule(Query *parsetree, List *activeRIRs) { Query *rule_action; - RangeTblEntry *rte, - *subrte; - RTEPermissionInfo *perminfo, - *sub_perminfo; + RangeTblEntry *rte; RowMarkClause *rc; if (list_length(rule->actions) != 1) @@ -1830,32 +1827,20 @@ ApplyRetrieveRule(Query *parsetree, * original RTE to a subquery RTE. */ rte = rt_fetch(rt_index, parsetree->rtable); - perminfo = getRTEPermissionInfo(parsetree->rteperminfos, rte); rte->rtekind = RTE_SUBQUERY; rte->subquery = rule_action; rte->security_barrier = RelationIsSecurityView(relation); - /* Clear fields that should not be set in a subquery RTE */ - rte->relid = InvalidOid; - rte->relkind = 0; - rte->rellockmode = 0; - rte->tablesample = NULL; - rte->perminfoindex = 0; /* no permission checking for this RTE */ - rte->inh = false; /* must not be set for a subquery */ /* - * We move the view's permission check data down to its RTEPermissionInfo - * contained in the view query, which the OLD entry in its range table - * points to. + * Clear fields that should not be set in a subquery RTE. Note that we + * leave the relid, rellockmode, and perminfoindex fields set, so that the + * view relation can be appropriately locked before execution and its + * permissions checked. */ - subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable); - Assert(subrte->relid == relation->rd_id); - sub_perminfo = getRTEPermissionInfo(rule_action->rteperminfos, subrte); - sub_perminfo->requiredPerms = perminfo->requiredPerms; - sub_perminfo->checkAsUser = perminfo->checkAsUser; - sub_perminfo->selectedCols = perminfo->selectedCols; - sub_perminfo->insertedCols = perminfo->insertedCols; - sub_perminfo->updatedCols = perminfo->updatedCols; + rte->relkind = 0; + rte->tablesample = NULL; + rte->inh = false; /* must not be set for a subquery */ return parsetree; } @@ -1867,9 +1852,10 @@ ApplyRetrieveRule(Query *parsetree, * aggregate. We leave it to the planner to detect that. * * NB: this must agree with the parser's transformLockingClause() routine. - * However, unlike the parser we have to be careful not to mark a view's - * OLD and NEW rels for updating. The best way to handle that seems to be - * to scan the jointree to determine which rels are used. + * However, we used to have to avoid marking a view's OLD and NEW rels for + * updating, which motivated scanning the jointree to determine which rels + * are used. Possibly that could now be simplified into just scanning the + * rangetable as the parser does. */ static void markQueryForLocking(Query *qry, Node *jtnode, diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c index 92f6d5795fc..77c2ba3f8f4 100644 --- a/src/backend/utils/cache/plancache.c +++ b/src/backend/utils/cache/plancache.c @@ -1769,7 +1769,8 @@ AcquireExecutorLocks(List *stmt_list, bool acquire) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2); - if (rte->rtekind != RTE_RELATION) + if (!(rte->rtekind == RTE_RELATION || + (rte->rtekind == RTE_SUBQUERY && OidIsValid(rte->relid)))) continue; /* |