aboutsummaryrefslogtreecommitdiff
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.c4
-rw-r--r--src/backend/optimizer/util/inherit.c5
-rw-r--r--src/backend/optimizer/util/orclauses.c3
-rw-r--r--src/backend/optimizer/util/placeholder.c2
-rw-r--r--src/backend/optimizer/util/restrictinfo.c39
-rw-r--r--src/backend/optimizer/util/var.c69
6 files changed, 81 insertions, 41 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 51d26a06915..d2470b7c6a7 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -1897,9 +1897,9 @@ is_pseudo_constant_clause_relids(Node *clause, Relids relids)
* Returns the number of different relations referenced in 'clause'.
*/
int
-NumRelids(Node *clause)
+NumRelids(PlannerInfo *root, Node *clause)
{
- Relids varnos = pull_varnos(clause);
+ Relids varnos = pull_varnos(root, clause);
int result = bms_num_members(varnos);
bms_free(varnos);
diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c
index 36d248beb51..be1c9ddd964 100644
--- a/src/backend/optimizer/util/inherit.c
+++ b/src/backend/optimizer/util/inherit.c
@@ -748,7 +748,8 @@ apply_child_basequals(PlannerInfo *root, RelOptInfo *parentrel,
}
/* reconstitute RestrictInfo with appropriate properties */
childquals = lappend(childquals,
- make_restrictinfo((Expr *) onecq,
+ make_restrictinfo(root,
+ (Expr *) onecq,
rinfo->is_pushed_down,
rinfo->outerjoin_delayed,
pseudoconstant,
@@ -785,7 +786,7 @@ apply_child_basequals(PlannerInfo *root, RelOptInfo *parentrel,
/* not likely that we'd see constants here, so no check */
childquals = lappend(childquals,
- make_restrictinfo(qual,
+ make_restrictinfo(root, qual,
true, false, false,
security_level,
NULL, NULL, NULL));
diff --git a/src/backend/optimizer/util/orclauses.c b/src/backend/optimizer/util/orclauses.c
index a4de576fd8a..d559f338268 100644
--- a/src/backend/optimizer/util/orclauses.c
+++ b/src/backend/optimizer/util/orclauses.c
@@ -268,7 +268,8 @@ consider_new_or_clause(PlannerInfo *root, RelOptInfo *rel,
* Build a RestrictInfo from the new OR clause. We can assume it's valid
* as a base restriction clause.
*/
- or_rinfo = make_restrictinfo(orclause,
+ or_rinfo = make_restrictinfo(root,
+ orclause,
true,
false,
false,
diff --git a/src/backend/optimizer/util/placeholder.c b/src/backend/optimizer/util/placeholder.c
index 2f21455c7bc..1c4202d864c 100644
--- a/src/backend/optimizer/util/placeholder.c
+++ b/src/backend/optimizer/util/placeholder.c
@@ -98,7 +98,7 @@ find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv,
* ph_eval_at. If no referenced rels are within the syntactic scope,
* force evaluation at the syntactic location.
*/
- rels_used = pull_varnos((Node *) phv->phexpr);
+ rels_used = pull_varnos(root, (Node *) phv->phexpr);
phinfo->ph_lateral = bms_difference(rels_used, phv->phrels);
if (bms_is_empty(phinfo->ph_lateral))
phinfo->ph_lateral = NULL; /* make it exactly NULL if empty */
diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c
index 221e1caa681..eb113d94c1e 100644
--- a/src/backend/optimizer/util/restrictinfo.c
+++ b/src/backend/optimizer/util/restrictinfo.c
@@ -21,7 +21,8 @@
#include "optimizer/restrictinfo.h"
-static RestrictInfo *make_restrictinfo_internal(Expr *clause,
+static RestrictInfo *make_restrictinfo_internal(PlannerInfo *root,
+ Expr *clause,
Expr *orclause,
bool is_pushed_down,
bool outerjoin_delayed,
@@ -30,7 +31,8 @@ static RestrictInfo *make_restrictinfo_internal(Expr *clause,
Relids required_relids,
Relids outer_relids,
Relids nullable_relids);
-static Expr *make_sub_restrictinfos(Expr *clause,
+static Expr *make_sub_restrictinfos(PlannerInfo *root,
+ Expr *clause,
bool is_pushed_down,
bool outerjoin_delayed,
bool pseudoconstant,
@@ -56,7 +58,8 @@ static Expr *make_sub_restrictinfos(Expr *clause,
* later.
*/
RestrictInfo *
-make_restrictinfo(Expr *clause,
+make_restrictinfo(PlannerInfo *root,
+ Expr *clause,
bool is_pushed_down,
bool outerjoin_delayed,
bool pseudoconstant,
@@ -70,7 +73,8 @@ make_restrictinfo(Expr *clause,
* above each subclause of the top-level AND/OR structure.
*/
if (is_orclause(clause))
- return (RestrictInfo *) make_sub_restrictinfos(clause,
+ return (RestrictInfo *) make_sub_restrictinfos(root,
+ clause,
is_pushed_down,
outerjoin_delayed,
pseudoconstant,
@@ -82,7 +86,8 @@ make_restrictinfo(Expr *clause,
/* Shouldn't be an AND clause, else AND/OR flattening messed up */
Assert(!is_andclause(clause));
- return make_restrictinfo_internal(clause,
+ return make_restrictinfo_internal(root,
+ clause,
NULL,
is_pushed_down,
outerjoin_delayed,
@@ -99,7 +104,8 @@ make_restrictinfo(Expr *clause,
* Common code for the main entry points and the recursive cases.
*/
static RestrictInfo *
-make_restrictinfo_internal(Expr *clause,
+make_restrictinfo_internal(PlannerInfo *root,
+ Expr *clause,
Expr *orclause,
bool is_pushed_down,
bool outerjoin_delayed,
@@ -137,8 +143,8 @@ make_restrictinfo_internal(Expr *clause,
*/
if (is_opclause(clause) && list_length(((OpExpr *) clause)->args) == 2)
{
- restrictinfo->left_relids = pull_varnos(get_leftop(clause));
- restrictinfo->right_relids = pull_varnos(get_rightop(clause));
+ restrictinfo->left_relids = pull_varnos(root, get_leftop(clause));
+ restrictinfo->right_relids = pull_varnos(root, get_rightop(clause));
restrictinfo->clause_relids = bms_union(restrictinfo->left_relids,
restrictinfo->right_relids);
@@ -165,7 +171,7 @@ make_restrictinfo_internal(Expr *clause,
restrictinfo->left_relids = NULL;
restrictinfo->right_relids = NULL;
/* and get the total relid set the hard way */
- restrictinfo->clause_relids = pull_varnos((Node *) clause);
+ restrictinfo->clause_relids = pull_varnos(root, (Node *) clause);
}
/* required_relids defaults to clause_relids */
@@ -225,7 +231,8 @@ make_restrictinfo_internal(Expr *clause,
* contained rels.
*/
static Expr *
-make_sub_restrictinfos(Expr *clause,
+make_sub_restrictinfos(PlannerInfo *root,
+ Expr *clause,
bool is_pushed_down,
bool outerjoin_delayed,
bool pseudoconstant,
@@ -241,7 +248,8 @@ make_sub_restrictinfos(Expr *clause,
foreach(temp, ((BoolExpr *) clause)->args)
orlist = lappend(orlist,
- make_sub_restrictinfos(lfirst(temp),
+ make_sub_restrictinfos(root,
+ lfirst(temp),
is_pushed_down,
outerjoin_delayed,
pseudoconstant,
@@ -249,7 +257,8 @@ make_sub_restrictinfos(Expr *clause,
NULL,
outer_relids,
nullable_relids));
- return (Expr *) make_restrictinfo_internal(clause,
+ return (Expr *) make_restrictinfo_internal(root,
+ clause,
make_orclause(orlist),
is_pushed_down,
outerjoin_delayed,
@@ -266,7 +275,8 @@ make_sub_restrictinfos(Expr *clause,
foreach(temp, ((BoolExpr *) clause)->args)
andlist = lappend(andlist,
- make_sub_restrictinfos(lfirst(temp),
+ make_sub_restrictinfos(root,
+ lfirst(temp),
is_pushed_down,
outerjoin_delayed,
pseudoconstant,
@@ -277,7 +287,8 @@ make_sub_restrictinfos(Expr *clause,
return make_andclause(andlist);
}
else
- return (Expr *) make_restrictinfo_internal(clause,
+ return (Expr *) make_restrictinfo_internal(root,
+ clause,
NULL,
is_pushed_down,
outerjoin_delayed,
diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c
index 19b2bba7077..e307d6fbb07 100644
--- a/src/backend/optimizer/util/var.c
+++ b/src/backend/optimizer/util/var.c
@@ -23,6 +23,7 @@
#include "access/sysattr.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
+#include "optimizer/placeholder.h"
#include "optimizer/prep.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteManip.h"
@@ -31,6 +32,7 @@
typedef struct
{
Relids varnos;
+ PlannerInfo *root;
int sublevels_up;
} pull_varnos_context;
@@ -92,11 +94,12 @@ static Relids alias_relid_set(Query *query, Relids relids);
* SubPlan, we only need to look at the parameters passed to the subplan.
*/
Relids
-pull_varnos(Node *node)
+pull_varnos(PlannerInfo *root, Node *node)
{
pull_varnos_context context;
context.varnos = NULL;
+ context.root = root;
context.sublevels_up = 0;
/*
@@ -117,11 +120,12 @@ pull_varnos(Node *node)
* Only Vars of the specified level are considered.
*/
Relids
-pull_varnos_of_level(Node *node, int levelsup)
+pull_varnos_of_level(PlannerInfo *root, Node *node, int levelsup)
{
pull_varnos_context context;
context.varnos = NULL;
+ context.root = root;
context.sublevels_up = levelsup;
/*
@@ -159,33 +163,56 @@ pull_varnos_walker(Node *node, pull_varnos_context *context)
}
if (IsA(node, PlaceHolderVar))
{
- /*
- * A PlaceHolderVar acts as a variable of its syntactic scope, or
- * lower than that if it references only a subset of the rels in its
- * syntactic scope. It might also contain lateral references, but we
- * should ignore such references when computing the set of varnos in
- * an expression tree. Also, if the PHV contains no variables within
- * its syntactic scope, it will be forced to be evaluated exactly at
- * the syntactic scope, so take that as the relid set.
- */
PlaceHolderVar *phv = (PlaceHolderVar *) node;
- pull_varnos_context subcontext;
- subcontext.varnos = NULL;
- subcontext.sublevels_up = context->sublevels_up;
- (void) pull_varnos_walker((Node *) phv->phexpr, &subcontext);
+ /*
+ * If a PlaceHolderVar is not of the target query level, ignore it,
+ * instead recursing into its expression to see if it contains any
+ * vars that are of the target level.
+ */
if (phv->phlevelsup == context->sublevels_up)
{
- subcontext.varnos = bms_int_members(subcontext.varnos,
- phv->phrels);
- if (bms_is_empty(subcontext.varnos))
+ /*
+ * Ideally, the PHV's contribution to context->varnos is its
+ * ph_eval_at set. However, this code can be invoked before
+ * that's been computed. If we cannot find a PlaceHolderInfo,
+ * fall back to the conservative assumption that the PHV will be
+ * evaluated at its syntactic level (phv->phrels).
+ *
+ * There is a second hazard: this code is also used to examine
+ * qual clauses during deconstruct_jointree, when we may have a
+ * PlaceHolderInfo but its ph_eval_at value is not yet final, so
+ * that theoretically we could obtain a relid set that's smaller
+ * than we'd see later on. That should never happen though,
+ * because we deconstruct the jointree working upwards. Any outer
+ * join that forces delay of evaluation of a given qual clause
+ * will be processed before we examine that clause here, so the
+ * ph_eval_at value should have been updated to include it.
+ */
+ PlaceHolderInfo *phinfo = NULL;
+
+ if (phv->phlevelsup == 0)
+ {
+ ListCell *lc;
+
+ foreach(lc, context->root->placeholder_list)
+ {
+ phinfo = (PlaceHolderInfo *) lfirst(lc);
+ if (phinfo->phid == phv->phid)
+ break;
+ phinfo = NULL;
+ }
+ }
+ if (phinfo != NULL)
+ context->varnos = bms_add_members(context->varnos,
+ phinfo->ph_eval_at);
+ else
context->varnos = bms_add_members(context->varnos,
phv->phrels);
+ return false; /* don't recurse into expression */
}
- context->varnos = bms_join(context->varnos, subcontext.varnos);
- return false;
}
- if (IsA(node, Query))
+ else if (IsA(node, Query))
{
/* Recurse into RTE subquery or not-yet-planned sublink subquery */
bool result;