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 + -
显示快捷键?