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.
This commit is contained in:
parent
1c7bef32b4
commit
71f2993c45
@ -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);
|
CaseWhen *w = (CaseWhen *) lfirst(args);
|
||||||
w->result = coerce_to_common_type(pstate, w->result,
|
|
||||||
ptype, "CASE/WHEN");
|
w->result = coerce_to_common_type(pstate,
|
||||||
|
w->result,
|
||||||
|
ptype,
|
||||||
|
"CASE/WHEN");
|
||||||
}
|
}
|
||||||
|
|
||||||
result = expr;
|
result = (Node *) newc;
|
||||||
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);
|
|
||||||
|
|
||||||
n->val.type = T_Null;
|
|
||||||
w->result = (Node *) n;
|
|
||||||
}
|
|
||||||
w->result = transformExpr(pstate, w->result, precedence);
|
|
||||||
result = expr;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user