allpaths.c
来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 1,160 行 · 第 1/3 页
C
1,160 行
foreach(l, tlist) { TargetEntry *tle = (TargetEntry *) lfirst(l); if (tle->resjunk) continue; /* ignore resjunk columns */ if (colType == NULL) elog(ERROR, "wrong number of tlist entries"); if (exprType((Node *) tle->expr) != lfirst_oid(colType)) differentTypes[tle->resno] = true; colType = lnext(colType); } if (colType != NULL) 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 the whole-row output of the subquery * (since there is no easy way to name that within the subquery itself). * * 3. 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(). * * 4. 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. * * 5. 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; ListCell *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); /* Check point 2 */ if (var->varattno == 0) { safe = false; break; } /* * 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 3 */ 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->resjunk); /* If subquery uses DISTINCT or DISTINCT ON, check point 4 */ if (subquery->distinctClause != NIL && !targetIsInSortList(tle, subquery->distinctClause)) { /* non-DISTINCT column, so fail */ safe = false; break; } /* Refuse functions returning sets (point 5) */ if (expression_returns_set((Node *) tle->expr)) { safe = false; break; } } list_free(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, RangeTblEntry *rte, Index rti, Node *qual){ if (subquery->setOperations != NULL) { /* Recurse to push it separately to each component query */ recurse_push_qual(subquery->setOperations, subquery, rte, 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, rte, subquery->targetList, CMD_SELECT, 0); /* * Now attach the qual to the proper place: normally WHERE, but if the * subquery uses grouping or aggregation, put it in HAVING (since the * qual really refers to the group-result rows). */ if (subquery->hasAggs || subquery->groupClause || subquery->havingQual) subquery->havingQual = make_and_qual(subquery->havingQual, qual); else subquery->jointree->quals = make_and_qual(subquery->jointree->quals, 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, RangeTblEntry *rte, Index rti, Node *qual){ if (IsA(setOp, RangeTblRef)) { RangeTblRef *rtr = (RangeTblRef *) setOp; RangeTblEntry *subrte = rt_fetch(rtr->rtindex, topquery->rtable); Query *subquery = subrte->subquery; Assert(subquery != NULL); subquery_push_qual(subquery, rte, rti, qual); } else if (IsA(setOp, SetOperationStmt)) { SetOperationStmt *op = (SetOperationStmt *) setOp; recurse_push_qual(op->larg, topquery, rte, rti, qual); recurse_push_qual(op->rarg, topquery, rte, 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(PlannerInfo *root, List *clauses){ ListCell *l; foreach(l, clauses) { RestrictInfo *c = lfirst(l); print_expr((Node *) c->clause, root->parse->rtable); if (lnext(l)) printf(", "); }}static voidprint_path(PlannerInfo *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_BitmapHeapPath: ptype = "BitmapHeapScan"; break; case T_BitmapAndPath: ptype = "BitmapAndPath"; break; case T_BitmapOrPath: ptype = "BitmapOrPath"; 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->parse->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(PlannerInfo *root, RelOptInfo *rel){ ListCell *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"); } if (rel->joininfo) { printf("\tjoininfo: "); print_restrictclauses(root, rel->joininfo); 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 + -
显示快捷键?