selfuncs.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,362 行 · 第 1/5 页
C
2,362 行
return result; if (!varonleft || !IsA(other, Const)) { ReleaseVariableStats(vardata); return result; } variable = (Node *) linitial(args); /* * If the constant is NULL, assume operator is strict and return zero, ie, * operator will never return TRUE. (It's zero even for a negator op.) */ if (((Const *) other)->constisnull) { ReleaseVariableStats(vardata); return 0.0; } constval = ((Const *) other)->constvalue; consttype = ((Const *) other)->consttype; /* * The right-hand const is type text or bytea for all supported operators. * We do not expect to see binary-compatible types here, since * const-folding should have relabeled the const to exactly match the * operator's declared type. */ if (consttype != TEXTOID && consttype != BYTEAOID) { ReleaseVariableStats(vardata); return result; } /* * Similarly, the exposed type of the left-hand side should be one of * those we know. (Do not look at vardata.atttype, which might be * something binary-compatible but different.) We can use it to choose * the index opfamily from which we must draw the comparison operators. * * NOTE: It would be more correct to use the PATTERN opfamilies than the * simple ones, but at the moment ANALYZE will not generate statistics for * the PATTERN operators. But our results are so approximate anyway that * it probably hardly matters. */ vartype = vardata.vartype; switch (vartype) { case TEXTOID: opfamily = TEXT_BTREE_FAM_OID; break; case BPCHAROID: opfamily = BPCHAR_BTREE_FAM_OID; break; case NAMEOID: opfamily = NAME_BTREE_FAM_OID; break; case BYTEAOID: opfamily = BYTEA_BTREE_FAM_OID; break; default: ReleaseVariableStats(vardata); return result; } /* divide pattern into fixed prefix and remainder */ patt = (Const *) other; pstatus = pattern_fixed_prefix(patt, ptype, &prefix, &rest); /* * If necessary, coerce the prefix constant to the right type. (The "rest" * constant need not be changed.) */ if (prefix && prefix->consttype != vartype) { char *prefixstr; switch (prefix->consttype) { case TEXTOID: prefixstr = DatumGetCString(DirectFunctionCall1(textout, prefix->constvalue)); break; case BYTEAOID: prefixstr = DatumGetCString(DirectFunctionCall1(byteaout, prefix->constvalue)); break; default: elog(ERROR, "unrecognized consttype: %u", prefix->consttype); ReleaseVariableStats(vardata); return result; } prefix = string_to_const(prefixstr, vartype); pfree(prefixstr); } if (pstatus == Pattern_Prefix_Exact) { /* * Pattern specifies an exact match, so pretend operator is '=' */ Oid eqopr = get_opfamily_member(opfamily, vartype, vartype, BTEqualStrategyNumber); List *eqargs; if (eqopr == InvalidOid) elog(ERROR, "no = operator for opfamily %u", opfamily); eqargs = list_make2(variable, prefix); result = DatumGetFloat8(DirectFunctionCall4(eqsel, PointerGetDatum(root), ObjectIdGetDatum(eqopr), PointerGetDatum(eqargs), Int32GetDatum(varRelid))); } else { /* * Not exact-match pattern. If we have a sufficiently large * histogram, estimate selectivity for the histogram part of the * population by counting matches in the histogram. If not, estimate * selectivity of the fixed prefix and remainder of pattern * separately, then combine the two to get an estimate of the * selectivity for the part of the column population represented by * the histogram. We then add up data for any most-common-values * values; these are not in the histogram population, and we can get * exact answers for them by applying the pattern operator, so there's * no reason to approximate. (If the MCVs cover a significant part of * the total population, this gives us a big leg up in accuracy.) */ Selectivity selec; FmgrInfo opproc; double nullfrac, mcv_selec, sumcommon; /* Try to use the histogram entries to get selectivity */ fmgr_info(get_opcode(operator), &opproc); selec = histogram_selectivity(&vardata, &opproc, constval, true, 100, 1); if (selec < 0) { /* Nope, so fake it with the heuristic method */ Selectivity prefixsel; Selectivity restsel; if (pstatus == Pattern_Prefix_Partial) prefixsel = prefix_selectivity(&vardata, vartype, opfamily, prefix); else prefixsel = 1.0; restsel = pattern_selectivity(rest, ptype); selec = prefixsel * restsel; } else { /* Yes, but don't believe extremely small or large estimates. */ if (selec < 0.0001) selec = 0.0001; else if (selec > 0.9999) selec = 0.9999; } /* * If we have most-common-values info, add up the fractions of the MCV * entries that satisfy MCV OP PATTERN. These fractions contribute * directly to the result selectivity. Also add up the total fraction * represented by MCV entries. */ mcv_selec = mcv_selectivity(&vardata, &opproc, constval, true, &sumcommon); if (HeapTupleIsValid(vardata.statsTuple)) nullfrac = ((Form_pg_statistic) GETSTRUCT(vardata.statsTuple))->stanullfrac; else nullfrac = 0.0; /* * Now merge the results from the MCV and histogram calculations, * realizing that the histogram covers only the non-null values that * are not listed in MCV. */ selec *= 1.0 - nullfrac - sumcommon; selec += mcv_selec; /* result should be in range, but make sure... */ CLAMP_PROBABILITY(selec); result = selec; } if (prefix) { pfree(DatumGetPointer(prefix->constvalue)); pfree(prefix); } ReleaseVariableStats(vardata); return negate ? (1.0 - result) : result;}/* * regexeqsel - Selectivity of regular-expression pattern match. */Datumregexeqsel(PG_FUNCTION_ARGS){ PG_RETURN_FLOAT8(patternsel(fcinfo, Pattern_Type_Regex, false));}/* * icregexeqsel - Selectivity of case-insensitive regex match. */Datumicregexeqsel(PG_FUNCTION_ARGS){ PG_RETURN_FLOAT8(patternsel(fcinfo, Pattern_Type_Regex_IC, false));}/* * likesel - Selectivity of LIKE pattern match. */Datumlikesel(PG_FUNCTION_ARGS){ PG_RETURN_FLOAT8(patternsel(fcinfo, Pattern_Type_Like, false));}/* * iclikesel - Selectivity of ILIKE pattern match. */Datumiclikesel(PG_FUNCTION_ARGS){ PG_RETURN_FLOAT8(patternsel(fcinfo, Pattern_Type_Like_IC, false));}/* * regexnesel - Selectivity of regular-expression pattern non-match. */Datumregexnesel(PG_FUNCTION_ARGS){ PG_RETURN_FLOAT8(patternsel(fcinfo, Pattern_Type_Regex, true));}/* * icregexnesel - Selectivity of case-insensitive regex non-match. */Datumicregexnesel(PG_FUNCTION_ARGS){ PG_RETURN_FLOAT8(patternsel(fcinfo, Pattern_Type_Regex_IC, true));}/* * nlikesel - Selectivity of LIKE pattern non-match. */Datumnlikesel(PG_FUNCTION_ARGS){ PG_RETURN_FLOAT8(patternsel(fcinfo, Pattern_Type_Like, true));}/* * icnlikesel - Selectivity of ILIKE pattern non-match. */Datumicnlikesel(PG_FUNCTION_ARGS){ PG_RETURN_FLOAT8(patternsel(fcinfo, Pattern_Type_Like_IC, true));}/* * booltestsel - Selectivity of BooleanTest Node. */Selectivitybooltestsel(PlannerInfo *root, BoolTestType booltesttype, Node *arg, int varRelid, JoinType jointype){ VariableStatData vardata; double selec; examine_variable(root, arg, varRelid, &vardata); if (HeapTupleIsValid(vardata.statsTuple)) { Form_pg_statistic stats; double freq_null; Datum *values; int nvalues; float4 *numbers; int nnumbers; stats = (Form_pg_statistic) GETSTRUCT(vardata.statsTuple); freq_null = stats->stanullfrac; if (get_attstatsslot(vardata.statsTuple, vardata.atttype, vardata.atttypmod, STATISTIC_KIND_MCV, InvalidOid, &values, &nvalues, &numbers, &nnumbers) && nnumbers > 0) { double freq_true; double freq_false; /* * Get first MCV frequency and derive frequency for true. */ if (DatumGetBool(values[0])) freq_true = numbers[0]; else freq_true = 1.0 - numbers[0] - freq_null; /* * Next derive frequency for false. Then use these as appropriate * to derive frequency for each case. */ freq_false = 1.0 - freq_true - freq_null; switch (booltesttype) { case IS_UNKNOWN: /* select only NULL values */ selec = freq_null; break; case IS_NOT_UNKNOWN: /* select non-NULL values */ selec = 1.0 - freq_null; break; case IS_TRUE: /* select only TRUE values */ selec = freq_true; break; case IS_NOT_TRUE: /* select non-TRUE values */ selec = 1.0 - freq_true; break; case IS_FALSE: /* select only FALSE values */ selec = freq_false; break; case IS_NOT_FALSE: /* select non-FALSE values */ selec = 1.0 - freq_false; break; default: elog(ERROR, "unrecognized booltesttype: %d", (int) booltesttype); selec = 0.0; /* Keep compiler quiet */ break; } free_attstatsslot(vardata.atttype, values, nvalues, numbers, nnumbers); } else { /* * No most-common-value info available. Still have null fraction * information, so use it for IS [NOT] UNKNOWN. Otherwise adjust * for null fraction and assume an even split for boolean tests. */ switch (booltesttype) { case IS_UNKNOWN: /* * Use freq_null directly. */ selec = freq_null; break; case IS_NOT_UNKNOWN: /* * Select not unknown (not null) values. Calculate from * freq_null. */ selec = 1.0 - freq_null; break; case IS_TRUE: case IS_NOT_TRUE: case IS_FALSE: case IS_NOT_FALSE: selec = (1.0 - freq_null) / 2.0; break; default: elog(ERROR, "unrecognized booltesttype: %d", (int) booltesttype); selec = 0.0; /* Keep compiler quiet */ break; } } } else { /* * If we can't get variable statistics for the argument, perhaps * clause_selectivity can do something with it. We ignore the * possibility of a NULL value when using clause_selectivity, and just * assume the value is either TRUE or FALSE. */ switch (booltesttype) { case IS_UNKNOWN: selec = DEFAULT_UNK_SEL; break; case IS_NOT_UNKNOWN: selec = DEFAULT_NOT_UNK_SEL; break; case IS_TRUE: case IS_NOT_FALSE: selec = (double) clause_selectivity(root, arg, varRelid, jointype); break; case IS_FALSE: case IS_NOT_TRUE: selec = 1.0 - (double) clause_selectivity(root, arg, varRelid, jointype); break; default: elog(ERROR, "unrecognized booltesttype: %d", (int) booltesttype); selec = 0.0; /* Keep compiler quiet */ break; } } ReleaseVariableStats(vardata); /* result should be in range, but make sure... */ CLAMP_PROBABILITY(selec); return (Selectivity) selec;}/* * nulltestsel - Selectivity of NullTest Node. */Selectivitynulltestsel(PlannerInfo *root, NullTestType nulltesttype, Node *arg, int varRelid, JoinType jointype){ VariableStatData vardata; double selec; /* * Special hack: an IS NULL test being applied at an outer join should not * be taken at face value, since it's very likely being used to select the * outer-side rows that don't have a match, and thus its selectivity has * nothing whatever to do with the statistics of the original table * column. We do not have nearly enough context here to determine its * true selectivity, so for the moment punt and guess at 0.5. Eventually * the planner should be made to provide enough info about the clause's * context to let us do better. */ if (IS_OUTER_JOIN(jointype) && nulltesttype == IS_NULL) return (Selectivity) 0.5; examine_variable(root, arg, varRelid, &vardata); if (HeapTupleIsValid(vardata.statsTuple)) { Form_pg_statistic stats; double freq_null; stats = (Form_pg_statistic) GETSTRUCT(vardata.statsTuple); freq_null = stats->stanullfrac; switch (nulltesttype) { case IS_NULL:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?