diff options
Diffstat (limited to 'src/backend/optimizer/plan/createplan.c')
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 332 |
1 files changed, 158 insertions, 174 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 1b4f7db649e..c7645acad2c 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -152,8 +152,13 @@ static MergeJoin *create_mergejoin_plan(PlannerInfo *root, MergePath *best_path) static HashJoin *create_hashjoin_plan(PlannerInfo *root, HashPath *best_path); static Node *replace_nestloop_params(PlannerInfo *root, Node *expr); static Node *replace_nestloop_params_mutator(Node *node, PlannerInfo *root); -static List *fix_indexqual_references(PlannerInfo *root, IndexPath *index_path); +static void fix_indexqual_references(PlannerInfo *root, IndexPath *index_path, + List **stripped_indexquals_p, + List **fixed_indexquals_p); static List *fix_indexorderby_references(PlannerInfo *root, IndexPath *index_path); +static Node *fix_indexqual_clause(PlannerInfo *root, + IndexOptInfo *index, int indexcol, + Node *clause, List *indexcolnos); static Node *fix_indexqual_operand(Node *node, IndexOptInfo *index, int indexcol); static List *get_switched_clauses(List *clauses, Relids outerrelids); static List *order_qual_clauses(PlannerInfo *root, List *clauses); @@ -2607,7 +2612,7 @@ create_indexscan_plan(PlannerInfo *root, bool indexonly) { Scan *scan_plan; - List *indexquals = best_path->indexquals; + List *indexclauses = best_path->indexclauses; List *indexorderbys = best_path->indexorderbys; Index baserelid = best_path->path.parent->relid; Oid indexoid = best_path->indexinfo->indexoid; @@ -2623,16 +2628,14 @@ create_indexscan_plan(PlannerInfo *root, Assert(best_path->path.parent->rtekind == RTE_RELATION); /* - * Build "stripped" indexquals structure (no RestrictInfos) to pass to - * executor as indexqualorig + * Extract the index qual expressions (stripped of RestrictInfos) from the + * IndexClauses list, and prepare a copy with index Vars substituted for + * table Vars. (This step also does replace_nestloop_params on the + * fixed_indexquals.) */ - stripped_indexquals = get_actual_clauses(indexquals); - - /* - * The executor needs a copy with the indexkey on the left of each clause - * and with index Vars substituted for table ones. - */ - fixed_indexquals = fix_indexqual_references(root, best_path); + fix_indexqual_references(root, best_path, + &stripped_indexquals, + &fixed_indexquals); /* * Likewise fix up index attr references in the ORDER BY expressions. @@ -2648,14 +2651,14 @@ create_indexscan_plan(PlannerInfo *root, * included in qpqual. The upshot is that qpqual must contain * scan_clauses minus whatever appears in indexquals. * - * In normal cases simple pointer equality checks will be enough to spot - * duplicate RestrictInfos, so we try that first. - * - * Another common case is that a scan_clauses entry is generated from the - * same EquivalenceClass as some indexqual, and is therefore redundant - * with it, though not equal. (This happens when indxpath.c prefers a + * is_redundant_with_indexclauses() detects cases where a scan clause is + * present in the indexclauses list or is generated from the same + * EquivalenceClass as some indexclause, and is therefore redundant with + * it, though not equal. (The latter happens when indxpath.c prefers a * different derived equality than what generate_join_implied_equalities - * picked for a parameterized scan's ppi_clauses.) + * picked for a parameterized scan's ppi_clauses.) Note that it will not + * match to lossy index clauses, which is critical because we have to + * include the original clause in qpqual in that case. * * In some situations (particularly with OR'd index conditions) we may * have scan_clauses that are not equal to, but are logically implied by, @@ -2674,12 +2677,11 @@ create_indexscan_plan(PlannerInfo *root, if (rinfo->pseudoconstant) continue; /* we may drop pseudoconstants here */ - if (list_member_ptr(indexquals, rinfo)) - continue; /* simple duplicate */ - if (is_redundant_derived_clause(rinfo, indexquals)) - continue; /* derived from same EquivalenceClass */ + if (is_redundant_with_indexclauses(rinfo, indexclauses)) + continue; /* dup or derived from same EquivalenceClass */ if (!contain_mutable_functions((Node *) rinfo->clause) && - predicate_implied_by(list_make1(rinfo->clause), indexquals, false)) + predicate_implied_by(list_make1(rinfo->clause), stripped_indexquals, + false)) continue; /* provably implied by indexquals */ qpqual = lappend(qpqual, rinfo); } @@ -3040,6 +3042,8 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual, { IndexPath *ipath = (IndexPath *) bitmapqual; IndexScan *iscan; + List *subquals; + List *subindexquals; List *subindexECs; ListCell *l; @@ -3060,8 +3064,26 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual, plan->plan_width = 0; /* meaningless */ plan->parallel_aware = false; plan->parallel_safe = ipath->path.parallel_safe; - *qual = get_actual_clauses(ipath->indexclauses); - *indexqual = get_actual_clauses(ipath->indexquals); + /* Extract original index clauses, actual index quals, relevant ECs */ + subquals = NIL; + subindexquals = NIL; + subindexECs = NIL; + foreach(l, ipath->indexclauses) + { + IndexClause *iclause = (IndexClause *) lfirst(l); + RestrictInfo *rinfo = iclause->rinfo; + + Assert(!rinfo->pseudoconstant); + subquals = lappend(subquals, rinfo->clause); + if (iclause->indexquals) + subindexquals = list_concat(subindexquals, + get_actual_clauses(iclause->indexquals)); + else + subindexquals = lappend(subindexquals, rinfo->clause); + if (rinfo->parent_ec) + subindexECs = lappend(subindexECs, rinfo->parent_ec); + } + /* We can add any index predicate conditions, too */ foreach(l, ipath->indexinfo->indpred) { Expr *pred = (Expr *) lfirst(l); @@ -3072,21 +3094,14 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual, * the conditions that got pushed into the bitmapqual. Avoid * generating redundant conditions. */ - if (!predicate_implied_by(list_make1(pred), ipath->indexclauses, - false)) + if (!predicate_implied_by(list_make1(pred), subquals, false)) { - *qual = lappend(*qual, pred); - *indexqual = lappend(*indexqual, pred); + subquals = lappend(subquals, pred); + subindexquals = lappend(subindexquals, pred); } } - subindexECs = NIL; - foreach(l, ipath->indexquals) - { - RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); - - if (rinfo->parent_ec) - subindexECs = lappend(subindexECs, rinfo->parent_ec); - } + *qual = subquals; + *indexqual = subindexquals; *indexECs = subindexECs; } else @@ -4446,138 +4461,67 @@ replace_nestloop_params_mutator(Node *node, PlannerInfo *root) * Adjust indexqual clauses to the form the executor's indexqual * machinery needs. * - * We have four tasks here: - * * Remove RestrictInfo nodes from the input clauses. + * We have three tasks here: + * * Select the actual qual clauses out of the input IndexClause list, + * and remove RestrictInfo nodes from the qual clauses. * * Replace any outer-relation Var or PHV nodes with nestloop Params. * (XXX eventually, that responsibility should go elsewhere?) * * Index keys must be represented by Var nodes with varattno set to the * index's attribute number, not the attribute number in the original rel. - * * If the index key is on the right, commute the clause to put it on the - * left. * - * The result is a modified copy of the path's indexquals list --- the - * original is not changed. Note also that the copy shares no substructure - * with the original; this is needed in case there is a subplan in it (we need - * two separate copies of the subplan tree, or things will go awry). + * *stripped_indexquals_p receives a list of the actual qual clauses. + * + * *fixed_indexquals_p receives a list of the adjusted quals. This is a copy + * that shares no substructure with the original; this is needed in case there + * are subplans in it (we need two separate copies of the subplan tree, or + * things will go awry). */ -static List * -fix_indexqual_references(PlannerInfo *root, IndexPath *index_path) +static void +fix_indexqual_references(PlannerInfo *root, IndexPath *index_path, + List **stripped_indexquals_p, List **fixed_indexquals_p) { IndexOptInfo *index = index_path->indexinfo; + List *stripped_indexquals; List *fixed_indexquals; - ListCell *lcc, - *lci; + ListCell *lc; - fixed_indexquals = NIL; + stripped_indexquals = fixed_indexquals = NIL; - forboth(lcc, index_path->indexquals, lci, index_path->indexqualcols) + foreach(lc, index_path->indexclauses) { - RestrictInfo *rinfo = lfirst_node(RestrictInfo, lcc); - int indexcol = lfirst_int(lci); - Node *clause; + IndexClause *iclause = lfirst_node(IndexClause, lc); + int indexcol = iclause->indexcol; - /* - * Replace any outer-relation variables with nestloop params. - * - * This also makes a copy of the clause, so it's safe to modify it - * in-place below. - */ - clause = replace_nestloop_params(root, (Node *) rinfo->clause); - - if (IsA(clause, OpExpr)) + if (iclause->indexquals == NIL) { - OpExpr *op = (OpExpr *) clause; - - if (list_length(op->args) != 2) - elog(ERROR, "indexqual clause is not binary opclause"); - - /* - * Check to see if the indexkey is on the right; if so, commute - * the clause. The indexkey should be the side that refers to - * (only) the base relation. - */ - if (!bms_equal(rinfo->left_relids, index->rel->relids)) - CommuteOpExpr(op); + /* rinfo->clause is directly usable as an indexqual */ + Node *clause = (Node *) iclause->rinfo->clause; - /* - * Now replace the indexkey expression with an index Var. - */ - linitial(op->args) = fix_indexqual_operand(linitial(op->args), - index, - indexcol); + stripped_indexquals = lappend(stripped_indexquals, clause); + clause = fix_indexqual_clause(root, index, indexcol, + clause, iclause->indexcols); + fixed_indexquals = lappend(fixed_indexquals, clause); } - else if (IsA(clause, RowCompareExpr)) + else { - RowCompareExpr *rc = (RowCompareExpr *) clause; - Expr *newrc; - List *indexcolnos; - bool var_on_left; - ListCell *lca, - *lcai; + /* Process the derived indexquals */ + ListCell *lc2; - /* - * Re-discover which index columns are used in the rowcompare. - */ - newrc = adjust_rowcompare_for_index(rc, - index, - indexcol, - &indexcolnos, - &var_on_left); - - /* - * Trouble if adjust_rowcompare_for_index thought the - * RowCompareExpr didn't match the index as-is; the clause should - * have gone through that routine already. - */ - if (newrc != (Expr *) rc) - elog(ERROR, "inconsistent results from adjust_rowcompare_for_index"); - - /* - * Check to see if the indexkey is on the right; if so, commute - * the clause. - */ - if (!var_on_left) - CommuteRowCompareExpr(rc); - - /* - * Now replace the indexkey expressions with index Vars. - */ - Assert(list_length(rc->largs) == list_length(indexcolnos)); - forboth(lca, rc->largs, lcai, indexcolnos) + foreach(lc2, iclause->indexquals) { - lfirst(lca) = fix_indexqual_operand(lfirst(lca), - index, - lfirst_int(lcai)); - } - } - else if (IsA(clause, ScalarArrayOpExpr)) - { - ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause; - - /* Never need to commute... */ + RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc2); + Node *clause = (Node *) rinfo->clause; - /* Replace the indexkey expression with an index Var. */ - linitial(saop->args) = fix_indexqual_operand(linitial(saop->args), - index, - indexcol); - } - else if (IsA(clause, NullTest)) - { - NullTest *nt = (NullTest *) clause; - - /* Replace the indexkey expression with an index Var. */ - nt->arg = (Expr *) fix_indexqual_operand((Node *) nt->arg, - index, - indexcol); + stripped_indexquals = lappend(stripped_indexquals, clause); + clause = fix_indexqual_clause(root, index, indexcol, + clause, iclause->indexcols); + fixed_indexquals = lappend(fixed_indexquals, clause); + } } - else - elog(ERROR, "unsupported indexqual type: %d", - (int) nodeTag(clause)); - - fixed_indexquals = lappend(fixed_indexquals, clause); } - return fixed_indexquals; + *stripped_indexquals_p = stripped_indexquals; + *fixed_indexquals_p = fixed_indexquals; } /* @@ -4585,11 +4529,8 @@ fix_indexqual_references(PlannerInfo *root, IndexPath *index_path) * Adjust indexorderby clauses to the form the executor's index * machinery needs. * - * This is a simplified version of fix_indexqual_references. The input does - * not have RestrictInfo nodes, and we assume that indxpath.c already - * commuted the clauses to put the index keys on the left. Also, we don't - * bother to support any cases except simple OpExprs, since nothing else - * is allowed for ordering operators. + * This is a simplified version of fix_indexqual_references. The input is + * bare clauses and a separate indexcol list, instead of IndexClauses. */ static List * fix_indexorderby_references(PlannerInfo *root, IndexPath *index_path) @@ -4606,36 +4547,79 @@ fix_indexorderby_references(PlannerInfo *root, IndexPath *index_path) Node *clause = (Node *) lfirst(lcc); int indexcol = lfirst_int(lci); - /* - * Replace any outer-relation variables with nestloop params. - * - * This also makes a copy of the clause, so it's safe to modify it - * in-place below. - */ - clause = replace_nestloop_params(root, clause); + clause = fix_indexqual_clause(root, index, indexcol, clause, NIL); + fixed_indexorderbys = lappend(fixed_indexorderbys, clause); + } - if (IsA(clause, OpExpr)) - { - OpExpr *op = (OpExpr *) clause; + return fixed_indexorderbys; +} - if (list_length(op->args) != 2) - elog(ERROR, "indexorderby clause is not binary opclause"); +/* + * fix_indexqual_clause + * Convert a single indexqual clause to the form needed by the executor. + * + * We replace nestloop params here, and replace the index key variables + * or expressions by index Var nodes. + */ +static Node * +fix_indexqual_clause(PlannerInfo *root, IndexOptInfo *index, int indexcol, + Node *clause, List *indexcolnos) +{ + /* + * Replace any outer-relation variables with nestloop params. + * + * This also makes a copy of the clause, so it's safe to modify it + * in-place below. + */ + clause = replace_nestloop_params(root, clause); - /* - * Now replace the indexkey expression with an index Var. - */ - linitial(op->args) = fix_indexqual_operand(linitial(op->args), - index, - indexcol); + if (IsA(clause, OpExpr)) + { + OpExpr *op = (OpExpr *) clause; + + /* Replace the indexkey expression with an index Var. */ + linitial(op->args) = fix_indexqual_operand(linitial(op->args), + index, + indexcol); + } + else if (IsA(clause, RowCompareExpr)) + { + RowCompareExpr *rc = (RowCompareExpr *) clause; + ListCell *lca, + *lcai; + + /* Replace the indexkey expressions with index Vars. */ + Assert(list_length(rc->largs) == list_length(indexcolnos)); + forboth(lca, rc->largs, lcai, indexcolnos) + { + lfirst(lca) = fix_indexqual_operand(lfirst(lca), + index, + lfirst_int(lcai)); } - else - elog(ERROR, "unsupported indexorderby type: %d", - (int) nodeTag(clause)); + } + else if (IsA(clause, ScalarArrayOpExpr)) + { + ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause; - fixed_indexorderbys = lappend(fixed_indexorderbys, clause); + /* Replace the indexkey expression with an index Var. */ + linitial(saop->args) = fix_indexqual_operand(linitial(saop->args), + index, + indexcol); } + else if (IsA(clause, NullTest)) + { + NullTest *nt = (NullTest *) clause; - return fixed_indexorderbys; + /* Replace the indexkey expression with an index Var. */ + nt->arg = (Expr *) fix_indexqual_operand((Node *) nt->arg, + index, + indexcol); + } + else + elog(ERROR, "unsupported indexqual type: %d", + (int) nodeTag(clause)); + + return clause; } /* |