]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix transformExpr() to not scribble on its input datastructure while
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 8 Oct 2001 21:46:59 +0000 (21:46 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 8 Oct 2001 21:46:59 +0000 (21:46 +0000)
transforming CASE expressions.  This was definitely confusing
FigureColname, and might lead to bad things elsewhere as well.

src/backend/parser/parse_expr.c

index d1512c61c0e61b43fd81a62cb3e5fe825f9842eb..5db1ab867fdddce85678578e8c358c8636a7551d 100644 (file)
@@ -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;
                        }