]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix pull_varnos' miscomputation of relids set for a PlaceHolderVar.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 21 Jan 2021 20:37:23 +0000 (15:37 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 21 Jan 2021 20:37:23 +0000 (15:37 -0500)
Previously, pull_varnos() took the relids of a PlaceHolderVar as being
equal to the relids in its contents, but that fails to account for the
possibility that we have to postpone evaluation of the PHV due to outer
joins.  This could result in a malformed plan.  The known cases end up
triggering the "failed to assign all NestLoopParams to plan nodes"
sanity check in createplan.c, but other symptoms may be possible.

The right value to use is the join level we actually intend to evaluate
the PHV at.  We can get that from the ph_eval_at field of the associated
PlaceHolderInfo.  However, there are some places that call pull_varnos()
before the PlaceHolderInfos have been created; in that case, fall back
to the conservative assumption that the PHV will be evaluated at its
syntactic level.  (In principle this might result in missing some legal
optimization, but I'm not aware of any cases where it's an issue in
practice.)  Things are also a bit ticklish for calls occurring during
deconstruct_jointree(), but AFAICS the ph_eval_at fields should have
reached their final values by the time we need them.

The main problem in making this work is that pull_varnos() has no
way to get at the PlaceHolderInfos.  We can fix that easily, if a
bit tediously, in HEAD by passing it the planner "root" pointer.
In the back branches that'd cause an unacceptable API/ABI break for
extensions, so leave the existing entry points alone and add new ones
with the additional parameter.  (If an old entry point is called and
encounters a PHV, it'll fall back to using the syntactic level,
again possibly missing some valid optimization.)

Back-patch to v12.  The computation is surely also wrong before that,
but it appears that we cannot reach a bad plan thanks to join order
restrictions imposed on the subquery that the PlaceHolderVar came from.
The error only became reachable when commit 4be058fe9 allowed trivial
subqueries to be collapsed out completely, eliminating their join order
restrictions.

Per report from Stephan Springl.

Discussion: https://postgr.es/m/171041.1610849523@sss.pgh.pa.us

24 files changed:
contrib/postgres_fdw/postgres_fdw.c
src/backend/optimizer/path/clausesel.c
src/backend/optimizer/path/equivclass.c
src/backend/optimizer/path/indxpath.c
src/backend/optimizer/path/pathkeys.c
src/backend/optimizer/path/tidpath.c
src/backend/optimizer/plan/analyzejoins.c
src/backend/optimizer/plan/initsplan.c
src/backend/optimizer/plan/subselect.c
src/backend/optimizer/prep/prepjointree.c
src/backend/optimizer/util/clauses.c
src/backend/optimizer/util/inherit.c
src/backend/optimizer/util/orclauses.c
src/backend/optimizer/util/placeholder.c
src/backend/optimizer/util/restrictinfo.c
src/backend/optimizer/util/var.c
src/backend/utils/adt/selfuncs.c
src/include/optimizer/clauses.h
src/include/optimizer/optimizer.h
src/include/optimizer/paths.h
src/include/optimizer/planmain.h
src/include/optimizer/restrictinfo.h
src/test/regress/expected/join.out
src/test/regress/sql/join.sql

index 1759b9e1b6d822b3809e719c4ca390910020ad2f..105d505409f4d03f4b608ec5e58b67f3cb9851e7 100644 (file)
@@ -44,6 +44,9 @@
 #include "utils/sampling.h"
 #include "utils/selfuncs.h"
 
+/* source-code-compatibility hacks for pull_varnos() API change */
+#define make_restrictinfo(a,b,c,d,e,f,g,h,i) make_restrictinfo_new(a,b,c,d,e,f,g,h,i)
+
 PG_MODULE_MAGIC;
 
 /* Default CPU cost to start up a foreign query. */
@@ -5665,7 +5668,8 @@ foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel,
                         * RestrictInfos, so we must make our own.
                         */
                        Assert(!IsA(expr, RestrictInfo));
-                       rinfo = make_restrictinfo(expr,
+                       rinfo = make_restrictinfo(root,
+                                                                         expr,
                                                                          true,
                                                                          false,
                                                                          false,
index 4bf777d82d3d3f7755b30e723371b504f53a7821..4c42145a3e514d1d8f63f93bdcd853349ec761fe 100644 (file)
@@ -27,6 +27,9 @@
 #include "statistics/statistics.h"
 
 
+/* source-code-compatibility hacks for pull_varnos() API change */
+#define NumRelids(a,b) NumRelids_new(a,b)
+
 /*
  * Data structure for accumulating info about possible range-query
  * clause pairs in clauselist_selectivity.
@@ -236,7 +239,7 @@ clauselist_selectivity_simple(PlannerInfo *root,
                        }
                        else
                        {
-                               ok = (NumRelids(clause) == 1) &&
+                               ok = (NumRelids(root, clause) == 1) &&
                                        (is_pseudo_constant_clause(lsecond(expr->args)) ||
                                         (varonleft = false,
                                          is_pseudo_constant_clause(linitial(expr->args))));
@@ -520,7 +523,7 @@ bms_is_subset_singleton(const Bitmapset *s, int x)
  *       restriction or join estimator.  Subroutine for clause_selectivity().
  */
 static inline bool
-treat_as_join_clause(Node *clause, RestrictInfo *rinfo,
+treat_as_join_clause(PlannerInfo *root, Node *clause, RestrictInfo *rinfo,
                                         int varRelid, SpecialJoinInfo *sjinfo)
 {
        if (varRelid != 0)
@@ -554,7 +557,7 @@ treat_as_join_clause(Node *clause, RestrictInfo *rinfo,
                if (rinfo)
                        return (bms_membership(rinfo->clause_relids) == BMS_MULTIPLE);
                else
-                       return (NumRelids(clause) > 1);
+                       return (NumRelids(root, clause) > 1);
        }
 }
 
@@ -760,7 +763,7 @@ clause_selectivity(PlannerInfo *root,
                OpExpr     *opclause = (OpExpr *) clause;
                Oid                     opno = opclause->opno;
 
-               if (treat_as_join_clause(clause, rinfo, varRelid, sjinfo))
+               if (treat_as_join_clause(root, clause, rinfo, varRelid, sjinfo))
                {
                        /* Estimate selectivity for a join clause. */
                        s1 = join_selectivity(root, opno,
@@ -796,7 +799,7 @@ clause_selectivity(PlannerInfo *root,
                                                                  funcclause->funcid,
                                                                  funcclause->args,
                                                                  funcclause->inputcollid,
-                                                                 treat_as_join_clause(clause, rinfo,
+                                                                 treat_as_join_clause(root, clause, rinfo,
                                                                                                           varRelid, sjinfo),
                                                                  varRelid,
                                                                  jointype,
@@ -807,7 +810,7 @@ clause_selectivity(PlannerInfo *root,
                /* Use node specific selectivity calculation function */
                s1 = scalararraysel(root,
                                                        (ScalarArrayOpExpr *) clause,
-                                                       treat_as_join_clause(clause, rinfo,
+                                                       treat_as_join_clause(root, clause, rinfo,
                                                                                                 varRelid, sjinfo),
                                                        varRelid,
                                                        jointype,
index b62b954e88023fed95bc03093665b2f0d1f180a2..e54da55924ea602782625443fde6392aa3afaaa7 100644 (file)
 #include "utils/lsyscache.h"
 
 
+/* source-code-compatibility hacks for pull_varnos() API change */
+#define pull_varnos(a,b) pull_varnos_new(a,b)
+#define make_restrictinfo(a,b,c,d,e,f,g,h,i) make_restrictinfo_new(a,b,c,d,e,f,g,h,i)
+
 static EquivalenceMember *add_eq_member(EquivalenceClass *ec,
                                                                                Expr *expr, Relids relids, Relids nullable_relids,
                                                                                bool is_child, Oid datatype);
@@ -191,7 +195,8 @@ process_equivalence(PlannerInfo *root,
                        ntest->location = -1;
 
                        *p_restrictinfo =
-                               make_restrictinfo((Expr *) ntest,
+                               make_restrictinfo(root,
+                                                                 (Expr *) ntest,
                                                                  restrictinfo->is_pushed_down,
                                                                  restrictinfo->outerjoin_delayed,
                                                                  restrictinfo->pseudoconstant,
@@ -708,7 +713,7 @@ get_eclass_for_sort_expr(PlannerInfo *root,
        /*
         * Get the precise set of nullable relids appearing in the expression.
         */
-       expr_relids = pull_varnos((Node *) expr);
+       expr_relids = pull_varnos(root, (Node *) expr);
        nullable_relids = bms_intersect(nullable_relids, expr_relids);
 
        newem = add_eq_member(newec, copyObject(expr), expr_relids,
@@ -1449,7 +1454,8 @@ create_join_clause(PlannerInfo *root,
         */
        oldcontext = MemoryContextSwitchTo(root->planner_cxt);
 
-       rinfo = build_implied_join_equality(opno,
+       rinfo = build_implied_join_equality(root,
+                                                                               opno,
                                                                                ec->ec_collation,
                                                                                leftem->em_expr,
                                                                                rightem->em_expr,
@@ -1763,7 +1769,8 @@ reconsider_outer_join_clause(PlannerInfo *root, RestrictInfo *rinfo,
                                                                                         cur_em->em_datatype);
                        if (!OidIsValid(eq_op))
                                continue;               /* can't generate equality */
-                       newrinfo = build_implied_join_equality(eq_op,
+                       newrinfo = build_implied_join_equality(root,
+                                                                                                  eq_op,
                                                                                                   cur_ec->ec_collation,
                                                                                                   innervar,
                                                                                                   cur_em->em_expr,
@@ -1906,7 +1913,8 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo)
                                                                                         cur_em->em_datatype);
                        if (OidIsValid(eq_op))
                        {
-                               newrinfo = build_implied_join_equality(eq_op,
+                               newrinfo = build_implied_join_equality(root,
+                                                                                                          eq_op,
                                                                                                           cur_ec->ec_collation,
                                                                                                           leftvar,
                                                                                                           cur_em->em_expr,
@@ -1921,7 +1929,8 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo)
                                                                                         cur_em->em_datatype);
                        if (OidIsValid(eq_op))
                        {
-                               newrinfo = build_implied_join_equality(eq_op,
+                               newrinfo = build_implied_join_equality(root,
+                                                                                                          eq_op,
                                                                                                           cur_ec->ec_collation,
                                                                                                           rightvar,
                                                                                                           cur_em->em_expr,
index 95ae99bcf308b63e991a55e09b6456e83bfc5ce3..44dff2a8025b9ed195530d5d4c26c4e18f0724e6 100644 (file)
 #include "utils/selfuncs.h"
 
 
+/* source-code-compatibility hacks for pull_varnos() API change */
+#define pull_varnos(a,b) pull_varnos_new(a,b)
+#undef make_simple_restrictinfo
+#define make_simple_restrictinfo(root, clause)  \
+       make_restrictinfo_new(root, clause, true, false, false, 0, NULL, NULL, NULL)
+
 /* XXX see PartCollMatchesExprColl */
 #define IndexCollMatchesExprColl(idxcollation, exprcollation) \
        ((idxcollation) == InvalidOid || (idxcollation) == (exprcollation))
@@ -153,7 +159,8 @@ static IndexClause *match_clause_to_indexcol(PlannerInfo *root,
                                                                                         RestrictInfo *rinfo,
                                                                                         int indexcol,
                                                                                         IndexOptInfo *index);
-static IndexClause *match_boolean_index_clause(RestrictInfo *rinfo,
+static IndexClause *match_boolean_index_clause(PlannerInfo *root,
+                                                                                          RestrictInfo *rinfo,
                                                                                           int indexcol, IndexOptInfo *index);
 static IndexClause *match_opclause_to_indexcol(PlannerInfo *root,
                                                                                           RestrictInfo *rinfo,
@@ -169,13 +176,16 @@ static IndexClause *get_index_clause_from_support(PlannerInfo *root,
                                                                                                  int indexarg,
                                                                                                  int indexcol,
                                                                                                  IndexOptInfo *index);
-static IndexClause *match_saopclause_to_indexcol(RestrictInfo *rinfo,
+static IndexClause *match_saopclause_to_indexcol(PlannerInfo *root,
+                                                                                                RestrictInfo *rinfo,
                                                                                                 int indexcol,
                                                                                                 IndexOptInfo *index);
-static IndexClause *match_rowcompare_to_indexcol(RestrictInfo *rinfo,
+static IndexClause *match_rowcompare_to_indexcol(PlannerInfo *root,
+                                                                                                RestrictInfo *rinfo,
                                                                                                 int indexcol,
                                                                                                 IndexOptInfo *index);
-static IndexClause *expand_indexqual_rowcompare(RestrictInfo *rinfo,
+static IndexClause *expand_indexqual_rowcompare(PlannerInfo *root,
+                                                                                               RestrictInfo *rinfo,
                                                                                                int indexcol,
                                                                                                IndexOptInfo *index,
                                                                                                Oid expr_op,
@@ -2313,7 +2323,7 @@ match_clause_to_indexcol(PlannerInfo *root,
        opfamily = index->opfamily[indexcol];
        if (IsBooleanOpfamily(opfamily))
        {
-               iclause = match_boolean_index_clause(rinfo, indexcol, index);
+               iclause = match_boolean_index_clause(root, rinfo, indexcol, index);
                if (iclause)
                        return iclause;
        }
@@ -2333,11 +2343,11 @@ match_clause_to_indexcol(PlannerInfo *root,
        }
        else if (IsA(clause, ScalarArrayOpExpr))
        {
-               return match_saopclause_to_indexcol(rinfo, indexcol, index);
+               return match_saopclause_to_indexcol(root, rinfo, indexcol, index);
        }
        else if (IsA(clause, RowCompareExpr))
        {
-               return match_rowcompare_to_indexcol(rinfo, indexcol, index);
+               return match_rowcompare_to_indexcol(root, rinfo, indexcol, index);
        }
        else if (index->amsearchnulls && IsA(clause, NullTest))
        {
@@ -2376,7 +2386,8 @@ match_clause_to_indexcol(PlannerInfo *root,
  * index's key, and if so, build a suitable IndexClause.
  */
 static IndexClause *
-match_boolean_index_clause(RestrictInfo *rinfo,
+match_boolean_index_clause(PlannerInfo *root,
+                                                  RestrictInfo *rinfo,
                                                   int indexcol,
                                                   IndexOptInfo *index)
 {
@@ -2446,7 +2457,7 @@ match_boolean_index_clause(RestrictInfo *rinfo,
                IndexClause *iclause = makeNode(IndexClause);
 
                iclause->rinfo = rinfo;
-               iclause->indexquals = list_make1(make_simple_restrictinfo(op));
+               iclause->indexquals = list_make1(make_simple_restrictinfo(root, op));
                iclause->lossy = false;
                iclause->indexcol = indexcol;
                iclause->indexcols = NIL;
@@ -2671,7 +2682,8 @@ get_index_clause_from_support(PlannerInfo *root,
                {
                        Expr       *clause = (Expr *) lfirst(lc);
 
-                       indexquals = lappend(indexquals, make_simple_restrictinfo(clause));
+                       indexquals = lappend(indexquals,
+                                                                make_simple_restrictinfo(root, clause));
                }
 
                iclause->rinfo = rinfo;
@@ -2692,7 +2704,8 @@ get_index_clause_from_support(PlannerInfo *root,
  *       which see for comments.
  */
 static IndexClause *
-match_saopclause_to_indexcol(RestrictInfo *rinfo,
+match_saopclause_to_indexcol(PlannerInfo *root,
+                                                        RestrictInfo *rinfo,
                                                         int indexcol,
                                                         IndexOptInfo *index)
 {
@@ -2711,7 +2724,7 @@ match_saopclause_to_indexcol(RestrictInfo *rinfo,
                return NULL;
        leftop = (Node *) linitial(saop->args);
        rightop = (Node *) lsecond(saop->args);
-       right_relids = pull_varnos(rightop);
+       right_relids = pull_varnos(root, rightop);
        expr_op = saop->opno;
        expr_coll = saop->inputcollid;
 
@@ -2759,7 +2772,8 @@ match_saopclause_to_indexcol(RestrictInfo *rinfo,
  * is handled by expand_indexqual_rowcompare().
  */
 static IndexClause *
-match_rowcompare_to_indexcol(RestrictInfo *rinfo,
+match_rowcompare_to_indexcol(PlannerInfo *root,
+                                                        RestrictInfo *rinfo,
                                                         int indexcol,
                                                         IndexOptInfo *index)
 {
@@ -2804,14 +2818,14 @@ match_rowcompare_to_indexcol(RestrictInfo *rinfo,
         * These syntactic tests are the same as in match_opclause_to_indexcol()
         */
        if (match_index_to_operand(leftop, indexcol, index) &&
-               !bms_is_member(index_relid, pull_varnos(rightop)) &&
+               !bms_is_member(index_relid, pull_varnos(root, rightop)) &&
                !contain_volatile_functions(rightop))
        {
                /* OK, indexkey is on left */
                var_on_left = true;
        }
        else if (match_index_to_operand(rightop, indexcol, index) &&
-                        !bms_is_member(index_relid, pull_varnos(leftop)) &&
+                        !bms_is_member(index_relid, pull_varnos(root, leftop)) &&
                         !contain_volatile_functions(leftop))
        {
                /* indexkey is on right, so commute the operator */
@@ -2830,7 +2844,8 @@ match_rowcompare_to_indexcol(RestrictInfo *rinfo,
                case BTLessEqualStrategyNumber:
                case BTGreaterEqualStrategyNumber:
                case BTGreaterStrategyNumber:
-                       return expand_indexqual_rowcompare(rinfo,
+                       return expand_indexqual_rowcompare(root,
+                                                                                          rinfo,
                                                                                           indexcol,
                                                                                           index,
                                                                                           expr_op,
@@ -2864,7 +2879,8 @@ match_rowcompare_to_indexcol(RestrictInfo *rinfo,
  * but we split it out for comprehensibility.
  */
 static IndexClause *
-expand_indexqual_rowcompare(RestrictInfo *rinfo,
+expand_indexqual_rowcompare(PlannerInfo *root,
+                                                       RestrictInfo *rinfo,
                                                        int indexcol,
                                                        IndexOptInfo *index,
                                                        Oid expr_op,
@@ -2942,7 +2958,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
                        if (expr_op == InvalidOid)
                                break;                  /* operator is not usable */
                }
-               if (bms_is_member(index->rel->relid, pull_varnos(constop)))
+               if (bms_is_member(index->rel->relid, pull_varnos(root, constop)))
                        break;                          /* no good, Var on wrong side */
                if (contain_volatile_functions(constop))
                        break;                          /* no good, volatile comparison value */
@@ -3055,7 +3071,8 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
                                                                          matching_cols);
                        rc->rargs = list_truncate(copyObject(non_var_args),
                                                                          matching_cols);
-                       iclause->indexquals = list_make1(make_simple_restrictinfo((Expr *) rc));
+                       iclause->indexquals = list_make1(make_simple_restrictinfo(root,
+                                                                                                                                         (Expr *) rc));
                }
                else
                {
@@ -3069,7 +3086,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
                                                           copyObject(linitial(non_var_args)),
                                                           InvalidOid,
                                                           linitial_oid(clause->inputcollids));
-                       iclause->indexquals = list_make1(make_simple_restrictinfo(op));
+                       iclause->indexquals = list_make1(make_simple_restrictinfo(root, op));
                }
        }
 
@@ -3686,7 +3703,9 @@ relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel,
  * specified index column matches a boolean restriction clause.
  */
 bool
-indexcol_is_bool_constant_for_query(IndexOptInfo *index, int indexcol)
+indexcol_is_bool_constant_for_query(PlannerInfo *root,
+                                                                       IndexOptInfo *index,
+                                                                       int indexcol)
 {
        ListCell   *lc;
 
@@ -3708,7 +3727,7 @@ indexcol_is_bool_constant_for_query(IndexOptInfo *index, int indexcol)
                        continue;
 
                /* See if we can match the clause's expression to the index column */
-               if (match_boolean_index_clause(rinfo, indexcol, index))
+               if (match_boolean_index_clause(root, rinfo, indexcol, index))
                        return true;
        }
 
@@ -3821,9 +3840,15 @@ match_index_to_operand(Node *operand,
  */
 bool
 is_pseudo_constant_for_index(Node *expr, IndexOptInfo *index)
+{
+       return is_pseudo_constant_for_index_new(NULL, expr, index);
+}
+
+bool
+is_pseudo_constant_for_index_new(PlannerInfo *root, Node *expr, IndexOptInfo *index)
 {
        /* pull_varnos is cheaper than volatility check, so do that first */
-       if (bms_is_member(index->rel->relid, pull_varnos(expr)))
+       if (bms_is_member(index->rel->relid, pull_varnos(root, expr)))
                return false;                   /* no good, contains Var of table */
        if (contain_volatile_functions(expr))
                return false;                   /* no good, volatile comparison value */
index 08b5061612821138a58f40a41963d1c1b1855b97..3c8b1ae98d2e256ad174e6d18a467d871308983e 100644 (file)
@@ -542,7 +542,7 @@ build_index_pathkeys(PlannerInfo *root,
                         * should stop considering index columns; any lower-order sort
                         * keys won't be useful either.
                         */
-                       if (!indexcol_is_bool_constant_for_query(index, i))
+                       if (!indexcol_is_bool_constant_for_query(root, index, i))
                                break;
                }
 
index 466e99601190291d360d79fd6b22fe1f2ae8733e..3ed6b283e3bc1ca0aa16c1b8c8491124eb3e6967 100644 (file)
@@ -45,6 +45,9 @@
 #include "optimizer/paths.h"
 #include "optimizer/restrictinfo.h"
 
+/* source-code-compatibility hacks for pull_varnos() API change */
+#define pull_varnos(a,b) pull_varnos_new(a,b)
+
 
 /*
  * Does this Var represent the CTID column of the specified baserel?
@@ -123,7 +126,7 @@ IsTidEqualClause(RestrictInfo *rinfo, RelOptInfo *rel)
  * other side of the clause does.
  */
 static bool
-IsTidEqualAnyClause(RestrictInfo *rinfo, RelOptInfo *rel)
+IsTidEqualAnyClause(PlannerInfo *root, RestrictInfo *rinfo, RelOptInfo *rel)
 {
        ScalarArrayOpExpr *node;
        Node       *arg1,
@@ -148,7 +151,7 @@ IsTidEqualAnyClause(RestrictInfo *rinfo, RelOptInfo *rel)
                IsCTIDVar((Var *) arg1, rel))
        {
                /* The other argument must be a pseudoconstant */
-               if (bms_is_member(rel->relid, pull_varnos(arg2)) ||
+               if (bms_is_member(rel->relid, pull_varnos(root, arg2)) ||
                        contain_volatile_functions(arg2))
                        return false;
 
@@ -190,7 +193,7 @@ IsCurrentOfClause(RestrictInfo *rinfo, RelOptInfo *rel)
  * (Using a List may seem a bit weird, but it simplifies the caller.)
  */
 static List *
-TidQualFromRestrictInfo(RestrictInfo *rinfo, RelOptInfo *rel)
+TidQualFromRestrictInfo(PlannerInfo *root, RestrictInfo *rinfo, RelOptInfo *rel)
 {
        /*
         * We may ignore pseudoconstant clauses (they can't contain Vars, so could
@@ -210,7 +213,7 @@ TidQualFromRestrictInfo(RestrictInfo *rinfo, RelOptInfo *rel)
         * Check all base cases.  If we get a match, return the clause.
         */
        if (IsTidEqualClause(rinfo, rel) ||
-               IsTidEqualAnyClause(rinfo, rel) ||
+               IsTidEqualAnyClause(root, rinfo, rel) ||
                IsCurrentOfClause(rinfo, rel))
                return list_make1(rinfo);
 
@@ -227,7 +230,7 @@ TidQualFromRestrictInfo(RestrictInfo *rinfo, RelOptInfo *rel)
  * This function is just concerned with handling AND/OR recursion.
  */
 static List *
-TidQualFromRestrictInfoList(List *rlist, RelOptInfo *rel)
+TidQualFromRestrictInfoList(PlannerInfo *root, List *rlist, RelOptInfo *rel)
 {
        List       *rlst = NIL;
        ListCell   *l;
@@ -255,14 +258,14 @@ TidQualFromRestrictInfoList(List *rlist, RelOptInfo *rel)
                                        List       *andargs = ((BoolExpr *) orarg)->args;
 
                                        /* Recurse in case there are sub-ORs */
-                                       sublist = TidQualFromRestrictInfoList(andargs, rel);
+                                       sublist = TidQualFromRestrictInfoList(root, andargs, rel);
                                }
                                else
                                {
                                        RestrictInfo *rinfo = castNode(RestrictInfo, orarg);
 
                                        Assert(!restriction_is_or_clause(rinfo));
-                                       sublist = TidQualFromRestrictInfo(rinfo, rel);
+                                       sublist = TidQualFromRestrictInfo(root, rinfo, rel);
                                }
 
                                /*
@@ -284,7 +287,7 @@ TidQualFromRestrictInfoList(List *rlist, RelOptInfo *rel)
                else
                {
                        /* Not an OR clause, so handle base cases */
-                       rlst = TidQualFromRestrictInfo(rinfo, rel);
+                       rlst = TidQualFromRestrictInfo(root, rinfo, rel);
                }
 
                /*
@@ -390,7 +393,7 @@ create_tidscan_paths(PlannerInfo *root, RelOptInfo *rel)
         * If any suitable quals exist in the rel's baserestrict list, generate a
         * plain (unparameterized) TidPath with them.
         */
-       tidquals = TidQualFromRestrictInfoList(rel->baserestrictinfo, rel);
+       tidquals = TidQualFromRestrictInfoList(root, rel->baserestrictinfo, rel);
 
        if (tidquals)
        {
index 32695db367b95a78c396a1362208996e8e290e18..bb377bd240fe4bc60ecf1e93909a5d6d9eff90bc 100644 (file)
@@ -32,6 +32,9 @@
 #include "optimizer/tlist.h"
 #include "utils/lsyscache.h"
 
+/* source-code-compatibility hacks for pull_varnos() API change */
+#define pull_varnos(a,b) pull_varnos_new(a,b)
+
 /* local functions */
 static bool join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo);
 static void remove_rel_from_query(PlannerInfo *root, int relid,
@@ -232,7 +235,7 @@ join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo)
                        continue;                       /* it definitely doesn't reference innerrel */
                if (bms_is_subset(phinfo->ph_eval_at, innerrel->relids))
                        return false;           /* there isn't any other place to eval PHV */
-               if (bms_overlap(pull_varnos((Node *) phinfo->ph_var->phexpr),
+               if (bms_overlap(pull_varnos(root, (Node *) phinfo->ph_var->phexpr),
                                                innerrel->relids))
                        return false;           /* it does reference innerrel */
        }
index 73da0c2d8e1d3e45fa080c26fad2b640b82a51f5..3fefc44c4c614203c9bcd2d1e81c23d2543a409d 100644 (file)
 #include "utils/lsyscache.h"
 
 
+/* source-code-compatibility hacks for pull_varnos() API change */
+#define pull_varnos(a,b) pull_varnos_new(a,b)
+#define make_restrictinfo(a,b,c,d,e,f,g,h,i) make_restrictinfo_new(a,b,c,d,e,f,g,h,i)
+
 /* These parameters are set by GUC */
 int                    from_collapse_limit;
 int                    join_collapse_limit;
@@ -61,7 +65,8 @@ static SpecialJoinInfo *make_outerjoininfo(PlannerInfo *root,
                                                                                   Relids left_rels, Relids right_rels,
                                                                                   Relids inner_join_rels,
                                                                                   JoinType jointype, List *clause);
-static void compute_semijoin_info(SpecialJoinInfo *sjinfo, List *clause);
+static void compute_semijoin_info(PlannerInfo *root, SpecialJoinInfo *sjinfo,
+                                                                 List *clause);
 static void distribute_qual_to_rels(PlannerInfo *root, Node *clause,
                                                                        bool is_deduced,
                                                                        bool below_outer_join,
@@ -1202,7 +1207,7 @@ make_outerjoininfo(PlannerInfo *root,
        /* this always starts out false */
        sjinfo->delay_upper_joins = false;
 
-       compute_semijoin_info(sjinfo, clause);
+       compute_semijoin_info(root, sjinfo, clause);
 
        /* If it's a full join, no need to be very smart */
        if (jointype == JOIN_FULL)
@@ -1216,7 +1221,7 @@ make_outerjoininfo(PlannerInfo *root,
        /*
         * Retrieve all relids mentioned within the join clause.
         */
-       clause_relids = pull_varnos((Node *) clause);
+       clause_relids = pull_varnos(root, (Node *) clause);
 
        /*
         * For which relids is the clause strict, ie, it cannot succeed if the
@@ -1396,7 +1401,7 @@ make_outerjoininfo(PlannerInfo *root,
  * SpecialJoinInfo; the rest may not be set yet.
  */
 static void
-compute_semijoin_info(SpecialJoinInfo *sjinfo, List *clause)
+compute_semijoin_info(PlannerInfo *root, SpecialJoinInfo *sjinfo, List *clause)
 {
        List       *semi_operators;
        List       *semi_rhs_exprs;
@@ -1460,7 +1465,7 @@ compute_semijoin_info(SpecialJoinInfo *sjinfo, List *clause)
                        list_length(op->args) != 2)
                {
                        /* No, but does it reference both sides? */
-                       all_varnos = pull_varnos((Node *) op);
+                       all_varnos = pull_varnos(root, (Node *) op);
                        if (!bms_overlap(all_varnos, sjinfo->syn_righthand) ||
                                bms_is_subset(all_varnos, sjinfo->syn_righthand))
                        {
@@ -1481,8 +1486,8 @@ compute_semijoin_info(SpecialJoinInfo *sjinfo, List *clause)
                opno = op->opno;
                left_expr = linitial(op->args);
                right_expr = lsecond(op->args);
-               left_varnos = pull_varnos(left_expr);
-               right_varnos = pull_varnos(right_expr);
+               left_varnos = pull_varnos(root, left_expr);
+               right_varnos = pull_varnos(root, right_expr);
                all_varnos = bms_union(left_varnos, right_varnos);
                opinputtype = exprType(left_expr);
 
@@ -1636,7 +1641,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
        /*
         * Retrieve all relids mentioned within the clause.
         */
-       relids = pull_varnos(clause);
+       relids = pull_varnos(root, clause);
 
        /*
         * In ordinary SQL, a WHERE or JOIN/ON clause can't reference any rels
@@ -1868,7 +1873,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
        /*
         * Build the RestrictInfo node itself.
         */
-       restrictinfo = make_restrictinfo((Expr *) clause,
+       restrictinfo = make_restrictinfo(root,
+                                                                        (Expr *) clause,
                                                                         is_pushed_down,
                                                                         outerjoin_delayed,
                                                                         pseudoconstant,
@@ -2352,7 +2358,8 @@ process_implied_equality(PlannerInfo *root,
  * caller's responsibility that left_ec/right_ec be set as necessary.
  */
 RestrictInfo *
-build_implied_join_equality(Oid opno,
+build_implied_join_equality(PlannerInfo *root,
+                                                       Oid opno,
                                                        Oid collation,
                                                        Expr *item1,
                                                        Expr *item2,
@@ -2378,7 +2385,8 @@ build_implied_join_equality(Oid opno,
        /*
         * Build the RestrictInfo node itself.
         */
-       restrictinfo = make_restrictinfo(clause,
+       restrictinfo = make_restrictinfo(root,
+                                                                        clause,
                                                                         true,  /* is_pushed_down */
                                                                         false, /* outerjoin_delayed */
                                                                         false, /* pseudoconstant */
index b23e9492f3144d8bc3b74cbceee3a9f59df0daa5..74e3e5b111b28f1f67754bc100d710f0fb3a11c3 100644 (file)
@@ -39,6 +39,9 @@
 #include "utils/syscache.h"
 
 
+/* source-code-compatibility hacks for pull_varnos() API change */
+#define pull_varnos(a,b) pull_varnos_new(a,b)
+
 typedef struct convert_testexpr_context
 {
        PlannerInfo *root;
@@ -1270,7 +1273,7 @@ convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink,
         * it's not gonna be a join.  (Note that it won't have Vars referring to
         * the subquery, rather Params.)
         */
-       upper_varnos = pull_varnos(sublink->testexpr);
+       upper_varnos = pull_varnos(root, sublink->testexpr);
        if (bms_is_empty(upper_varnos))
                return NULL;
 
@@ -1453,7 +1456,7 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
         * The ones <= rtoffset belong to the upper query; the ones > rtoffset do
         * not.
         */
-       clause_varnos = pull_varnos(whereClause);
+       clause_varnos = pull_varnos(root, whereClause);
        upper_varnos = NULL;
        while ((varno = bms_first_member(clause_varnos)) >= 0)
        {
index 722fd16eeb4962eed84ba0c40e56455fe5049bce..92a90e40f04dec3849b036af9a8733fa9ae33f05 100644 (file)
 #include "rewrite/rewriteManip.h"
 
 
+/* source-code-compatibility hacks for pull_varnos() API change */
+#define pull_varnos(a,b) pull_varnos_new(a,b)
+#define pull_varnos_of_level(a,b,c) pull_varnos_of_level_new(a,b,c)
+
 typedef struct pullup_replace_vars_context
 {
        PlannerInfo *root;
@@ -81,7 +85,8 @@ static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root,
                                                                           int childRToffset);
 static void make_setop_translation_list(Query *query, Index newvarno,
                                                                                List **translated_vars);
-static bool is_simple_subquery(Query *subquery, RangeTblEntry *rte,
+static bool is_simple_subquery(PlannerInfo *root, Query *subquery,
+                                                          RangeTblEntry *rte,
                                                           JoinExpr *lowest_outer_join);
 static Node *pull_up_simple_values(PlannerInfo *root, Node *jtnode,
                                                                   RangeTblEntry *rte);
@@ -90,7 +95,8 @@ static bool is_simple_union_all(Query *subquery);
 static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery,
                                                                                List *colTypes);
 static bool is_safe_append_member(Query *subquery);
-static bool jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted,
+static bool jointree_contains_lateral_outer_refs(PlannerInfo *root,
+                                                                                                Node *jtnode, bool restricted,
                                                                                                 Relids safe_upper_varnos);
 static void replace_vars_in_jointree(Node *jtnode,
                                                                         pullup_replace_vars_context *context,
@@ -723,7 +729,7 @@ pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode,
                 * unless is_safe_append_member says so.
                 */
                if (rte->rtekind == RTE_SUBQUERY &&
-                       is_simple_subquery(rte->subquery, rte, lowest_outer_join) &&
+                       is_simple_subquery(root, rte->subquery, rte, lowest_outer_join) &&
                        (containing_appendrel == NULL ||
                         is_safe_append_member(rte->subquery)))
                        return pull_up_simple_subquery(root, jtnode, rte,
@@ -942,7 +948,7 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
         * easier just to keep this "if" looking the same as the one in
         * pull_up_subqueries_recurse.
         */
-       if (is_simple_subquery(subquery, rte, lowest_outer_join) &&
+       if (is_simple_subquery(root, subquery, rte, lowest_outer_join) &&
                (containing_appendrel == NULL || is_safe_append_member(subquery)))
        {
                /* good to go */
@@ -1420,7 +1426,7 @@ make_setop_translation_list(Query *query, Index newvarno,
  * lowest_outer_join is the lowest outer join above the subquery, or NULL.
  */
 static bool
-is_simple_subquery(Query *subquery, RangeTblEntry *rte,
+is_simple_subquery(PlannerInfo *root, Query *subquery, RangeTblEntry *rte,
                                   JoinExpr *lowest_outer_join)
 {
        /*
@@ -1499,7 +1505,8 @@ is_simple_subquery(Query *subquery, RangeTblEntry *rte,
                        safe_upper_varnos = NULL;       /* doesn't matter */
                }
 
-               if (jointree_contains_lateral_outer_refs((Node *) subquery->jointree,
+               if (jointree_contains_lateral_outer_refs(root,
+                                                                                                (Node *) subquery->jointree,
                                                                                                 restricted, safe_upper_varnos))
                        return false;
 
@@ -1518,7 +1525,9 @@ is_simple_subquery(Query *subquery, RangeTblEntry *rte,
                 */
                if (lowest_outer_join != NULL)
                {
-                       Relids          lvarnos = pull_varnos_of_level((Node *) subquery->targetList, 1);
+                       Relids          lvarnos = pull_varnos_of_level(root,
+                                                                                                          (Node *) subquery->targetList,
+                                                                                                          1);
 
                        if (!bms_is_subset(lvarnos, safe_upper_varnos))
                                return false;
@@ -1838,7 +1847,8 @@ is_safe_append_member(Query *subquery)
  * in safe_upper_varnos.
  */
 static bool
-jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted,
+jointree_contains_lateral_outer_refs(PlannerInfo *root, Node *jtnode,
+                                                                        bool restricted,
                                                                         Relids safe_upper_varnos)
 {
        if (jtnode == NULL)
@@ -1853,7 +1863,8 @@ jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted,
                /* First, recurse to check child joins */
                foreach(l, f->fromlist)
                {
-                       if (jointree_contains_lateral_outer_refs(lfirst(l),
+                       if (jointree_contains_lateral_outer_refs(root,
+                                                                                                        lfirst(l),
                                                                                                         restricted,
                                                                                                         safe_upper_varnos))
                                return true;
@@ -1861,7 +1872,7 @@ jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted,
 
                /* Then check the top-level quals */
                if (restricted &&
-                       !bms_is_subset(pull_varnos_of_level(f->quals, 1),
+                       !bms_is_subset(pull_varnos_of_level(root, f->quals, 1),
                                                   safe_upper_varnos))
                        return true;
        }
@@ -1880,18 +1891,20 @@ jointree_contains_lateral_outer_refs(Node *jtnode, bool restricted,
                }
 
                /* Check the child joins */
-               if (jointree_contains_lateral_outer_refs(j->larg,
+               if (jointree_contains_lateral_outer_refs(root,
+                                                                                                j->larg,
                                                                                                 restricted,
                                                                                                 safe_upper_varnos))
                        return true;
-               if (jointree_contains_lateral_outer_refs(j->rarg,
+               if (jointree_contains_lateral_outer_refs(root,
+                                                                                                j->rarg,
                                                                                                 restricted,
                                                                                                 safe_upper_varnos))
                        return true;
 
                /* Check the JOIN's qual clauses */
                if (restricted &&
-                       !bms_is_subset(pull_varnos_of_level(j->quals, 1),
+                       !bms_is_subset(pull_varnos_of_level(root, j->quals, 1),
                                                   safe_upper_varnos))
                        return true;
        }
@@ -2187,7 +2200,8 @@ pullup_replace_vars_callback(Var *var,
                                 * level-zero var must belong to the subquery.
                                 */
                                if ((rcon->target_rte->lateral ?
-                                        bms_overlap(pull_varnos((Node *) newnode), rcon->relids) :
+                                        bms_overlap(pull_varnos(rcon->root, (Node *) newnode),
+                                                                rcon->relids) :
                                         contain_vars_of_level((Node *) newnode, 0)) &&
                                        !contain_nonstrict_functions((Node *) newnode))
                                {
@@ -2626,7 +2640,7 @@ reduce_outer_joins_pass2(Node *jtnode,
                        overlap = list_intersection(local_nonnullable_vars,
                                                                                forced_null_vars);
                        if (overlap != NIL &&
-                               bms_overlap(pull_varnos((Node *) overlap),
+                               bms_overlap(pull_varnos(root, (Node *) overlap),
                                                        right_state->relids))
                                jointype = JOIN_ANTI;
                }
index a3ae2a02f77d2081baf8ef5d818ecc0dd07db37f..e549ad150ae3a49f72eb100a99fc8c21262290d8 100644 (file)
@@ -54,6 +54,9 @@
 #include "utils/typcache.h"
 
 
+/* source-code-compatibility hacks for pull_varnos() API change */
+#define pull_varnos(a,b) pull_varnos_new(a,b)
+
 typedef struct
 {
        PlannerInfo *root;
@@ -2182,7 +2185,13 @@ is_pseudo_constant_clause_relids(Node *clause, Relids relids)
 int
 NumRelids(Node *clause)
 {
-       Relids          varnos = pull_varnos(clause);
+       return NumRelids_new(NULL, clause);
+}
+
+int
+NumRelids_new(PlannerInfo *root, Node *clause)
+{
+       Relids          varnos = pull_varnos(root, clause);
        int                     result = bms_num_members(varnos);
 
        bms_free(varnos);
index 38bc61e6878407d4cbd0d7232ef1f86b4712221b..f0953475b1f5fc7d7c158bd45a1e19a9d1d54c29 100644 (file)
@@ -35,6 +35,9 @@
 #include "utils/rel.h"
 
 
+/* source-code-compatibility hacks for pull_varnos() API change */
+#define make_restrictinfo(a,b,c,d,e,f,g,h,i) make_restrictinfo_new(a,b,c,d,e,f,g,h,i)
+
 static void expand_partitioned_rtentry(PlannerInfo *root, RelOptInfo *relinfo,
                                                                           RangeTblEntry *parentrte,
                                                                           Index parentRTindex, Relation parentrel,
@@ -682,7 +685,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,
@@ -719,7 +723,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));
index 18ebc51bcac38e17ce2816b791b8d5ee7a46fca5..d5b058c227ec3ee8dc42ee54d7256a5464bf14da 100644 (file)
@@ -24,6 +24,9 @@
 #include "optimizer/restrictinfo.h"
 
 
+/* source-code-compatibility hacks for pull_varnos() API change */
+#define make_restrictinfo(a,b,c,d,e,f,g,h,i) make_restrictinfo_new(a,b,c,d,e,f,g,h,i)
+
 static bool is_safe_restriction_clause_for(RestrictInfo *rinfo, RelOptInfo *rel);
 static Expr *extract_or_clause(RestrictInfo *or_rinfo, RelOptInfo *rel);
 static void consider_new_or_clause(PlannerInfo *root, RelOptInfo *rel,
@@ -268,7 +271,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,
index bbe6486287cc0cf083d4270c9583a3bfde54765b..4cda433831a6aa0daa5f888fe1c11c55aa57615f 100644 (file)
@@ -23,6 +23,9 @@
 #include "optimizer/planmain.h"
 #include "utils/lsyscache.h"
 
+/* source-code-compatibility hacks for pull_varnos() API change */
+#define pull_varnos(a,b) pull_varnos_new(a,b)
+
 /* Local functions */
 static void find_placeholders_recurse(PlannerInfo *root, Node *jtnode);
 static void find_placeholders_in_expr(PlannerInfo *root, Node *expr);
@@ -98,7 +101,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 */
index 3b50fd29ad69f938746fd95b096650cd87583540..2c3a6f2cf7ca954faa7129c5da60f98424194832 100644 (file)
 #include "optimizer/restrictinfo.h"
 
 
-static RestrictInfo *make_restrictinfo_internal(Expr *clause,
+/* source-code-compatibility hacks for pull_varnos() API change */
+#define pull_varnos(a,b) pull_varnos_new(a,b)
+
+static RestrictInfo *make_restrictinfo_internal(PlannerInfo *root,
+                                                                                               Expr *clause,
                                                                                                Expr *orclause,
                                                                                                bool is_pushed_down,
                                                                                                bool outerjoin_delayed,
@@ -30,7 +34,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,
@@ -64,13 +69,36 @@ make_restrictinfo(Expr *clause,
                                  Relids required_relids,
                                  Relids outer_relids,
                                  Relids nullable_relids)
+{
+       return make_restrictinfo_new(NULL,
+                                                                clause,
+                                                                is_pushed_down,
+                                                                outerjoin_delayed,
+                                                                pseudoconstant,
+                                                                security_level,
+                                                                required_relids,
+                                                                outer_relids,
+                                                                nullable_relids);
+}
+
+RestrictInfo *
+make_restrictinfo_new(PlannerInfo *root,
+                                         Expr *clause,
+                                         bool is_pushed_down,
+                                         bool outerjoin_delayed,
+                                         bool pseudoconstant,
+                                         Index security_level,
+                                         Relids required_relids,
+                                         Relids outer_relids,
+                                         Relids nullable_relids)
 {
        /*
         * If it's an OR clause, build a modified copy with RestrictInfos inserted
         * 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 +110,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 +128,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 +167,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 +195,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 +255,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 +272,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 +281,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 +299,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 +311,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,
index 15cc518a82e2925a71232719b09a8f219369e992..58d093c1c1105b81c05cc3a8c6d18f8d7ac09909 100644 (file)
@@ -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;
 
@@ -93,10 +95,17 @@ static Relids alias_relid_set(Query *query, Relids relids);
  */
 Relids
 pull_varnos(Node *node)
+{
+       return pull_varnos_new(NULL, node);
+}
+
+Relids
+pull_varnos_new(PlannerInfo *root, Node *node)
 {
        pull_varnos_context context;
 
        context.varnos = NULL;
+       context.root = root;
        context.sublevels_up = 0;
 
        /*
@@ -118,10 +127,17 @@ pull_varnos(Node *node)
  */
 Relids
 pull_varnos_of_level(Node *node, int levelsup)
+{
+       return pull_varnos_of_level_new(NULL, node, levelsup);
+}
+
+Relids
+pull_varnos_of_level_new(PlannerInfo *root, Node *node, int levelsup)
 {
        pull_varnos_context context;
 
        context.varnos = NULL;
+       context.root = root;
        context.sublevels_up = levelsup;
 
        /*
@@ -159,33 +175,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 && context->root)
+                       {
+                               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;
index a8f984037f9e88c4c0ea38b90a45e8be0b11baab..2fefa9162162617b9e2ed8951b8c5d025676a7dd 100644 (file)
 #include "utils/typcache.h"
 
 
+/* source-code-compatibility hacks for pull_varnos() API change */
+#define pull_varnos(a,b) pull_varnos_new(a,b)
+#define NumRelids(a,b) NumRelids_new(a,b)
+
 /* Hooks for plugins to get control when we ask for stats */
 get_relation_stats_hook_type get_relation_stats_hook = NULL;
 get_index_stats_hook_type get_index_stats_hook = NULL;
@@ -2017,7 +2021,7 @@ rowcomparesel(PlannerInfo *root,
                /*
                 * Otherwise, it's a join if there's more than one relation used.
                 */
-               is_join_clause = (NumRelids((Node *) opargs) > 1);
+               is_join_clause = (NumRelids(root, (Node *) opargs) > 1);
        }
 
        if (is_join_clause)
@@ -4536,7 +4540,7 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
         * membership.  Note that when varRelid isn't zero, only vars of that
         * relation are considered "real" vars.
         */
-       varnos = pull_varnos(basenode);
+       varnos = pull_varnos(root, basenode);
 
        onerel = NULL;
 
index c87c194bcd05630e5269ae4b51eb92d17b4d0152..f66d51a84502240c4a5699c4b7cade9e3eef2647 100644 (file)
@@ -50,6 +50,7 @@ extern bool is_pseudo_constant_clause(Node *clause);
 extern bool is_pseudo_constant_clause_relids(Node *clause, Relids relids);
 
 extern int     NumRelids(Node *clause);
+extern int     NumRelids_new(PlannerInfo *root, Node *clause);
 
 extern void CommuteOpExpr(OpExpr *clause);
 
index 6b8fd3f285ed8b7955926b957e2775303ca7de0a..136d1cf17ef582db9ba461c62111af32ba9467d4 100644 (file)
@@ -87,6 +87,8 @@ extern double clamp_row_est(double nrows);
 /* in path/indxpath.c: */
 
 extern bool is_pseudo_constant_for_index(Node *expr, IndexOptInfo *index);
+extern bool is_pseudo_constant_for_index_new(PlannerInfo *root, Node *expr,
+                                                                                        IndexOptInfo *index);
 
 /* in plan/planner.c: */
 
@@ -178,6 +180,8 @@ extern SortGroupClause *get_sortgroupref_clause_noerr(Index sortref,
 
 extern Bitmapset *pull_varnos(Node *node);
 extern Bitmapset *pull_varnos_of_level(Node *node, int levelsup);
+extern Bitmapset *pull_varnos_new(PlannerInfo *root, Node *node);
+extern Bitmapset *pull_varnos_of_level_new(PlannerInfo *root, Node *node, int levelsup);
 extern void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos);
 extern List *pull_vars_of_level(Node *node, int levelsup);
 extern bool contain_var_clause(Node *node);
index c6c34630c2828563a4dd1666e3e35861f47580af..e9b0bff57ec15861533caa8a8dc27f95e3540b7d 100644 (file)
@@ -73,7 +73,8 @@ extern void create_index_paths(PlannerInfo *root, RelOptInfo *rel);
 extern bool relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel,
                                                                                  List *restrictlist,
                                                                                  List *exprlist, List *oprlist);
-extern bool indexcol_is_bool_constant_for_query(IndexOptInfo *index,
+extern bool indexcol_is_bool_constant_for_query(PlannerInfo *root,
+                                                                                               IndexOptInfo *index,
                                                                                                int indexcol);
 extern bool match_index_to_operand(Node *operand, int indexcol,
                                                                   IndexOptInfo *index);
index e7aaddd50d6040b2d805ad6b34b422da73fac00c..80dc4bf4e8833b07de84faba604028d708f7971e 100644 (file)
@@ -84,7 +84,8 @@ extern void process_implied_equality(PlannerInfo *root,
                                                                         Index security_level,
                                                                         bool below_outer_join,
                                                                         bool both_const);
-extern RestrictInfo *build_implied_join_equality(Oid opno,
+extern RestrictInfo *build_implied_join_equality(PlannerInfo *root,
+                                                                                                Oid opno,
                                                                                                 Oid collation,
                                                                                                 Expr *item1,
                                                                                                 Expr *item2,
index 0fe92ad428247293fdcff6c708c1240cb2c9ccbf..0f0ab801c0495769e1d5723e94476dfede55f659 100644 (file)
@@ -29,6 +29,15 @@ extern RestrictInfo *make_restrictinfo(Expr *clause,
                                                                           Relids required_relids,
                                                                           Relids outer_relids,
                                                                           Relids nullable_relids);
+extern RestrictInfo *make_restrictinfo_new(PlannerInfo *root,
+                                                                                  Expr *clause,
+                                                                                  bool is_pushed_down,
+                                                                                  bool outerjoin_delayed,
+                                                                                  bool pseudoconstant,
+                                                                                  Index security_level,
+                                                                                  Relids required_relids,
+                                                                                  Relids outer_relids,
+                                                                                  Relids nullable_relids);
 extern RestrictInfo *commute_restrictinfo(RestrictInfo *rinfo, Oid comm_op);
 extern bool restriction_is_or_clause(RestrictInfo *restrictinfo);
 extern bool restriction_is_securely_promotable(RestrictInfo *restrictinfo,
index 3d889314a24fa681838f8a5e5fd8b73beb9748fc..7154909632226dcb45c84fea733d8c5535aac802 100644 (file)
@@ -4593,6 +4593,42 @@ where ss.stringu2 !~* ss.case1;
 (1 row)
 
 rollback;
+-- test case to expose miscomputation of required relid set for a PHV
+explain (verbose, costs off)
+select i8.*, ss.v, t.unique2
+  from int8_tbl i8
+    left join int4_tbl i4 on i4.f1 = 1
+    left join lateral (select i4.f1 + 1 as v) as ss on true
+    left join tenk1 t on t.unique2 = ss.v
+where q2 = 456;
+                         QUERY PLAN                          
+-------------------------------------------------------------
+ Nested Loop Left Join
+   Output: i8.q1, i8.q2, ((i4.f1 + 1)), t.unique2
+   ->  Nested Loop Left Join
+         Output: i8.q1, i8.q2, (i4.f1 + 1)
+         ->  Seq Scan on public.int8_tbl i8
+               Output: i8.q1, i8.q2
+               Filter: (i8.q2 = 456)
+         ->  Seq Scan on public.int4_tbl i4
+               Output: i4.f1
+               Filter: (i4.f1 = 1)
+   ->  Index Only Scan using tenk1_unique2 on public.tenk1 t
+         Output: t.unique2
+         Index Cond: (t.unique2 = ((i4.f1 + 1)))
+(13 rows)
+
+select i8.*, ss.v, t.unique2
+  from int8_tbl i8
+    left join int4_tbl i4 on i4.f1 = 1
+    left join lateral (select i4.f1 + 1 as v) as ss on true
+    left join tenk1 t on t.unique2 = ss.v
+where q2 = 456;
+ q1  | q2  | v | unique2 
+-----+-----+---+---------
+ 123 | 456 |   |        
+(1 row)
+
 -- bug #8444: we've historically allowed duplicate aliases within aliased JOINs
 select * from
   int8_tbl x join (int4_tbl x cross join int4_tbl y) j on q1 = f1; -- error
index 9e8dfd156ab8987c759f5fd530dcdbde1aa55982..7af22b9f67a94e9784165f8b307ff7b7a5e48139 100644 (file)
@@ -1619,6 +1619,22 @@ where ss.stringu2 !~* ss.case1;
 
 rollback;
 
+-- test case to expose miscomputation of required relid set for a PHV
+explain (verbose, costs off)
+select i8.*, ss.v, t.unique2
+  from int8_tbl i8
+    left join int4_tbl i4 on i4.f1 = 1
+    left join lateral (select i4.f1 + 1 as v) as ss on true
+    left join tenk1 t on t.unique2 = ss.v
+where q2 = 456;
+
+select i8.*, ss.v, t.unique2
+  from int8_tbl i8
+    left join int4_tbl i4 on i4.f1 = 1
+    left join lateral (select i4.f1 + 1 as v) as ss on true
+    left join tenk1 t on t.unique2 = ss.v
+where q2 = 456;
+
 -- bug #8444: we've historically allowed duplicate aliases within aliased JOINs
 
 select * from