*** pgsql/src/backend/parser/parse_relation.c 2009/01/01 17:23:46 1.140 --- pgsql/src/backend/parser/parse_relation.c 2009/01/22 20:16:05 1.141 *************** *** 8,14 **** * * * IDENTIFICATION ! * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.139 2008/10/08 01:14:44 tgl Exp $ * *------------------------------------------------------------------------- */ --- 8,14 ---- * * * IDENTIFICATION ! * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.140 2009/01/01 17:23:46 momjian Exp $ * *------------------------------------------------------------------------- */ *************** static RangeTblEntry *scanNameSpaceForRe *** 39,44 **** --- 39,46 ---- const char *refname, int location); static RangeTblEntry *scanNameSpaceForRelid(ParseState *pstate, Oid relid, int location); + static void markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte, + int rtindex, AttrNumber col); static bool isLockedRel(ParseState *pstate, char *refname); static void expandRelation(Oid relid, Alias *eref, int rtindex, int sublevels_up, *************** GetCTEForRTE(ParseState *pstate, RangeTb *** 435,448 **** * If found, return an appropriate Var node, else return NULL. * If the name proves ambiguous within this RTE, raise error. * ! * Side effect: if we find a match, mark the RTE as requiring read access. ! * See comments in setTargetTable(). ! * ! * NOTE: if the RTE is for a join, marking it as requiring read access does ! * nothing. It might seem that we need to propagate the mark to all the ! * contained RTEs, but that is not necessary. This is so because a join ! * expression can only appear in a FROM clause, and any table named in ! * FROM will be marked as requiring read access from the beginning. */ Node * scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname, --- 437,444 ---- * If found, return an appropriate Var node, else return NULL. * If the name proves ambiguous within this RTE, raise error. * ! * Side effect: if we find a match, mark the RTE as requiring read access ! * for the column. */ Node * scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname, *************** scanRTEForColumn(ParseState *pstate, Ran *** 450,455 **** --- 446,452 ---- { Node *result = NULL; int attnum = 0; + Var *var; ListCell *c; /* *************** scanRTEForColumn(ParseState *pstate, Ran *** 476,484 **** errmsg("column reference \"%s\" is ambiguous", colname), parser_errposition(pstate, location))); ! result = (Node *) make_var(pstate, rte, attnum, location); ! /* Require read access */ ! rte->requiredPerms |= ACL_SELECT; } } --- 473,482 ---- errmsg("column reference \"%s\" is ambiguous", colname), parser_errposition(pstate, location))); ! var = make_var(pstate, rte, attnum, location); ! /* Require read access to the column */ ! markVarForSelectPriv(pstate, var, rte); ! result = (Node *) var; } } *************** scanRTEForColumn(ParseState *pstate, Ran *** 504,512 **** Int16GetDatum(attnum), 0, 0)) { ! result = (Node *) make_var(pstate, rte, attnum, location); ! /* Require read access */ ! rte->requiredPerms |= ACL_SELECT; } } } --- 502,511 ---- Int16GetDatum(attnum), 0, 0)) { ! var = make_var(pstate, rte, attnum, location); ! /* Require read access to the column */ ! markVarForSelectPriv(pstate, var, rte); ! result = (Node *) var; } } } *************** qualifiedNameToVar(ParseState *pstate, *** 595,600 **** --- 594,715 ---- } /* + * markRTEForSelectPriv + * Mark the specified column of an RTE as requiring SELECT privilege + * + * col == InvalidAttrNumber means a "whole row" reference + * + * The caller should pass the actual RTE if it has it handy; otherwise pass + * NULL, and we'll look it up here. (This uglification of the API is + * worthwhile because nearly all external callers have the RTE at hand.) + */ + static void + markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte, + int rtindex, AttrNumber col) + { + if (rte == NULL) + rte = rt_fetch(rtindex, pstate->p_rtable); + + if (rte->rtekind == RTE_RELATION) + { + /* Make sure the rel as a whole is marked for SELECT access */ + rte->requiredPerms |= ACL_SELECT; + /* Must offset the attnum to fit in a bitmapset */ + rte->selectedCols = bms_add_member(rte->selectedCols, + col - FirstLowInvalidHeapAttributeNumber); + } + else if (rte->rtekind == RTE_JOIN) + { + if (col == InvalidAttrNumber) + { + /* + * A whole-row reference to a join has to be treated as + * whole-row references to the two inputs. + */ + JoinExpr *j; + + if (rtindex > 0 && rtindex <= list_length(pstate->p_joinexprs)) + j = (JoinExpr *) list_nth(pstate->p_joinexprs, rtindex - 1); + else + j = NULL; + if (j == NULL) + elog(ERROR, "could not find JoinExpr for whole-row reference"); + Assert(IsA(j, JoinExpr)); + + /* Note: we can't see FromExpr here */ + if (IsA(j->larg, RangeTblRef)) + { + int varno = ((RangeTblRef *) j->larg)->rtindex; + + markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber); + } + else if (IsA(j->larg, JoinExpr)) + { + int varno = ((JoinExpr *) j->larg)->rtindex; + + markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber); + } + else + elog(ERROR, "unrecognized node type: %d", + (int) nodeTag(j->larg)); + if (IsA(j->rarg, RangeTblRef)) + { + int varno = ((RangeTblRef *) j->rarg)->rtindex; + + markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber); + } + else if (IsA(j->rarg, JoinExpr)) + { + int varno = ((JoinExpr *) j->rarg)->rtindex; + + markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber); + } + else + elog(ERROR, "unrecognized node type: %d", + (int) nodeTag(j->rarg)); + } + else + { + /* + * Regular join attribute, look at the alias-variable list. + * + * The aliasvar could be either a Var or a COALESCE expression, + * but in the latter case we should already have marked the two + * referent variables as being selected, due to their use in the + * JOIN clause. So we need only be concerned with the simple + * Var case. + */ + Var *aliasvar; + + Assert(col > 0 && col <= list_length(rte->joinaliasvars)); + aliasvar = (Var *) list_nth(rte->joinaliasvars, col - 1); + if (IsA(aliasvar, Var)) + markVarForSelectPriv(pstate, aliasvar, NULL); + } + } + /* other RTE types don't require privilege marking */ + } + + /* + * markVarForSelectPriv + * Mark the RTE referenced by a Var as requiring SELECT privilege + * + * The caller should pass the Var's referenced RTE if it has it handy + * (nearly all do); otherwise pass NULL. + */ + void + markVarForSelectPriv(ParseState *pstate, Var *var, RangeTblEntry *rte) + { + Index lv; + + Assert(IsA(var, Var)); + /* Find the appropriate pstate if it's an uplevel Var */ + for (lv = 0; lv < var->varlevelsup; lv++) + pstate = pstate->parentParseState; + markRTEForSelectPriv(pstate, rte, var->varno, var->varattno); + } + + /* * buildRelationAliases * Construct the eref column name list for a relation RTE. * This code is also used for the case of a function RTE returning *************** addRangeTableEntry(ParseState *pstate, *** 838,843 **** --- 953,960 ---- rte->requiredPerms = ACL_SELECT; rte->checkAsUser = InvalidOid; /* not set-uid by default, either */ + rte->selectedCols = NULL; + rte->modifiedCols = NULL; /* * Add completed RTE to pstate's range table list, but not to join list *************** addRangeTableEntryForRelation(ParseState *** 891,896 **** --- 1008,1015 ---- rte->requiredPerms = ACL_SELECT; rte->checkAsUser = InvalidOid; /* not set-uid by default, either */ + rte->selectedCols = NULL; + rte->modifiedCols = NULL; /* * Add completed RTE to pstate's range table list, but not to join list *************** addRangeTableEntryForSubquery(ParseState *** 969,974 **** --- 1088,1095 ---- rte->requiredPerms = 0; rte->checkAsUser = InvalidOid; + rte->selectedCols = NULL; + rte->modifiedCols = NULL; /* * Add completed RTE to pstate's range table list, but not to join list *************** addRangeTableEntryForFunction(ParseState *** 1101,1106 **** --- 1222,1229 ---- rte->requiredPerms = 0; rte->checkAsUser = InvalidOid; + rte->selectedCols = NULL; + rte->modifiedCols = NULL; /* * Add completed RTE to pstate's range table list, but not to join list *************** addRangeTableEntryForValues(ParseState * *** 1168,1175 **** --- 1291,1301 ---- */ rte->inh = false; /* never true for values RTEs */ rte->inFromCl = inFromCl; + rte->requiredPerms = 0; rte->checkAsUser = InvalidOid; + rte->selectedCols = NULL; + rte->modifiedCols = NULL; /* * Add completed RTE to pstate's range table list, but not to join list *************** addRangeTableEntryForJoin(ParseState *ps *** 1239,1244 **** --- 1365,1372 ---- rte->requiredPerms = 0; rte->checkAsUser = InvalidOid; + rte->selectedCols = NULL; + rte->modifiedCols = NULL; /* * Add completed RTE to pstate's range table list, but not to join list *************** addRangeTableEntryForCTE(ParseState *pst *** 1320,1325 **** --- 1448,1455 ---- rte->requiredPerms = 0; rte->checkAsUser = InvalidOid; + rte->selectedCols = NULL; + rte->modifiedCols = NULL; /* * Add completed RTE to pstate's range table list, but not to join list *************** expandTupleDesc(TupleDesc tupdesc, Alias *** 1803,1808 **** --- 1933,1939 ---- * As with expandRTE, rtindex/sublevels_up determine the varno/varlevelsup * fields of the Vars produced, and location sets their location. * pstate->p_next_resno determines the resnos assigned to the TLEs. + * The referenced columns are marked as requiring SELECT access. */ List * expandRelAttrs(ParseState *pstate, RangeTblEntry *rte, *************** expandRelAttrs(ParseState *pstate, Range *** 1817,1826 **** expandRTE(rte, rtindex, sublevels_up, location, false, &names, &vars); forboth(name, names, var, vars) { char *label = strVal(lfirst(name)); ! Node *varnode = (Node *) lfirst(var); TargetEntry *te; te = makeTargetEntry((Expr *) varnode, --- 1948,1964 ---- expandRTE(rte, rtindex, sublevels_up, location, false, &names, &vars); + /* + * Require read access to the table. This is normally redundant with the + * markVarForSelectPriv calls below, but not if the table has zero + * columns. + */ + rte->requiredPerms |= ACL_SELECT; + forboth(name, names, var, vars) { char *label = strVal(lfirst(name)); ! Var *varnode = (Var *) lfirst(var); TargetEntry *te; te = makeTargetEntry((Expr *) varnode, *************** expandRelAttrs(ParseState *pstate, Range *** 1828,1833 **** --- 1966,1974 ---- label, false); te_list = lappend(te_list, te); + + /* Require read access to each column */ + markVarForSelectPriv(pstate, varnode, rte); } Assert(name == NULL && var == NULL); /* lists not the same length? */