clauses.c

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

C
2,256
字号
/*------------------------------------------------------------------------- * * clauses.c *	  routines to manipulate qualification clauses * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.154.2.2 2004/01/28 00:05:25 tgl Exp $ * * HISTORY *	  AUTHOR			DATE			MAJOR EVENT *	  Andrew Yu			Nov 3, 1994		clause.c and clauses.c combined * *------------------------------------------------------------------------- */#include "postgres.h"#include "catalog/pg_language.h"#include "catalog/pg_proc.h"#include "catalog/pg_type.h"#include "executor/executor.h"#include "miscadmin.h"#include "nodes/makefuncs.h"#include "optimizer/clauses.h"#include "optimizer/cost.h"#include "optimizer/planmain.h"#include "optimizer/var.h"#include "parser/analyze.h"#include "parser/parse_clause.h"#include "parser/parse_expr.h"#include "tcop/tcopprot.h"#include "utils/acl.h"#include "utils/builtins.h"#include "utils/datum.h"#include "utils/lsyscache.h"#include "utils/memutils.h"#include "utils/syscache.h"/* note that pg_type.h hardwires size of bool as 1 ... duplicate it */#define MAKEBOOLCONST(val,isnull) \	((Node *) makeConst(BOOLOID, 1, (Datum) (val), (isnull), true))typedef struct{	int			nargs;	List	   *args;	int		   *usecounts;} substitute_actual_parameters_context;static bool contain_agg_clause_walker(Node *node, void *context);static bool contain_distinct_agg_clause_walker(Node *node, void *context);static bool count_agg_clause_walker(Node *node, int *count);static bool expression_returns_set_walker(Node *node, void *context);static bool contain_subplans_walker(Node *node, void *context);static bool contain_mutable_functions_walker(Node *node, void *context);static bool contain_volatile_functions_walker(Node *node, void *context);static bool contain_nonstrict_functions_walker(Node *node, void *context);static Node *eval_const_expressions_mutator(Node *node, List *active_fns);static Expr *simplify_function(Oid funcid, Oid result_type, List *args,				  bool allow_inline, List *active_fns);static Expr *evaluate_function(Oid funcid, Oid result_type, List *args,				  HeapTuple func_tuple);static Expr *inline_function(Oid funcid, Oid result_type, List *args,				HeapTuple func_tuple, List *active_fns);static Node *substitute_actual_parameters(Node *expr, int nargs, List *args,							 int *usecounts);static Node *substitute_actual_parameters_mutator(Node *node,						  substitute_actual_parameters_context *context);static void sql_inline_error_callback(void *arg);static Expr *evaluate_expr(Expr *expr, Oid result_type);/***************************************************************************** *		OPERATOR clause functions *****************************************************************************//* * make_opclause *	  Creates an operator clause given its operator info, left operand, *	  and right operand (pass NULL to create single-operand clause). */Expr *make_opclause(Oid opno, Oid opresulttype, bool opretset,			  Expr *leftop, Expr *rightop){	OpExpr	   *expr = makeNode(OpExpr);	expr->opno = opno;	expr->opfuncid = InvalidOid;	expr->opresulttype = opresulttype;	expr->opretset = opretset;	if (rightop)		expr->args = makeList2(leftop, rightop);	else		expr->args = makeList1(leftop);	return (Expr *) expr;}/* * get_leftop * * Returns the left operand of a clause of the form (op expr expr) *		or (op expr) */Node *get_leftop(Expr *clause){	OpExpr	   *expr = (OpExpr *) clause;	if (expr->args != NIL)		return lfirst(expr->args);	else		return NULL;}/* * get_rightop * * Returns the right operand in a clause of the form (op expr expr). * NB: result will be NULL if applied to a unary op clause. */Node *get_rightop(Expr *clause){	OpExpr	   *expr = (OpExpr *) clause;	if (expr->args != NIL && lnext(expr->args) != NIL)		return lfirst(lnext(expr->args));	else		return NULL;}/***************************************************************************** *		NOT clause functions *****************************************************************************//* * not_clause * * Returns t iff this is a 'not' clause: (NOT expr). */boolnot_clause(Node *clause){	return (clause != NULL &&			IsA(clause, BoolExpr) &&			((BoolExpr *) clause)->boolop == NOT_EXPR);}/* * make_notclause * * Create a 'not' clause given the expression to be negated. */Expr *make_notclause(Expr *notclause){	BoolExpr   *expr = makeNode(BoolExpr);	expr->boolop = NOT_EXPR;	expr->args = makeList1(notclause);	return (Expr *) expr;}/* * get_notclausearg * * Retrieve the clause within a 'not' clause */Expr *get_notclausearg(Expr *notclause){	return lfirst(((BoolExpr *) notclause)->args);}/***************************************************************************** *		OR clause functions *****************************************************************************//* * or_clause * * Returns t iff the clause is an 'or' clause: (OR { expr }). */boolor_clause(Node *clause){	return (clause != NULL &&			IsA(clause, BoolExpr) &&			((BoolExpr *) clause)->boolop == OR_EXPR);}/* * make_orclause * * Creates an 'or' clause given a list of its subclauses. */Expr *make_orclause(List *orclauses){	BoolExpr   *expr = makeNode(BoolExpr);	expr->boolop = OR_EXPR;	expr->args = orclauses;	return (Expr *) expr;}/***************************************************************************** *		AND clause functions *****************************************************************************//* * and_clause * * Returns t iff its argument is an 'and' clause: (AND { expr }). */booland_clause(Node *clause){	return (clause != NULL &&			IsA(clause, BoolExpr) &&			((BoolExpr *) clause)->boolop == AND_EXPR);}/* * make_andclause * * Creates an 'and' clause given a list of its subclauses. */Expr *make_andclause(List *andclauses){	BoolExpr   *expr = makeNode(BoolExpr);	expr->boolop = AND_EXPR;	expr->args = andclauses;	return (Expr *) expr;}/* * make_and_qual * * Variant of make_andclause for ANDing two qual conditions together. * Qual conditions have the property that a NULL nodetree is interpreted * as 'true'. */Node *make_and_qual(Node *qual1, Node *qual2){	if (qual1 == NULL)		return qual2;	if (qual2 == NULL)		return qual1;	return (Node *) make_andclause(makeList2(qual1, qual2));}/* * Sometimes (such as in the result of canonicalize_qual or the input of * ExecQual), we use lists of expression nodes with implicit AND semantics. * * These functions convert between an AND-semantics expression list and the * ordinary representation of a boolean expression. * * Note that an empty list is considered equivalent to TRUE. */Expr *make_ands_explicit(List *andclauses){	if (andclauses == NIL)		return (Expr *) MAKEBOOLCONST(true, false);	else if (lnext(andclauses) == NIL)		return (Expr *) lfirst(andclauses);	else		return make_andclause(andclauses);}List *make_ands_implicit(Expr *clause){	/*	 * NB: because the parser sets the qual field to NULL in a query that	 * has no WHERE clause, we must consider a NULL input clause as TRUE,	 * even though one might more reasonably think it FALSE.  Grumble. If	 * this causes trouble, consider changing the parser's behavior.	 */	if (clause == NULL)		return NIL;				/* NULL -> NIL list == TRUE */	else if (and_clause((Node *) clause))		return ((BoolExpr *) clause)->args;	else if (IsA(clause, Const) &&			 !((Const *) clause)->constisnull &&			 DatumGetBool(((Const *) clause)->constvalue))		return NIL;				/* constant TRUE input -> NIL list */	else		return makeList1(clause);}/***************************************************************************** *		Aggregate-function clause manipulation *****************************************************************************//* * contain_agg_clause *	  Recursively search for Aggref nodes within a clause. * *	  Returns true if any aggregate found. * * This does not descend into subqueries, and so should be used only after * reduction of sublinks to subplans, or in contexts where it's known there * are no subqueries.  There mustn't be outer-aggregate references either. * * (If you want something like this but able to deal with subqueries, * see rewriteManip.c's checkExprHasAggs().) */boolcontain_agg_clause(Node *clause){	return contain_agg_clause_walker(clause, NULL);}static boolcontain_agg_clause_walker(Node *node, void *context){	if (node == NULL)		return false;	if (IsA(node, Aggref))	{		Assert(((Aggref *) node)->agglevelsup == 0);		return true;			/* abort the tree traversal and return								 * true */	}	Assert(!IsA(node, SubLink));	return expression_tree_walker(node, contain_agg_clause_walker, context);}/* * contain_distinct_agg_clause *	  Recursively search for DISTINCT Aggref nodes within a clause. * *	  Returns true if any DISTINCT aggregate found. * * This does not descend into subqueries, and so should be used only after * reduction of sublinks to subplans, or in contexts where it's known there * are no subqueries.  There mustn't be outer-aggregate references either. */boolcontain_distinct_agg_clause(Node *clause){	return contain_distinct_agg_clause_walker(clause, NULL);}static boolcontain_distinct_agg_clause_walker(Node *node, void *context){	if (node == NULL)		return false;	if (IsA(node, Aggref))	{		Assert(((Aggref *) node)->agglevelsup == 0);		if (((Aggref *) node)->aggdistinct)			return true;		/* abort the tree traversal and return								 * true */	}	Assert(!IsA(node, SubLink));	return expression_tree_walker(node, contain_distinct_agg_clause_walker, context);}/* * count_agg_clause *	  Recursively count the Aggref nodes in an expression tree. * *	  Note: this also checks for nested aggregates, which are an error. * * This does not descend into subqueries, and so should be used only after * reduction of sublinks to subplans, or in contexts where it's known there * are no subqueries.  There mustn't be outer-aggregate references either. */intcount_agg_clause(Node *clause){	int			result = 0;	count_agg_clause_walker(clause, &result);	return result;}static boolcount_agg_clause_walker(Node *node, int *count){	if (node == NULL)		return false;	if (IsA(node, Aggref))	{		Assert(((Aggref *) node)->agglevelsup == 0);		(*count)++;		/*		 * Complain if the aggregate's argument contains any aggregates;		 * nested agg functions are semantically nonsensical.		 */		if (contain_agg_clause((Node *) ((Aggref *) node)->target))			ereport(ERROR,					(errcode(ERRCODE_GROUPING_ERROR),				  errmsg("aggregate function calls may not 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_clause_walker,								  (void *) count);}/***************************************************************************** *		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;

⌨️ 快捷键说明

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