summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util')
-rw-r--r--src/backend/optimizer/util/clauses.c14
-rw-r--r--src/backend/optimizer/util/orclauses.c3
-rw-r--r--src/backend/optimizer/util/relnode.c14
-rw-r--r--src/backend/optimizer/util/restrictinfo.c125
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;