When expanding a whole-row Var into a RowExpr during ResolveNew(), attach
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 6 Oct 2008 17:39:26 +0000 (17:39 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 6 Oct 2008 17:39:26 +0000 (17:39 +0000)
the column alias names of the RTE referenced by the Var to the RowExpr.
This is needed to allow ruleutils.c to correctly deparse FieldSelect nodes
referencing such a construct.  Per my recent bug report.

Adding a field to RowExpr forces initdb (because of stored rules changes)
so this solution is not back-patchable; which is unfortunate because 8.2
and 8.3 have this issue.  But it only affects EXPLAIN for some pretty odd
corner cases, so we can probably live without a solution for the back
branches.

13 files changed:
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/nodeFuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/prep/prepunion.c
src/backend/optimizer/util/var.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_expr.c
src/backend/rewrite/rewriteManip.c
src/backend/utils/adt/ruleutils.c
src/include/catalog/catversion.h
src/include/nodes/primnodes.h

index bb5072118f68442ac4d3afb2d5c92fb180aef9ef..aaa6c1463e960f23c1ecde4a543f9e993d70347f 100644 (file)
@@ -1257,6 +1257,7 @@ _copyRowExpr(RowExpr *from)
        COPY_NODE_FIELD(args);
        COPY_SCALAR_FIELD(row_typeid);
        COPY_SCALAR_FIELD(row_format);
+       COPY_NODE_FIELD(colnames);
        COPY_LOCATION_FIELD(location);
 
        return newnode;
index 7385fd52c4a7acaae3e316f690072fee72d42c6a..2fe31ee976fcdd08587dc5ac513f8ac1b3d6faa6 100644 (file)
@@ -511,6 +511,7 @@ _equalRowExpr(RowExpr *a, RowExpr *b)
                b->row_format != COERCE_DONTCARE)
                return false;
 
+       COMPARE_NODE_FIELD(colnames);
        COMPARE_LOCATION_FIELD(location);
 
        return true;
index da8d4fd00df74529f90c8ec8351e1a2105c6e532..62957c347471fa0067118c38a40f7777d74a70ea 100644 (file)
@@ -1172,6 +1172,7 @@ expression_tree_walker(Node *node,
                case T_ArrayExpr:
                        return walker(((ArrayExpr *) node)->elements, context);
                case T_RowExpr:
+                       /* Assume colnames isn't interesting */
                        return walker(((RowExpr *) node)->args, context);
                case T_RowCompareExpr:
                        {
@@ -1735,6 +1736,7 @@ expression_tree_mutator(Node *node,
 
                                FLATCOPY(newnode, rowexpr, RowExpr);
                                MUTATE(newnode->args, rowexpr->args, List *);
+                               /* Assume colnames needn't be duplicated */
                                return (Node *) newnode;
                        }
                        break;
@@ -2174,6 +2176,7 @@ raw_expression_tree_walker(Node *node, bool (*walker) (), void *context)
                        }
                        break;
                case T_RowExpr:
+                       /* Assume colnames isn't interesting */
                        return walker(((RowExpr *) node)->args, context);
                case T_CoalesceExpr:
                        return walker(((CoalesceExpr *) node)->args, context);
index 948741652934572234d5d5225deeb86c2a5a53ca..c859535aecca0c9eb75040b70889d87bbacf69be 100644 (file)
@@ -1037,6 +1037,7 @@ _outRowExpr(StringInfo str, RowExpr *node)
        WRITE_NODE_FIELD(args);
        WRITE_OID_FIELD(row_typeid);
        WRITE_ENUM_FIELD(row_format, CoercionForm);
+       WRITE_NODE_FIELD(colnames);
        WRITE_LOCATION_FIELD(location);
 }
 
index 531665ecd9104915d336343148def98510eb851c..a66087e6108629734a80d9d94a3b9721d7ba9bc4 100644 (file)
@@ -744,6 +744,7 @@ _readRowExpr(void)
        READ_NODE_FIELD(args);
        READ_OID_FIELD(row_typeid);
        READ_ENUM_FIELD(row_format, CoercionForm);
+       READ_NODE_FIELD(colnames);
        READ_LOCATION_FIELD(location);
 
        READ_DONE();
index 840d28bad2eb0fa5ba0b3dd107353b388e83f927..842465c4fb411a4d9dcf4ca5783bf61cfa867608 100644 (file)
@@ -1493,6 +1493,7 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context)
                                        rowexpr->args = fields;
                                        rowexpr->row_typeid = var->vartype;
                                        rowexpr->row_format = COERCE_IMPLICIT_CAST;
+                                       rowexpr->colnames = NIL;
                                        rowexpr->location = -1;
 
                                        return (Node *) rowexpr;
index 99e6cb6b097ab6b0402ad697b8958e720b91260e..de1bd4e637acb4dca03085c1e5dc7d6767306968 100644 (file)
@@ -663,6 +663,7 @@ flatten_join_alias_vars_mutator(Node *node,
                        rowexpr->args = fields;
                        rowexpr->row_typeid = var->vartype;
                        rowexpr->row_format = COERCE_IMPLICIT_CAST;
+                       rowexpr->colnames = NIL;
                        rowexpr->location = -1;
 
                        return (Node *) rowexpr;
index feb9d10f741db62bf776acaf3b8454edde7440ac..70a09bf2404052e44a9d96174630e784e455827e 100644 (file)
@@ -926,6 +926,7 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
        rowexpr->args = newargs;
        rowexpr->row_typeid = targetTypeId;
        rowexpr->row_format = cformat;
+       rowexpr->colnames = NIL;        /* not needed for named target type */
        rowexpr->location = location;
        return (Node *) rowexpr;
 }
index f822ed494eeeccb11b6949e039ed28edac5ac951..f750f809a64a356f35f0104c5c3e722870553286 100644 (file)
@@ -1534,6 +1534,7 @@ transformRowExpr(ParseState *pstate, RowExpr *r)
        /* Barring later casting, we consider the type RECORD */
        newr->row_typeid = RECORDOID;
        newr->row_format = COERCE_IMPLICIT_CAST;
+       newr->colnames = NIL;           /* ROW() has anonymous columns */
        newr->location = r->location;
 
        return (Node *) newr;
index 75735c4bca13c67471f47ae4a8233834bca87463..89159b65b6d49608d7032982bf361e4fbeec1bd8 100644 (file)
@@ -1057,18 +1057,20 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context)
                        {
                                /* Must expand whole-tuple reference into RowExpr */
                                RowExpr    *rowexpr;
+                               List       *colnames;
                                List       *fields;
 
                                /*
                                 * If generating an expansion for a var of a named rowtype
                                 * (ie, this is a plain relation RTE), then we must include
                                 * dummy items for dropped columns.  If the var is RECORD (ie,
-                                * this is a JOIN), then omit dropped columns.
+                                * this is a JOIN), then omit dropped columns.  Either way,
+                                * attach column names to the RowExpr for use of ruleutils.c.
                                 */
                                expandRTE(context->target_rte,
                                                  this_varno, this_varlevelsup, var->location,
                                                  (var->vartype != RECORDOID),
-                                                 NULL, &fields);
+                                                 &colnames, &fields);
                                /* Adjust the generated per-field Vars... */
                                fields = (List *) ResolveNew_mutator((Node *) fields,
                                                                                                         context);
@@ -1076,6 +1078,7 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context)
                                rowexpr->args = fields;
                                rowexpr->row_typeid = var->vartype;
                                rowexpr->row_format = COERCE_IMPLICIT_CAST;
+                               rowexpr->colnames = colnames;
                                rowexpr->location = -1;
 
                                return (Node *) rowexpr;
index f756b786d9e4662f80ab3faa2c629f7c6d659d6b..d962822bf860cdde1f2d8eb7cbaa7f223676d9d2 100644 (file)
@@ -3236,6 +3236,18 @@ get_name_for_var_field(Var *var, int fieldno,
        TupleDesc       tupleDesc;
        Node       *expr;
 
+       /*
+        * If it's a RowExpr that was expanded from a whole-row Var, use the
+        * column names attached to it.
+        */
+       if (IsA(var, RowExpr))
+       {
+               RowExpr    *r = (RowExpr *) var;
+
+               if (fieldno > 0 && fieldno <= list_length(r->colnames))
+                       return strVal(list_nth(r->colnames, fieldno - 1));
+       }
+
        /*
         * If it's a Var of type RECORD, we have to find what the Var refers to;
         * if not, we can use get_expr_result_type. If that fails, we try
index 8eb31ff37cdd7e70df099c5d65def8d7c74ff452..8d2d759e13880b91abcbc8486be170482e9f5f73 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200810062
+#define CATALOG_VERSION_NO     200810063
 
 #endif
index 67f651218256d1fa26788f46bd1b189c915fa9f6..e5637bef430f51653f6532f8935556f0e5ac2330 100644 (file)
@@ -740,6 +740,12 @@ typedef struct ArrayExpr
  * not RECORD types, since those are built from the RowExpr itself rather
  * than vice versa.)  It is important not to assume that length(args) is
  * the same as the number of columns logically present in the rowtype.
+ *
+ * colnames is NIL in a RowExpr built from an ordinary ROW() expression.
+ * It is provided in cases where we expand a whole-row Var into a RowExpr,
+ * to retain the column alias names of the RTE that the Var referenced
+ * (which would otherwise be very difficult to extract from the parsetree).
+ * Like the args list, it is one-for-one with physical fields of the rowtype.
  */
 typedef struct RowExpr
 {
@@ -754,6 +760,7 @@ typedef struct RowExpr
         * parsetrees.  We must assume typmod -1 for a RowExpr node.
         */
        CoercionForm row_format;        /* how to display this node */
+       List       *colnames;           /* list of String, or NIL */
        int                     location;               /* token location, or -1 if unknown */
 } RowExpr;