aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_expr.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2003-02-16 02:30:39 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2003-02-16 02:30:39 +0000
commit51972a9d5d068dd34b24ff4923981ffb90e5cc2d (patch)
treec68fddbb3eaafbd332e84afbafe3c171f6372d4e /src/backend/parser/parse_expr.c
parentde25638d2fbe9e56ecfc60a7dda8a0c56028317a (diff)
downloadpostgresql-51972a9d5d068dd34b24ff4923981ffb90e5cc2d.tar.gz
postgresql-51972a9d5d068dd34b24ff4923981ffb90e5cc2d.zip
COALESCE() and NULLIF() are now first-class expressions, not macros
that turn into CASE expressions. They evaluate their arguments at most once. Patch by Kris Jurka, review and (very light) editorializing by me.
Diffstat (limited to 'src/backend/parser/parse_expr.c')
-rw-r--r--src/backend/parser/parse_expr.c95
1 files changed, 94 insertions, 1 deletions
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: