diff options
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/gram.y | 29 | ||||
-rw-r--r-- | src/backend/parser/parse_clause.c | 17 | ||||
-rw-r--r-- | src/backend/parser/parse_expr.c | 95 | ||||
-rw-r--r-- | src/backend/parser/parse_target.c | 14 |
4 files changed, 120 insertions, 35 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 5a7dff919d8..c593196dfc8 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.403 2003/02/13 05:25:24 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.404 2003/02/16 02:30:38 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -6650,6 +6650,10 @@ in_expr: select_with_parens * COALESCE(a,b,...) * same as CASE WHEN a IS NOT NULL THEN a WHEN b IS NOT NULL THEN b ... END * - thomas 1998-11-09 + * + * NULLIF and COALESCE have become first class nodes to + * prevent double evaluation of arguments. + * - Kris Jurka 2003-02-11 */ case_expr: CASE case_arg when_clause_list case_default END_P { @@ -6661,29 +6665,12 @@ case_expr: CASE case_arg when_clause_list case_default END_P } | NULLIF '(' a_expr ',' a_expr ')' { - CaseExpr *c = makeNode(CaseExpr); - CaseWhen *w = makeNode(CaseWhen); - - w->expr = (Expr *) makeSimpleA_Expr(AEXPR_OP, "=", $3, $5); - /* w->result is left NULL */ - c->args = makeList1(w); - c->defresult = (Expr *) $3; - $$ = (Node *)c; + $$ = (Node *) makeSimpleA_Expr(AEXPR_NULLIF, "=", $3, $5); } | COALESCE '(' expr_list ')' { - CaseExpr *c = makeNode(CaseExpr); - List *l; - foreach (l,$3) - { - CaseWhen *w = makeNode(CaseWhen); - NullTest *n = makeNode(NullTest); - n->arg = lfirst(l); - n->nulltesttype = IS_NOT_NULL; - w->expr = (Expr *) n; - w->result = lfirst(l); - c->args = lappend(c->args, w); - } + CoalesceExpr *c = makeNode(CoalesceExpr); + c->args = $3; $$ = (Node *)c; } ; diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index d65df553acf..33e7cce4203 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.109 2003/02/13 20:45:21 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.110 2003/02/16 02:30:38 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -922,17 +922,10 @@ buildMergedJoinVar(JoinType jointype, Var *l_colvar, Var *r_colvar) * Here we must build a COALESCE expression to ensure that * the join output is non-null if either input is. */ - CaseExpr *c = makeNode(CaseExpr); - CaseWhen *w = makeNode(CaseWhen); - NullTest *n = makeNode(NullTest); - - n->arg = (Expr *) l_node; - n->nulltesttype = IS_NOT_NULL; - w->expr = (Expr *) n; - w->result = (Expr *) l_node; - c->casetype = outcoltype; - c->args = makeList1(w); - c->defresult = (Expr *) r_node; + CoalesceExpr *c = makeNode(CoalesceExpr); + + c->coalescetype = outcoltype; + c->args = makeList2(l_node, r_node); res_node = (Node *) c; break; } diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index f059a1db2c0..2ec65b52c21 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.145 2003/02/13 18:29:07 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.146 2003/02/16 02:30:38 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -277,6 +277,24 @@ transformExpr(ParseState *pstate, Node *expr) NodeSetTag(result, T_DistinctExpr); } break; + case AEXPR_NULLIF: + { + Node *lexpr = transformExpr(pstate, + a->lexpr); + Node *rexpr = transformExpr(pstate, + a->rexpr); + + result = (Node *) make_op(a->name, + lexpr, + rexpr); + if (((OpExpr *) result)->opresulttype != BOOLOID) + elog(ERROR, "NULLIF requires = operator to yield boolean"); + /* + * We rely on NullIfExpr and OpExpr being same struct + */ + NodeSetTag(result, T_NullIfExpr); + } + break; case AEXPR_OF: { /* @@ -615,6 +633,43 @@ transformExpr(ParseState *pstate, Node *expr) break; } + case T_CoalesceExpr: + { + CoalesceExpr *c = (CoalesceExpr *) expr; + CoalesceExpr *newc = makeNode(CoalesceExpr); + List *newargs = NIL; + List *newcoercedargs = NIL; + List *typeids = NIL; + List *args; + + foreach(args, c->args) + { + Node *e = (Node *) lfirst(args); + Node *newe; + + newe = transformExpr(pstate, e); + newargs = lappend(newargs, newe); + typeids = lappendo(typeids, exprType(newe)); + } + + newc->coalescetype = select_common_type(typeids, "COALESCE"); + + /* Convert arguments if necessary */ + foreach(args, newargs) + { + Node *e = (Node *) lfirst(args); + Node *newe; + + newe = coerce_to_common_type(e, newc->coalescetype, + "COALESCE"); + newcoercedargs = lappend(newcoercedargs, newe); + } + + newc->args = newcoercedargs; + result = (Node *) newc; + break; + } + case T_NullTest: { NullTest *n = (NullTest *) expr; @@ -680,6 +735,7 @@ transformExpr(ParseState *pstate, Node *expr) case T_FuncExpr: case T_OpExpr: case T_DistinctExpr: + case T_NullIfExpr: case T_BoolExpr: case T_FieldSelect: case T_RelabelType: @@ -1020,6 +1076,12 @@ exprType(Node *expr) case T_CaseWhen: type = exprType((Node *) ((CaseWhen *) expr)->result); break; + case T_CoalesceExpr: + type = ((CoalesceExpr *) expr)->coalescetype; + break; + case T_NullIfExpr: + type = exprType((Node *) lfirst(((NullIfExpr *) expr)->args)); + break; case T_NullTest: type = BOOLOID; break; @@ -1126,6 +1188,37 @@ exprTypmod(Node *expr) return typmod; } break; + case T_CoalesceExpr: + { + /* + * If all the alternatives agree on type/typmod, return + * that typmod, else use -1 + */ + CoalesceExpr *cexpr = (CoalesceExpr *) expr; + Oid coalescetype = cexpr->coalescetype; + int32 typmod; + List *arg; + + typmod = exprTypmod((Node *) lfirst(cexpr->args)); + foreach(arg, cexpr->args) + { + Node *e = (Node *) lfirst(arg); + + if (exprType(e) != coalescetype) + return -1; + if (exprTypmod(e) != typmod) + return -1; + } + return typmod; + } + break; + case T_NullIfExpr: + { + NullIfExpr *nexpr = (NullIfExpr *) expr; + + return exprTypmod((Node *) lfirst(nexpr->args)); + } + break; case T_CoerceToDomain: return ((CoerceToDomain *) expr)->resulttypmod; case T_CoerceToDomainValue: diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 70aaf18ef58..4108e7557da 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.97 2003/02/13 05:53:46 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.98 2003/02/16 02:30:38 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -482,6 +482,14 @@ FigureColnameInternal(Node *node, char **name) case T_FuncCall: *name = strVal(llast(((FuncCall *) node)->funcname)); return 2; + case T_A_Expr: + /* make nullif() act like a regular function */ + if (((A_Expr *) node)->kind == AEXPR_NULLIF) + { + *name = "nullif"; + return 2; + } + break; case T_A_Const: if (((A_Const *) node)->typename != NULL) { @@ -510,6 +518,10 @@ FigureColnameInternal(Node *node, char **name) return 1; } break; + case T_CoalesceExpr: + /* make coalesce() act like a regular function */ + *name = "coalesce"; + return 2; default: break; } |