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 + -
显示快捷键?