📄 xfunc.c
字号:
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 it's a Postquel function, its cost is stored in the * * associated plan. */ if (proc->prolang == SQLlanguageId) { LispValue tmpplan; List planlist; if (IsA(node, Oper) ||get_func_planlist((Func) node) == LispNil) { Oid *argOidVect; /* vector of argtypes */ char *pq_src; /* text of PQ function */ int nargs; /* num args to PQ function */ QueryTreeList *queryTree_list; /* dummy variable */ /* * * plan the function, storing it in the Func node for later * * use by the executor. */ pq_src = (char *) textout(&(proc->prosrc)); nargs = proc->pronargs; if (nargs > 0) argOidVect = proc->proargtypes; planlist = (List) pg_parse_and_plan(pq_src, argOidVect, nargs, &parseTree_list, None, FALSE); if (IsA(node, Func)) set_func_planlist((Func) node, planlist); } else { /* plan has been cached inside the Func * node already */ planlist = get_func_planlist((Func) node); } /* * * Return the sum of the costs of the plans (the PQ function * * may have many queries in its body). */ foreach(tmpplan, planlist) cost += get_cost((Plan) lfirst(tmpplan)); return cost; } else { /* it's a C function */ /* * * find the cost of evaluating the function's arguments * and * the width of the operands */ for (tmpclause = args; tmpclause != LispNil; tmpclause = lnext(tmpclause)) { if ((operand = lfirst(tmpclause)) != LispNil) { cost += xfunc_local_expense(operand); width += xfunc_width(operand); } } /* * * when stats become available, add in cost of accessing * secondary * and tertiary storage here. */ return (cost + (Cost) proc->propercall_cpu + (Cost) proc->properbyte_cpu * (Cost) proc->probyte_pct / 100.00 * (Cost) width /* * Pct_of_obj_in_mem DISK_COST * proc->probyte_pct/100.00 * width * Pct_of_obj_on_disk + ARCH_COST * proc->probyte_pct/100.00 * * width Pct_of_obj_on_arch */ ); }}/* ** xfunc_width ** recursively find the width of a expression */intxfunc_width(LispValue clause){ Relation rd; /* Relation Descriptor */ HeapTuple tupl; /* structure to hold a cached tuple */ Form_pg_type type; /* structure to hold a type tuple */ int retval = 0; if (IsA(clause, Const)) { /* base case: width is the width of this constant */ retval = get_constlen((Const) clause); goto exit; } else if (IsA(clause, ArrayRef)) { /* base case: width is width of the refelem within the array */ retval = get_refelemlength((ArrayRef) clause); goto exit; } else if (IsA(clause, Var)) { /* base case: width is width of this attribute */ tupl = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(get_vartype((Var) clause)), 0, 0, 0); if (!HeapTupleIsValid(tupl)) elog(ERROR, "Cache lookup failed for type %u", get_vartype((Var) clause)); type = (Form_pg_type) GETSTRUCT(tupl); if (get_varattno((Var) clause) == 0) { /* clause is a tuple. Get its width */ rd = heap_open(type->typrelid); retval = xfunc_tuple_width(rd); heap_close(rd); } else { /* attribute is a base type */ retval = type->typlen; } goto exit; } else if (IsA(clause, Param)) { if (typeidTypeRelids(get_paramtype((Param) clause))) { /* Param node returns a tuple. Find its width */ rd = heap_open(typeidTypeRelids(get_paramtype((Param) clause))); retval = xfunc_tuple_width(rd); heap_close(rd); } else if (get_param_tlist((Param) clause) != LispNil) { /* Param node projects a complex type */ Assert(length(get_param_tlist((Param) clause)) == 1); /* sanity */ retval = xfunc_width((LispValue) get_expr(lfirst(get_param_tlist((Param) clause)))); } else { /* Param node returns a base type */ retval = typeLen(typeidType(get_paramtype((Param) clause))); } goto exit; } else if (IsA(clause, Iter)) { /* * * An Iter returns a setof things, so return the width of a * single * thing. * Note: THIS MAY NOT WORK RIGHT WHEN AGGS GET * FIXED, * SINCE AGG FUNCTIONS CHEW ON THE WHOLE SETOF THINGS!!!! * * This whole Iter business is bogus, anyway. */ retval = xfunc_width(get_iterexpr((Iter) clause)); goto exit; } else if (fast_is_clause(clause)) { /* * * get function associated with this Oper, and treat this as * a * Func */ tupl = SearchSysCacheTuple(OPROID, ObjectIdGetDatum(get_opno((Oper) get_op(clause))), 0, 0, 0); if (!HeapTupleIsValid(tupl)) elog(ERROR, "Cache lookup failed for procedure %u", get_opno((Oper) get_op(clause))); return (xfunc_func_width ((RegProcedure) (((Form_pg_operator) (GETSTRUCT(tupl)))->oprcode), (LispValue) get_opargs(clause))); } else if (fast_is_funcclause(clause)) { Func func = (Func) get_function(clause); if (get_func_tlist(func) != LispNil) { /* * this function has a projection on it. Get the length of * the projected attribute */ Assert(length(get_func_tlist(func)) == 1); /* sanity */ retval = xfunc_width((LispValue) get_expr(lfirst(get_func_tlist(func)))); goto exit; } else { return (xfunc_func_width((RegProcedure) get_funcid(func), (LispValue) get_funcargs(clause))); } } else { elog(ERROR, "Clause node of undetermined type"); return -1; }exit: if (retval == -1) retval = VARLEN_DEFAULT; return retval;}/* ** xfunc_card_unreferenced: ** find all relations not referenced in clause, and multiply their ** cardinalities. Ignore relation of cardinality 0. ** User may pass in referenced list, if they know it (useful ** for joins). */static Countxfunc_card_unreferenced(Query *queryInfo, LispValue clause, Relids referenced){ Relids unreferenced, allrelids = LispNil; LispValue temp; /* find all relids of base relations referenced in query */ foreach(temp, queryInfo->base_rel_list) { Assert(lnext(get_relids((RelOptInfo) lfirst(temp))) == LispNil); allrelids = lappend(allrelids, lfirst(get_relids((RelOptInfo) lfirst(temp)))); } /* find all relids referenced in query but not in clause */ if (!referenced) referenced = xfunc_find_references(clause); unreferenced = set_difference(allrelids, referenced); return xfunc_card_product(unreferenced);}/* ** xfunc_card_product ** multiple together cardinalities of a list relations. */Countxfunc_card_product(Query *queryInfo, Relids relids){ LispValue cinfonode; LispValue temp; RelOptInfo currel; Cost tuples; Count retval = 0; foreach(temp, relids) { currel = get_rel(lfirst(temp)); tuples = get_tuples(currel); if (tuples) { /* not of cardinality 0 */ /* factor in the selectivity of all zero-cost clauses */ foreach(cinfonode, get_restrictinfo(currel)) { if (!xfunc_expense(queryInfo, get_clause((RestrictInfo) lfirst(cinfonode)))) tuples *= compute_clause_selec(queryInfo, get_clause((RestrictInfo) lfirst(cinfonode)), LispNil); } if (retval == 0) retval = tuples; else retval *= tuples; } } if (retval == 0) retval = 1; /* saves caller from dividing by zero */ return retval;}/* ** xfunc_find_references: ** Traverse a clause and find all relids referenced in the clause. */Listxfunc_find_references(LispValue clause){ List retval = (List) LispNil; LispValue tmpclause; /* Base cases */ if (IsA(clause, Var)) return lispCons(lfirst(get_varid((Var) clause)), LispNil); else if (IsA(clause, Const) ||IsA(clause, Param)) return (List) LispNil; /* recursion */ else if (IsA(clause, Iter)) /* * Too low. Should multiply by the expected number of iterations. * maybe */ return xfunc_find_references(get_iterexpr((Iter) clause)); else if (IsA(clause, ArrayRef)) return xfunc_find_references(get_refexpr((ArrayRef) clause)); else if (fast_is_clause(clause)) { /* string together result of all operands of Oper */ for (tmpclause = (LispValue) get_opargs(clause); tmpclause != LispNil; tmpclause = lnext(tmpclause)) retval = nconc(retval, xfunc_find_references(lfirst(tmpclause))); return retval; } else if (fast_is_funcclause(clause)) { /* string together result of all args of Func */ for (tmpclause = (LispValue) get_funcargs(clause); tmpclause != LispNil; tmpclause = lnext(tmpclause)) retval = nconc(retval, xfunc_find_references(lfirst(tmpclause))); return retval; } else if (fast_not_clause(clause)) return xfunc_find_references(lsecond(clause)); else if (fast_or_clause(clause) || fast_and_clause(clause)) { /* string together result of all operands of OR */ for (tmpclause = lnext(clause); tmpclause != LispNil; tmpclause = lnext(tmpclause)) retval = nconc(retval, xfunc_find_references(lfirst(tmpclause))); return retval; } else { elog(ERROR, "Clause node of undetermined type"); return (List) LispNil; }}/* ** xfunc_primary_join: ** Find the primary join clause: for Hash and Merge Joins, this is the ** min rank Hash or Merge clause, while for Nested Loop it's the ** min rank pathclause */LispValuexfunc_primary_join(JoinPath pathnode){ LispValue joinclauselist = get_pathrestrictinfo(pathnode); RestrictInfo mincinfo; LispValue tmplist; LispValue minclause = LispNil; Cost minrank, tmprank; if (IsA(pathnode, MergePath)) { for (tmplist = get_path_mergeclauses((MergePath) pathnode), minclause = lfirst(tmplist), minrank = xfunc_rank(minclause); tmplist != LispNil; tmplist = lnext(tmplist)) if ((tmprank = xfunc_rank(lfirst(tmplist))) < minrank) { minrank = tmprank; minclause = lfirst(tmplist); } return minclause; } else if (IsA(pathnode, HashPath)) { for (tmplist = get_path_hashclauses((HashPath) pathnode), minclause = lfirst(tmplist), minrank = xfunc_rank(minclause); tmplist != LispNil; tmplist = lnext(tmplist)) if ((tmprank = xfunc_rank(lfirst(tmplist))) < minrank) { minrank = tmprank; minclause = lfirst(tmplist); } return minclause; } /* if we drop through, it's nested loop join */ if (joinclauselist == LispNil) return LispNil; for (tmplist = joinclauselist, mincinfo = (RestrictInfo) lfirst(joinclauselist), minrank = xfunc_rank(get_clause((RestrictInfo) lfirst(tmplist))); tmplist != LispNil; tmplist = lnext(tmplist)) if ((tmprank = xfunc_rank(get_clause((RestrictInfo) lfirst(tmplist)))) < minrank) { minrank = tmprank; mincinfo = (RestrictInfo) lfirst(tmplist); } return (LispValue) get_clause(mincinfo);}/* ** xfunc_get_path_cost ** get the expensive function costs of the path */Costxfunc_get_path_cost(Query *queryInfo, Path pathnode){ Cost cost = 0; LispValue tmplist; Cost selec = 1.0; /* * * first add in the expensive local function costs. * We ensure that * the clauses are sorted by rank, so that we * know (via * selectivities) the number of tuples that will be checked * by each * function. If we're not doing any optimization of expensive * * functions, we don't sort. */ if (XfuncMode != XFUNC_OFF) set_locrestrictinfo(pathnode, lisp_qsort(get_loc_restrictinfo(pathnode), xfunc_cinfo_compare)); for (tmplist = get_loc_restrictinfo(pathnode), selec = 1.0; tmplist != LispNil; tmplist = lnext(tmplist)) { cost += (Cost) (xfunc_local_expense(get_clause((RestrictInfo) lfirst(tmplist))) * (Cost) get_tuples(get_parent(pathnode)) * selec); selec *= compute_clause_selec(queryInfo, get_clause((RestrictInfo) lfirst(tmplist)), LispNil); } /* * * Now add in any node-specific expensive function costs. * Again, * we must ensure that the clauses are sorted by rank. */ if (IsA(pathnode, JoinPath)) { if (XfuncMode != XFUNC_OFF) set_pathrestrictinfo((JoinPath) pathnode, lisp_qsort (get_pathrestrictinfo((JoinPath) pathnode), xfunc_cinfo_compare)); for (tmplist = get_pathrestrictinfo((JoinPath) pathnode), selec = 1.0; tmplist != LispNil; tmplist = lnext(tmplist)) { cost += (Cost) (xfunc_local_expense(get_clause((RestrictInfo) lfirst(tmplist))) * (Cost) get_tuples(get_parent(pathnode)) * selec); selec *= compute_clause_selec(queryInfo, get_clause((RestrictInfo) lfirst(tmplist)), LispNil); } } if (IsA(pathnode, HashPath)) { if (XfuncMode != XFUNC_OFF) set_path_hashclauses ((HashPath) pathnode, lisp_qsort(get_path_hashclauses((HashPath) pathnode), xfunc_clause_compare)); for (tmplist = get_path_hashclauses((HashPath) pathnode), selec = 1.0; 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); } } if (IsA(pathnode, MergePath)) { if (XfuncMode != XFUNC_OFF) set_path_mergeclauses ((MergePath) pathnode, lisp_qsort(get_path_mergeclauses((MergePath) pathnode), xfunc_clause_compare)); for (tmplist = get_path_mergeclauses((MergePath) pathnode), selec = 1.0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -