📄 parse_expr.c
字号:
/*------------------------------------------------------------------------- * * 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 + -