diff options
author | Joe Conway <mail@joeconway.com> | 2015-07-24 12:55:30 -0700 |
---|---|---|
committer | Joe Conway <mail@joeconway.com> | 2015-07-24 12:55:30 -0700 |
commit | b26e3d660df51a088d14c3c2cfce5990c13c1195 (patch) | |
tree | 8bea46a185f0ce157f051445ec9fb57e7ea74d6d /src/backend | |
parent | d9a356ff2e6bb7ed5fb1145af49fa3e51e68a98a (diff) | |
download | postgresql-b26e3d660df51a088d14c3c2cfce5990c13c1195.tar.gz |
Make RLS work with UPDATE ... WHERE CURRENT OF
UPDATE ... WHERE CURRENT OF would not work in conjunction with
RLS. Arrange to allow the CURRENT OF expression to be pushed down.
Issue noted by Peter Geoghegan. Patch by Dean Rasheed. Back patch
to 9.5 where RLS was introduced.
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/optimizer/path/allpaths.c | 40 | ||||
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 10 |
2 files changed, 50 insertions, 0 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 0b831891fc..888eeac515 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -2177,6 +2177,46 @@ subquery_push_qual(Query *subquery, RangeTblEntry *rte, Index rti, Node *qual) recurse_push_qual(subquery->setOperations, subquery, rte, rti, qual); } + else if (IsA(qual, CurrentOfExpr)) + { + /* + * This is possible when a WHERE CURRENT OF expression is applied to a + * table with row-level security. In that case, the subquery should + * contain precisely one rtable entry for the table, and we can safely + * push the expression down into the subquery. This will cause a TID + * scan subquery plan to be generated allowing the target relation to + * be updated. + * + * Someday we might also be able to use a WHERE CURRENT OF expression + * on a view, but currently the rewriter prevents that, so we should + * never see any other case here, but generate sane error messages in + * case it does somehow happen. + */ + if (subquery->rtable == NIL) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("WHERE CURRENT OF is not supported on a view with no underlying relation"))); + + if (list_length(subquery->rtable) > 1) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("WHERE CURRENT OF is not supported on a view with more than one underlying relation"))); + + if (subquery->hasAggs || subquery->groupClause || subquery->groupingSets || subquery->havingQual) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("WHERE CURRENT OF is not supported on a view with grouping or aggregation"))); + + /* + * Adjust the CURRENT OF expression to refer to the underlying table + * in the subquery, and attach it to the subquery's WHERE clause. + */ + qual = copyObject(qual); + ((CurrentOfExpr *) qual)->cvarno = 1; + + subquery->jointree->quals = + make_and_qual(subquery->jointree->quals, qual); + } else { /* diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index d40083d396..0137e0ecfc 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -1492,6 +1492,16 @@ contain_leaked_vars_walker(Node *node, void *context) } break; + case T_CurrentOfExpr: + + /* + * WHERE CURRENT OF doesn't contain function calls. Moreover, it + * is important that this can be pushed down into a + * security_barrier view, since the planner must always generate + * a TID scan when CURRENT OF is present -- c.f. cost_tidscan. + */ + return false; + default: /* |