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