clauses.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,256 行 · 第 1/5 页

C
2,256
字号
				}				/* Else we still need a NOT node */				return (Node *) make_notclause(lfirst(args));			default:				elog(ERROR, "unrecognized boolop: %d",					 (int) expr->boolop);				break;		}	}	if (IsA(node, SubPlan))	{		/*		 * Return a SubPlan unchanged --- too late to do anything with it.		 *		 * XXX should we ereport() here instead?  Probably this routine		 * should never be invoked after SubPlan creation.		 */		return node;	}	if (IsA(node, RelabelType))	{		/*		 * If we can simplify the input to a constant, then we don't need		 * the RelabelType node anymore: just change the type field of the		 * Const node.	Otherwise, must copy the RelabelType node.		 */		RelabelType *relabel = (RelabelType *) node;		Node	   *arg;		arg = eval_const_expressions_mutator((Node *) relabel->arg,											 active_fns);		/*		 * If we find stacked RelabelTypes (eg, from foo :: int :: oid) we		 * can discard all but the top one.		 */		while (arg && IsA(arg, RelabelType))			arg = (Node *) ((RelabelType *) arg)->arg;		if (arg && IsA(arg, Const))		{			Const	   *con = (Const *) arg;			con->consttype = relabel->resulttype;			/*			 * relabel's resulttypmod is discarded, which is OK for now;			 * if the type actually needs a runtime length coercion then			 * there should be a function call to do it just above this			 * node.			 */			return (Node *) con;		}		else		{			RelabelType *newrelabel = makeNode(RelabelType);			newrelabel->arg = (Expr *) arg;			newrelabel->resulttype = relabel->resulttype;			newrelabel->resulttypmod = relabel->resulttypmod;			return (Node *) newrelabel;		}	}	if (IsA(node, CaseExpr))	{		/*----------		 * CASE expressions can be simplified if there are constant		 * condition clauses:		 *		FALSE (or NULL): drop the alternative		 *		TRUE: drop all remaining alternatives		 * If the first non-FALSE alternative is a constant TRUE, we can		 * simplify the entire CASE to that alternative's expression.		 * If there are no non-FALSE alternatives, we simplify the entire		 * CASE to the default result (ELSE result).		 *----------		 */		CaseExpr   *caseexpr = (CaseExpr *) node;		CaseExpr   *newcase;		FastList	newargs;		Node	   *defresult;		Const	   *const_input;		List	   *arg;		FastListInit(&newargs);		foreach(arg, caseexpr->args)		{			/* Simplify this alternative's condition and result */			CaseWhen   *casewhen = (CaseWhen *)			expression_tree_mutator((Node *) lfirst(arg),									eval_const_expressions_mutator,									(void *) active_fns);			Assert(IsA(casewhen, CaseWhen));			if (casewhen->expr == NULL ||				!IsA(casewhen->expr, Const))			{				FastAppend(&newargs, casewhen);				continue;			}			const_input = (Const *) casewhen->expr;			if (const_input->constisnull ||				!DatumGetBool(const_input->constvalue))				continue;		/* drop alternative with FALSE condition */			/*			 * Found a TRUE condition.	If it's the first (un-dropped)			 * alternative, the CASE reduces to just this alternative.			 */			if (FastListValue(&newargs) == NIL)				return (Node *) casewhen->result;			/*			 * Otherwise, add it to the list, and drop all the rest.			 */			FastAppend(&newargs, casewhen);			break;		}		/* Simplify the default result */		defresult = eval_const_expressions_mutator((Node *) caseexpr->defresult,												   active_fns);		/*		 * If no non-FALSE alternatives, CASE reduces to the default		 * result		 */		if (FastListValue(&newargs) == NIL)			return defresult;		/* Otherwise we need a new CASE node */		newcase = makeNode(CaseExpr);		newcase->casetype = caseexpr->casetype;		newcase->arg = NULL;		newcase->args = FastListValue(&newargs);		newcase->defresult = (Expr *) defresult;		return (Node *) newcase;	}	if (IsA(node, ArrayExpr))	{		ArrayExpr  *arrayexpr = (ArrayExpr *) node;		ArrayExpr  *newarray;		bool		all_const = true;		FastList	newelems;		List	   *element;		FastListInit(&newelems);		foreach(element, arrayexpr->elements)		{			Node	   *e;			e = eval_const_expressions_mutator((Node *) lfirst(element),											   active_fns);			if (!IsA(e, Const))				all_const = false;			FastAppend(&newelems, e);		}		newarray = makeNode(ArrayExpr);		newarray->array_typeid = arrayexpr->array_typeid;		newarray->element_typeid = arrayexpr->element_typeid;		newarray->elements = FastListValue(&newelems);		newarray->multidims = arrayexpr->multidims;		if (all_const)			return (Node *) evaluate_expr((Expr *) newarray,										  newarray->array_typeid);		return (Node *) newarray;	}	if (IsA(node, CoalesceExpr))	{		CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;		CoalesceExpr *newcoalesce;		FastList	newargs;		List	   *arg;		FastListInit(&newargs);		foreach(arg, coalesceexpr->args)		{			Node	   *e;			e = eval_const_expressions_mutator((Node *) lfirst(arg),											   active_fns);			/*			 * We can remove null constants from the list. For a non-null			 * constant, if it has not been preceded by any other			 * non-null-constant expressions then that is the result.			 */			if (IsA(e, Const))			{				if (((Const *) e)->constisnull)					continue;	/* drop null constant */				if (FastListValue(&newargs) == NIL)					return e;	/* first expr */			}			FastAppend(&newargs, e);		}		newcoalesce = makeNode(CoalesceExpr);		newcoalesce->coalescetype = coalesceexpr->coalescetype;		newcoalesce->args = FastListValue(&newargs);		return (Node *) newcoalesce;	}	if (IsA(node, FieldSelect))	{		/*		 * We can optimize field selection from a whole-row Var into a		 * simple Var.	(This case won't be generated directly by the		 * parser, because ParseComplexProjection short-circuits it. But		 * it can arise while simplifying functions.)  If the argument		 * isn't a whole-row Var, just fall through to do generic		 * processing.		 */		FieldSelect *fselect = (FieldSelect *) node;		Var		   *argvar = (Var *) fselect->arg;		if (argvar && IsA(argvar, Var) &&			argvar->varattno == InvalidAttrNumber)		{			return (Node *) makeVar(argvar->varno,									fselect->fieldnum,									fselect->resulttype,									fselect->resulttypmod,									argvar->varlevelsup);		}	}	/*	 * For any node type not handled above, we recurse using	 * expression_tree_mutator, which will copy the node unchanged but try	 * to simplify its arguments (if any) using this routine. For example:	 * we cannot eliminate an ArrayRef node, but we might be able to	 * simplify constant expressions in its subscripts.	 */	return expression_tree_mutator(node, eval_const_expressions_mutator,								   (void *) active_fns);}/* * Subroutine for eval_const_expressions: try to simplify a function call * (which might originally have been an operator; we don't care) * * Inputs are the function OID, actual result type OID (which is needed for * polymorphic functions), and the pre-simplified argument list; * also a list of already-active inline function expansions. * * Returns a simplified expression if successful, or NULL if cannot * simplify the function call. */static Expr *simplify_function(Oid funcid, Oid result_type, List *args,				  bool allow_inline, List *active_fns){	HeapTuple	func_tuple;	Expr	   *newexpr;	/*	 * We have two strategies for simplification: either execute the	 * function to deliver a constant result, or expand in-line the body	 * of the function definition (which only works for simple	 * SQL-language functions, but that is a common case).	In either case	 * we need access to the function's pg_proc tuple, so fetch it just	 * once to use in both attempts.	 */	func_tuple = SearchSysCache(PROCOID,								ObjectIdGetDatum(funcid),								0, 0, 0);	if (!HeapTupleIsValid(func_tuple))		elog(ERROR, "cache lookup failed for function %u", funcid);	newexpr = evaluate_function(funcid, result_type, args, func_tuple);	if (!newexpr && allow_inline)		newexpr = inline_function(funcid, result_type, args,								  func_tuple, active_fns);	ReleaseSysCache(func_tuple);	return newexpr;}/* * evaluate_function: try to pre-evaluate a function call * * We can do this if the function is strict and has any constant-null inputs * (just return a null constant), or if the function is immutable and has all * constant inputs (call it and return the result as a Const node). * * Returns a simplified expression if successful, or NULL if cannot * simplify the function. */static Expr *evaluate_function(Oid funcid, Oid result_type, List *args,				  HeapTuple func_tuple){	Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);	bool		has_nonconst_input = false;	bool		has_null_input = false;	List	   *arg;	FuncExpr   *newexpr;	char		result_typtype;	/*	 * Can't simplify if it returns a set.	 */	if (funcform->proretset)		return NULL;	/*	 * Check for constant inputs and especially constant-NULL inputs.	 */	foreach(arg, args)	{		if (IsA(lfirst(arg), Const))			has_null_input |= ((Const *) lfirst(arg))->constisnull;		else			has_nonconst_input = true;	}	/*	 * If the function is strict and has a constant-NULL input, it will	 * never be called at all, so we can replace the call by a NULL	 * constant, even if there are other inputs that aren't constant, and	 * even if the function is not otherwise immutable.	 */	if (funcform->proisstrict && has_null_input)		return (Expr *) makeNullConst(result_type);	/*	 * Otherwise, can simplify only if the function is immutable and all	 * inputs are constants. (For a non-strict function, constant NULL	 * inputs are treated the same as constant non-NULL inputs.)	 */	if (funcform->provolatile != PROVOLATILE_IMMUTABLE ||		has_nonconst_input)		return NULL;	/*	 * Can't simplify functions returning composite types (mainly because	 * datumCopy() doesn't cope; FIXME someday when we have a saner	 * representation for whole-tuple results).	 */	result_typtype = get_typtype(funcform->prorettype);	if (result_typtype == 'c')		return NULL;	/*	 * OK, looks like we can simplify this operator/function.	 *	 * Build a new FuncExpr node containing the already-simplified arguments.	 */	newexpr = makeNode(FuncExpr);	newexpr->funcid = funcid;	newexpr->funcresulttype = result_type;	newexpr->funcretset = false;	newexpr->funcformat = COERCE_EXPLICIT_CALL; /* doesn't matter */	newexpr->args = args;	return evaluate_expr((Expr *) newexpr, result_type);}/* * inline_function: try to expand a function call inline * * If the function is a sufficiently simple SQL-language function * (just "SELECT expression"), then we can inline it and avoid the rather * high per-call overhead of SQL functions.  Furthermore, this can expose * opportunities for constant-folding within the function expression. * * We have to beware of some special cases however.  A directly or * indirectly recursive function would cause us to recurse forever, * so we keep track of which functions we are already expanding and * do not re-expand them.  Also, if a parameter is used more than once * in the SQL-function body, we require it not to contain any volatile * functions (volatiles might deliver inconsistent answers) nor to be * unreasonably expensive to evaluate.	The expensiveness check not only * prevents us from doing multiple evaluations of an expensive parameter * at runtime, but is a safety value to limit growth of an expression due * to repeated inlining. * * We must also beware of changing the volatility or strictness status of * functions by inlining them. * * Returns a simplified expression if successful, or NULL if cannot * simplify the function. */static Expr *inline_function(Oid funcid, Oid result_type, List *args,				HeapTuple func_tuple, List *active_fns){	Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);	char		result_typtype;	bool		polymorphic = false;	Oid			argtypes[FUNC_MAX_ARGS];	char	   *src;	Datum		tmp;	bool		isNull;	MemoryContext oldcxt;	MemoryContext mycxt;	ErrorContextCallback sqlerrcontext;	List	   *raw_parsetree_list;	List	   *querytree_list;	Query	   *querytree;	Node	   *newexpr;	int		   *usecounts;	List	   *arg;	int			i;	/*	 * Forget it if the function is not SQL-language or has other	 * showstopper properties.	(The nargs check is just paranoia.)	 */	if (funcform->prolang != SQLlanguageId ||		funcform->prosecdef ||		funcform->proretset ||		funcform->pronargs != length(args))		return NULL;	/*	 * Forget it if declared return type is not base, domain, or	 * polymorphic	 */	result_typtype = get_typtype(funcform->prorettype);	if (result_typtype != 'b' &&		result_typtype != 'd')	{		if (funcform->prorettype == ANYARRAYOID ||			funcform->prorettype == ANYELEMENTOID)			polymorphic = true;		else			return NULL;	}	/* Check for recursive function, and give up trying to expand if so */	if (oidMember(funcid, active_fns))		return NULL;	/* Check permission to call function (fail later, if not) */	if (pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE) != ACLCHECK_OK)		return NULL;	/* Check for polymorphic arguments, and substitute actual arg types */	memcpy(argtypes, funcform->proargtypes, FUNC_MAX_ARGS * sizeof(Oid));	for (i = 0; i < funcform->pronargs; i++)	{		if (argtypes[i] == ANYARRAYOID ||			argtypes[i] == ANYELEMENTOID)		{			polymorphic = true;			argtypes[i] = exprType((Node *) nth(i, args));		}

⌨️ 快捷键说明

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