Re: Proof of concept: auto updatable views [Review of Patch]

From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: Dean Rasheed <dean(dot)a(dot)rasheed(at)gmail(dot)com>
Cc: Peter Eisentraut <peter_e(at)gmx(dot)net>, Amit kapila <amit(dot)kapila(at)huawei(dot)com>, "robertmhaas(at)gmail(dot)com" <robertmhaas(at)gmail(dot)com>, "pgsql-hackers(at)postgresql(dot)org" <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: Proof of concept: auto updatable views [Review of Patch]
Date: 2012-12-08 15:21:04
Message-ID: 13546.1354980064@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Continuing to work on this ... I found multiple things I didn't like
about the permission-field update code. Attached are some heavily
commented extracts from the code as I've changed it. Does anybody
object to either the code or the objectives given in the comments?

regards, tom lane

/*
* adjust_view_column_set - map a set of column numbers according to targetlist
*
* This is used with simply-updatable views to map column-permissions sets for
* the view columns onto the matching columns in the underlying base relation.
* The targetlist is expected to be a list of plain Vars of the underlying
* relation (as per the checks above in view_is_auto_updatable).
*/
static Bitmapset *
adjust_view_column_set(Bitmapset *cols, List *targetlist)
{
Bitmapset *result = NULL;
Bitmapset *tmpcols;
AttrNumber col;

tmpcols = bms_copy(cols);
while ((col = bms_first_member(tmpcols)) >= 0)
{
/* bit numbers are offset by FirstLowInvalidHeapAttributeNumber */
AttrNumber attno = col + FirstLowInvalidHeapAttributeNumber;

if (attno == InvalidAttrNumber)
{
/*
* There's a whole-row reference to the view. For permissions
* purposes, treat it as a reference to each column available from
* the view. (We should *not* convert this to a whole-row
* reference to the base relation, since the view may not touch
* all columns of the base relation.)
*/
ListCell *lc;

foreach(lc, targetlist)
{
TargetEntry *tle = (TargetEntry *) lfirst(lc);
Var *var;

if (tle->resjunk)
continue;
var = (Var *) tle->expr;
Assert(IsA(var, Var));
result = bms_add_member(result,
var->varattno - FirstLowInvalidHeapAttributeNumber);
}
}
else
{
/*
* Views do not have system columns, so we do not expect to see
* any other system attnos here. If we do find one, the error
* case will apply.
*/
TargetEntry *tle = get_tle_by_resno(targetlist, attno);

if (tle != NULL && IsA(tle->expr, Var))
{
Var *var = (Var *) tle->expr;

result = bms_add_member(result,
var->varattno - FirstLowInvalidHeapAttributeNumber);
}
else
elog(ERROR, "attribute number %d not found in view targetlist",
attno);
}
}
bms_free(tmpcols);

return result;
}

/*
* Mark the new target RTE for the permissions checks that we want to
* enforce against the view owner, as distinct from the query caller. At
* the relation level, require the same INSERT/UPDATE/DELETE permissions
* that the query caller needs against the view. We drop the ACL_SELECT
* bit that is presumably in new_rte->requiredPerms initially.
*
* Note: the original view RTE remains in the query's rangetable list.
* Although it will be unused in the query plan, we need it there so that
* the executor still performs appropriate permissions checks for the
* query caller's use of the view.
*/
new_rte->checkAsUser = view->rd_rel->relowner;
new_rte->requiredPerms = view_rte->requiredPerms;

/*
* Now for the per-column permissions bits.
*
* Initially, new_rte contains selectedCols permission check bits for all
* base-rel columns referenced by the view, but since the view is a SELECT
* query its modifiedCols is empty. We set modifiedCols to include all
* the columns the outer query is trying to modify, adjusting the column
* numbers as needed. But we leave selectedCols as-is, so the view owner
* must have read permission for all columns used in the view definition,
* even if some of them are not read by the upper query. We could try to
* limit selectedCols to only columns used in the transformed query, but
* that does not correspond to what happens in ordinary SELECT usage of a
* view: all referenced columns must have read permission, even if
* optimization finds that some of them can be discarded during query
* transformation. The flattening we're doing here is an optional
* optimization, too. (If you are unpersuaded and want to change this,
* note that applying adjust_view_column_set to view_rte->selectedCols is
* clearly *not* the right answer, since that neglects base-rel columns
* used in the view's WHERE quals.)
*/
Assert(bms_is_empty(new_rte->modifiedCols));
new_rte->modifiedCols = adjust_view_column_set(view_rte->modifiedCols,
view_targetlist);

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Andres Freund 2012-12-08 15:33:54 Re: review: pgbench - aggregation of info written into log
Previous Message Guillaume Lelarge 2012-12-08 15:15:42 Re: Slow query: bitmap scan troubles