aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2001-10-08 21:46:59 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2001-10-08 21:46:59 +0000
commit71f2993c45251b009a59a422cf2c43db06aaf1a0 (patch)
tree40bec323f94236b42f6c0dac02c41e780483a74a
parent1c7bef32b46ac602d5478314dcfe1154858e970e (diff)
downloadpostgresql-71f2993c45251b009a59a422cf2c43db06aaf1a0.tar.gz
postgresql-71f2993c45251b009a59a422cf2c43db06aaf1a0.zip
Fix transformExpr() to not scribble on its input datastructure while
transforming CASE expressions. This was definitely confusing FigureColname, and might lead to bad things elsewhere as well.
-rw-r--r--src/backend/parser/parse_expr.c106
1 files changed, 57 insertions, 49 deletions
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index d1512c61c0e..5db1ab867fd 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.102 2001/09/28 08:09:09 thomas Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.103 2001/10/08 21:46:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -426,15 +426,23 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
case T_CaseExpr:
{
CaseExpr *c = (CaseExpr *) expr;
- CaseWhen *w;
+ CaseExpr *newc = makeNode(CaseExpr);
+ List *newargs = NIL;
List *typeids = NIL;
List *args;
+ Node *defresult;
Oid ptype;
/* transform the list of arguments */
foreach(args, c->args)
{
- w = lfirst(args);
+ CaseWhen *w = (CaseWhen *) lfirst(args);
+ CaseWhen *neww = makeNode(CaseWhen);
+ Node *warg;
+
+ Assert(IsA(w, CaseWhen));
+
+ warg = w->expr;
if (c->arg != NULL)
{
/* shorthand form was specified, so expand... */
@@ -443,31 +451,51 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
a->oper = OP;
a->opname = "=";
a->lexpr = c->arg;
- a->rexpr = w->expr;
- w->expr = (Node *) a;
+ a->rexpr = warg;
+ warg = (Node *) a;
}
- lfirst(args) = transformExpr(pstate, (Node *) w, precedence);
- typeids = lappendi(typeids, exprType(w->result));
+ neww->expr = transformExpr(pstate, warg, precedence);
+
+ if (! coerce_to_boolean(pstate, &neww->expr))
+ elog(ERROR, "WHEN clause must have a boolean result");
+
+ /*
+ * result is NULL for NULLIF() construct - thomas
+ * 1998-11-11
+ */
+ warg = w->result;
+ if (warg == NULL)
+ {
+ A_Const *n = makeNode(A_Const);
+
+ n->val.type = T_Null;
+ warg = (Node *) n;
+ }
+ neww->result = transformExpr(pstate, warg, precedence);
+
+ newargs = lappend(newargs, neww);
+ typeids = lappendi(typeids, exprType(neww->result));
}
+ newc->args = newargs;
+
/*
* It's not shorthand anymore, so drop the implicit
- * argument. This is necessary to keep the executor from
- * seeing an untransformed expression... not to mention
- * keeping a re-application of transformExpr from doing
- * the wrong thing.
+ * argument. This is necessary to keep any re-application
+ * of transformExpr from doing the wrong thing.
*/
- c->arg = NULL;
+ newc->arg = NULL;
/* transform the default clause */
- if (c->defresult == NULL)
+ defresult = c->defresult;
+ if (defresult == NULL)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Null;
- c->defresult = (Node *) n;
+ defresult = (Node *) n;
}
- c->defresult = transformExpr(pstate, c->defresult, precedence);
+ newc->defresult = transformExpr(pstate, defresult, precedence);
/*
* Note: default result is considered the most significant
@@ -475,49 +503,29 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
* code worked before, but it seems a little bogus to me
* --- tgl
*/
- typeids = lconsi(exprType(c->defresult), typeids);
+ typeids = lconsi(exprType(newc->defresult), typeids);
ptype = select_common_type(typeids, "CASE");
- c->casetype = ptype;
+ newc->casetype = ptype;
/* Convert default result clause, if necessary */
- c->defresult = coerce_to_common_type(pstate, c->defresult,
- ptype, "CASE/ELSE");
+ newc->defresult = coerce_to_common_type(pstate,
+ newc->defresult,
+ ptype,
+ "CASE/ELSE");
/* Convert when-clause results, if necessary */
- foreach(args, c->args)
- {
- w = lfirst(args);
- w->result = coerce_to_common_type(pstate, w->result,
- ptype, "CASE/WHEN");
- }
-
- result = expr;
- break;
- }
-
- case T_CaseWhen:
- {
- CaseWhen *w = (CaseWhen *) expr;
-
- w->expr = transformExpr(pstate, w->expr, precedence);
-
- if (! coerce_to_boolean(pstate, &w->expr))
- elog(ERROR, "WHEN clause must have a boolean result");
-
- /*
- * result is NULL for NULLIF() construct - thomas
- * 1998-11-11
- */
- if (w->result == NULL)
+ foreach(args, newc->args)
{
- A_Const *n = makeNode(A_Const);
+ CaseWhen *w = (CaseWhen *) lfirst(args);
- n->val.type = T_Null;
- w->result = (Node *) n;
+ w->result = coerce_to_common_type(pstate,
+ w->result,
+ ptype,
+ "CASE/WHEN");
}
- w->result = transformExpr(pstate, w->result, precedence);
- result = expr;
+
+ result = (Node *) newc;
break;
}