diff options
Diffstat (limited to 'src/backend/optimizer/util')
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 14 | ||||
-rw-r--r-- | src/backend/optimizer/util/orclauses.c | 3 | ||||
-rw-r--r-- | src/backend/optimizer/util/relnode.c | 14 | ||||
-rw-r--r-- | src/backend/optimizer/util/restrictinfo.c | 125 |
4 files changed, 68 insertions, 88 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 59ccdf43d49..9e122e383d8 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -1500,10 +1500,8 @@ contain_context_dependent_node_walker(Node *node, int *flags) * * Returns true if the clause contains any non-leakproof functions that are * passed Var nodes of the current query level, and which might therefore leak - * data. Qualifiers from outside a security_barrier view that might leak data - * in this way should not be pushed down into the view in case the contents of - * tuples intended to be filtered out by the view are revealed by the leaky - * functions. + * data. Such clauses must be applied after any lower-level security barrier + * clauses. */ bool contain_leaked_vars(Node *clause) @@ -1598,10 +1596,10 @@ contain_leaked_vars_walker(Node *node, void *context) 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. + * WHERE CURRENT OF doesn't contain leaky function calls. + * Moreover, it is essential that this is considered non-leaky, + * since the planner must always generate a TID scan when CURRENT + * OF is present -- c.f. cost_tidscan. */ return false; diff --git a/src/backend/optimizer/util/orclauses.c b/src/backend/optimizer/util/orclauses.c index e36e30f2596..c965bb678d3 100644 --- a/src/backend/optimizer/util/orclauses.c +++ b/src/backend/optimizer/util/orclauses.c @@ -270,6 +270,7 @@ consider_new_or_clause(PlannerInfo *root, RelOptInfo *rel, true, false, false, + join_or_rinfo->security_level, NULL, NULL, NULL); @@ -296,6 +297,8 @@ consider_new_or_clause(PlannerInfo *root, RelOptInfo *rel, * OK, add it to the rel's restriction-clause list. */ rel->baserestrictinfo = lappend(rel->baserestrictinfo, or_rinfo); + rel->baserestrict_min_security = Min(rel->baserestrict_min_security, + or_rinfo->security_level); /* * Adjust the original join OR clause's cached selectivity to compensate diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 7a8674df82f..adc1db94f41 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -14,6 +14,8 @@ */ #include "postgres.h" +#include <limits.h> + #include "miscadmin.h" #include "optimizer/clauses.h" #include "optimizer/cost.h" @@ -135,6 +137,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) rel->baserestrictinfo = NIL; rel->baserestrictcost.startup = 0; rel->baserestrictcost.per_tuple = 0; + rel->baserestrict_min_security = UINT_MAX; rel->joininfo = NIL; rel->has_eclass_joins = false; @@ -173,6 +176,16 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) root->simple_rel_array[relid] = rel; /* + * This is a convenient spot at which to note whether rels participating + * in the query have any securityQuals attached. If so, increase + * root->qual_security_level to ensure it's larger than the maximum + * security level needed for securityQuals. + */ + if (rte->securityQuals) + root->qual_security_level = Max(root->qual_security_level, + list_length(rte->securityQuals)); + + /* * If this rel is an appendrel parent, recurse to build "other rel" * RelOptInfos for its children. They are "other rels" because they are * not in the main join tree, but we will need RelOptInfos to plan access @@ -407,6 +420,7 @@ build_join_rel(PlannerInfo *root, joinrel->baserestrictinfo = NIL; joinrel->baserestrictcost.startup = 0; joinrel->baserestrictcost.per_tuple = 0; + joinrel->baserestrict_min_security = UINT_MAX; joinrel->joininfo = NIL; joinrel->has_eclass_joins = false; diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c index 60d377776d2..8f10520f813 100644 --- a/src/backend/optimizer/util/restrictinfo.c +++ b/src/backend/optimizer/util/restrictinfo.c @@ -24,6 +24,7 @@ static RestrictInfo *make_restrictinfo_internal(Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, + Index security_level, Relids required_relids, Relids outer_relids, Relids nullable_relids); @@ -31,6 +32,7 @@ static Expr *make_sub_restrictinfos(Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, + Index security_level, Relids required_relids, Relids outer_relids, Relids nullable_relids); @@ -43,7 +45,7 @@ static Expr *make_sub_restrictinfos(Expr *clause, * * The is_pushed_down, outerjoin_delayed, and pseudoconstant flags for the * RestrictInfo must be supplied by the caller, as well as the correct values - * for outer_relids and nullable_relids. + * for security_level, outer_relids, and nullable_relids. * required_relids can be NULL, in which case it defaults to the actual clause * contents (i.e., clause_relids). * @@ -56,6 +58,7 @@ make_restrictinfo(Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, + Index security_level, Relids required_relids, Relids outer_relids, Relids nullable_relids) @@ -69,6 +72,7 @@ make_restrictinfo(Expr *clause, is_pushed_down, outerjoin_delayed, pseudoconstant, + security_level, required_relids, outer_relids, nullable_relids); @@ -81,65 +85,13 @@ make_restrictinfo(Expr *clause, is_pushed_down, outerjoin_delayed, pseudoconstant, + security_level, required_relids, outer_relids, nullable_relids); } /* - * make_restrictinfos_from_actual_clauses - * - * Given a list of implicitly-ANDed restriction clauses, produce a list - * of RestrictInfo nodes. This is used to reconstitute the RestrictInfo - * representation after doing transformations of a list of clauses. - * - * We assume that the clauses are relation-level restrictions and therefore - * we don't have to worry about is_pushed_down, outerjoin_delayed, - * outer_relids, and nullable_relids (these can be assumed true, false, - * NULL, and NULL, respectively). - * We do take care to recognize pseudoconstant clauses properly. - */ -List * -make_restrictinfos_from_actual_clauses(PlannerInfo *root, - List *clause_list) -{ - List *result = NIL; - ListCell *l; - - foreach(l, clause_list) - { - Expr *clause = (Expr *) lfirst(l); - bool pseudoconstant; - RestrictInfo *rinfo; - - /* - * It's pseudoconstant if it contains no Vars and no volatile - * functions. We probably can't see any sublinks here, so - * contain_var_clause() would likely be enough, but for safety use - * contain_vars_of_level() instead. - */ - pseudoconstant = - !contain_vars_of_level((Node *) clause, 0) && - !contain_volatile_functions((Node *) clause); - if (pseudoconstant) - { - /* tell createplan.c to check for gating quals */ - root->hasPseudoConstantQuals = true; - } - - rinfo = make_restrictinfo(clause, - true, - false, - pseudoconstant, - NULL, - NULL, - NULL); - result = lappend(result, rinfo); - } - return result; -} - -/* * make_restrictinfo_internal * * Common code for the main entry points and the recursive cases. @@ -150,6 +102,7 @@ make_restrictinfo_internal(Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, + Index security_level, Relids required_relids, Relids outer_relids, Relids nullable_relids) @@ -162,10 +115,21 @@ make_restrictinfo_internal(Expr *clause, restrictinfo->outerjoin_delayed = outerjoin_delayed; restrictinfo->pseudoconstant = pseudoconstant; restrictinfo->can_join = false; /* may get set below */ + restrictinfo->security_level = security_level; restrictinfo->outer_relids = outer_relids; restrictinfo->nullable_relids = nullable_relids; /* + * If it's potentially delayable by lower-level security quals, figure out + * whether it's leakproof. We can skip testing this for level-zero quals, + * since they would never get delayed on security grounds anyway. + */ + if (security_level > 0) + restrictinfo->leakproof = !contain_leaked_vars((Node *) clause); + else + restrictinfo->leakproof = false; /* really, "don't know" */ + + /* * If it's a binary opclause, set up left/right relids info. In any case * set up the total clause relids info. */ @@ -250,7 +214,7 @@ make_restrictinfo_internal(Expr *clause, * * The same is_pushed_down, outerjoin_delayed, and pseudoconstant flag * values can be applied to all RestrictInfo nodes in the result. Likewise - * for outer_relids and nullable_relids. + * for security_level, outer_relids, and nullable_relids. * * The given required_relids are attached to our top-level output, * but any OR-clause constituents are allowed to default to just the @@ -261,6 +225,7 @@ make_sub_restrictinfos(Expr *clause, bool is_pushed_down, bool outerjoin_delayed, bool pseudoconstant, + Index security_level, Relids required_relids, Relids outer_relids, Relids nullable_relids) @@ -276,6 +241,7 @@ make_sub_restrictinfos(Expr *clause, is_pushed_down, outerjoin_delayed, pseudoconstant, + security_level, NULL, outer_relids, nullable_relids)); @@ -284,6 +250,7 @@ make_sub_restrictinfos(Expr *clause, is_pushed_down, outerjoin_delayed, pseudoconstant, + security_level, required_relids, outer_relids, nullable_relids); @@ -299,6 +266,7 @@ make_sub_restrictinfos(Expr *clause, is_pushed_down, outerjoin_delayed, pseudoconstant, + security_level, required_relids, outer_relids, nullable_relids)); @@ -310,6 +278,7 @@ make_sub_restrictinfos(Expr *clause, is_pushed_down, outerjoin_delayed, pseudoconstant, + security_level, required_relids, outer_relids, nullable_relids); @@ -330,42 +299,36 @@ restriction_is_or_clause(RestrictInfo *restrictinfo) } /* - * get_actual_clauses + * restriction_is_securely_promotable * - * Returns a list containing the bare clauses from 'restrictinfo_list'. - * - * This is only to be used in cases where none of the RestrictInfos can - * be pseudoconstant clauses (for instance, it's OK on indexqual lists). + * Returns true if it's okay to evaluate this clause "early", that is before + * other restriction clauses attached to the specified relation. */ -List * -get_actual_clauses(List *restrictinfo_list) +bool +restriction_is_securely_promotable(RestrictInfo *restrictinfo, + RelOptInfo *rel) { - List *result = NIL; - ListCell *l; - - foreach(l, restrictinfo_list) - { - RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); - - Assert(IsA(rinfo, RestrictInfo)); - - Assert(!rinfo->pseudoconstant); - - result = lappend(result, rinfo->clause); - } - return result; + /* + * It's okay if there are no baserestrictinfo clauses for the rel that + * would need to go before this one, *or* if this one is leakproof. + */ + if (restrictinfo->security_level <= rel->baserestrict_min_security || + restrictinfo->leakproof) + return true; + else + return false; } /* - * get_all_actual_clauses + * get_actual_clauses * * Returns a list containing the bare clauses from 'restrictinfo_list'. * - * This loses the distinction between regular and pseudoconstant clauses, - * so be careful what you use it for. + * This is only to be used in cases where none of the RestrictInfos can + * be pseudoconstant clauses (for instance, it's OK on indexqual lists). */ List * -get_all_actual_clauses(List *restrictinfo_list) +get_actual_clauses(List *restrictinfo_list) { List *result = NIL; ListCell *l; @@ -376,6 +339,8 @@ get_all_actual_clauses(List *restrictinfo_list) Assert(IsA(rinfo, RestrictInfo)); + Assert(!rinfo->pseudoconstant); + result = lappend(result, rinfo->clause); } return result; |