clauses.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,294 行 · 第 1/5 页

C
2,294
字号
		 * value itself, plus palloc overhead.		 */		if (!get_typbyval(aggtranstype))		{			int32		aggtranstypmod;			int32		avgwidth;			/*			 * If transition state is of same type as first input, assume it's			 * the same typmod (same width) as well.  This works for cases			 * like MAX/MIN and is probably somewhat reasonable otherwise.			 */			if (numArguments > 0 && aggtranstype == inputTypes[0])				aggtranstypmod = exprTypmod((Node *) linitial(aggref->args));			else				aggtranstypmod = -1;			avgwidth = get_typavgwidth(aggtranstype, aggtranstypmod);			avgwidth = MAXALIGN(avgwidth);			counts->transitionSpace += avgwidth + 2 * sizeof(void *);		}		/*		 * Complain if the aggregate's arguments contain any aggregates;		 * nested agg functions are semantically nonsensical.		 */		if (contain_agg_clause((Node *) aggref->args))			ereport(ERROR,					(errcode(ERRCODE_GROUPING_ERROR),					 errmsg("aggregate function calls cannot be nested")));		/*		 * Having checked that, we need not recurse into the argument.		 */		return false;	}	Assert(!IsA(node, SubLink));	return expression_tree_walker(node, count_agg_clauses_walker,								  (void *) counts);}/***************************************************************************** *		Support for expressions returning sets *****************************************************************************//* * expression_returns_set *	  Test whether an expression returns a set result. * * Because we use expression_tree_walker(), this can also be applied to * whole targetlists; it'll produce TRUE if any one of the tlist items * returns a set. */boolexpression_returns_set(Node *clause){	return expression_returns_set_walker(clause, NULL);}static boolexpression_returns_set_walker(Node *node, void *context){	if (node == NULL)		return false;	if (IsA(node, FuncExpr))	{		FuncExpr   *expr = (FuncExpr *) node;		if (expr->funcretset)			return true;		/* else fall through to check args */	}	if (IsA(node, OpExpr))	{		OpExpr	   *expr = (OpExpr *) node;		if (expr->opretset)			return true;		/* else fall through to check args */	}	/* Avoid recursion for some cases that can't return a set */	if (IsA(node, Aggref))		return false;	if (IsA(node, DistinctExpr))		return false;	if (IsA(node, ScalarArrayOpExpr))		return false;	if (IsA(node, BoolExpr))		return false;	if (IsA(node, SubLink))		return false;	if (IsA(node, SubPlan))		return false;	if (IsA(node, ArrayExpr))		return false;	if (IsA(node, RowExpr))		return false;	if (IsA(node, RowCompareExpr))		return false;	if (IsA(node, CoalesceExpr))		return false;	if (IsA(node, MinMaxExpr))		return false;	if (IsA(node, XmlExpr))		return false;	if (IsA(node, NullIfExpr))		return false;	return expression_tree_walker(node, expression_returns_set_walker,								  context);}/* * expression_returns_set_rows *	  Estimate the number of rows in a set result. * * We use the product of the rowcount estimates of all the functions in * the given tree.	The result is 1 if there are no set-returning functions. */doubleexpression_returns_set_rows(Node *clause){	double		result = 1;	(void) expression_returns_set_rows_walker(clause, &result);	return result;}static boolexpression_returns_set_rows_walker(Node *node, double *count){	if (node == NULL)		return false;	if (IsA(node, FuncExpr))	{		FuncExpr   *expr = (FuncExpr *) node;		if (expr->funcretset)			*count *= get_func_rows(expr->funcid);	}	if (IsA(node, OpExpr))	{		OpExpr	   *expr = (OpExpr *) node;		if (expr->opretset)		{			set_opfuncid(expr);			*count *= get_func_rows(expr->opfuncid);		}	}	/* Avoid recursion for some cases that can't return a set */	if (IsA(node, Aggref))		return false;	if (IsA(node, DistinctExpr))		return false;	if (IsA(node, ScalarArrayOpExpr))		return false;	if (IsA(node, BoolExpr))		return false;	if (IsA(node, SubLink))		return false;	if (IsA(node, SubPlan))		return false;	if (IsA(node, ArrayExpr))		return false;	if (IsA(node, RowExpr))		return false;	if (IsA(node, RowCompareExpr))		return false;	if (IsA(node, CoalesceExpr))		return false;	if (IsA(node, MinMaxExpr))		return false;	if (IsA(node, XmlExpr))		return false;	if (IsA(node, NullIfExpr))		return false;	return expression_tree_walker(node, expression_returns_set_rows_walker,								  (void *) count);}/***************************************************************************** *		Subplan clause manipulation *****************************************************************************//* * contain_subplans *	  Recursively search for subplan nodes within a clause. * * If we see a SubLink node, we will return TRUE.  This is only possible if * the expression tree hasn't yet been transformed by subselect.c.  We do not * know whether the node will produce a true subplan or just an initplan, * but we make the conservative assumption that it will be a subplan. * * Returns true if any subplan found. */boolcontain_subplans(Node *clause){	return contain_subplans_walker(clause, NULL);}static boolcontain_subplans_walker(Node *node, void *context){	if (node == NULL)		return false;	if (IsA(node, SubPlan) ||		IsA(node, SubLink))		return true;			/* abort the tree traversal and return true */	return expression_tree_walker(node, contain_subplans_walker, context);}/***************************************************************************** *		Check clauses for mutable functions *****************************************************************************//* * contain_mutable_functions *	  Recursively search for mutable functions within a clause. * * Returns true if any mutable function (or operator implemented by a * mutable function) is found.	This test is needed so that we don't * mistakenly think that something like "WHERE random() < 0.5" can be treated * as a constant qualification. * * XXX we do not examine sub-selects to see if they contain uses of * mutable functions.  It's not real clear if that is correct or not... */boolcontain_mutable_functions(Node *clause){	return contain_mutable_functions_walker(clause, NULL);}static boolcontain_mutable_functions_walker(Node *node, void *context){	if (node == NULL)		return false;	if (IsA(node, FuncExpr))	{		FuncExpr   *expr = (FuncExpr *) node;		if (func_volatile(expr->funcid) != PROVOLATILE_IMMUTABLE)			return true;		/* else fall through to check args */	}	else if (IsA(node, OpExpr))	{		OpExpr	   *expr = (OpExpr *) node;		set_opfuncid(expr);		if (func_volatile(expr->opfuncid) != PROVOLATILE_IMMUTABLE)			return true;		/* else fall through to check args */	}	else if (IsA(node, DistinctExpr))	{		DistinctExpr *expr = (DistinctExpr *) node;		set_opfuncid((OpExpr *) expr);	/* rely on struct equivalence */		if (func_volatile(expr->opfuncid) != PROVOLATILE_IMMUTABLE)			return true;		/* else fall through to check args */	}	else if (IsA(node, ScalarArrayOpExpr))	{		ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;		set_sa_opfuncid(expr);		if (func_volatile(expr->opfuncid) != PROVOLATILE_IMMUTABLE)			return true;		/* else fall through to check args */	}	else if (IsA(node, CoerceViaIO))	{		CoerceViaIO *expr = (CoerceViaIO *) node;		Oid			iofunc;		Oid			typioparam;		bool		typisvarlena;		/* check the result type's input function */		getTypeInputInfo(expr->resulttype,						 &iofunc, &typioparam);		if (func_volatile(iofunc) != PROVOLATILE_IMMUTABLE)			return true;		/* check the input type's output function */		getTypeOutputInfo(exprType((Node *) expr->arg),						  &iofunc, &typisvarlena);		if (func_volatile(iofunc) != PROVOLATILE_IMMUTABLE)			return true;		/* else fall through to check args */	}	else if (IsA(node, ArrayCoerceExpr))	{		ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node;		if (OidIsValid(expr->elemfuncid) &&			func_volatile(expr->elemfuncid) != PROVOLATILE_IMMUTABLE)			return true;		/* else fall through to check args */	}	else if (IsA(node, NullIfExpr))	{		NullIfExpr *expr = (NullIfExpr *) node;		set_opfuncid((OpExpr *) expr);	/* rely on struct equivalence */		if (func_volatile(expr->opfuncid) != PROVOLATILE_IMMUTABLE)			return true;		/* else fall through to check args */	}	else if (IsA(node, RowCompareExpr))	{		RowCompareExpr *rcexpr = (RowCompareExpr *) node;		ListCell   *opid;		foreach(opid, rcexpr->opnos)		{			if (op_volatile(lfirst_oid(opid)) != PROVOLATILE_IMMUTABLE)				return true;		}		/* else fall through to check args */	}	return expression_tree_walker(node, contain_mutable_functions_walker,								  context);}/***************************************************************************** *		Check clauses for volatile functions *****************************************************************************//* * contain_volatile_functions *	  Recursively search for volatile functions within a clause. * * Returns true if any volatile function (or operator implemented by a * volatile function) is found. This test prevents invalid conversions * of volatile expressions into indexscan quals. * * XXX we do not examine sub-selects to see if they contain uses of * volatile functions.	It's not real clear if that is correct or not... */boolcontain_volatile_functions(Node *clause){	return contain_volatile_functions_walker(clause, NULL);}static boolcontain_volatile_functions_walker(Node *node, void *context){	if (node == NULL)		return false;	if (IsA(node, FuncExpr))	{		FuncExpr   *expr = (FuncExpr *) node;		if (func_volatile(expr->funcid) == PROVOLATILE_VOLATILE)			return true;		/* else fall through to check args */	}	else if (IsA(node, OpExpr))	{		OpExpr	   *expr = (OpExpr *) node;		set_opfuncid(expr);		if (func_volatile(expr->opfuncid) == PROVOLATILE_VOLATILE)			return true;		/* else fall through to check args */	}	else if (IsA(node, DistinctExpr))	{		DistinctExpr *expr = (DistinctExpr *) node;		set_opfuncid((OpExpr *) expr);	/* rely on struct equivalence */		if (func_volatile(expr->opfuncid) == PROVOLATILE_VOLATILE)			return true;		/* else fall through to check args */	}	else if (IsA(node, ScalarArrayOpExpr))	{		ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;		set_sa_opfuncid(expr);		if (func_volatile(expr->opfuncid) == PROVOLATILE_VOLATILE)			return true;		/* else fall through to check args */	}	else if (IsA(node, CoerceViaIO))	{		CoerceViaIO *expr = (CoerceViaIO *) node;		Oid			iofunc;		Oid			typioparam;		bool		typisvarlena;		/* check the result type's input function */		getTypeInputInfo(expr->resulttype,						 &iofunc, &typioparam);		if (func_volatile(iofunc) == PROVOLATILE_VOLATILE)			return true;		/* check the input type's output function */		getTypeOutputInfo(exprType((Node *) expr->arg),						  &iofunc, &typisvarlena);		if (func_volatile(iofunc) == PROVOLATILE_VOLATILE)			return true;		/* else fall through to check args */	}	else if (IsA(node, ArrayCoerceExpr))	{		ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node;		if (OidIsValid(expr->elemfuncid) &&			func_volatile(expr->elemfuncid) == PROVOLATILE_VOLATILE)			return true;		/* else fall through to check args */	}	else if (IsA(node, NullIfExpr))	{		NullIfExpr *expr = (NullIfExpr *) node;		set_opfuncid((OpExpr *) expr);	/* rely on struct equivalence */		if (func_volatile(expr->opfuncid) == PROVOLATILE_VOLATILE)			return true;		/* else fall through to check args */	}	else if (IsA(node, RowCompareExpr))	{		/* RowCompare probably can't have volatile ops, but check anyway */		RowCompareExpr *rcexpr = (RowCompareExpr *) node;		ListCell   *opid;		foreach(opid, rcexpr->opnos)		{			if (op_volatile(lfirst_oid(opid)) == PROVOLATILE_VOLATILE)				return true;		}		/* else fall through to check args */	}	return expression_tree_walker(node, contain_volatile_functions_walker,								  context);}/***************************************************************************** *		Check clauses for nonstrict functions *****************************************************************************//* * contain_nonstrict_functions *	  Recursively search for nonstrict functions within a clause.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?