diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 1759b9e1b6d..105d505409f 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -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, diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c index 4bf777d82d3..4c42145a3e5 100644 --- a/src/backend/optimizer/path/clausesel.c +++ b/src/backend/optimizer/path/clausesel.c @@ -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, diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index b62b954e880..e54da55924e 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -32,6 +32,10 @@ #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, diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 95ae99bcf30..44dff2a8025 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -36,6 +36,12 @@ #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 */ diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index 08b50616128..3c8b1ae98d2 100644 --- a/src/backend/optimizer/path/pathkeys.c +++ b/src/backend/optimizer/path/pathkeys.c @@ -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; } diff --git a/src/backend/optimizer/path/tidpath.c b/src/backend/optimizer/path/tidpath.c index 466e9960119..3ed6b283e3b 100644 --- a/src/backend/optimizer/path/tidpath.c +++ b/src/backend/optimizer/path/tidpath.c @@ -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) { diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c index 32695db367b..bb377bd240f 100644 --- a/src/backend/optimizer/plan/analyzejoins.c +++ b/src/backend/optimizer/plan/analyzejoins.c @@ -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 */ } diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 73da0c2d8e1..3fefc44c4c6 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -35,6 +35,10 @@ #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 */ diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index b23e9492f31..74e3e5b111b 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -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) { diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index 722fd16eeb4..92a90e40f04 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -39,6 +39,10 @@ #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; } diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index a3ae2a02f77..e549ad150ae 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -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); diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c index 38bc61e6878..f0953475b1f 100644 --- a/src/backend/optimizer/util/inherit.c +++ b/src/backend/optimizer/util/inherit.c @@ -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)); diff --git a/src/backend/optimizer/util/orclauses.c b/src/backend/optimizer/util/orclauses.c index 18ebc51bcac..d5b058c227e 100644 --- a/src/backend/optimizer/util/orclauses.c +++ b/src/backend/optimizer/util/orclauses.c @@ -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, diff --git a/src/backend/optimizer/util/placeholder.c b/src/backend/optimizer/util/placeholder.c index bbe6486287c..4cda433831a 100644 --- a/src/backend/optimizer/util/placeholder.c +++ b/src/backend/optimizer/util/placeholder.c @@ -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 */ diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c index 3b50fd29ad6..2c3a6f2cf7c 100644 --- a/src/backend/optimizer/util/restrictinfo.c +++ b/src/backend/optimizer/util/restrictinfo.c @@ -21,7 +21,11 @@ #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, diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index 15cc518a82e..58d093c1c11 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; @@ -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; diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index a8f984037f9..2fefa916216 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -139,6 +139,10 @@ #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; diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h index c87c194bcd0..f66d51a8450 100644 --- a/src/include/optimizer/clauses.h +++ b/src/include/optimizer/clauses.h @@ -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); diff --git a/src/include/optimizer/optimizer.h b/src/include/optimizer/optimizer.h index 6b8fd3f285e..136d1cf17ef 100644 --- a/src/include/optimizer/optimizer.h +++ b/src/include/optimizer/optimizer.h @@ -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); diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h index c6c34630c28..e9b0bff57ec 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -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); diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h index e7aaddd50d6..80dc4bf4e88 100644 --- a/src/include/optimizer/planmain.h +++ b/src/include/optimizer/planmain.h @@ -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, diff --git a/src/include/optimizer/restrictinfo.h b/src/include/optimizer/restrictinfo.h index 0fe92ad4282..0f0ab801c04 100644 --- a/src/include/optimizer/restrictinfo.h +++ b/src/include/optimizer/restrictinfo.h @@ -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, diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out index 3d889314a24..71549096322 100644 --- a/src/test/regress/expected/join.out +++ b/src/test/regress/expected/join.out @@ -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 diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql index 9e8dfd156ab..7af22b9f67a 100644 --- a/src/test/regress/sql/join.sql +++ b/src/test/regress/sql/join.sql @@ -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