⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clauses.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
									  fselect->resulttype,									  fselect->resulttypmod))				return (Node *) makeVar(((Var *) arg)->varno,										fselect->fieldnum,										fselect->resulttype,										fselect->resulttypmod,										((Var *) arg)->varlevelsup);		}		if (arg && IsA(arg, RowExpr))		{			RowExpr    *rowexpr = (RowExpr *) arg;			if (fselect->fieldnum > 0 &&				fselect->fieldnum <= list_length(rowexpr->args))			{				Node	   *fld = (Node *) list_nth(rowexpr->args,													fselect->fieldnum - 1);				if (rowtype_field_matches(rowexpr->row_typeid,										  fselect->fieldnum,										  fselect->resulttype,										  fselect->resulttypmod) &&					fselect->resulttype == exprType(fld) &&					fselect->resulttypmod == exprTypmod(fld))					return fld;			}		}		newfselect = makeNode(FieldSelect);		newfselect->arg = (Expr *) arg;		newfselect->fieldnum = fselect->fieldnum;		newfselect->resulttype = fselect->resulttype;		newfselect->resulttypmod = fselect->resulttypmod;		return (Node *) newfselect;	}	/*	 * 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 *) context);}/* * Subroutine for eval_const_expressions: process arguments of an OR clause * * This includes flattening of nested ORs as well as recursion to * eval_const_expressions to simplify the OR arguments. * * After simplification, OR arguments are handled as follows: *		non constant: keep *		FALSE: drop (does not affect result) *		TRUE: force result to TRUE *		NULL: keep only one * We must keep one NULL input because ExecEvalOr returns NULL when no input * is TRUE and at least one is NULL.  We don't actually include the NULL * here, that's supposed to be done by the caller. * * The output arguments *haveNull and *forceTrue must be initialized FALSE * by the caller.  They will be set TRUE if a null constant or true constant, * respectively, is detected anywhere in the argument list. */static List *simplify_or_arguments(List *args,					  eval_const_expressions_context *context,					  bool *haveNull, bool *forceTrue){	List	   *newargs = NIL;	List	   *unprocessed_args;	/*	 * Since the parser considers OR to be a binary operator, long OR lists	 * become deeply nested expressions.  We must flatten these into long	 * argument lists of a single OR operator.	To avoid blowing out the stack	 * with recursion of eval_const_expressions, we resort to some tenseness	 * here: we keep a list of not-yet-processed inputs, and handle flattening	 * of nested ORs by prepending to the to-do list instead of recursing.	 */	unprocessed_args = list_copy(args);	while (unprocessed_args)	{		Node	   *arg = (Node *) linitial(unprocessed_args);		unprocessed_args = list_delete_first(unprocessed_args);		/* flatten nested ORs as per above comment */		if (or_clause(arg))		{			List	   *subargs = list_copy(((BoolExpr *) arg)->args);			/* overly tense code to avoid leaking unused list header */			if (!unprocessed_args)				unprocessed_args = subargs;			else			{				List	   *oldhdr = unprocessed_args;				unprocessed_args = list_concat(subargs, unprocessed_args);				pfree(oldhdr);			}			continue;		}		/* If it's not an OR, simplify it */		arg = eval_const_expressions_mutator(arg, context);		/*		 * It is unlikely but not impossible for simplification of a non-OR		 * clause to produce an OR.  Recheck, but don't be too tense about it		 * since it's not a mainstream case. In particular we don't worry		 * about const-simplifying the input twice.		 */		if (or_clause(arg))		{			List	   *subargs = list_copy(((BoolExpr *) arg)->args);			unprocessed_args = list_concat(subargs, unprocessed_args);			continue;		}		/*		 * OK, we have a const-simplified non-OR argument.	Process it per		 * comments above.		 */		if (IsA(arg, Const))		{			Const	   *const_input = (Const *) arg;			if (const_input->constisnull)				*haveNull = true;			else if (DatumGetBool(const_input->constvalue))			{				*forceTrue = true;				/*				 * Once we detect a TRUE result we can just exit the loop				 * immediately.  However, if we ever add a notion of				 * non-removable functions, we'd need to keep scanning.				 */				return NIL;			}			/* otherwise, we can drop the constant-false input */			continue;		}		/* else emit the simplified arg into the result list */		newargs = lappend(newargs, arg);	}	return newargs;}/* * Subroutine for eval_const_expressions: process arguments of an AND clause * * This includes flattening of nested ANDs as well as recursion to * eval_const_expressions to simplify the AND arguments. * * After simplification, AND arguments are handled as follows: *		non constant: keep *		TRUE: drop (does not affect result) *		FALSE: force result to FALSE *		NULL: keep only one * We must keep one NULL input because ExecEvalAnd returns NULL when no input * is FALSE and at least one is NULL.  We don't actually include the NULL * here, that's supposed to be done by the caller. * * The output arguments *haveNull and *forceFalse must be initialized FALSE * by the caller.  They will be set TRUE if a null constant or false constant, * respectively, is detected anywhere in the argument list. */static List *simplify_and_arguments(List *args,					   eval_const_expressions_context *context,					   bool *haveNull, bool *forceFalse){	List	   *newargs = NIL;	List	   *unprocessed_args;	/* See comments in simplify_or_arguments */	unprocessed_args = list_copy(args);	while (unprocessed_args)	{		Node	   *arg = (Node *) linitial(unprocessed_args);		unprocessed_args = list_delete_first(unprocessed_args);		/* flatten nested ANDs as per above comment */		if (and_clause(arg))		{			List	   *subargs = list_copy(((BoolExpr *) arg)->args);			/* overly tense code to avoid leaking unused list header */			if (!unprocessed_args)				unprocessed_args = subargs;			else			{				List	   *oldhdr = unprocessed_args;				unprocessed_args = list_concat(subargs, unprocessed_args);				pfree(oldhdr);			}			continue;		}		/* If it's not an AND, simplify it */		arg = eval_const_expressions_mutator(arg, context);		/*		 * It is unlikely but not impossible for simplification of a non-AND		 * clause to produce an AND.  Recheck, but don't be too tense about it		 * since it's not a mainstream case. In particular we don't worry		 * about const-simplifying the input twice.		 */		if (and_clause(arg))		{			List	   *subargs = list_copy(((BoolExpr *) arg)->args);			unprocessed_args = list_concat(subargs, unprocessed_args);			continue;		}		/*		 * OK, we have a const-simplified non-AND argument.  Process it per		 * comments above.		 */		if (IsA(arg, Const))		{			Const	   *const_input = (Const *) arg;			if (const_input->constisnull)				*haveNull = true;			else if (!DatumGetBool(const_input->constvalue))			{				*forceFalse = true;				/*				 * Once we detect a FALSE result we can just exit the loop				 * immediately.  However, if we ever add a notion of				 * non-removable functions, we'd need to keep scanning.				 */				return NIL;			}			/* otherwise, we can drop the constant-true input */			continue;		}		/* else emit the simplified arg into the result list */		newargs = lappend(newargs, arg);	}	return newargs;}/* * Subroutine for eval_const_expressions: try to simplify boolean equality * * Input is the list of simplified arguments to the operator. * Returns a simplified expression if successful, or NULL if cannot * simplify the expression. * * The idea here is to reduce "x = true" to "x" and "x = false" to "NOT x". * This is only marginally useful in itself, but doing it in constant folding * ensures that we will recognize the two forms as being equivalent in, for * example, partial index matching. * * We come here only if simplify_function has failed; therefore we cannot * see two constant inputs, nor a constant-NULL input. */static Expr *simplify_boolean_equality(List *args){	Expr	   *leftop;	Expr	   *rightop;	Assert(list_length(args) == 2);	leftop = linitial(args);	rightop = lsecond(args);	if (leftop && IsA(leftop, Const))	{		Assert(!((Const *) leftop)->constisnull);		if (DatumGetBool(((Const *) leftop)->constvalue))			return rightop;		/* true = foo */		else			return make_notclause(rightop);		/* false = foo */	}	if (rightop && IsA(rightop, Const))	{		Assert(!((Const *) rightop)->constisnull);		if (DatumGetBool(((Const *) rightop)->constvalue))			return leftop;		/* foo = true */		else			return make_notclause(leftop);		/* foo = false */	}	return NULL;}/* * 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 the context data for eval_const_expressions. * * 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,				  eval_const_expressions_context *context){	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, context);	if (!newexpr && allow_inline)		newexpr = inline_function(funcid, result_type, args,								  func_tuple, context);	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).  In * estimation mode we are willing to pre-evaluate stable functions too. * * 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,				  eval_const_expressions_context *context){	Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);	bool		has_nonconst_input = false;	bool		has_null_input = false;	ListCell   *arg;	FuncExpr   *newexpr;	/*	 * Can't simplify if it returns a set.	 */	if (funcform->proretset)		return NULL;	/*	 * Can't simplify if it returns RECORD.  The immediate problem is that it	 * will be needing an expected tupdesc which we can't supply here.	 *	 * In the case where it has OUT parameters, it could get by without an	 * expected tupdesc, but we still have issues: get_expr_result_type()	 * doesn't know how to extract type info from a RECORD constant, and in	 * the case of a NULL function result there doesn't seem to be any clean	 * way to fix that.  In view of the likelihood of there being still other	 * gotchas, seems best to leave the function call unreduced.	 */	if (funcform->prorettype == RECORDOID)		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 all inputs are constants. (For a	 * non-strict function, constant NULL inputs are treated the same as	 * constant non-NULL inputs.)	 */	if (has_nonconst_input)		return NULL;	/*	 * Ordinarily we are only allowed to simplify immutable functions. But for	 * purposes of estimation, we consider it okay to simplify functions that	 * are merely stable; the risk that the result might change from planning	 * time to execution time is worth taking in preference to not being able	 * to estimate the value at all.	 */	if (funcform->provolatile == PROVOLATILE_IMMUTABLE)		 /* okay */ ;	else if (context->estimate && funcform->provolatile == PROVOLATILE_STABLE)		 /* okay */ ;	else		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_DONTCARE;		/* 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 speci

⌨️ 快捷键说明

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