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

📄 parse_expr.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * parse_expr.c *	  handle expressions in parser * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.50.2.1 1999/09/13 04:21:21 thomas Exp $ * *------------------------------------------------------------------------- */#include <stdio.h>#include <stdlib.h>#include <string.h>#include "postgres.h"#include "catalog/pg_type.h"#include "nodes/makefuncs.h"#include "nodes/nodes.h"#include "nodes/params.h"#include "nodes/relation.h"#include "parse.h"#include "parser/analyze.h"#include "parser/gramparse.h"#include "parser/parse_expr.h"#include "parser/parse_func.h"#include "parser/parse_node.h"#include "parser/parse_relation.h"#include "parser/parse_target.h"#include "parser/parse_coerce.h"#include "utils/builtins.h"static Node *parser_typecast(Value *expr, TypeName *typename, int32 atttypmod);static Node *transformIdent(ParseState *pstate, Node *expr, int precedence);/* * 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. */Node *transformExpr(ParseState *pstate, Node *expr, int precedence){	Node	   *result = NULL;	if (expr == NULL)		return NULL;	switch (nodeTag(expr))	{		case T_Attr:			{				Attr	   *att = (Attr *) expr;				Node	   *temp;				/* what if att.attrs == "*"? */				temp = ParseNestedFuncOrColumn(pstate, att, &pstate->p_last_resno,											   precedence);				if (att->indirection != NIL)				{					List	   *idx = att->indirection;					while (idx != NIL)					{						A_Indices  *ai = (A_Indices *) lfirst(idx);						Node	   *lexpr = NULL,								   *uexpr;						uexpr = transformExpr(pstate, ai->uidx, precedence);	/* must exists */						if (exprType(uexpr) != INT4OID)							elog(ERROR, "array index expressions must be int4's");						if (ai->lidx != NULL)						{							lexpr = transformExpr(pstate, ai->lidx, precedence);							if (exprType(lexpr) != INT4OID)								elog(ERROR, "array index expressions must be int4's");						}						ai->lidx = lexpr;						ai->uidx = uexpr;						/*						 * note we reuse the list of indices, make sure we						 * don't free them! Otherwise, make a new list						 * here						 */						idx = lnext(idx);					}					result = (Node *) make_array_ref(temp, att->indirection);				}				else					result = temp;				break;			}		case T_A_Const:			{				A_Const    *con = (A_Const *) expr;				Value	   *val = &con->val;				if (con->typename != NULL)					result = parser_typecast(val, con->typename, -1);				else					result = (Node *) make_const(val);				break;			}		case T_ParamNo:			{				ParamNo    *pno = (ParamNo *) expr;				Oid			toid;				int			paramno;				Param	   *param;				paramno = pno->number;				toid = param_type(paramno);				if (!OidIsValid(toid))					elog(ERROR, "Parameter '$%d' is out of range", paramno);				param = makeNode(Param);				param->paramkind = PARAM_NUM;				param->paramid = (AttrNumber) paramno;				param->paramname = "<unnamed>";				param->paramtype = (Oid) toid;				param->param_tlist = (List *) NULL;				if (pno->indirection != NIL)				{					List	   *idx = pno->indirection;					while (idx != NIL)					{						A_Indices  *ai = (A_Indices *) lfirst(idx);						Node	   *lexpr = NULL,								   *uexpr;						uexpr = transformExpr(pstate, ai->uidx, precedence);	/* must exists */						if (exprType(uexpr) != INT4OID)							elog(ERROR, "array index expressions must be int4's");						if (ai->lidx != NULL)						{							lexpr = transformExpr(pstate, ai->lidx, precedence);							if (exprType(lexpr) != INT4OID)								elog(ERROR, "array index expressions must be int4's");						}						ai->lidx = lexpr;						ai->uidx = uexpr;						/*						 * note we reuse the list of indices, make sure we						 * don't free them! Otherwise, make a new list						 * here						 */						idx = lnext(idx);					}					result = (Node *) make_array_ref((Node *) param, pno->indirection);				}				else					result = (Node *) param;				break;			}		case T_A_Expr:			{				A_Expr	   *a = (A_Expr *) expr;				switch (a->oper)				{					case OP:						{							Node	   *lexpr = transformExpr(pstate, a->lexpr, precedence);							Node	   *rexpr = transformExpr(pstate, a->rexpr, precedence);							result = (Node *) make_op(a->opname, lexpr, rexpr);						}						break;					case ISNULL:						{							Node	   *lexpr = transformExpr(pstate, a->lexpr, precedence);							result = ParseFuncOrColumn(pstate,										  "nullvalue", lcons(lexpr, NIL),												   &pstate->p_last_resno,													   precedence);						}						break;					case NOTNULL:						{							Node	   *lexpr = transformExpr(pstate, a->lexpr, precedence);							result = ParseFuncOrColumn(pstate,									   "nonnullvalue", lcons(lexpr, NIL),												   &pstate->p_last_resno,													   precedence);						}						break;					case AND:						{							Expr	   *expr = makeNode(Expr);							Node	   *lexpr = transformExpr(pstate, a->lexpr, precedence);							Node	   *rexpr = transformExpr(pstate, a->rexpr, precedence);							if (exprType(lexpr) != BOOLOID)								elog(ERROR, "left-hand side of AND is type '%s', not bool",									 typeidTypeName(exprType(lexpr)));							if (exprType(rexpr) != BOOLOID)								elog(ERROR, "right-hand side of AND is type '%s', not bool",									 typeidTypeName(exprType(rexpr)));							expr->typeOid = BOOLOID;							expr->opType = AND_EXPR;							expr->args = makeList(lexpr, rexpr, -1);							result = (Node *) expr;						}						break;					case OR:						{							Expr	   *expr = makeNode(Expr);							Node	   *lexpr = transformExpr(pstate, a->lexpr, precedence);							Node	   *rexpr = transformExpr(pstate, a->rexpr, precedence);							if (exprType(lexpr) != BOOLOID)								elog(ERROR, "left-hand side of OR is type '%s', not bool",									 typeidTypeName(exprType(lexpr)));							if (exprType(rexpr) != BOOLOID)								elog(ERROR, "right-hand side of OR is type '%s', not bool",									 typeidTypeName(exprType(rexpr)));							expr->typeOid = BOOLOID;							expr->opType = OR_EXPR;							expr->args = makeList(lexpr, rexpr, -1);							result = (Node *) expr;						}						break;					case NOT:						{							Expr	   *expr = makeNode(Expr);							Node	   *rexpr = transformExpr(pstate, a->rexpr, precedence);							if (exprType(rexpr) != BOOLOID)								elog(ERROR, "argument to NOT is type '%s', not bool",									 typeidTypeName(exprType(rexpr)));							expr->typeOid = BOOLOID;							expr->opType = NOT_EXPR;							expr->args = makeList(rexpr, -1);							result = (Node *) expr;						}						break;				}				break;			}		case T_Ident:			{				/*				 * look for a column name or a relation name (the default				 * behavior)				 */				result = transformIdent(pstate, expr, precedence);				break;			}		case T_FuncCall:			{				FuncCall   *fn = (FuncCall *) expr;				List	   *args;				/* transform the list of arguments */				foreach(args, fn->args)					lfirst(args) = transformExpr(pstate, (Node *) lfirst(args), precedence);				result = ParseFuncOrColumn(pstate,										   fn->funcname,										   fn->args,										   &pstate->p_last_resno,										   precedence);				break;			}		case T_SubLink:			{				SubLink    *sublink = (SubLink *) expr;				List	   *qtrees;				Query	   *qtree;				pstate->p_hasSubLinks = true;				qtrees = parse_analyze(lcons(sublink->subselect, NIL), pstate);				if (length(qtrees) != 1)					elog(ERROR, "parser: bad query in subselect");				qtree = (Query *) lfirst(qtrees);				if (qtree->commandType != CMD_SELECT ||					qtree->resultRelation != 0)					elog(ERROR, "parser: bad query in subselect");				sublink->subselect = (Node *) qtree;				if (sublink->subLinkType != EXISTS_SUBLINK)				{					char	   *op = lfirst(sublink->oper);					List	   *left_list = sublink->lefthand;					List	   *right_list = qtree->targetList;					List	   *elist;					foreach(elist, left_list)						lfirst(elist) = transformExpr(pstate, lfirst(elist),													  precedence);					if (length(left_list) > 1 &&						strcmp(op, "=") != 0 && strcmp(op, "<>") != 0)						elog(ERROR, "parser: '%s' is not relational operator",							 op);					sublink->oper = NIL;					/* Scan subquery's targetlist to find values that will be					 * matched against lefthand values.  We need to ignore					 * resjunk targets, so doing the outer iteration over					 * right_list is easier than doing it over left_list.					 */					while (right_list != NIL)					{						TargetEntry *tent = (TargetEntry *) lfirst(right_list);						Node	   *lexpr;						Expr	   *op_expr;						if (! tent->resdom->resjunk)						{							if (left_list == NIL)								elog(ERROR, "parser: Subselect has too many fields.");							lexpr = lfirst(left_list);							left_list = lnext(left_list);							op_expr = make_op(op, lexpr, tent->expr);							if (op_expr->typeOid != BOOLOID &&								sublink->subLinkType != EXPR_SUBLINK)								elog(ERROR, "parser: '%s' must return 'bool' to be used with quantified predicate subquery", op);							sublink->oper = lappend(sublink->oper, op_expr);						}						right_list = lnext(right_list);					}					if (left_list != NIL)						elog(ERROR, "parser: Subselect has too few fields.");				}				else					sublink->oper = NIL;				result = (Node *) expr;				break;			}		case T_CaseExpr:			{				CaseExpr   *c = (CaseExpr *) expr;				CaseWhen   *w;				List	   *args;				Oid			ptype;				CATEGORY	pcategory;				/* transform the list of arguments */				foreach(args, c->args)				{					w = lfirst(args);					if (c->arg != NULL)					{						/* shorthand form was specified, so expand... */						A_Expr	   *a = makeNode(A_Expr);						a->oper = OP;						a->opname = "=";						a->lexpr = c->arg;						a->rexpr = w->expr;						w->expr = (Node *) a;					}					lfirst(args) = transformExpr(pstate, (Node *) w, precedence);				}				/*				 * It's not shorthand anymore, so drop the implicit				 * argument. This is necessary to keep the executor from				 * seeing an untransformed expression...				 */				c->arg = NULL;				/* transform the default clause */				if (c->defresult == NULL)				{					A_Const    *n = makeNode(A_Const);					n->val.type = T_Null;					c->defresult = (Node *) n;				}				c->defresult = transformExpr(pstate, (Node *) c->defresult, precedence);				/* now check types across result clauses... */				c->casetype = exprType(c->defresult);				ptype = c->casetype;				pcategory = TypeCategory(ptype);				foreach(args, c->args)				{					Oid			wtype;					w = lfirst(args);					wtype = exprType(w->result);					/* move on to next one if no new information... */					if (wtype && (wtype != UNKNOWNOID)						&& (wtype != ptype))					{						/* so far, only nulls so take anything... */						if (!ptype)						{							ptype = wtype;							pcategory = TypeCategory(ptype);						}						/*						 * both types in different categories? then not						 * much hope...						 */						else if ((TypeCategory(wtype) != pcategory)								 || ((TypeCategory(wtype) == USER_TYPE)							&& (TypeCategory(c->casetype) == USER_TYPE)))						{							elog(ERROR, "CASE/WHEN types '%s' and '%s' not matched",								 typeidTypeName(c->casetype), typeidTypeName(wtype));						}						/*						 * new one is preferred and can convert? then take						 * it...						 */						else if (IsPreferredType(pcategory, wtype)								 && can_coerce_type(1, &ptype, &wtype))						{							ptype = wtype;							pcategory = TypeCategory(ptype);						}					}				}				/* Convert default result clause, if necessary */				if (c->casetype != ptype)				{					if (!c->casetype)					{						/*						 * default clause is NULL, so assign preferred						 * type from WHEN clauses...

⌨️ 快捷键说明

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