📄 xfunc.c
字号:
tmplist != LispNil; tmplist = lnext(tmplist)) { cost += (Cost) (xfunc_local_expense(lfirst(tmplist)) * (Cost) get_tuples(get_parent(pathnode)) * selec); selec *= compute_clause_selec(queryInfo, lfirst(tmplist), LispNil); } } Assert(cost >= 0); return cost;}/* ** Recalculate the cost of a path node. This includes the basic cost of the ** node, as well as the cost of its expensive functions. ** We need to do this to the parent after pulling a clause from a child into a ** parent. Thus we should only be calling this function on JoinPaths. */Costxfunc_total_path_cost(JoinPath pathnode){ Cost cost = xfunc_get_path_cost((Path) pathnode); Assert(IsA(pathnode, JoinPath)); if (IsA(pathnode, MergePath)) { MergePath mrgnode = (MergePath) pathnode; cost += cost_mergejoin(get_path_cost((Path) get_outerjoinpath(mrgnode)), get_path_cost((Path) get_innerjoinpath(mrgnode)), get_outersortkeys(mrgnode), get_innersortkeys(mrgnode), get_tuples(get_parent((Path) get_outerjoinpath (mrgnode))), get_tuples(get_parent((Path) get_innerjoinpath (mrgnode))), get_width(get_parent((Path) get_outerjoinpath (mrgnode))), get_width(get_parent((Path) get_innerjoinpath (mrgnode)))); Assert(cost >= 0); return cost; } else if (IsA(pathnode, HashPath)) { HashPath hashnode = (HashPath) pathnode; cost += cost_hashjoin(get_path_cost((Path) get_outerjoinpath(hashnode)), get_path_cost((Path) get_innerjoinpath(hashnode)), get_outerhashkeys(hashnode), get_innerhashkeys(hashnode), get_tuples(get_parent((Path) get_outerjoinpath (hashnode))), get_tuples(get_parent((Path) get_innerjoinpath (hashnode))), get_width(get_parent((Path) get_outerjoinpath (hashnode))), get_width(get_parent((Path) get_innerjoinpath (hashnode)))); Assert(cost >= 0); return cost; } else/* Nested Loop Join */ { cost += cost_nestloop(get_path_cost((Path) get_outerjoinpath(pathnode)), get_path_cost((Path) get_innerjoinpath(pathnode)), get_tuples(get_parent((Path) get_outerjoinpath (pathnode))), get_tuples(get_parent((Path) get_innerjoinpath (pathnode))), get_pages(get_parent((Path) get_outerjoinpath (pathnode))), IsA(get_innerjoinpath(pathnode), IndexPath)); Assert(cost >= 0); return cost; }}/* ** xfunc_expense_per_tuple ** return the expense of the join *per-tuple* of the input relation. ** The cost model here is that a join costs ** k*card(outer)*card(inner) + l*card(outer) + m*card(inner) + n ** ** We treat the l and m terms by considering them to be like restrictions ** constrained to be right under the join. Thus the cost per inner and ** cost per outer of the join is different, reflecting these virtual nodes. ** ** The cost per tuple of outer is k + l/referenced(inner). Cost per tuple ** of inner is k + m/referenced(outer). ** The constants k, l, m and n depend on the join method. Measures here are ** based on the costs in costsize.c, with fudging for HashJoin and Sorts to ** make it fit our model (the 'q' in HashJoin results in a ** card(outer)/card(inner) term, and sorting results in a log term. */Costxfunc_expense_per_tuple(JoinPath joinnode, int whichchild){ RelOptInfo outerrel = get_parent((Path) get_outerjoinpath(joinnode)); RelOptInfo innerrel = get_parent((Path) get_innerjoinpath(joinnode)); Count outerwidth = get_width(outerrel); Count outers_per_page = ceil(BLCKSZ / (outerwidth + MinTupleSize)); if (IsA(joinnode, HashPath)) { if (whichchild == INNER) return (1 + _CPU_PAGE_WEIGHT_) * outers_per_page / NBuffers; else return (((1 + _CPU_PAGE_WEIGHT_) * outers_per_page / NBuffers) + _CPU_PAGE_WEIGHT_ / xfunc_card_product(get_relids(innerrel))); } else if (IsA(joinnode, MergePath)) { /* assumes sort exists, and costs one (I/O + CPU) per tuple */ if (whichchild == INNER) return ((2 * _CPU_PAGE_WEIGHT_ + 1) / xfunc_card_product(get_relids(outerrel))); else return ((2 * _CPU_PAGE_WEIGHT_ + 1) / xfunc_card_product(get_relids(innerrel))); } else/* nestloop */ { Assert(IsA(joinnode, JoinPath)); return _CPU_PAGE_WEIGHT_; }}/* ** xfunc_fixvars ** After pulling up a clause, we must walk its expression tree, fixing Var ** nodes to point to the correct varno (either INNER or OUTER, depending ** on which child the clause was pulled from), and the right varattno in the ** target list of the child's former relation. If the target list of the ** child RelOptInfo does not contain the attribute we need, we add it. */voidxfunc_fixvars(LispValue clause, /* clause being pulled up */ RelOptInfo rel, /* rel it's being pulled from */ int varno) /* whether rel is INNER or OUTER of join */{ LispValue tmpclause; /* temporary variable */ TargetEntry *tle; /* tlist member corresponding to var */ if (IsA(clause, Const) ||IsA(clause, Param)) return; else if (IsA(clause, Var)) { /* here's the meat */ tle = tlistentry_member((Var) clause, get_targetlist(rel)); if (tle == LispNil) { /* * * The attribute we need is not in the target list, * so we * have to add it. * * */ add_var_to_tlist(rel, (Var) clause); tle = tlistentry_member((Var) clause, get_targetlist(rel)); } set_varno(((Var) clause), varno); set_varattno(((Var) clause), get_resno(get_resdom(get_entry(tle)))); } else if (IsA(clause, Iter)) xfunc_fixvars(get_iterexpr((Iter) clause), rel, varno); else if (fast_is_clause(clause)) { xfunc_fixvars(lfirst(lnext(clause)), rel, varno); xfunc_fixvars(lfirst(lnext(lnext(clause))), rel, varno); } else if (fast_is_funcclause(clause)) for (tmpclause = lnext(clause); tmpclause != LispNil; tmpclause = lnext(tmpclause)) xfunc_fixvars(lfirst(tmpclause), rel, varno); else if (fast_not_clause(clause)) xfunc_fixvars(lsecond(clause), rel, varno); else if (fast_or_clause(clause) || fast_and_clause(clause)) for (tmpclause = lnext(clause); tmpclause != LispNil; tmpclause = lnext(tmpclause)) xfunc_fixvars(lfirst(tmpclause), rel, varno); else elog(ERROR, "Clause node of undetermined type");}/* ** Comparison function for lisp_qsort() on a list of RestrictInfo's. ** arg1 and arg2 should really be of type (RestrictInfo *). */intxfunc_cinfo_compare(void *arg1, void *arg2){ RestrictInfo info1 = *(RestrictInfo *) arg1; RestrictInfo info2 = *(RestrictInfo *) arg2; LispValue clause1 = (LispValue) get_clause(info1), clause2 = (LispValue) get_clause(info2); return xfunc_clause_compare((void *) &clause1, (void *) &clause2);}/* ** xfunc_clause_compare: comparison function for lisp_qsort() that compares two ** clauses based on expense/(1 - selectivity) ** arg1 and arg2 are really pointers to clauses. */intxfunc_clause_compare(void *arg1, void *arg2){ LispValue clause1 = *(LispValue *) arg1; LispValue clause2 = *(LispValue *) arg2; Cost rank1, /* total xfunc rank of clause1 */ rank2; /* total xfunc rank of clause2 */ rank1 = xfunc_rank(clause1); rank2 = xfunc_rank(clause2); if (rank1 < rank2) return -1; else if (rank1 == rank2) return 0; else return 1;}/* ** xfunc_disjunct_sort ** given a list of clauses, for each clause sort the disjuncts by cost ** (this assumes the predicates have been converted to Conjunctive NF) ** Modifies the clause list! */voidxfunc_disjunct_sort(LispValue clause_list){ LispValue temp; foreach(temp, clause_list) if (or_clause(lfirst(temp))) lnext(lfirst(temp)) = lisp_qsort(lnext(lfirst(temp)), xfunc_disjunct_compare);}/* ** xfunc_disjunct_compare: comparison function for qsort() that compares two ** disjuncts based on cost/selec. ** arg1 and arg2 are really pointers to disjuncts */intxfunc_disjunct_compare(Query *queryInfo, void *arg1, void *arg2){ LispValue disjunct1 = *(LispValue *) arg1; LispValue disjunct2 = *(LispValue *) arg2; Cost cost1, /* total cost of disjunct1 */ cost2, /* total cost of disjunct2 */ selec1, selec2; Cost rank1, rank2; cost1 = xfunc_expense(queryInfo, disjunct1); cost2 = xfunc_expense(queryInfo, disjunct2); selec1 = compute_clause_selec(queryInfo, disjunct1, LispNil); selec2 = compute_clause_selec(queryInfo, disjunct2, LispNil); if (selec1 == 0) rank1 = MAXFLOAT; else if (cost1 == 0) rank1 = 0; else rank1 = cost1 / selec1; if (selec2 == 0) rank2 = MAXFLOAT; else if (cost2 == 0) rank2 = 0; else rank2 = cost2 / selec2; if (rank1 < rank2) return -1; else if (rank1 == rank2) return 0; else return 1;}/* ------------------------ UTILITY FUNCTIONS ------------------------------- *//* ** xfunc_func_width ** Given a function OID and operands, find the width of the return value. */intxfunc_func_width(RegProcedure funcid, LispValue args){ Relation rd; /* Relation Descriptor */ HeapTuple tupl; /* structure to hold a cached tuple */ Form_pg_proc proc; /* structure to hold the pg_proc tuple */ Form_pg_type type; /* structure to hold the pg_type tuple */ LispValue tmpclause; int retval; /* lookup function and find its return type */ Assert(RegProcedureIsValid(funcid)); tupl = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid), 0, 0, 0); if (!HeapTupleIsValid(tupl)) elog(ERROR, "Cache lookup failed for procedure %u", funcid); proc = (Form_pg_proc) GETSTRUCT(tupl); /* if function returns a tuple, get the width of that */ if (typeidTypeRelids(proc->prorettype)) { rd = heap_open(typeidTypeRelids(proc->prorettype)); retval = xfunc_tuple_width(rd); heap_close(rd); goto exit; } else/* function returns a base type */ { tupl = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(proc->prorettype), 0, 0, 0); if (!HeapTupleIsValid(tupl)) elog(ERROR, "Cache lookup failed for type %u", proc->prorettype); type = (Form_pg_type) GETSTRUCT(tupl); /* if the type length is known, return that */ if (type->typlen != -1) { retval = type->typlen; goto exit; } else/* estimate the return size */ { /* find width of the function's arguments */ for (tmpclause = args; tmpclause != LispNil; tmpclause = lnext(tmpclause)) retval += xfunc_width(lfirst(tmpclause)); /* multiply by outin_ratio */ retval = (int) (proc->prooutin_ratio / 100.0 * retval); goto exit; } }exit: return retval;}/* ** xfunc_tuple_width ** Return the sum of the lengths of all the attributes of a given relation */intxfunc_tuple_width(Relation rd){ int i; int retval = 0; TupleDesc tdesc = RelationGetDescr(rd); for (i = 0; i < tdesc->natts; i++) { if (tdesc->attrs[i]->attlen != -1) retval += tdesc->attrs[i]->attlen; else retval += VARLEN_DEFAULT; } return retval;}/* ** xfunc_num_join_clauses ** Find the number of join clauses associated with this join path */intxfunc_num_join_clauses(JoinPath path){ int num = length(get_pathrestrictinfo(path)); if (IsA(path, MergePath)) return num + length(get_path_mergeclauses((MergePath) path)); else if (IsA(path, HashPath)) return num + length(get_path_hashclauses((HashPath) path)); else return num;}/* ** xfunc_LispRemove ** Just like LispRemove, but it whines if the item to be removed ain't there */LispValuexfunc_LispRemove(LispValue foo, List bar){ LispValue temp = LispNil; LispValue result = LispNil; int sanity = false; for (temp = bar; !null(temp); temp = lnext(temp)) if (!equal((Node) (foo), (Node) (lfirst(temp)))) result = lappend(result, lfirst(temp)); else sanity = true; /* found a matching item to remove! */ if (!sanity) elog(ERROR, "xfunc_LispRemove: didn't find a match!"); return result;}#define Node_Copy(a, b, c, d) \do { \ if (NodeCopy((Node)((a)->d), (Node*)&((b)->d), c) != true) \ { \ return false; \ } \} while(0)/* ** xfunc_copyrel ** Just like _copyRel, but doesn't copy the paths */boolxfunc_copyrel(RelOptInfo from, RelOptInfo *to){ RelOptInfo newnode; Pointer (*alloc) () = palloc; /* COPY_CHECKARGS() */ if (to == NULL) return false; /* COPY_CHECKNULL() */ if (from == NULL) { (*to) = NULL; return true; } /* COPY_NEW(c) */ newnode = (RelOptInfo) (*alloc) (classSize(RelOptInfo)); if (newnode == NULL) return false; /* ---------------- * copy node superclass fields * ---------------- */ CopyNodeFields((Node) from, (Node) newnode, alloc); /* ---------------- * copy remainder of node * ---------------- */ Node_Copy(from, newnode, alloc, relids); newnode->indexed = from->indexed; newnode->pages = from->pages; newnode->tuples = from->tuples; newnode->size = from->size; newnode->width = from->width; Node_Copy(from, newnode, alloc, targetlist); /* * No!!!! Node_Copy(from, newnode, alloc, pathlist); * Node_Copy(from, newnode, alloc, unorderedpath); Node_Copy(from, * newnode, alloc, cheapestpath); */#if 0 /* can't use Node_copy now. 2/95 -ay */ Node_Copy(from, newnode, alloc, classlist); Node_Copy(from, newnode, alloc, indexkeys); Node_Copy(from, newnode, alloc, ordering);#endif Node_Copy(from, newnode, alloc, restrictinfo); Node_Copy(from, newnode, alloc, joininfo); Node_Copy(from, newnode, alloc, innerjoin); (*to) = newnode; return true;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -