clauses.c

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

C
2,256
字号
	}	/* It's a simple DISTINCT */	return false;}/***************************************************************************** *																			 * *		General clause-manipulating routines								 * *																			 * *****************************************************************************//* * clause_get_relids_vars *	  Retrieves distinct relids and vars appearing within a clause. * * '*relids' is set to the set of all distinct "varno"s appearing *		in Vars within the clause. * '*vars' is set to a list of all distinct Vars appearing within the clause. *		Var nodes are considered distinct if they have different varno *		or varattno values.  If there are several occurrences of the same *		varno/varattno, you get a randomly chosen one... * * Note that upper-level vars are ignored, since they normally will * become Params with respect to this query level. */voidclause_get_relids_vars(Node *clause, Relids *relids, List **vars){	List	   *clvars = pull_var_clause(clause, false);	Relids		varnos = NULL;	List	   *var_list = NIL;	List	   *i;	foreach(i, clvars)	{		Var		   *var = (Var *) lfirst(i);		List	   *vi;		varnos = bms_add_member(varnos, var->varno);		foreach(vi, var_list)		{			Var		   *in_list = (Var *) lfirst(vi);			if (in_list->varno == var->varno &&				in_list->varattno == var->varattno)				break;		}		if (vi == NIL)			var_list = lcons(var, var_list);	}	freeList(clvars);	*relids = varnos;	*vars = var_list;}/* * NumRelids *		(formerly clause_relids) * * Returns the number of different relations referenced in 'clause'. */intNumRelids(Node *clause){	Relids		varnos = pull_varnos(clause);	int			result = bms_num_members(varnos);	bms_free(varnos);	return result;}/* * CommuteClause: commute a binary operator clause * * XXX the clause is destructively modified! */voidCommuteClause(OpExpr *clause){	Oid			opoid;	Node	   *temp;	/* Sanity checks: caller is at fault if these fail */	if (!is_opclause(clause) ||		length(clause->args) != 2)		elog(ERROR, "cannot commute non-binary-operator clause");	opoid = get_commutator(clause->opno);	if (!OidIsValid(opoid))		elog(ERROR, "could not find commutator for operator %u",			 clause->opno);	/*	 * modify the clause in-place!	 */	clause->opno = opoid;	clause->opfuncid = InvalidOid;	/* opresulttype and opretset are assumed not to change */	temp = lfirst(clause->args);	lfirst(clause->args) = lsecond(clause->args);	lsecond(clause->args) = temp;}/*-------------------- * eval_const_expressions * * Reduce any recognizably constant subexpressions of the given * expression tree, for example "2 + 2" => "4".  More interestingly, * we can reduce certain boolean expressions even when they contain * non-constant subexpressions: "x OR true" => "true" no matter what * the subexpression x is.	(XXX We assume that no such subexpression * will have important side-effects, which is not necessarily a good * assumption in the presence of user-defined functions; do we need a * pg_proc flag that prevents discarding the execution of a function?) * * We do understand that certain functions may deliver non-constant * results even with constant inputs, "nextval()" being the classic * example.  Functions that are not marked "immutable" in pg_proc * will not be pre-evaluated here, although we will reduce their * arguments as far as possible. * * We assume that the tree has already been type-checked and contains * only operators and functions that are reasonable to try to execute. *-------------------- */Node *eval_const_expressions(Node *node){	/*	 * The context for the mutator is a list of SQL functions being	 * recursively simplified, so we start with an empty list.	 */	return eval_const_expressions_mutator(node, NIL);}static Node *eval_const_expressions_mutator(Node *node, List *active_fns){	if (node == NULL)		return NULL;	if (IsA(node, FuncExpr))	{		FuncExpr   *expr = (FuncExpr *) node;		List	   *args;		Expr	   *simple;		FuncExpr   *newexpr;		/*		 * Reduce constants in the FuncExpr'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 *) active_fns);		/*		 * Code for op/func reduction is pretty bulky, so split it out as		 * a separate function.		 */		simple = simplify_function(expr->funcid, expr->funcresulttype, args,								   true, active_fns);		if (simple)				/* successfully simplified it */			return (Node *) simple;		/*		 * The expression cannot be simplified any further, so build and		 * return a replacement FuncExpr node using the		 * possibly-simplified arguments.		 */		newexpr = makeNode(FuncExpr);		newexpr->funcid = expr->funcid;		newexpr->funcresulttype = expr->funcresulttype;		newexpr->funcretset = expr->funcretset;		newexpr->funcformat = expr->funcformat;		newexpr->args = args;		return (Node *) newexpr;	}	if (IsA(node, OpExpr))	{		OpExpr	   *expr = (OpExpr *) node;		List	   *args;		Expr	   *simple;		OpExpr	   *newexpr;		/*		 * Reduce constants in the OpExpr'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 *) active_fns);		/*		 * 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, args,								   true, active_fns);		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;		List	   *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 *) active_fns);		/*		 * 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,									   args, false, active_fns);			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;		List	   *args;		Const	   *const_input;		/*		 * Reduce constants in the BoolExpr'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 *) active_fns);		switch (expr->boolop)		{			case OR_EXPR:				{					/*----------					 * 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 keep one NULL input because ExecEvalOr returns NULL					 * when no input is TRUE and at least one is NULL.					 *----------					 */					FastList	newargs;					List	   *arg;					bool		haveNull = false;					bool		forceTrue = false;					FastListInit(&newargs);					foreach(arg, args)					{						if (!IsA(lfirst(arg), Const))						{							FastAppend(&newargs, lfirst(arg));							continue;						}						const_input = (Const *) lfirst(arg);						if (const_input->constisnull)							haveNull = true;						else if (DatumGetBool(const_input->constvalue))							forceTrue = true;						/* otherwise, we can drop the constant-false input */					}					/*					 * We could return TRUE before falling out of the					 * loop, but this coding method will be easier to					 * adapt if we ever add a notion of non-removable					 * functions. We'd need to check all the inputs for					 * non-removability.					 */					if (forceTrue)						return MAKEBOOLCONST(true, false);					if (haveNull)						FastAppend(&newargs, MAKEBOOLCONST(false, true));					/* If all the inputs are FALSE, result is FALSE */					if (FastListValue(&newargs) == NIL)						return MAKEBOOLCONST(false, false);					/* If only one nonconst-or-NULL input, it's the result */					if (lnext(FastListValue(&newargs)) == NIL)						return (Node *) lfirst(FastListValue(&newargs));					/* Else we still need an OR node */					return (Node *) make_orclause(FastListValue(&newargs));				}			case AND_EXPR:				{					/*----------					 * 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 keep one NULL input because ExecEvalAnd returns NULL					 * when no input is FALSE and at least one is NULL.					 *----------					 */					FastList	newargs;					List	   *arg;					bool		haveNull = false;					bool		forceFalse = false;					FastListInit(&newargs);					foreach(arg, args)					{						if (!IsA(lfirst(arg), Const))						{							FastAppend(&newargs, lfirst(arg));							continue;						}						const_input = (Const *) lfirst(arg);						if (const_input->constisnull)							haveNull = true;						else if (!DatumGetBool(const_input->constvalue))							forceFalse = true;						/* otherwise, we can drop the constant-true input */					}					/*					 * We could return FALSE before falling out of the					 * loop, but this coding method will be easier to					 * adapt if we ever add a notion of non-removable					 * functions. We'd need to check all the inputs for					 * non-removability.					 */					if (forceFalse)						return MAKEBOOLCONST(false, false);					if (haveNull)						FastAppend(&newargs, MAKEBOOLCONST(false, true));					/* If all the inputs are TRUE, result is TRUE */					if (FastListValue(&newargs) == NIL)						return MAKEBOOLCONST(true, false);					/* If only one nonconst-or-NULL input, it's the result */					if (lnext(FastListValue(&newargs)) == NIL)						return (Node *) lfirst(FastListValue(&newargs));					/* Else we still need an AND node */					return (Node *) make_andclause(FastListValue(&newargs));				}			case NOT_EXPR:				Assert(length(args) == 1);				if (IsA(lfirst(args), Const))				{					const_input = (Const *) lfirst(args);					/* NOT NULL => NULL */					if (const_input->constisnull)						return MAKEBOOLCONST(false, true);					/* otherwise pretty easy */					return MAKEBOOLCONST(!DatumGetBool(const_input->constvalue),										 false);

⌨️ 快捷键说明

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