clauses.c

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

C
2,294
字号
		/*		 * Need to get OID of underlying function.	Okay to scribble on input		 * to this extent.		 */		set_opfuncid(expr);		/*		 * Code for op/func reduction is pretty bulky, so split it out as a		 * separate function.		 */		simple = simplify_function(expr->opfuncid,								   expr->opresulttype, -1,								   args,								   true, context);		if (simple)				/* successfully simplified it */			return (Node *) simple;		/*		 * If the operator is boolean equality, we know how to simplify cases		 * involving one constant and one non-constant argument.		 */		if (expr->opno == BooleanEqualOperator)		{			simple = simplify_boolean_equality(args);			if (simple)			/* successfully simplified it */				return (Node *) simple;		}		/*		 * The expression cannot be simplified any further, so build and		 * return a replacement OpExpr node using the possibly-simplified		 * arguments.		 */		newexpr = makeNode(OpExpr);		newexpr->opno = expr->opno;		newexpr->opfuncid = expr->opfuncid;		newexpr->opresulttype = expr->opresulttype;		newexpr->opretset = expr->opretset;		newexpr->args = args;		return (Node *) newexpr;	}	if (IsA(node, DistinctExpr))	{		DistinctExpr *expr = (DistinctExpr *) node;		List	   *args;		ListCell   *arg;		bool		has_null_input = false;		bool		all_null_input = true;		bool		has_nonconst_input = false;		Expr	   *simple;		DistinctExpr *newexpr;		/*		 * Reduce constants in the DistinctExpr's arguments.  We know args is		 * either NIL or a List node, so we can call expression_tree_mutator		 * directly rather than recursing to self.		 */		args = (List *) expression_tree_mutator((Node *) expr->args,											  eval_const_expressions_mutator,												(void *) context);		/*		 * We must do our own check for NULLs because DistinctExpr has		 * different results for NULL input than the underlying operator does.		 */		foreach(arg, args)		{			if (IsA(lfirst(arg), Const))			{				has_null_input |= ((Const *) lfirst(arg))->constisnull;				all_null_input &= ((Const *) lfirst(arg))->constisnull;			}			else				has_nonconst_input = true;		}		/* all constants? then can optimize this out */		if (!has_nonconst_input)		{			/* all nulls? then not distinct */			if (all_null_input)				return makeBoolConst(false, false);			/* one null? then distinct */			if (has_null_input)				return makeBoolConst(true, false);			/* otherwise try to evaluate the '=' operator */			/* (NOT okay to try to inline it, though!) */			/*			 * Need to get OID of underlying function.	Okay to scribble on			 * input to this extent.			 */			set_opfuncid((OpExpr *) expr);		/* rely on struct equivalence */			/*			 * Code for op/func reduction is pretty bulky, so split it out as			 * a separate function.			 */			simple = simplify_function(expr->opfuncid,									   expr->opresulttype, -1,									   args,									   false, context);			if (simple)			/* successfully simplified it */			{				/*				 * Since the underlying operator is "=", must negate its				 * result				 */				Const	   *csimple = (Const *) simple;				Assert(IsA(csimple, Const));				csimple->constvalue =					BoolGetDatum(!DatumGetBool(csimple->constvalue));				return (Node *) csimple;			}		}		/*		 * The expression cannot be simplified any further, so build and		 * return a replacement DistinctExpr node using the		 * possibly-simplified arguments.		 */		newexpr = makeNode(DistinctExpr);		newexpr->opno = expr->opno;		newexpr->opfuncid = expr->opfuncid;		newexpr->opresulttype = expr->opresulttype;		newexpr->opretset = expr->opretset;		newexpr->args = args;		return (Node *) newexpr;	}	if (IsA(node, BoolExpr))	{		BoolExpr   *expr = (BoolExpr *) node;		switch (expr->boolop)		{			case OR_EXPR:				{					List	   *newargs;					bool		haveNull = false;					bool		forceTrue = false;					newargs = simplify_or_arguments(expr->args, context,													&haveNull, &forceTrue);					if (forceTrue)						return makeBoolConst(true, false);					if (haveNull)						newargs = lappend(newargs, makeBoolConst(false, true));					/* If all the inputs are FALSE, result is FALSE */					if (newargs == NIL)						return makeBoolConst(false, false);					/* If only one nonconst-or-NULL input, it's the result */					if (list_length(newargs) == 1)						return (Node *) linitial(newargs);					/* Else we still need an OR node */					return (Node *) make_orclause(newargs);				}			case AND_EXPR:				{					List	   *newargs;					bool		haveNull = false;					bool		forceFalse = false;					newargs = simplify_and_arguments(expr->args, context,													 &haveNull, &forceFalse);					if (forceFalse)						return makeBoolConst(false, false);					if (haveNull)						newargs = lappend(newargs, makeBoolConst(false, true));					/* If all the inputs are TRUE, result is TRUE */					if (newargs == NIL)						return makeBoolConst(true, false);					/* If only one nonconst-or-NULL input, it's the result */					if (list_length(newargs) == 1)						return (Node *) linitial(newargs);					/* Else we still need an AND node */					return (Node *) make_andclause(newargs);				}			case NOT_EXPR:				{					Node	   *arg;					Assert(list_length(expr->args) == 1);					arg = eval_const_expressions_mutator(linitial(expr->args),														 context);					if (IsA(arg, Const))					{						Const	   *const_input = (Const *) arg;						/* NOT NULL => NULL */						if (const_input->constisnull)							return makeBoolConst(false, true);						/* otherwise pretty easy */						return makeBoolConst(!DatumGetBool(const_input->constvalue),											 false);					}					else if (not_clause(arg))					{						/* Cancel NOT/NOT */						return (Node *) get_notclausearg((Expr *) arg);					}					/* Else we still need a NOT node */					return (Node *) make_notclause((Expr *) arg);				}			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,											 context);		/*		 * 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;			con->consttypmod = relabel->resulttypmod;			return (Node *) con;		}		else		{			RelabelType *newrelabel = makeNode(RelabelType);			newrelabel->arg = (Expr *) arg;			newrelabel->resulttype = relabel->resulttype;			newrelabel->resulttypmod = relabel->resulttypmod;			newrelabel->relabelformat = relabel->relabelformat;			return (Node *) newrelabel;		}	}	if (IsA(node, CoerceViaIO))	{		CoerceViaIO *expr = (CoerceViaIO *) node;		Expr	   *arg;		Oid			outfunc;		bool		outtypisvarlena;		Oid			infunc;		Oid			intypioparam;		Expr	   *simple;		CoerceViaIO *newexpr;		/*		 * Reduce constants in the CoerceViaIO's argument.		 */		arg = (Expr *) eval_const_expressions_mutator((Node *) expr->arg,													  context);		/*		 * CoerceViaIO represents calling the source type's output function		 * then the result type's input function.  So, try to simplify it		 * as though it were a stack of two such function calls.  First we		 * need to know what the functions are.		 */		getTypeOutputInfo(exprType((Node *) arg), &outfunc, &outtypisvarlena);		getTypeInputInfo(expr->resulttype, &infunc, &intypioparam);		simple = simplify_function(outfunc,								   CSTRINGOID, -1,								   list_make1(arg),								   true, context);		if (simple)				/* successfully simplified output fn */		{			/*			 * Input functions may want 1 to 3 arguments.  We always supply			 * all three, trusting that nothing downstream will complain.			 */			List	   *args;			args = list_make3(simple,							  makeConst(OIDOID, -1, sizeof(Oid),										ObjectIdGetDatum(intypioparam),										false, true),							  makeConst(INT4OID, -1, sizeof(int32),										Int32GetDatum(-1),										false, true));			simple = simplify_function(infunc,									   expr->resulttype, -1,									   args,									   true, context);			if (simple)			/* successfully simplified input fn */				return (Node *) simple;		}		/*		 * The expression cannot be simplified any further, so build and		 * return a replacement CoerceViaIO node using the possibly-simplified		 * argument.		 */		newexpr = makeNode(CoerceViaIO);		newexpr->arg = arg;		newexpr->resulttype = expr->resulttype;		newexpr->coerceformat = expr->coerceformat;		return (Node *) newexpr;	}	if (IsA(node, ArrayCoerceExpr))	{		ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node;		Expr	   *arg;		ArrayCoerceExpr *newexpr;		/*		 * Reduce constants in the ArrayCoerceExpr's argument, then build		 * a new ArrayCoerceExpr.		 */		arg = (Expr *) eval_const_expressions_mutator((Node *) expr->arg,													  context);		newexpr = makeNode(ArrayCoerceExpr);		newexpr->arg = arg;		newexpr->elemfuncid = expr->elemfuncid;		newexpr->resulttype = expr->resulttype;		newexpr->resulttypmod = expr->resulttypmod;		newexpr->isExplicit = expr->isExplicit;		newexpr->coerceformat = expr->coerceformat;		/*		 * If constant argument and it's a binary-coercible or immutable		 * conversion, we can simplify it to a constant.		 */		if (arg && IsA(arg, Const) &&			(!OidIsValid(newexpr->elemfuncid) ||			 func_volatile(newexpr->elemfuncid) == PROVOLATILE_IMMUTABLE))			return (Node *) evaluate_expr((Expr *) newexpr,										  newexpr->resulttype,										  newexpr->resulttypmod);		/* Else we must return the partially-simplified node */		return (Node *) newexpr;	}	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).		 *		 * If we have a simple-form CASE with constant test expression,		 * we substitute the constant value for contained CaseTestExpr		 * placeholder nodes, so that we have the opportunity to reduce		 * constant test conditions.  For example this allows		 *		CASE 0 WHEN 0 THEN 1 ELSE 1/0 END		 * to reduce to 1 rather than drawing a divide-by-0 error.		 *----------		 */		CaseExpr   *caseexpr = (CaseExpr *) node;		CaseExpr   *newcase;		Node	   *save_case_val;		Node	   *newarg;		List	   *newargs;		bool		const_true_cond;		Node	   *defresult = NULL;		ListCell   *arg;		/* Simplify the test expression, if any */		newarg = eval_const_expressions_mutator((Node *) caseexpr->arg,												context);		/* Set up for contained CaseTestExpr nodes */		save_case_val = context->case_val;		if (newarg && IsA(newarg, Const))			context->case_val = newarg;		else			context->case_val = NULL;		/* Simplify the WHEN clauses */		newargs = NIL;		const_true_cond = false;		foreach(arg, caseexpr->args)		{			CaseWhen   *oldcasewhen = (CaseWhen *) lfirst(arg);			Node	   *casecond;			Node	   *caseresult;			Assert(IsA(oldcasewhen, CaseWhen));			/* Simplify this alternative's test condition */			casecond =				eval_const_expressions_mutator((Node *) oldcasewhen->expr,											   context);			/*			 * If the test condition is constant FALSE (or NULL), then drop			 * this WHEN clause completely, without processing the result.			 */			if (casecond && IsA(casecond, Const))			{				Const	   *const_input = (Const *) casecond;				if (const_input->constisnull ||					!DatumGetBool(const_input->constvalue))					continue;	/* drop alternative with FALSE condition */				/* Else it's constant TRUE */				const_true_cond = true;			}			/* Simplify this alternative's result value */			caseresult =				eval_const_expressions_mutator((Node *) oldcasewhen->result,											   context);			/* If non-constant test condition, emit a new WHEN node */			if (!const_true_cond)			{				CaseWhen   *newcasewhen = makeNode(CaseWhen);				newcasewhen->expr = (Expr *) casecond;				newcasewhen->result = (Expr *) caseresult;				newargs = lappend(newargs, newcasewhen);				continue;			}			/*			 * Found a TRUE condition, so none of the remaining alternatives			 * can be reached.	We treat the result as the default result.			 */			defresult = caseresult;			break;		}		/* Simplify the default result, unless we replaced it above */		if (

⌨️ 快捷键说明

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