allpaths.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,027 行 · 第 1/2 页
C
1,027 行
* pair of lower-level relations. */ joinitems[lev] = make_rels_by_joins(root, lev, joinitems); /* * Do cleanup work on each just-processed rel. */ foreach(x, joinitems[lev]) { rel = (RelOptInfo *) lfirst(x);#ifdef NOT_USED /* * * for each expensive predicate in each path in each * distinct rel, * consider doing pullup -- JMH */ if (XfuncMode != XFUNC_NOPULL && XfuncMode != XFUNC_OFF) xfunc_trypullup(rel);#endif /* Find and save the cheapest paths for this rel */ set_cheapest(rel);#ifdef OPTIMIZER_DEBUG debug_print_rel(root, rel);#endif } } /* * We should have a single rel at the final level. */ if (joinitems[levels_needed] == NIL) elog(ERROR, "failed to build any %d-way joins", levels_needed); Assert(length(joinitems[levels_needed]) == 1); rel = (RelOptInfo *) lfirst(joinitems[levels_needed]); return rel;}/***************************************************************************** * PUSHING QUALS DOWN INTO SUBQUERIES *****************************************************************************//* * subquery_is_pushdown_safe - is a subquery safe for pushing down quals? * * subquery is the particular component query being checked. topquery * is the top component of a set-operations tree (the same Query if no * set-op is involved). * * Conditions checked here: * * 1. If the subquery has a LIMIT clause, we must not push down any quals, * since that could change the set of rows returned. * * 2. If the subquery contains EXCEPT or EXCEPT ALL set ops we cannot push * quals into it, because that would change the results. * * 3. For subqueries using UNION/UNION ALL/INTERSECT/INTERSECT ALL, we can * push quals into each component query, but the quals can only reference * subquery columns that suffer no type coercions in the set operation. * Otherwise there are possible semantic gotchas. So, we check the * component queries to see if any of them have different output types; * differentTypes[k] is set true if column k has different type in any * component. */static boolsubquery_is_pushdown_safe(Query *subquery, Query *topquery, bool *differentTypes){ SetOperationStmt *topop; /* Check point 1 */ if (subquery->limitOffset != NULL || subquery->limitCount != NULL) return false; /* Are we at top level, or looking at a setop component? */ if (subquery == topquery) { /* Top level, so check any component queries */ if (subquery->setOperations != NULL) if (!recurse_pushdown_safe(subquery->setOperations, topquery, differentTypes)) return false; } else { /* Setop component must not have more components (too weird) */ if (subquery->setOperations != NULL) return false; /* Check whether setop component output types match top level */ topop = (SetOperationStmt *) topquery->setOperations; Assert(topop && IsA(topop, SetOperationStmt)); compare_tlist_datatypes(subquery->targetList, topop->colTypes, differentTypes); } return true;}/* * Helper routine to recurse through setOperations tree */static boolrecurse_pushdown_safe(Node *setOp, Query *topquery, bool *differentTypes){ if (IsA(setOp, RangeTblRef)) { RangeTblRef *rtr = (RangeTblRef *) setOp; RangeTblEntry *rte = rt_fetch(rtr->rtindex, topquery->rtable); Query *subquery = rte->subquery; Assert(subquery != NULL); return subquery_is_pushdown_safe(subquery, topquery, differentTypes); } else if (IsA(setOp, SetOperationStmt)) { SetOperationStmt *op = (SetOperationStmt *) setOp; /* EXCEPT is no good */ if (op->op == SETOP_EXCEPT) return false; /* Else recurse */ if (!recurse_pushdown_safe(op->larg, topquery, differentTypes)) return false; if (!recurse_pushdown_safe(op->rarg, topquery, differentTypes)) return false; } else { elog(ERROR, "unrecognized node type: %d", (int) nodeTag(setOp)); } return true;}/* * Compare tlist's datatypes against the list of set-operation result types. * For any items that are different, mark the appropriate element of * differentTypes[] to show that this column will have type conversions. */static voidcompare_tlist_datatypes(List *tlist, List *colTypes, bool *differentTypes){ List *i; foreach(i, tlist) { TargetEntry *tle = (TargetEntry *) lfirst(i); if (tle->resdom->resjunk) continue; /* ignore resjunk columns */ if (colTypes == NIL) elog(ERROR, "wrong number of tlist entries"); if (tle->resdom->restype != lfirsto(colTypes)) differentTypes[tle->resdom->resno] = true; colTypes = lnext(colTypes); } if (colTypes != NIL) elog(ERROR, "wrong number of tlist entries");}/* * qual_is_pushdown_safe - is a particular qual safe to push down? * * qual is a restriction clause applying to the given subquery (whose RTE * has index rti in the parent query). * * Conditions checked here: * * 1. The qual must not contain any subselects (mainly because I'm not sure * it will work correctly: sublinks will already have been transformed into * subplans in the qual, but not in the subquery). * * 2. The qual must not refer to any subquery output columns that were * found to have inconsistent types across a set operation tree by * subquery_is_pushdown_safe(). * * 3. If the subquery uses DISTINCT ON, we must not push down any quals that * refer to non-DISTINCT output columns, because that could change the set * of rows returned. This condition is vacuous for DISTINCT, because then * there are no non-DISTINCT output columns, but unfortunately it's fairly * expensive to tell the difference between DISTINCT and DISTINCT ON in the * parsetree representation. It's cheaper to just make sure all the Vars * in the qual refer to DISTINCT columns. * * 4. We must not push down any quals that refer to subselect outputs that * return sets, else we'd introduce functions-returning-sets into the * subquery's WHERE/HAVING quals. */static boolqual_is_pushdown_safe(Query *subquery, Index rti, Node *qual, bool *differentTypes){ bool safe = true; List *vars; List *vl; Bitmapset *tested = NULL; /* Refuse subselects (point 1) */ if (contain_subplans(qual)) return false; /* * Examine all Vars used in clause; since it's a restriction clause, * all such Vars must refer to subselect output columns. */ vars = pull_var_clause(qual, false); foreach(vl, vars) { Var *var = (Var *) lfirst(vl); TargetEntry *tle; Assert(var->varno == rti); /* * We use a bitmapset to avoid testing the same attno more than * once. (NB: this only works because subquery outputs can't have * negative attnos.) */ if (bms_is_member(var->varattno, tested)) continue; tested = bms_add_member(tested, var->varattno); /* Check point 2 */ if (differentTypes[var->varattno]) { safe = false; break; } /* Must find the tlist element referenced by the Var */ tle = get_tle_by_resno(subquery->targetList, var->varattno); Assert(tle != NULL); Assert(!tle->resdom->resjunk); /* If subquery uses DISTINCT or DISTINCT ON, check point 3 */ if (subquery->distinctClause != NIL && !targetIsInSortList(tle, subquery->distinctClause)) { /* non-DISTINCT column, so fail */ safe = false; break; } /* Refuse functions returning sets (point 4) */ if (expression_returns_set((Node *) tle->expr)) { safe = false; break; } } freeList(vars); bms_free(tested); return safe;}/* * subquery_push_qual - push down a qual that we have determined is safe */static voidsubquery_push_qual(Query *subquery, Index rti, Node *qual){ if (subquery->setOperations != NULL) { /* Recurse to push it separately to each component query */ recurse_push_qual(subquery->setOperations, subquery, rti, qual); } else { /* * We need to replace Vars in the qual (which must refer to * outputs of the subquery) with copies of the subquery's * targetlist expressions. Note that at this point, any uplevel * Vars in the qual should have been replaced with Params, so they * need no work. * * This step also ensures that when we are pushing into a setop tree, * each component query gets its own copy of the qual. */ qual = ResolveNew(qual, rti, 0, subquery->targetList, CMD_SELECT, 0); subquery->havingQual = make_and_qual(subquery->havingQual, qual); /* * We need not change the subquery's hasAggs or hasSublinks flags, * since we can't be pushing down any aggregates that weren't * there before, and we don't push down subselects at all. */ }}/* * Helper routine to recurse through setOperations tree */static voidrecurse_push_qual(Node *setOp, Query *topquery, Index rti, Node *qual){ if (IsA(setOp, RangeTblRef)) { RangeTblRef *rtr = (RangeTblRef *) setOp; RangeTblEntry *rte = rt_fetch(rtr->rtindex, topquery->rtable); Query *subquery = rte->subquery; Assert(subquery != NULL); subquery_push_qual(subquery, rti, qual); } else if (IsA(setOp, SetOperationStmt)) { SetOperationStmt *op = (SetOperationStmt *) setOp; recurse_push_qual(op->larg, topquery, rti, qual); recurse_push_qual(op->rarg, topquery, rti, qual); } else { elog(ERROR, "unrecognized node type: %d", (int) nodeTag(setOp)); }}/***************************************************************************** * DEBUG SUPPORT *****************************************************************************/#ifdef OPTIMIZER_DEBUGstatic voidprint_relids(Relids relids){ Relids tmprelids; int x; bool first = true; tmprelids = bms_copy(relids); while ((x = bms_first_member(tmprelids)) >= 0) { if (!first) printf(" "); printf("%d", x); first = false; } bms_free(tmprelids);}static voidprint_restrictclauses(Query *root, List *clauses){ List *l; foreach(l, clauses) { RestrictInfo *c = lfirst(l); print_expr((Node *) c->clause, root->rtable); if (lnext(l)) printf(", "); }}static voidprint_path(Query *root, Path *path, int indent){ const char *ptype; bool join = false; Path *subpath = NULL; int i; switch (nodeTag(path)) { case T_Path: ptype = "SeqScan"; break; case T_IndexPath: ptype = "IdxScan"; break; case T_TidPath: ptype = "TidScan"; break; case T_AppendPath: ptype = "Append"; break; case T_ResultPath: ptype = "Result"; subpath = ((ResultPath *) path)->subpath; break; case T_MaterialPath: ptype = "Material"; subpath = ((MaterialPath *) path)->subpath; break; case T_UniquePath: ptype = "Unique"; subpath = ((UniquePath *) path)->subpath; break; case T_NestPath: ptype = "NestLoop"; join = true; break; case T_MergePath: ptype = "MergeJoin"; join = true; break; case T_HashPath: ptype = "HashJoin"; join = true; break; default: ptype = "???Path"; break; } for (i = 0; i < indent; i++) printf("\t"); printf("%s", ptype); if (path->parent) { printf("("); print_relids(path->parent->relids); printf(") rows=%.0f", path->parent->rows); } printf(" cost=%.2f..%.2f\n", path->startup_cost, path->total_cost); if (path->pathkeys) { for (i = 0; i < indent; i++) printf("\t"); printf(" pathkeys: "); print_pathkeys(path->pathkeys, root->rtable); } if (join) { JoinPath *jp = (JoinPath *) path; for (i = 0; i < indent; i++) printf("\t"); printf(" clauses: "); print_restrictclauses(root, jp->joinrestrictinfo); printf("\n"); if (IsA(path, MergePath)) { MergePath *mp = (MergePath *) path; if (mp->outersortkeys || mp->innersortkeys) { for (i = 0; i < indent; i++) printf("\t"); printf(" sortouter=%d sortinner=%d\n", ((mp->outersortkeys) ? 1 : 0), ((mp->innersortkeys) ? 1 : 0)); } } print_path(root, jp->outerjoinpath, indent + 1); print_path(root, jp->innerjoinpath, indent + 1); } if (subpath) print_path(root, subpath, indent + 1);}voiddebug_print_rel(Query *root, RelOptInfo *rel){ List *l; printf("RELOPTINFO ("); print_relids(rel->relids); printf("): rows=%.0f width=%d\n", rel->rows, rel->width); if (rel->baserestrictinfo) { printf("\tbaserestrictinfo: "); print_restrictclauses(root, rel->baserestrictinfo); printf("\n"); } foreach(l, rel->joininfo) { JoinInfo *j = (JoinInfo *) lfirst(l); printf("\tjoininfo ("); print_relids(j->unjoined_relids); printf("): "); print_restrictclauses(root, j->jinfo_restrictinfo); printf("\n"); } printf("\tpath list:\n"); foreach(l, rel->pathlist) print_path(root, lfirst(l), 1); printf("\n\tcheapest startup path:\n"); print_path(root, rel->cheapest_startup_path, 1); printf("\n\tcheapest total path:\n"); print_path(root, rel->cheapest_total_path, 1); printf("\n"); fflush(stdout);}#endif /* OPTIMIZER_DEBUG */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?