summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2008-10-06 17:39:26 +0000
committerTom Lane2008-10-06 17:39:26 +0000
commitc0a1b283e78221a2486f3c6fc072c055b1ba53d6 (patch)
tree20de76f4ab062355ad6721aea03027a1cd1d6fd8
parentbb18feef1034e76e9a94822a1d3ea1974808dbc3 (diff)
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.
-rw-r--r--src/backend/nodes/copyfuncs.c1
-rw-r--r--src/backend/nodes/equalfuncs.c1
-rw-r--r--src/backend/nodes/nodeFuncs.c3
-rw-r--r--src/backend/nodes/outfuncs.c1
-rw-r--r--src/backend/nodes/readfuncs.c1
-rw-r--r--src/backend/optimizer/prep/prepunion.c1
-rw-r--r--src/backend/optimizer/util/var.c1
-rw-r--r--src/backend/parser/parse_coerce.c1
-rw-r--r--src/backend/parser/parse_expr.c1
-rw-r--r--src/backend/rewrite/rewriteManip.c7
-rw-r--r--src/backend/utils/adt/ruleutils.c12
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/nodes/primnodes.h7
13 files changed, 36 insertions, 3 deletions
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index bb5072118f..aaa6c1463e 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -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 7385fd52c4..2fe31ee976 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -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 da8d4fd00d..62957c3474 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -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 9487416529..c859535aec 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -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 531665ecd9..a66087e610 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -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 840d28bad2..842465c4fb 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -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 99e6cb6b09..de1bd4e637 100644
--- a/src/backend/optimizer/util/var.c
+++ b/src/backend/optimizer/util/var.c
@@ -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 feb9d10f74..70a09bf240 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -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 f822ed494e..f750f809a6 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -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 75735c4bca..89159b65b6 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -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 f756b786d9..d962822bf8 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3237,6 +3237,18 @@ get_name_for_var_field(Var *var, int fieldno,
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
* lookup_rowtype_tupdesc, which will probably fail too, but will ereport
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 8eb31ff37c..8d2d759e13 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -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 67f6512182..e5637bef43 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -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;