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.
REL7_2_STABLE
Tom Lane 24 years ago
parent 1c7bef32b4
commit 71f2993c45
  1. 106
      src/backend/parser/parse_expr.c

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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: case T_CaseExpr:
{ {
CaseExpr *c = (CaseExpr *) expr; CaseExpr *c = (CaseExpr *) expr;
CaseWhen *w; CaseExpr *newc = makeNode(CaseExpr);
List *newargs = NIL;
List *typeids = NIL; List *typeids = NIL;
List *args; List *args;
Node *defresult;
Oid ptype; Oid ptype;
/* transform the list of arguments */ /* transform the list of arguments */
foreach(args, c->args) 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) if (c->arg != NULL)
{ {
/* shorthand form was specified, so expand... */ /* shorthand form was specified, so expand... */
@ -443,31 +451,51 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
a->oper = OP; a->oper = OP;
a->opname = "="; a->opname = "=";
a->lexpr = c->arg; a->lexpr = c->arg;
a->rexpr = w->expr; a->rexpr = warg;
w->expr = (Node *) a; warg = (Node *) a;
} }
lfirst(args) = transformExpr(pstate, (Node *) w, precedence); neww->expr = transformExpr(pstate, warg, precedence);
typeids = lappendi(typeids, exprType(w->result));
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 * It's not shorthand anymore, so drop the implicit
* argument. This is necessary to keep the executor from * argument. This is necessary to keep any re-application
* seeing an untransformed expression... not to mention * of transformExpr from doing the wrong thing.
* keeping a re-application of transformExpr from doing
* the wrong thing.
*/ */
c->arg = NULL; newc->arg = NULL;
/* transform the default clause */ /* transform the default clause */
if (c->defresult == NULL) defresult = c->defresult;
if (defresult == NULL)
{ {
A_Const *n = makeNode(A_Const); A_Const *n = makeNode(A_Const);
n->val.type = T_Null; 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 * 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 * code worked before, but it seems a little bogus to me
* --- tgl * --- tgl
*/ */
typeids = lconsi(exprType(c->defresult), typeids); typeids = lconsi(exprType(newc->defresult), typeids);
ptype = select_common_type(typeids, "CASE"); ptype = select_common_type(typeids, "CASE");
c->casetype = ptype; newc->casetype = ptype;
/* Convert default result clause, if necessary */ /* Convert default result clause, if necessary */
c->defresult = coerce_to_common_type(pstate, c->defresult, newc->defresult = coerce_to_common_type(pstate,
ptype, "CASE/ELSE"); newc->defresult,
ptype,
"CASE/ELSE");
/* Convert when-clause results, if necessary */ /* Convert when-clause results, if necessary */
foreach(args, c->args) foreach(args, newc->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)
{ {
A_Const *n = makeNode(A_Const); CaseWhen *w = (CaseWhen *) lfirst(args);
n->val.type = T_Null; w->result = coerce_to_common_type(pstate,
w->result = (Node *) n; w->result,
ptype,
"CASE/WHEN");
} }
w->result = transformExpr(pstate, w->result, precedence);
result = expr; result = (Node *) newc;
break; break;
} }

Loading…
Cancel
Save