From bf461538e18b67ec05d89846fcf15fa9c0cb9a74 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 6 Oct 2008 17:39:26 +0000 Subject: [PATCH] When expanding a whole-row Var into a RowExpr during ResolveNew(), attach 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. --- src/backend/nodes/copyfuncs.c | 3 ++- src/backend/nodes/equalfuncs.c | 3 ++- src/backend/nodes/nodeFuncs.c | 5 ++++- src/backend/nodes/outfuncs.c | 3 ++- src/backend/nodes/readfuncs.c | 3 ++- src/backend/optimizer/prep/prepunion.c | 3 ++- src/backend/optimizer/util/var.c | 3 ++- src/backend/parser/parse_coerce.c | 3 ++- src/backend/parser/parse_expr.c | 3 ++- src/backend/rewrite/rewriteManip.c | 9 ++++++--- src/backend/utils/adt/ruleutils.c | 14 +++++++++++++- src/include/catalog/catversion.h | 4 ++-- src/include/nodes/primnodes.h | 9 ++++++++- 13 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 57ef558c40..1e7eb605f5 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.406 2008/10/04 21:56:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.407 2008/10/06 17:39:25 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index f01ebe33e8..96eec16ebc 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -22,7 +22,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.332 2008/10/04 21:56:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.333 2008/10/06 17:39:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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; diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index 0127c6e14b..baf98b6763 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/nodeFuncs.c,v 1.33 2008/10/04 21:56:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/nodeFuncs.c,v 1.34 2008/10/06 17:39:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 6d39a51a98..b25ef4b577 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.340 2008/10/04 21:56:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.341 2008/10/06 17:39:26 tgl Exp $ * * NOTES * Every node type that can appear in stored rules' parsetrees *must* @@ -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); } diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 3f7ce455df..d48715d36b 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.215 2008/10/04 21:56:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.216 2008/10/06 17:39:26 tgl Exp $ * * NOTES * Path and Plan nodes do not have any readfuncs support, because we @@ -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(); diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 0836fde517..e8b7850947 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -22,7 +22,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.156 2008/10/04 21:56:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.157 2008/10/06 17:39:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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; diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index 748a3cb93a..2e23091396 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.79 2008/09/01 20:42:44 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.80 2008/10/06 17:39:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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; diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 86e47661aa..69efaddfec 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.167 2008/09/10 18:29:40 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.168 2008/10/06 17:39:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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; } diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 1091d87473..ddd041818a 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.234 2008/09/01 20:42:44 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.235 2008/10/06 17:39:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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; diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c index b5d82dd0e7..2a9645bf42 100644 --- a/src/backend/rewrite/rewriteManip.c +++ b/src/backend/rewrite/rewriteManip.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.114 2008/10/04 21:56:54 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.115 2008/10/06 17:39:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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; diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index fd21152b49..72b7e3c3d8 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.285 2008/10/04 21:56:54 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.286 2008/10/06 17:39:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index cdd9fa272e..3f27787992 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.495 2008/10/06 14:13:17 heikki Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.496 2008/10/06 17:39:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200810062 +#define CATALOG_VERSION_NO 200810063 #endif diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index e8614492fe..2a2ea18520 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -10,7 +10,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.142 2008/10/04 21:56:55 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.143 2008/10/06 17:39:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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; -- GitLab