summaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2004-03-17 20:48:43 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2004-03-17 20:48:43 +0000
commit55f7c3300d164d370d28b127210223d078da524d (patch)
treee5c91b7d50eef3b40dd395e3ecce877bb6663636 /src/backend/parser
parent8c702ea7ace30026dfff4f2e514027cd4d6d7579 (diff)
downloadpostgresql-55f7c3300d164d370d28b127210223d078da524d.tar.gz
Reimplement CASE val WHEN compval1 THEN ... WHEN compval2 THEN ... END
so that the 'val' is computed only once, per recent discussion. The speedup is not much when 'val' is just a simple variable, but could be significant for larger expressions. More importantly this avoids issues with multiple evaluations of a volatile 'val', and it allows the CASE expression to be reverse-listed in its original form by ruleutils.c.
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/gram.y3
-rw-r--r--src/backend/parser/parse_expr.c62
2 files changed, 40 insertions, 25 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 9fd2e5b579..e8abfe039f 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.448 2004/03/11 01:47:37 ishii Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.449 2004/03/17 20:48:42 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -6965,6 +6965,7 @@ in_expr: select_with_parens
case_expr: CASE case_arg when_clause_list case_default END_P
{
CaseExpr *c = makeNode(CaseExpr);
+ c->casetype = InvalidOid; /* not analyzed yet */
c->arg = (Expr *) $2;
c->args = $3;
c->defresult = (Expr *) $4;
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index c23e39a25d..3881cc3953 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.165 2004/02/13 01:08:20 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.166 2004/03/17 20:48:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -637,14 +637,39 @@ transformExpr(ParseState *pstate, Node *expr)
case T_CaseExpr:
{
CaseExpr *c = (CaseExpr *) expr;
- CaseExpr *newc = makeNode(CaseExpr);
- List *newargs = NIL;
- List *typeids = NIL;
+ CaseExpr *newc;
+ Node *arg;
+ CaseTestExpr *placeholder;
+ List *newargs;
+ List *typeids;
List *args;
Node *defresult;
Oid ptype;
+ /* If we already transformed this node, do nothing */
+ if (OidIsValid(c->casetype))
+ {
+ result = expr;
+ break;
+ }
+ newc = makeNode(CaseExpr);
+
+ /* transform the test expression, if any */
+ arg = transformExpr(pstate, (Node *) c->arg);
+ newc->arg = (Expr *) arg;
+ /* generate placeholder for test expression */
+ if (arg)
+ {
+ placeholder = makeNode(CaseTestExpr);
+ placeholder->typeId = exprType(arg);
+ placeholder->typeMod = exprTypmod(arg);
+ }
+ else
+ placeholder = NULL;
+
/* transform the list of arguments */
+ newargs = NIL;
+ typeids = NIL;
foreach(args, c->args)
{
CaseWhen *w = (CaseWhen *) lfirst(args);
@@ -654,11 +679,11 @@ transformExpr(ParseState *pstate, Node *expr)
Assert(IsA(w, CaseWhen));
warg = (Node *) w->expr;
- if (c->arg != NULL)
+ if (placeholder)
{
/* shorthand form was specified, so expand... */
warg = (Node *) makeSimpleA_Expr(AEXPR_OP, "=",
- (Node *) c->arg,
+ (Node *) placeholder,
warg);
}
neww->expr = (Expr *) transformExpr(pstate, warg);
@@ -667,18 +692,7 @@ transformExpr(ParseState *pstate, Node *expr)
(Node *) neww->expr,
"CASE/WHEN");
- /*
- * result is NULL for NULLIF() construct - thomas
- * 1998-11-11
- */
warg = (Node *) w->result;
- if (warg == NULL)
- {
- A_Const *n = makeNode(A_Const);
-
- n->val.type = T_Null;
- warg = (Node *) n;
- }
neww->result = (Expr *) transformExpr(pstate, warg);
newargs = lappend(newargs, neww);
@@ -687,13 +701,6 @@ transformExpr(ParseState *pstate, Node *expr)
newc->args = newargs;
- /*
- * It's not shorthand anymore, so drop the implicit
- * argument. This is necessary to keep any re-application
- * of transformExpr from doing the wrong thing.
- */
- newc->arg = NULL;
-
/* transform the default clause */
defresult = (Node *) c->defresult;
if (defresult == NULL)
@@ -714,6 +721,7 @@ transformExpr(ParseState *pstate, Node *expr)
typeids = lconso(exprType((Node *) newc->defresult), typeids);
ptype = select_common_type(typeids, "CASE");
+ Assert(OidIsValid(ptype));
newc->casetype = ptype;
/* Convert default result clause, if necessary */
@@ -915,6 +923,7 @@ transformExpr(ParseState *pstate, Node *expr)
case T_BoolExpr:
case T_FieldSelect:
case T_RelabelType:
+ case T_CaseTestExpr:
case T_CoerceToDomain:
case T_CoerceToDomainValue:
case T_SetToDefault:
@@ -1288,6 +1297,9 @@ exprType(Node *expr)
case T_CaseWhen:
type = exprType((Node *) ((CaseWhen *) expr)->result);
break;
+ case T_CaseTestExpr:
+ type = ((CaseTestExpr *) expr)->typeId;
+ break;
case T_ArrayExpr:
type = ((ArrayExpr *) expr)->array_typeid;
break;
@@ -1408,6 +1420,8 @@ exprTypmod(Node *expr)
return typmod;
}
break;
+ case T_CaseTestExpr:
+ return ((CaseTestExpr *) expr)->typeMod;
case T_CoalesceExpr:
{
/*