1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-22 21:53:06 +03:00

Support column-level privileges, as required by SQL standard.

Stephen Frost, with help from KaiGai Kohei and others
This commit is contained in:
Tom Lane
2009-01-22 20:16:10 +00:00
parent bf136cf6e3
commit 3cb5d6580a
59 changed files with 2314 additions and 722 deletions

View File

@@ -17,13 +17,14 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.387 2009/01/08 13:42:33 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.388 2009/01/22 20:16:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/sysattr.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
@@ -422,6 +423,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
* bugs of just that nature...)
*/
sub_pstate->p_rtable = sub_rtable;
sub_pstate->p_joinexprs = NIL; /* sub_rtable has no joins */
sub_pstate->p_relnamespace = sub_relnamespace;
sub_pstate->p_varnamespace = sub_varnamespace;
@@ -629,7 +631,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
/*
* Generate query's target list using the computed list of expressions.
* Also, mark all the target columns as needing insert permissions.
*/
rte = pstate->p_target_rangetblentry;
qry->targetList = NIL;
icols = list_head(icolumns);
attnos = list_head(attrnos);
@@ -637,17 +641,22 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
{
Expr *expr = (Expr *) lfirst(lc);
ResTarget *col;
AttrNumber attr_num;
TargetEntry *tle;
col = (ResTarget *) lfirst(icols);
Assert(IsA(col, ResTarget));
attr_num = (AttrNumber) lfirst_int(attnos);
tle = makeTargetEntry(expr,
(AttrNumber) lfirst_int(attnos),
attr_num,
col->name,
false);
qry->targetList = lappend(qry->targetList, tle);
rte->modifiedCols = bms_add_member(rte->modifiedCols,
attr_num - FirstLowInvalidHeapAttributeNumber);
icols = lnext(icols);
attnos = lnext(attnos);
}
@@ -1129,8 +1138,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
List *targetvars,
*targetnames,
*sv_relnamespace,
*sv_varnamespace,
*sv_rtable;
*sv_varnamespace;
int sv_rtable_length;
RangeTblEntry *jrte;
int tllen;
@@ -1254,16 +1263,15 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
* "ORDER BY upper(foo)" will draw the right error message rather than
* "foo not found".
*/
jrte = addRangeTableEntryForJoin(NULL,
sv_rtable_length = list_length(pstate->p_rtable);
jrte = addRangeTableEntryForJoin(pstate,
targetnames,
JOIN_INNER,
targetvars,
NULL,
false);
sv_rtable = pstate->p_rtable;
pstate->p_rtable = list_make1(jrte);
sv_relnamespace = pstate->p_relnamespace;
pstate->p_relnamespace = NIL; /* no qualified names allowed */
@@ -1283,7 +1291,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
&qry->targetList,
false /* no unknowns expected */ );
pstate->p_rtable = sv_rtable;
pstate->p_rtable = list_truncate(pstate->p_rtable, sv_rtable_length);
pstate->p_relnamespace = sv_relnamespace;
pstate->p_varnamespace = sv_varnamespace;
@@ -1618,6 +1626,7 @@ static Query *
transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
{
Query *qry = makeNode(Query);
RangeTblEntry *target_rte;
Node *qual;
ListCell *origTargetList;
ListCell *tl;
@@ -1675,6 +1684,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
pstate->p_next_resno = pstate->p_target_relation->rd_rel->relnatts + 1;
/* Prepare non-junk columns for assignment to target table */
target_rte = pstate->p_target_rangetblentry;
origTargetList = list_head(stmt->targetList);
foreach(tl, qry->targetList)
@@ -1715,6 +1725,10 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
origTarget->indirection,
origTarget->location);
/* Mark the target column as requiring update permissions */
target_rte->modifiedCols = bms_add_member(target_rte->modifiedCols,
attrno - FirstLowInvalidHeapAttributeNumber);
origTargetList = lnext(origTargetList);
}
if (origTargetList != NULL)

View File

@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.655 2009/01/16 13:27:23 heikki Exp $
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.656 2009/01/22 20:16:05 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -94,6 +94,13 @@ extern List *parsetree; /* final parse result is delivered here */
static bool QueryIsRule = FALSE;
/* Private struct for the result of privilege_target production */
typedef struct PrivTarget
{
GrantObjectType objtype;
List *objs;
} PrivTarget;
/*
* If you need access to certain yacc-generated variables and find that
* they're static by default, uncomment the next line. (this is not a
@@ -167,7 +174,8 @@ static TypeName *TableFuncTypeName(List *columns);
WithClause *with;
A_Indices *aind;
ResTarget *target;
PrivTarget *privtarget;
struct PrivTarget *privtarget;
AccessPriv *accesspriv;
InsertStmt *istmt;
VariableSetStmt *vsetstmt;
@@ -254,7 +262,7 @@ static TypeName *TableFuncTypeName(List *columns);
%type <str> iso_level opt_encoding
%type <node> grantee
%type <list> grantee_list
%type <str> privilege
%type <accesspriv> privilege
%type <list> privileges privilege_list
%type <privtarget> privilege_target
%type <funwithargs> function_with_argtypes
@@ -4210,12 +4218,11 @@ RevokeStmt:
/*
* A privilege list is represented as a list of strings; the validity of
* the privilege names gets checked at execution. This is a bit annoying
* but we have little choice because of the syntactic conflict with lists
* of role names in GRANT/REVOKE. What's more, we have to call out in
* the "privilege" production any reserved keywords that need to be usable
* as privilege names.
* Privilege names are represented as strings; the validity of the privilege
* names gets checked at execution. This is a bit annoying but we have little
* choice because of the syntactic conflict with lists of role names in
* GRANT/REVOKE. What's more, we have to call out in the "privilege"
* production any reserved keywords that need to be usable as privilege names.
*/
/* either ALL [PRIVILEGES] or a list of individual privileges */
@@ -4225,18 +4232,54 @@ privileges: privilege_list
{ $$ = NIL; }
| ALL PRIVILEGES
{ $$ = NIL; }
| ALL '(' columnList ')'
{
AccessPriv *n = makeNode(AccessPriv);
n->priv_name = NULL;
n->cols = $3;
$$ = list_make1(n);
}
| ALL PRIVILEGES '(' columnList ')'
{
AccessPriv *n = makeNode(AccessPriv);
n->priv_name = NULL;
n->cols = $4;
$$ = list_make1(n);
}
;
privilege_list: privilege
{ $$ = list_make1(makeString($1)); }
| privilege_list ',' privilege
{ $$ = lappend($1, makeString($3)); }
privilege_list: privilege { $$ = list_make1($1); }
| privilege_list ',' privilege { $$ = lappend($1, $3); }
;
privilege: SELECT { $$ = pstrdup($1); }
| REFERENCES { $$ = pstrdup($1); }
| CREATE { $$ = pstrdup($1); }
| ColId { $$ = $1; }
privilege: SELECT opt_column_list
{
AccessPriv *n = makeNode(AccessPriv);
n->priv_name = pstrdup($1);
n->cols = $2;
$$ = n;
}
| REFERENCES opt_column_list
{
AccessPriv *n = makeNode(AccessPriv);
n->priv_name = pstrdup($1);
n->cols = $2;
$$ = n;
}
| CREATE opt_column_list
{
AccessPriv *n = makeNode(AccessPriv);
n->priv_name = pstrdup($1);
n->cols = $2;
$$ = n;
}
| ColId opt_column_list
{
AccessPriv *n = makeNode(AccessPriv);
n->priv_name = $1;
n->cols = $2;
$$ = n;
}
;
@@ -4246,70 +4289,70 @@ privilege: SELECT { $$ = pstrdup($1); }
privilege_target:
qualified_name_list
{
PrivTarget *n = makeNode(PrivTarget);
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
n->objtype = ACL_OBJECT_RELATION;
n->objs = $1;
$$ = n;
}
| TABLE qualified_name_list
{
PrivTarget *n = makeNode(PrivTarget);
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
n->objtype = ACL_OBJECT_RELATION;
n->objs = $2;
$$ = n;
}
| SEQUENCE qualified_name_list
{
PrivTarget *n = makeNode(PrivTarget);
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
n->objtype = ACL_OBJECT_SEQUENCE;
n->objs = $2;
$$ = n;
}
| FOREIGN DATA_P WRAPPER name_list
{
PrivTarget *n = makeNode(PrivTarget);
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
n->objtype = ACL_OBJECT_FDW;
n->objs = $4;
$$ = n;
}
| FOREIGN SERVER name_list
{
PrivTarget *n = makeNode(PrivTarget);
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
n->objtype = ACL_OBJECT_FOREIGN_SERVER;
n->objs = $3;
$$ = n;
}
| FUNCTION function_with_argtypes_list
{
PrivTarget *n = makeNode(PrivTarget);
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
n->objtype = ACL_OBJECT_FUNCTION;
n->objs = $2;
$$ = n;
}
| DATABASE name_list
{
PrivTarget *n = makeNode(PrivTarget);
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
n->objtype = ACL_OBJECT_DATABASE;
n->objs = $2;
$$ = n;
}
| LANGUAGE name_list
{
PrivTarget *n = makeNode(PrivTarget);
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
n->objtype = ACL_OBJECT_LANGUAGE;
n->objs = $2;
$$ = n;
}
| SCHEMA name_list
{
PrivTarget *n = makeNode(PrivTarget);
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
n->objtype = ACL_OBJECT_NAMESPACE;
n->objs = $2;
$$ = n;
}
| TABLESPACE name_list
{
PrivTarget *n = makeNode(PrivTarget);
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
n->objtype = ACL_OBJECT_TABLESPACE;
n->objs = $2;
$$ = n;

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.185 2009/01/01 17:23:45 momjian Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.186 2009/01/22 20:16:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,7 @@ static void extractRemainingColumns(List *common_colnames,
List *src_colnames, List *src_colvars,
List **res_colnames, List **res_colvars);
static Node *transformJoinUsingClause(ParseState *pstate,
RangeTblEntry *leftRTE, RangeTblEntry *rightRTE,
List *leftVars, List *rightVars);
static Node *transformJoinOnClause(ParseState *pstate, JoinExpr *j,
RangeTblEntry *l_rte,
@@ -194,8 +195,7 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
*
* If we find an explicit reference to the rel later during parse
* analysis, we will add the ACL_SELECT bit back again; see
* scanRTEForColumn (for simple field references), ExpandColumnRefStar
* (for foo.*) and ExpandAllTables (for *).
* markVarForSelectPriv and its callers.
*/
rte->requiredPerms = requiredPerms;
@@ -305,7 +305,9 @@ extractRemainingColumns(List *common_colnames,
* Result is a transformed qualification expression.
*/
static Node *
transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
transformJoinUsingClause(ParseState *pstate,
RangeTblEntry *leftRTE, RangeTblEntry *rightRTE,
List *leftVars, List *rightVars)
{
Node *result = NULL;
ListCell *lvars,
@@ -315,17 +317,25 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
* We cheat a little bit here by building an untransformed operator tree
* whose leaves are the already-transformed Vars. This is OK because
* transformExpr() won't complain about already-transformed subnodes.
* However, this does mean that we have to mark the columns as requiring
* SELECT privilege for ourselves; transformExpr() won't do it.
*/
forboth(lvars, leftVars, rvars, rightVars)
{
Node *lvar = (Node *) lfirst(lvars);
Node *rvar = (Node *) lfirst(rvars);
Var *lvar = (Var *) lfirst(lvars);
Var *rvar = (Var *) lfirst(rvars);
A_Expr *e;
/* Require read access to the join variables */
markVarForSelectPriv(pstate, lvar, leftRTE);
markVarForSelectPriv(pstate, rvar, rightRTE);
/* Now create the lvar = rvar join condition */
e = makeSimpleA_Expr(AEXPR_OP, "=",
copyObject(lvar), copyObject(rvar),
-1);
/* And combine into an AND clause, if multiple join columns */
if (result == NULL)
result = (Node *) e;
else
@@ -728,6 +738,7 @@ transformFromClauseItem(ParseState *pstate, Node *n,
*r_colvars,
*res_colvars;
RangeTblEntry *rte;
int k;
/*
* Recursively process the left and right subtrees
@@ -912,6 +923,8 @@ transformFromClauseItem(ParseState *pstate, Node *n,
}
j->quals = transformJoinUsingClause(pstate,
l_rte,
r_rte,
l_usingvars,
r_usingvars);
}
@@ -972,6 +985,12 @@ transformFromClauseItem(ParseState *pstate, Node *n,
*top_rte = rte;
*top_rti = j->rtindex;
/* make a matching link to the JoinExpr for later use */
for (k = list_length(pstate->p_joinexprs) + 1; k < j->rtindex; k++)
pstate->p_joinexprs = lappend(pstate->p_joinexprs, NULL);
pstate->p_joinexprs = lappend(pstate->p_joinexprs, j);
Assert(list_length(pstate->p_joinexprs) == j->rtindex);
/*
* Prepare returned namespace list. If the JOIN has an alias then it
* hides the contained RTEs as far as the relnamespace goes;

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.239 2009/01/01 17:23:45 momjian Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.240 2009/01/22 20:16:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1977,6 +1977,9 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
/* location is not filled in by makeVar */
result->location = location;
/* mark relation as requiring whole-row SELECT access */
markVarForSelectPriv(pstate, result, rte);
return (Node *) result;
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.140 2009/01/01 17:23:46 momjian Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.141 2009/01/22 20:16:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -39,6 +39,8 @@ static RangeTblEntry *scanNameSpaceForRefname(ParseState *pstate,
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,
@@ -435,14 +437,8 @@ GetCTEForRTE(ParseState *pstate, RangeTblEntry *rte, int rtelevelsup)
* 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.
* 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,
@@ -450,6 +446,7 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname,
{
Node *result = NULL;
int attnum = 0;
Var *var;
ListCell *c;
/*
@@ -476,9 +473,10 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname,
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;
var = make_var(pstate, rte, attnum, location);
/* Require read access to the column */
markVarForSelectPriv(pstate, var, rte);
result = (Node *) var;
}
}
@@ -504,9 +502,10 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname,
Int16GetDatum(attnum),
0, 0))
{
result = (Node *) make_var(pstate, rte, attnum, location);
/* Require read access */
rte->requiredPerms |= ACL_SELECT;
var = make_var(pstate, rte, attnum, location);
/* Require read access to the column */
markVarForSelectPriv(pstate, var, rte);
result = (Node *) var;
}
}
}
@@ -594,6 +593,122 @@ qualifiedNameToVar(ParseState *pstate,
return scanRTEForColumn(pstate, rte, colname, location);
}
/*
* 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.
@@ -838,6 +953,8 @@ addRangeTableEntry(ParseState *pstate,
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
@@ -891,6 +1008,8 @@ addRangeTableEntryForRelation(ParseState *pstate,
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
@@ -969,6 +1088,8 @@ addRangeTableEntryForSubquery(ParseState *pstate,
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
@@ -1101,6 +1222,8 @@ addRangeTableEntryForFunction(ParseState *pstate,
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
@@ -1168,8 +1291,11 @@ addRangeTableEntryForValues(ParseState *pstate,
*/
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
@@ -1239,6 +1365,8 @@ addRangeTableEntryForJoin(ParseState *pstate,
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
@@ -1320,6 +1448,8 @@ addRangeTableEntryForCTE(ParseState *pstate,
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
@@ -1803,6 +1933,7 @@ expandTupleDesc(TupleDesc tupdesc, Alias *eref,
* 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,
@@ -1817,10 +1948,17 @@ expandRelAttrs(ParseState *pstate, RangeTblEntry *rte,
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));
Node *varnode = (Node *) lfirst(var);
Var *varnode = (Var *) lfirst(var);
TargetEntry *te;
te = makeTargetEntry((Expr *) varnode,
@@ -1828,6 +1966,9 @@ expandRelAttrs(ParseState *pstate, RangeTblEntry *rte,
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? */

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.169 2009/01/01 17:23:46 momjian Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.170 2009/01/22 20:16:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -850,6 +850,8 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
* in a SELECT target list (where we want TargetEntry nodes in the result)
* and foo.* in a ROW() or VALUES() construct (where we want just bare
* expressions).
*
* The referenced columns are marked as requiring SELECT access.
*/
static List *
ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
@@ -929,20 +931,37 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
makeRangeVar(schemaname, relname,
cref->location));
/* Require read access --- see comments in setTargetTable() */
rte->requiredPerms |= ACL_SELECT;
rtindex = RTERangeTablePosn(pstate, rte, &sublevels_up);
if (targetlist)
{
/* expandRelAttrs handles permissions marking */
return expandRelAttrs(pstate, rte, rtindex, sublevels_up,
cref->location);
}
else
{
List *vars;
ListCell *l;
expandRTE(rte, rtindex, sublevels_up, cref->location, false,
NULL, &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;
/* Require read access to each column */
foreach(l, vars)
{
Var *var = (Var *) lfirst(l);
markVarForSelectPriv(pstate, var, rte);
}
return vars;
}
}
@@ -956,6 +975,8 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
* varnamespace. We do not consider relnamespace because that would include
* input tables of aliasless JOINs, NEW/OLD pseudo-entries, implicit RTEs,
* etc.
*
* The referenced relations/columns are marked as requiring SELECT access.
*/
static List *
ExpandAllTables(ParseState *pstate, int location)
@@ -975,9 +996,6 @@ ExpandAllTables(ParseState *pstate, int location)
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
int rtindex = RTERangeTablePosn(pstate, rte, NULL);
/* Require read access --- see comments in setTargetTable() */
rte->requiredPerms |= ACL_SELECT;
target = list_concat(target,
expandRelAttrs(pstate, rte, rtindex, 0,
location));