parse_expr.c

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

C
1,537
字号
/*------------------------------------------------------------------------- * * parse_expr.c *	  handle expressions in parser * * 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/parser/parse_expr.c,v 1.163.2.1 2004/04/18 18:13:31 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "catalog/pg_operator.h"#include "catalog/pg_proc.h"#include "commands/dbcommands.h"#include "miscadmin.h"#include "nodes/makefuncs.h"#include "nodes/params.h"#include "nodes/plannodes.h"#include "parser/analyze.h"#include "parser/gramparse.h"#include "parser/parse_coerce.h"#include "parser/parse_expr.h"#include "parser/parse_func.h"#include "parser/parse_oper.h"#include "parser/parse_relation.h"#include "parser/parse_type.h"#include "utils/builtins.h"#include "utils/lsyscache.h"#include "utils/syscache.h"int			max_expr_depth = DEFAULT_MAX_EXPR_DEPTH;static int	expr_depth_counter = 0;bool		Transform_null_equals = false;static Node *typecast_expression(ParseState *pstate, Node *expr,					TypeName *typename);static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);static Node *transformIndirection(ParseState *pstate, Node *basenode,					 List *indirection);/* * Initialize for parsing a new query. * * We reset the expression depth counter here, in case it was left nonzero * due to ereport()'ing out of the last parsing operation. */voidparse_expr_init(void){	expr_depth_counter = 0;}/* * transformExpr - *	  Analyze and transform expressions. Type checking and type casting is *	  done here. The optimizer and the executor cannot handle the original *	  (raw) expressions collected by the parse tree. Hence the transformation *	  here. * * NOTE: there are various cases in which this routine will get applied to * an already-transformed expression.  Some examples: *	1. At least one construct (BETWEEN/AND) puts the same nodes *	into two branches of the parse tree; hence, some nodes *	are transformed twice. *	2. Another way it can happen is that coercion of an operator or *	function argument to the required type (via coerce_type()) *	can apply transformExpr to an already-transformed subexpression. *	An example here is "SELECT count(*) + 1.0 FROM table". * While it might be possible to eliminate these cases, the path of * least resistance so far has been to ensure that transformExpr() does * no damage if applied to an already-transformed tree.  This is pretty * easy for cases where the transformation replaces one node type with * another, such as A_Const => Const; we just do nothing when handed * a Const.  More care is needed for node types that are used as both * input and output of transformExpr; see SubLink for example. */Node *transformExpr(ParseState *pstate, Node *expr){	Node	   *result = NULL;	if (expr == NULL)		return NULL;	/*	 * Guard against an overly complex expression leading to coredump due	 * to stack overflow here, or in later recursive routines that	 * traverse expression trees.  Note that this is very unlikely to	 * happen except with pathological queries; but we don't want someone	 * to be able to crash the backend quite that easily...	 */	if (++expr_depth_counter > max_expr_depth)		ereport(ERROR,				(errcode(ERRCODE_STATEMENT_TOO_COMPLEX),				 errmsg("expression too complex"),				 errdetail("Nesting depth exceeds maximum expression depth %d.",						   max_expr_depth),				 errhint("Increase the configuration parameter \"max_expr_depth\".")));	switch (nodeTag(expr))	{		case T_ColumnRef:			{				result = transformColumnRef(pstate, (ColumnRef *) expr);				break;			}		case T_ParamRef:			{				ParamRef   *pref = (ParamRef *) expr;				int			paramno = pref->number;				ParseState *toppstate;				Param	   *param;				List	   *fields;				/*				 * Find topmost ParseState, which is where paramtype info				 * lives.				 */				toppstate = pstate;				while (toppstate->parentParseState != NULL)					toppstate = toppstate->parentParseState;				/* Check parameter number is in range */				if (paramno <= 0)		/* probably can't happen? */					ereport(ERROR,							(errcode(ERRCODE_UNDEFINED_PARAMETER),						  errmsg("there is no parameter $%d", paramno)));				if (paramno > toppstate->p_numparams)				{					if (!toppstate->p_variableparams)						ereport(ERROR,								(errcode(ERRCODE_UNDEFINED_PARAMETER),								 errmsg("there is no parameter $%d",										paramno)));					/* Okay to enlarge param array */					if (toppstate->p_paramtypes)						toppstate->p_paramtypes =							(Oid *) repalloc(toppstate->p_paramtypes,											 paramno * sizeof(Oid));					else						toppstate->p_paramtypes =							(Oid *) palloc(paramno * sizeof(Oid));					/* Zero out the previously-unreferenced slots */					MemSet(toppstate->p_paramtypes + toppstate->p_numparams,						   0,					   (paramno - toppstate->p_numparams) * sizeof(Oid));					toppstate->p_numparams = paramno;				}				if (toppstate->p_variableparams)				{					/* If not seen before, initialize to UNKNOWN type */					if (toppstate->p_paramtypes[paramno - 1] == InvalidOid)						toppstate->p_paramtypes[paramno - 1] = UNKNOWNOID;				}				param = makeNode(Param);				param->paramkind = PARAM_NUM;				param->paramid = (AttrNumber) paramno;				param->paramtype = toppstate->p_paramtypes[paramno - 1];				result = (Node *) param;				/* handle qualification, if any */				foreach(fields, pref->fields)				{					result = ParseFuncOrColumn(pstate,											   makeList1(lfirst(fields)),											   makeList1(result),											   false, false, true);				}				/* handle subscripts, if any */				result = transformIndirection(pstate, result,											  pref->indirection);				break;			}		case T_A_Const:			{				A_Const    *con = (A_Const *) expr;				Value	   *val = &con->val;				result = (Node *) make_const(val);				if (con->typename != NULL)					result = typecast_expression(pstate, result,												 con->typename);				break;			}		case T_ExprFieldSelect:			{				ExprFieldSelect *efs = (ExprFieldSelect *) expr;				List	   *fields;				result = transformExpr(pstate, efs->arg);				/* handle qualification, if any */				foreach(fields, efs->fields)				{					result = ParseFuncOrColumn(pstate,											   makeList1(lfirst(fields)),											   makeList1(result),											   false, false, true);				}				/* handle subscripts, if any */				result = transformIndirection(pstate, result,											  efs->indirection);				break;			}		case T_TypeCast:			{				TypeCast   *tc = (TypeCast *) expr;				Node	   *arg = transformExpr(pstate, tc->arg);				result = typecast_expression(pstate, arg, tc->typename);				break;			}		case T_A_Expr:			{				A_Expr	   *a = (A_Expr *) expr;				switch (a->kind)				{					case AEXPR_OP:						{							/*							 * Special-case "foo = NULL" and "NULL = foo"							 * for compatibility with standards-broken							 * products (like Microsoft's).  Turn these							 * into IS NULL exprs.							 */							if (Transform_null_equals &&								length(a->name) == 1 &&							 strcmp(strVal(lfirst(a->name)), "=") == 0 &&								(exprIsNullConstant(a->lexpr) ||								 exprIsNullConstant(a->rexpr)))							{								NullTest   *n = makeNode(NullTest);								n->nulltesttype = IS_NULL;								if (exprIsNullConstant(a->lexpr))									n->arg = (Expr *) a->rexpr;								else									n->arg = (Expr *) a->lexpr;								result = transformExpr(pstate,													   (Node *) n);							}							else							{								Node	   *lexpr = transformExpr(pstate,															   a->lexpr);								Node	   *rexpr = transformExpr(pstate,															   a->rexpr);								result = (Node *) make_op(pstate,														  a->name,														  lexpr,														  rexpr);							}						}						break;					case AEXPR_AND:						{							Node	   *lexpr = transformExpr(pstate,															  a->lexpr);							Node	   *rexpr = transformExpr(pstate,															  a->rexpr);							lexpr = coerce_to_boolean(pstate, lexpr, "AND");							rexpr = coerce_to_boolean(pstate, rexpr, "AND");							result = (Node *) makeBoolExpr(AND_EXPR,														 makeList2(lexpr,																 rexpr));						}						break;					case AEXPR_OR:						{							Node	   *lexpr = transformExpr(pstate,															  a->lexpr);							Node	   *rexpr = transformExpr(pstate,															  a->rexpr);							lexpr = coerce_to_boolean(pstate, lexpr, "OR");							rexpr = coerce_to_boolean(pstate, rexpr, "OR");							result = (Node *) makeBoolExpr(OR_EXPR,														 makeList2(lexpr,																 rexpr));						}						break;					case AEXPR_NOT:						{							Node	   *rexpr = transformExpr(pstate,															  a->rexpr);							rexpr = coerce_to_boolean(pstate, rexpr, "NOT");							result = (Node *) makeBoolExpr(NOT_EXPR,													   makeList1(rexpr));						}						break;					case AEXPR_OP_ANY:						{							Node	   *lexpr = transformExpr(pstate,															  a->lexpr);							Node	   *rexpr = transformExpr(pstate,															  a->rexpr);							result = (Node *) make_scalar_array_op(pstate,																 a->name,																   true,																   lexpr,																   rexpr);						}						break;					case AEXPR_OP_ALL:						{							Node	   *lexpr = transformExpr(pstate,															  a->lexpr);							Node	   *rexpr = transformExpr(pstate,															  a->rexpr);							result = (Node *) make_scalar_array_op(pstate,																 a->name,																   false,																   lexpr,																   rexpr);						}						break;					case AEXPR_DISTINCT:						{							Node	   *lexpr = transformExpr(pstate,															  a->lexpr);							Node	   *rexpr = transformExpr(pstate,															  a->rexpr);							result = (Node *) make_op(pstate,													  a->name,													  lexpr,													  rexpr);							if (((OpExpr *) result)->opresulttype != BOOLOID)								ereport(ERROR,									 (errcode(ERRCODE_DATATYPE_MISMATCH),									  errmsg("IS DISTINCT FROM requires = operator to yield boolean")));							/*							 * We rely on DistinctExpr and OpExpr being							 * same struct							 */							NodeSetTag(result, T_DistinctExpr);						}						break;					case AEXPR_NULLIF:						{							Node	   *lexpr = transformExpr(pstate,															  a->lexpr);							Node	   *rexpr = transformExpr(pstate,															  a->rexpr);							result = (Node *) make_op(pstate,													  a->name,													  lexpr,													  rexpr);							if (((OpExpr *) result)->opresulttype != BOOLOID)								ereport(ERROR,									 (errcode(ERRCODE_DATATYPE_MISMATCH),									  errmsg("NULLIF requires = operator to yield boolean")));							/*							 * We rely on NullIfExpr and OpExpr being same							 * struct							 */							NodeSetTag(result, T_NullIfExpr);						}						break;					case AEXPR_OF:						{							/*							 * Checking an expression for match to type.							 * Will result in a boolean constant node.							 */							List	   *telem;							A_Const    *n;							Oid			ltype,										rtype;							bool		matched = FALSE;							Node	   *lexpr = transformExpr(pstate,															  a->lexpr);							ltype = exprType(lexpr);							foreach(telem, (List *) a->rexpr)							{								rtype = LookupTypeName(lfirst(telem));								matched = (rtype == ltype);								if (matched)									break;							}							/*							 * Expect two forms: equals or not equals.							 * Flip the sense of the result for not							 * equals.							 */							if (strcmp(strVal(lfirst(a->name)), "!=") == 0)								matched = (!matched);							n = makeNode(A_Const);							n->val.type = T_String;							n->val.val.str = (matched ? "t" : "f");							n->typename = SystemTypeName("bool");							result = transformExpr(pstate, (Node *) n);						}						break;				}				break;			}		case T_FuncCall:			{				FuncCall   *fn = (FuncCall *) expr;				List	   *targs;				List	   *args;				/*				 * Transform the list of arguments.  We use a shallow list				 * copy and then transform-in-place to avoid O(N^2)				 * behavior from repeated lappend's.				 */				targs = listCopy(fn->args);				foreach(args, targs)				{					lfirst(args) = transformExpr(pstate,												 (Node *) lfirst(args));				}				result = ParseFuncOrColumn(pstate,										   fn->funcname,										   targs,										   fn->agg_star,										   fn->agg_distinct,										   false);				break;			}		case T_SubLink:			{				SubLink    *sublink = (SubLink *) expr;				List	   *qtrees;				Query	   *qtree;				/* If we already transformed this node, do nothing */				if (IsA(sublink->subselect, Query))				{					result = expr;					break;				}				pstate->p_hasSubLinks = true;				qtrees = parse_sub_analyze(sublink->subselect, pstate);				if (length(qtrees) != 1)					elog(ERROR, "bad query in sub-select");				qtree = (Query *) lfirst(qtrees);				if (qtree->commandType != CMD_SELECT ||					qtree->resultRelation != 0)					elog(ERROR, "bad query in sub-select");				sublink->subselect = (Node *) qtree;				if (sublink->subLinkType == EXISTS_SUBLINK)				{					/*					 * EXISTS needs no lefthand or combining operator.					 * These fields should be NIL already, but make sure.					 */					sublink->lefthand = NIL;					sublink->operName = NIL;					sublink->operOids = NIL;					sublink->useOr = FALSE;				}				else if (sublink->subLinkType == EXPR_SUBLINK ||						 sublink->subLinkType == ARRAY_SUBLINK)				{					List	   *tlist = qtree->targetList;					/*					 * Make sure the subselect delivers a single column					 * (ignoring resjunk targets).					 */					if (tlist == NIL ||						((TargetEntry *) lfirst(tlist))->resdom->resjunk)						ereport(ERROR,								(errcode(ERRCODE_SYNTAX_ERROR),							 errmsg("subquery must return a column")));					while ((tlist = lnext(tlist)) != NIL)					{						if (!((TargetEntry *) lfirst(tlist))->resdom->resjunk)							ereport(ERROR,									(errcode(ERRCODE_SYNTAX_ERROR),									 errmsg("subquery must return only one column")));					}					/*					 * EXPR and ARRAY need no lefthand or combining					 * operator. These fields should be NIL already, but					 * make sure.					 */					sublink->lefthand = NIL;					sublink->operName = NIL;					sublink->operOids = NIL;

⌨️ 快捷键说明

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