Avoid coercing a whole-row variable that is already coerced.
authorRobert Haas <rhaas@postgresql.org>
Thu, 12 Oct 2017 21:10:48 +0000 (17:10 -0400)
committerRobert Haas <rhaas@postgresql.org>
Thu, 12 Oct 2017 21:10:48 +0000 (17:10 -0400)
Marginal efficiency and beautification hack.  I'm not sure whether
this case ever arises currently, but the pending patch for update
tuple routing will cause it to arise.

Amit Khandekar

Discussion: http://postgr.es/m/CAJ3gD9cazfppe7-wwUbabPcQ4_0SubkiPFD1+0r5_DkVNWo5yg@mail.gmail.com

src/backend/rewrite/rewriteManip.c

index c5773efd19296d2562beb17dd8c18a1ff14e9739..9290c7f793600b621b929b5ea0462ca053053d56 100644 (file)
@@ -1224,6 +1224,7 @@ typedef struct
    /* Target type when converting whole-row vars */
    Oid         to_rowtype;
    bool       *found_whole_row;    /* output flag */
+   bool        coerced_var;    /* var is under ConvertRowTypeExpr */
 } map_variable_attnos_context;
 
 static Node *
@@ -1267,22 +1268,29 @@ map_variable_attnos_mutator(Node *node,
                    /* Don't convert unless necessary. */
                    if (context->to_rowtype != var->vartype)
                    {
-                       ConvertRowtypeExpr *r;
-
                        /* Var itself is converted to the requested type. */
                        newvar->vartype = context->to_rowtype;
 
                        /*
-                        * And a conversion node on top to convert back to the
-                        * original type.
+                        * If this var is already under a ConvertRowtypeExpr,
+                        * we don't have to add another one.
                         */
-                       r = makeNode(ConvertRowtypeExpr);
-                       r->arg = (Expr *) newvar;
-                       r->resulttype = var->vartype;
-                       r->convertformat = COERCE_IMPLICIT_CAST;
-                       r->location = -1;
-
-                       return (Node *) r;
+                       if (!context->coerced_var)
+                       {
+                           ConvertRowtypeExpr *r;
+
+                           /*
+                            * And a conversion node on top to convert back to
+                            * the original type.
+                            */
+                           r = makeNode(ConvertRowtypeExpr);
+                           r->arg = (Expr *) newvar;
+                           r->resulttype = var->vartype;
+                           r->convertformat = COERCE_IMPLICIT_CAST;
+                           r->location = -1;
+
+                           return (Node *) r;
+                       }
                    }
                }
            }
@@ -1290,6 +1298,28 @@ map_variable_attnos_mutator(Node *node,
        }
        /* otherwise fall through to copy the var normally */
    }
+   else if (IsA(node, ConvertRowtypeExpr))
+   {
+       ConvertRowtypeExpr *r = (ConvertRowtypeExpr *) node;
+
+       /*
+        * If this is coercing a var (which is typical), convert only the var,
+        * as against adding another ConvertRowtypeExpr over it.
+        */
+       if (IsA(r->arg, Var))
+       {
+           ConvertRowtypeExpr *newnode;
+
+           newnode = (ConvertRowtypeExpr *) palloc(sizeof(ConvertRowtypeExpr));
+           *newnode = *r;
+           context->coerced_var = true;
+           newnode->arg = (Expr *) map_variable_attnos_mutator((Node *) r->arg, context);
+           context->coerced_var = false;
+
+           return (Node *) newnode;
+       }
+       /* Else fall through the expression tree mutator */
+   }
    else if (IsA(node, Query))
    {
        /* Recurse into RTE subquery or not-yet-planned sublink subquery */
@@ -1321,6 +1351,7 @@ map_variable_attnos(Node *node,
    context.map_length = map_length;
    context.to_rowtype = to_rowtype;
    context.found_whole_row = found_whole_row;
+   context.coerced_var = false;
 
    *found_whole_row = false;