selfuncs.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,362 行 · 第 1/5 页
C
2,362 行
/* * Use freq_null directly. */ selec = freq_null; break; case IS_NOT_NULL: /* * Select not unknown (not null) values. Calculate from * freq_null. */ selec = 1.0 - freq_null; break; default: elog(ERROR, "unrecognized nulltesttype: %d", (int) nulltesttype); return (Selectivity) 0; /* keep compiler quiet */ } } else { /* * No ANALYZE stats available, so make a guess */ switch (nulltesttype) { case IS_NULL: selec = DEFAULT_UNK_SEL; break; case IS_NOT_NULL: selec = DEFAULT_NOT_UNK_SEL; break; default: elog(ERROR, "unrecognized nulltesttype: %d", (int) nulltesttype); return (Selectivity) 0; /* keep compiler quiet */ } } ReleaseVariableStats(vardata); /* result should be in range, but make sure... */ CLAMP_PROBABILITY(selec); return (Selectivity) selec;}/* * strip_array_coercion - strip binary-compatible relabeling from an array expr * * For array values, the parser normally generates ArrayCoerceExpr conversions, * but it seems possible that RelabelType might show up. Also, the planner * is not currently tense about collapsing stacked ArrayCoerceExpr nodes, * so we need to be ready to deal with more than one level. */static Node *strip_array_coercion(Node *node){ for (;;) { if (node && IsA(node, ArrayCoerceExpr) && ((ArrayCoerceExpr *) node)->elemfuncid == InvalidOid) { node = (Node *) ((ArrayCoerceExpr *) node)->arg; } else if (node && IsA(node, RelabelType)) { /* We don't really expect this case, but may as well cope */ node = (Node *) ((RelabelType *) node)->arg; } else break; } return node;}/* * scalararraysel - Selectivity of ScalarArrayOpExpr Node. */Selectivityscalararraysel(PlannerInfo *root, ScalarArrayOpExpr *clause, bool is_join_clause, int varRelid, JoinType jointype){ Oid operator = clause->opno; bool useOr = clause->useOr; Node *leftop; Node *rightop; Oid nominal_element_type; RegProcedure oprsel; FmgrInfo oprselproc; Datum selarg4; Selectivity s1; /* * First, look up the underlying operator's selectivity estimator. Punt if * it hasn't got one. */ if (is_join_clause) { oprsel = get_oprjoin(operator); selarg4 = Int16GetDatum(jointype); } else { oprsel = get_oprrest(operator); selarg4 = Int32GetDatum(varRelid); } if (!oprsel) return (Selectivity) 0.5; fmgr_info(oprsel, &oprselproc); /* deconstruct the expression */ Assert(list_length(clause->args) == 2); leftop = (Node *) linitial(clause->args); rightop = (Node *) lsecond(clause->args); /* get nominal (after relabeling) element type of rightop */ nominal_element_type = get_element_type(exprType(rightop)); if (!OidIsValid(nominal_element_type)) return (Selectivity) 0.5; /* probably shouldn't happen */ /* look through any binary-compatible relabeling of rightop */ rightop = strip_array_coercion(rightop); /* * We consider three cases: * * 1. rightop is an Array constant: deconstruct the array, apply the * operator's selectivity function for each array element, and merge the * results in the same way that clausesel.c does for AND/OR combinations. * * 2. rightop is an ARRAY[] construct: apply the operator's selectivity * function for each element of the ARRAY[] construct, and merge. * * 3. otherwise, make a guess ... */ if (rightop && IsA(rightop, Const)) { Datum arraydatum = ((Const *) rightop)->constvalue; bool arrayisnull = ((Const *) rightop)->constisnull; ArrayType *arrayval; int16 elmlen; bool elmbyval; char elmalign; int num_elems; Datum *elem_values; bool *elem_nulls; int i; if (arrayisnull) /* qual can't succeed if null array */ return (Selectivity) 0.0; arrayval = DatumGetArrayTypeP(arraydatum); get_typlenbyvalalign(ARR_ELEMTYPE(arrayval), &elmlen, &elmbyval, &elmalign); deconstruct_array(arrayval, ARR_ELEMTYPE(arrayval), elmlen, elmbyval, elmalign, &elem_values, &elem_nulls, &num_elems); s1 = useOr ? 0.0 : 1.0; for (i = 0; i < num_elems; i++) { List *args; Selectivity s2; args = list_make2(leftop, makeConst(nominal_element_type, -1, elmlen, elem_values[i], elem_nulls[i], elmbyval)); s2 = DatumGetFloat8(FunctionCall4(&oprselproc, PointerGetDatum(root), ObjectIdGetDatum(operator), PointerGetDatum(args), selarg4)); if (useOr) s1 = s1 + s2 - s1 * s2; else s1 = s1 * s2; } } else if (rightop && IsA(rightop, ArrayExpr) && !((ArrayExpr *) rightop)->multidims) { ArrayExpr *arrayexpr = (ArrayExpr *) rightop; int16 elmlen; bool elmbyval; ListCell *l; get_typlenbyval(arrayexpr->element_typeid, &elmlen, &elmbyval); s1 = useOr ? 0.0 : 1.0; foreach(l, arrayexpr->elements) { Node *elem = (Node *) lfirst(l); List *args; Selectivity s2; /* * Theoretically, if elem isn't of nominal_element_type we should * insert a RelabelType, but it seems unlikely that any operator * estimation function would really care ... */ args = list_make2(leftop, elem); s2 = DatumGetFloat8(FunctionCall4(&oprselproc, PointerGetDatum(root), ObjectIdGetDatum(operator), PointerGetDatum(args), selarg4)); if (useOr) s1 = s1 + s2 - s1 * s2; else s1 = s1 * s2; } } else { CaseTestExpr *dummyexpr; List *args; Selectivity s2; int i; /* * We need a dummy rightop to pass to the operator selectivity * routine. It can be pretty much anything that doesn't look like a * constant; CaseTestExpr is a convenient choice. */ dummyexpr = makeNode(CaseTestExpr); dummyexpr->typeId = nominal_element_type; dummyexpr->typeMod = -1; args = list_make2(leftop, dummyexpr); s2 = DatumGetFloat8(FunctionCall4(&oprselproc, PointerGetDatum(root), ObjectIdGetDatum(operator), PointerGetDatum(args), selarg4)); s1 = useOr ? 0.0 : 1.0; /* * Arbitrarily assume 10 elements in the eventual array value (see * also estimate_array_length) */ for (i = 0; i < 10; i++) { if (useOr) s1 = s1 + s2 - s1 * s2; else s1 = s1 * s2; } } /* result should be in range, but make sure... */ CLAMP_PROBABILITY(s1); return s1;}/* * Estimate number of elements in the array yielded by an expression. * * It's important that this agree with scalararraysel. */intestimate_array_length(Node *arrayexpr){ /* look through any binary-compatible relabeling of arrayexpr */ arrayexpr = strip_array_coercion(arrayexpr); if (arrayexpr && IsA(arrayexpr, Const)) { Datum arraydatum = ((Const *) arrayexpr)->constvalue; bool arrayisnull = ((Const *) arrayexpr)->constisnull; ArrayType *arrayval; if (arrayisnull) return 0; arrayval = DatumGetArrayTypeP(arraydatum); return ArrayGetNItems(ARR_NDIM(arrayval), ARR_DIMS(arrayval)); } else if (arrayexpr && IsA(arrayexpr, ArrayExpr) && !((ArrayExpr *) arrayexpr)->multidims) { return list_length(((ArrayExpr *) arrayexpr)->elements); } else { /* default guess --- see also scalararraysel */ return 10; }}/* * rowcomparesel - Selectivity of RowCompareExpr Node. * * We estimate RowCompare selectivity by considering just the first (high * order) columns, which makes it equivalent to an ordinary OpExpr. While * this estimate could be refined by considering additional columns, it * seems unlikely that we could do a lot better without multi-column * statistics. */Selectivityrowcomparesel(PlannerInfo *root, RowCompareExpr *clause, int varRelid, JoinType jointype){ Selectivity s1; Oid opno = linitial_oid(clause->opnos); List *opargs; bool is_join_clause; /* Build equivalent arg list for single operator */ opargs = list_make2(linitial(clause->largs), linitial(clause->rargs)); /* Decide if it's a join clause, same as for OpExpr */ if (varRelid != 0) { /* * If we are considering a nestloop join then all clauses are * restriction clauses, since we are only interested in the one * relation. */ is_join_clause = false; } else { /* * Otherwise, it's a join if there's more than one relation used. * Notice we ignore the low-order columns here. */ is_join_clause = (NumRelids((Node *) opargs) > 1); } if (is_join_clause) { /* Estimate selectivity for a join clause. */ s1 = join_selectivity(root, opno, opargs, jointype); } else { /* Estimate selectivity for a restriction clause. */ s1 = restriction_selectivity(root, opno, opargs, varRelid); } return s1;}/* * eqjoinsel - Join selectivity of "=" */Datumeqjoinsel(PG_FUNCTION_ARGS){ PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0); Oid operator = PG_GETARG_OID(1); List *args = (List *) PG_GETARG_POINTER(2); JoinType jointype = (JoinType) PG_GETARG_INT16(3); double selec; VariableStatData vardata1; VariableStatData vardata2; double nd1; double nd2; Form_pg_statistic stats1 = NULL; Form_pg_statistic stats2 = NULL; bool have_mcvs1 = false; Datum *values1 = NULL; int nvalues1 = 0; float4 *numbers1 = NULL; int nnumbers1 = 0; bool have_mcvs2 = false; Datum *values2 = NULL; int nvalues2 = 0; float4 *numbers2 = NULL; int nnumbers2 = 0; get_join_variables(root, args, &vardata1, &vardata2); nd1 = get_variable_numdistinct(&vardata1); nd2 = get_variable_numdistinct(&vardata2); if (HeapTupleIsValid(vardata1.statsTuple)) { stats1 = (Form_pg_statistic) GETSTRUCT(vardata1.statsTuple); have_mcvs1 = get_attstatsslot(vardata1.statsTuple, vardata1.atttype, vardata1.atttypmod, STATISTIC_KIND_MCV, InvalidOid, &values1, &nvalues1, &numbers1, &nnumbers1); } if (HeapTupleIsValid(vardata2.statsTuple)) { stats2 = (Form_pg_statistic) GETSTRUCT(vardata2.statsTuple); have_mcvs2 = get_attstatsslot(vardata2.statsTuple, vardata2.atttype, vardata2.atttypmod, STATISTIC_KIND_MCV, InvalidOid, &values2, &nvalues2, &numbers2, &nnumbers2); } if (have_mcvs1 && have_mcvs2) { /* * We have most-common-value lists for both relations. Run through * the lists to see which MCVs actually join to each other with the * given operator. This allows us to determine the exact join * selectivity for the portion of the relations represented by the MCV * lists. We still have to estimate for the remaining population, but * in a skewed distribution this gives us a big leg up in accuracy. * For motivation see the analysis in Y. Ioannidis and S. * Christodoulakis, "On the propagation of errors in the size of join * results", Technical Report 1018, Computer Science Dept., University * of Wisconsin, Madison, March 1991 (available from ftp.cs.wisc.edu). */ FmgrInfo eqproc; bool *hasmatch1; bool *hasmatch2; double nullfrac1 = stats1->stanullfrac; double nullfrac2 = stats2->stanullfrac; double matchprodfreq, matchfreq1, matchfreq2, unmatchfreq1, unmatchfreq2, otherfreq1, otherfreq2, totalsel1, totalsel2; int i, nmatches; fmgr_info(get_opcode(operator), &eqproc); hasmatch1 = (bool *) palloc0(nvalues1 * sizeof(bool)); hasmatch2 = (bool *) palloc0(nvalues2 * sizeof(bool)); /* * If we are doing any variant of JOIN_IN, pretend all the values of * the righthand relation are unique (ie, act as if it's been * DISTINCT'd). * * NOTE: it might seem that we should unique-ify the lefthand input * when considering JOIN_REVERSE_IN. But this is not so, because the * join clause we've been handed has not been commuted from the way * the parser originally wrote it. We know that the unique side of * the IN clause is *always* on the right. * * NOTE: it would be dangerous to try to be smart about JOIN_LEFT or * JOIN_RIGHT here, because we do not have enough information to * determine which var is really on which side of the join. Perhaps * someday we should pass in more information. */ if (jointype == JOIN_IN || jointype == JOIN_REVERSE_IN || jointype == JOIN_UNIQUE_INNER || jointype == JOIN_UNIQUE_OUTER) { float4 oneovern = 1.0 / nd2; for (i = 0; i < nvalues2; i++) numbers2[i] = oneovern; nullfrac2 = oneovern; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?