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.
COPY_NODE_FIELD(args);
COPY_SCALAR_FIELD(row_typeid);
COPY_SCALAR_FIELD(row_format);
+ COPY_NODE_FIELD(colnames);
COPY_LOCATION_FIELD(location);
return newnode;
b->row_format != COERCE_DONTCARE)
return false;
+ COMPARE_NODE_FIELD(colnames);
COMPARE_LOCATION_FIELD(location);
return true;
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:
{
FLATCOPY(newnode, rowexpr, RowExpr);
MUTATE(newnode->args, rowexpr->args, List *);
+ /* Assume colnames needn't be duplicated */
return (Node *) newnode;
}
break;
}
break;
case T_RowExpr:
+ /* Assume colnames isn't interesting */
return walker(((RowExpr *) node)->args, context);
case T_CoalesceExpr:
return walker(((CoalesceExpr *) node)->args, context);
WRITE_NODE_FIELD(args);
WRITE_OID_FIELD(row_typeid);
WRITE_ENUM_FIELD(row_format, CoercionForm);
+ WRITE_NODE_FIELD(colnames);
WRITE_LOCATION_FIELD(location);
}
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();
rowexpr->args = fields;
rowexpr->row_typeid = var->vartype;
rowexpr->row_format = COERCE_IMPLICIT_CAST;
+ rowexpr->colnames = NIL;
rowexpr->location = -1;
return (Node *) rowexpr;
rowexpr->args = fields;
rowexpr->row_typeid = var->vartype;
rowexpr->row_format = COERCE_IMPLICIT_CAST;
+ rowexpr->colnames = NIL;
rowexpr->location = -1;
return (Node *) rowexpr;
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;
}
/* 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;
{
/* 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);
rowexpr->args = fields;
rowexpr->row_typeid = var->vartype;
rowexpr->row_format = COERCE_IMPLICIT_CAST;
+ rowexpr->colnames = colnames;
rowexpr->location = -1;
return (Node *) rowexpr;
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
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200810062
+#define CATALOG_VERSION_NO 200810063
#endif
* 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
{
* 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;