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

📄 parse_expr.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
/*------------------------------------------------------------------------- * * parse_expr.c *	  handle expressions in parser * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.185.2.2 2005/11/22 18:23:13 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "catalog/pg_operator.h"#include "catalog/pg_proc.h"#include "commands/dbcommands.h"#include "mb/pg_wchar.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"bool		Transform_null_equals = false;static Node *transformParamRef(ParseState *pstate, ParamRef *pref);static Node *transformAExprOp(ParseState *pstate, A_Expr *a);static Node *transformAExprAnd(ParseState *pstate, A_Expr *a);static Node *transformAExprOr(ParseState *pstate, A_Expr *a);static Node *transformAExprNot(ParseState *pstate, A_Expr *a);static Node *transformAExprOpAny(ParseState *pstate, A_Expr *a);static Node *transformAExprOpAll(ParseState *pstate, A_Expr *a);static Node *transformAExprDistinct(ParseState *pstate, A_Expr *a);static Node *transformAExprNullIf(ParseState *pstate, A_Expr *a);static Node *transformAExprOf(ParseState *pstate, A_Expr *a);static Node *transformFuncCall(ParseState *pstate, FuncCall *fn);static Node *transformCaseExpr(ParseState *pstate, CaseExpr *c);static Node *transformSubLink(ParseState *pstate, SubLink *sublink);static Node *transformArrayExpr(ParseState *pstate, ArrayExpr *a);static Node *transformRowExpr(ParseState *pstate, RowExpr *r);static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c);static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m);static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);static Node *transformWholeRowRef(ParseState *pstate, char *schemaname,					 char *relname);static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);static Node *transformIndirection(ParseState *pstate, Node *basenode,					 List *indirection);static Node *typecast_expression(ParseState *pstate, Node *expr,					TypeName *typename);static Node *make_row_op(ParseState *pstate, List *opname,			Node *ltree, Node *rtree);static Node *make_row_distinct_op(ParseState *pstate, List *opname,					 Node *ltree, Node *rtree);static Expr *make_distinct_op(ParseState *pstate, List *opname,				 Node *ltree, Node *rtree);/* * 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 stack overflow due to overly complex expressions */	check_stack_depth();	switch (nodeTag(expr))	{		case T_ColumnRef:			result = transformColumnRef(pstate, (ColumnRef *) expr);			break;		case T_ParamRef:			result = transformParamRef(pstate, (ParamRef *) expr);			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_A_Indirection:			{				A_Indirection *ind = (A_Indirection *) expr;				result = transformExpr(pstate, ind->arg);				result = transformIndirection(pstate, result,											  ind->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:						result = transformAExprOp(pstate, a);						break;					case AEXPR_AND:						result = transformAExprAnd(pstate, a);						break;					case AEXPR_OR:						result = transformAExprOr(pstate, a);						break;					case AEXPR_NOT:						result = transformAExprNot(pstate, a);						break;					case AEXPR_OP_ANY:						result = transformAExprOpAny(pstate, a);						break;					case AEXPR_OP_ALL:						result = transformAExprOpAll(pstate, a);						break;					case AEXPR_DISTINCT:						result = transformAExprDistinct(pstate, a);						break;					case AEXPR_NULLIF:						result = transformAExprNullIf(pstate, a);						break;					case AEXPR_OF:						result = transformAExprOf(pstate, a);						break;					default:						elog(ERROR, "unrecognized A_Expr kind: %d", a->kind);				}				break;			}		case T_FuncCall:			result = transformFuncCall(pstate, (FuncCall *) expr);			break;		case T_SubLink:			result = transformSubLink(pstate, (SubLink *) expr);			break;		case T_CaseExpr:			result = transformCaseExpr(pstate, (CaseExpr *) expr);			break;		case T_ArrayExpr:			result = transformArrayExpr(pstate, (ArrayExpr *) expr);			break;		case T_RowExpr:			result = transformRowExpr(pstate, (RowExpr *) expr);			break;		case T_CoalesceExpr:			result = transformCoalesceExpr(pstate, (CoalesceExpr *) expr);			break;		case T_MinMaxExpr:			result = transformMinMaxExpr(pstate, (MinMaxExpr *) expr);			break;		case T_NullTest:			{				NullTest   *n = (NullTest *) expr;				n->arg = (Expr *) transformExpr(pstate, (Node *) n->arg);				/* the argument can be any type, so don't coerce it */				result = expr;				break;			}		case T_BooleanTest:			result = transformBooleanTest(pstate, (BooleanTest *) expr);			break;			/*********************************************			 * Quietly accept node types that may be presented when we are			 * called on an already-transformed tree.			 *			 * Do any other node types need to be accepted?  For now we are			 * taking a conservative approach, and only accepting node			 * types that are demonstrably necessary to accept.			 *********************************************/		case T_Var:		case T_Const:		case T_Param:		case T_Aggref:		case T_ArrayRef:		case T_FuncExpr:		case T_OpExpr:		case T_DistinctExpr:		case T_ScalarArrayOpExpr:		case T_NullIfExpr:		case T_BoolExpr:		case T_FieldSelect:		case T_FieldStore:		case T_RelabelType:		case T_ConvertRowtypeExpr:		case T_CaseTestExpr:		case T_CoerceToDomain:		case T_CoerceToDomainValue:		case T_SetToDefault:			{				result = (Node *) expr;				break;			}		default:			/* should not reach here */			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));			break;	}	return result;}static Node *transformIndirection(ParseState *pstate, Node *basenode, List *indirection){	Node	   *result = basenode;	List	   *subscripts = NIL;	ListCell   *i;	/*	 * We have to split any field-selection operations apart from	 * subscripting.  Adjacent A_Indices nodes have to be treated as a single	 * multidimensional subscript operation.	 */	foreach(i, indirection)	{		Node	   *n = lfirst(i);		if (IsA(n, A_Indices))			subscripts = lappend(subscripts, n);		else		{			Assert(IsA(n, String));			/* process subscripts before this field selection */			if (subscripts)				result = (Node *) transformArraySubscripts(pstate,														   result,														   exprType(result),														   InvalidOid,														   -1,														   subscripts,														   NULL);			subscripts = NIL;			result = ParseFuncOrColumn(pstate,									   list_make1(n),									   list_make1(result),									   false, false, true);		}	}	/* process trailing subscripts, if any */	if (subscripts)		result = (Node *) transformArraySubscripts(pstate,												   result,												   exprType(result),												   InvalidOid,												   -1,												   subscripts,												   NULL);	return result;}static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref){	int			numnames = list_length(cref->fields);	Node	   *node;	int			levels_up;	/*----------	 * The allowed syntaxes are:	 *	 * A		First try to resolve as unqualified column name;	 *			if no luck, try to resolve as unqualified table name (A.*).	 * A.B		A is an unqualified table name; B is either a	 *			column or function name (trying column name first).	 * A.B.C	schema A, table B, col or func name C.	 * A.B.C.D	catalog A, schema B, table C, col or func D.	 * A.*		A is an unqualified table name; means whole-row value.	 * A.B.*	whole-row value of table B in schema A.	 * A.B.C.*	whole-row value of table C in schema B in catalog A.	 *	 * We do not need to cope with bare "*"; that will only be accepted by	 * the grammar at the top level of a SELECT list, and transformTargetList	 * will take care of it before it ever gets here.  Also, "A.*" etc will	 * be expanded by transformTargetList if they appear at SELECT top level,	 * so here we are only going to see them as function or operator inputs.	 *	 * Currently, if a catalog name is given then it must equal the current	 * database name; we check it here and then discard it.	 *----------	 */	switch (numnames)	{		case 1:			{				char	   *name = strVal(linitial(cref->fields));				/* Try to identify as an unqualified column */				node = colNameToVar(pstate, name, false);				if (node == NULL)				{					/*					 * Not known as a column of any range-table entry.					 *					 * Consider the possibility that it's VALUE in a domain					 * check expression.  (We handle VALUE as a name, not a					 * keyword, to avoid breaking a lot of applications that					 * have used VALUE as a column name in the past.)					 */					if (pstate->p_value_substitute != NULL &&						strcmp(name, "value") == 0)					{						node = (Node *) copyObject(pstate->p_value_substitute);						break;					}					/*					 * Try to find the name as a relation.	Note that only					 * relations already entered into the rangetable will be					 * recognized.					 *					 * This is a hack for backwards compatibility with					 * PostQUEL-inspired syntax.  The preferred form now is					 * "rel.*".					 */					if (refnameRangeTblEntry(pstate, NULL, name,											 &levels_up) != NULL)						node = transformWholeRowRef(pstate, NULL, name);					else						ereport(ERROR,								(errcode(ERRCODE_UNDEFINED_COLUMN),								 errmsg("column \"%s\" does not exist",										name)));				}				break;			}		case 2:			{				char	   *name1 = strVal(linitial(cref->fields));				char	   *name2 = strVal(lsecond(cref->fields));				/* Whole-row reference? */				if (strcmp(name2, "*") == 0)				{					node = transformWholeRowRef(pstate, NULL, name1);					break;				}				/* Try to identify as a once-qualified column */				node = qualifiedNameToVar(pstate, NULL, name1, name2, true);				if (node == NULL)				{					/*					 * Not known as a column of any range-table entry, so try					 * it as a function call.  Here, we will create an					 * implicit RTE for tables not already entered.					 */					node = transformWholeRowRef(pstate, NULL, name1);					node = ParseFuncOrColumn(pstate,											 list_make1(makeString(name2)),											 list_make1(node),											 false, false, true);				}				break;			}		case 3:			{				char	   *name1 = strVal(linitial(cref->fields));				char	   *name2 = strVal(lsecond(cref->fields));				char	   *name3 = strVal(lthird(cref->fields));				/* Whole-row reference? */				if (strcmp(name3, "*") == 0)				{					node = transformWholeRowRef(pstate, name1, name2);					break;				}				/* Try to identify as a twice-qualified column */				node = qualifiedNameToVar(pstate, name1, name2, name3, true);				if (node == NULL)				{					/* Try it as a function call */					node = transformWholeRowRef(pstate, name1, name2);					node = ParseFuncOrColumn(pstate,											 list_make1(makeString(name3)),											 list_make1(node),											 false, false, true);				}				break;			}		case 4:			{				char	   *name1 = strVal(linitial(cref->fields));				char	   *name2 = strVal(lsecond(cref->fields));				char	   *name3 = strVal(lthird(cref->fields));				char	   *name4 = strVal(lfourth(cref->fields));				/*				 * We check the catalog name and then ignore it.				 */				if (strcmp(name1, get_database_name(MyDatabaseId)) != 0)					ereport(ERROR,							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),							 errmsg("cross-database references are not implemented: %s",									NameListToString(cref->fields))));				/* Whole-row reference? */				if (strcmp(name4, "*") == 0)				{					node = transformWholeRowRef(pstate, name2, name3);					break;				}				/* Try to identify as a twice-qualified column */				node = qualifiedNameToVar(pstate, name2, name3, name4, true);				if (node == NULL)				{					/* Try it as a function call */					node = transformWholeRowRef(pstate, name2, name3);					node = ParseFuncOrColumn(pstate,											 list_make1(makeString(name4)),											 list_make1(node),											 false, false, true);				}				break;			}		default:			ereport(ERROR,					(errcode(ERRCODE_SYNTAX_ERROR),

⌨️ 快捷键说明

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