aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/prep/prepunion.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2012-02-14 17:34:19 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2012-02-14 17:34:56 -0500
commit398f70ec070fe60151584eaa448f04708aa77892 (patch)
tree508ae6812ca581b5e39e11bb80206aa87e115046 /src/backend/optimizer/prep/prepunion.c
parentc1d9df4fa227781b31be44a5a3024865a7f48049 (diff)
downloadpostgresql-398f70ec070fe60151584eaa448f04708aa77892.tar.gz
postgresql-398f70ec070fe60151584eaa448f04708aa77892.zip
Preserve column names in the execution-time tupledesc for a RowExpr.
The hstore and json datatypes both have record-conversion functions that pay attention to column names in the composite values they're handed. We used to not worry about inserting correct field names into tuple descriptors generated at runtime, but given these examples it seems useful to do so. Observe the nicer-looking results in the regression tests whose results changed. catversion bump because there is a subtle change in requirements for stored rule parsetrees: RowExprs from ROW() constructs now have to include field names. Andrew Dunstan and Tom Lane
Diffstat (limited to 'src/backend/optimizer/prep/prepunion.c')
-rw-r--r--src/backend/optimizer/prep/prepunion.c98
1 files changed, 61 insertions, 37 deletions
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index cff5a865316..e361fb8ce96 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -49,6 +49,12 @@
#include "utils/selfuncs.h"
+typedef struct
+{
+ PlannerInfo *root;
+ AppendRelInfo *appinfo;
+} adjust_appendrel_attrs_context;
+
static Plan *recurse_set_operations(Node *setOp, PlannerInfo *root,
double tuple_fraction,
List *colTypes, List *colCollations,
@@ -99,7 +105,7 @@ static void make_inh_translation_list(Relation oldrelation,
static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
List *translated_vars);
static Node *adjust_appendrel_attrs_mutator(Node *node,
- AppendRelInfo *context);
+ adjust_appendrel_attrs_context *context);
static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid);
static List *adjust_inherited_tlist(List *tlist,
AppendRelInfo *context);
@@ -1569,9 +1575,13 @@ translate_col_privs(const Bitmapset *parent_privs,
* maybe we should try to fold the two routines together.
*/
Node *
-adjust_appendrel_attrs(Node *node, AppendRelInfo *appinfo)
+adjust_appendrel_attrs(PlannerInfo *root, Node *node, AppendRelInfo *appinfo)
{
Node *result;
+ adjust_appendrel_attrs_context context;
+
+ context.root = root;
+ context.appinfo = appinfo;
/*
* Must be prepared to start with a Query or a bare expression tree.
@@ -1582,7 +1592,7 @@ adjust_appendrel_attrs(Node *node, AppendRelInfo *appinfo)
newnode = query_tree_mutator((Query *) node,
adjust_appendrel_attrs_mutator,
- (void *) appinfo,
+ (void *) &context,
QTW_IGNORE_RC_SUBQUERIES);
if (newnode->resultRelation == appinfo->parent_relid)
{
@@ -1596,14 +1606,17 @@ adjust_appendrel_attrs(Node *node, AppendRelInfo *appinfo)
result = (Node *) newnode;
}
else
- result = adjust_appendrel_attrs_mutator(node, appinfo);
+ result = adjust_appendrel_attrs_mutator(node, &context);
return result;
}
static Node *
-adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context)
+adjust_appendrel_attrs_mutator(Node *node,
+ adjust_appendrel_attrs_context *context)
{
+ AppendRelInfo *appinfo = context->appinfo;
+
if (node == NULL)
return NULL;
if (IsA(node, Var))
@@ -1611,22 +1624,22 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context)
Var *var = (Var *) copyObject(node);
if (var->varlevelsup == 0 &&
- var->varno == context->parent_relid)
+ var->varno == appinfo->parent_relid)
{
- var->varno = context->child_relid;
- var->varnoold = context->child_relid;
+ var->varno = appinfo->child_relid;
+ var->varnoold = appinfo->child_relid;
if (var->varattno > 0)
{
Node *newnode;
- if (var->varattno > list_length(context->translated_vars))
+ if (var->varattno > list_length(appinfo->translated_vars))
elog(ERROR, "attribute %d of relation \"%s\" does not exist",
- var->varattno, get_rel_name(context->parent_reloid));
- newnode = copyObject(list_nth(context->translated_vars,
+ var->varattno, get_rel_name(appinfo->parent_reloid));
+ newnode = copyObject(list_nth(appinfo->translated_vars,
var->varattno - 1));
if (newnode == NULL)
elog(ERROR, "attribute %d of relation \"%s\" does not exist",
- var->varattno, get_rel_name(context->parent_reloid));
+ var->varattno, get_rel_name(appinfo->parent_reloid));
return newnode;
}
else if (var->varattno == 0)
@@ -1637,19 +1650,19 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context)
* step to convert the tuple layout to the parent's rowtype.
* Otherwise we have to generate a RowExpr.
*/
- if (OidIsValid(context->child_reltype))
+ if (OidIsValid(appinfo->child_reltype))
{
- Assert(var->vartype == context->parent_reltype);
- if (context->parent_reltype != context->child_reltype)
+ Assert(var->vartype == appinfo->parent_reltype);
+ if (appinfo->parent_reltype != appinfo->child_reltype)
{
ConvertRowtypeExpr *r = makeNode(ConvertRowtypeExpr);
r->arg = (Expr *) var;
- r->resulttype = context->parent_reltype;
+ r->resulttype = appinfo->parent_reltype;
r->convertformat = COERCE_IMPLICIT_CAST;
r->location = -1;
/* Make sure the Var node has the right type ID, too */
- var->vartype = context->child_reltype;
+ var->vartype = appinfo->child_reltype;
return (Node *) r;
}
}
@@ -1657,16 +1670,27 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context)
{
/*
* Build a RowExpr containing the translated variables.
+ *
+ * In practice var->vartype will always be RECORDOID here,
+ * so we need to come up with some suitable column names.
+ * We use the parent RTE's column names.
+ *
+ * Note: we can't get here for inheritance cases, so there
+ * is no need to worry that translated_vars might contain
+ * some dummy NULLs.
*/
RowExpr *rowexpr;
List *fields;
+ RangeTblEntry *rte;
- fields = (List *) copyObject(context->translated_vars);
+ rte = rt_fetch(appinfo->parent_relid,
+ context->root->parse->rtable);
+ fields = (List *) copyObject(appinfo->translated_vars);
rowexpr = makeNode(RowExpr);
rowexpr->args = fields;
rowexpr->row_typeid = var->vartype;
rowexpr->row_format = COERCE_IMPLICIT_CAST;
- rowexpr->colnames = NIL;
+ rowexpr->colnames = copyObject(rte->eref->colnames);
rowexpr->location = -1;
return (Node *) rowexpr;
@@ -1680,16 +1704,16 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context)
{
CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
- if (cexpr->cvarno == context->parent_relid)
- cexpr->cvarno = context->child_relid;
+ if (cexpr->cvarno == appinfo->parent_relid)
+ cexpr->cvarno = appinfo->child_relid;
return (Node *) cexpr;
}
if (IsA(node, RangeTblRef))
{
RangeTblRef *rtr = (RangeTblRef *) copyObject(node);
- if (rtr->rtindex == context->parent_relid)
- rtr->rtindex = context->child_relid;
+ if (rtr->rtindex == appinfo->parent_relid)
+ rtr->rtindex = appinfo->child_relid;
return (Node *) rtr;
}
if (IsA(node, JoinExpr))
@@ -1701,8 +1725,8 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context)
adjust_appendrel_attrs_mutator,
(void *) context);
/* now fix JoinExpr's rtindex (probably never happens) */
- if (j->rtindex == context->parent_relid)
- j->rtindex = context->child_relid;
+ if (j->rtindex == appinfo->parent_relid)
+ j->rtindex = appinfo->child_relid;
return (Node *) j;
}
if (IsA(node, PlaceHolderVar))
@@ -1716,8 +1740,8 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context)
/* now fix PlaceHolderVar's relid sets */
if (phv->phlevelsup == 0)
phv->phrels = adjust_relid_set(phv->phrels,
- context->parent_relid,
- context->child_relid);
+ appinfo->parent_relid,
+ appinfo->child_relid);
return (Node *) phv;
}
/* Shouldn't need to handle planner auxiliary nodes here */
@@ -1749,20 +1773,20 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context)
/* adjust relid sets too */
newinfo->clause_relids = adjust_relid_set(oldinfo->clause_relids,
- context->parent_relid,
- context->child_relid);
+ appinfo->parent_relid,
+ appinfo->child_relid);
newinfo->required_relids = adjust_relid_set(oldinfo->required_relids,
- context->parent_relid,
- context->child_relid);
+ appinfo->parent_relid,
+ appinfo->child_relid);
newinfo->nullable_relids = adjust_relid_set(oldinfo->nullable_relids,
- context->parent_relid,
- context->child_relid);
+ appinfo->parent_relid,
+ appinfo->child_relid);
newinfo->left_relids = adjust_relid_set(oldinfo->left_relids,
- context->parent_relid,
- context->child_relid);
+ appinfo->parent_relid,
+ appinfo->child_relid);
newinfo->right_relids = adjust_relid_set(oldinfo->right_relids,
- context->parent_relid,
- context->child_relid);
+ appinfo->parent_relid,
+ appinfo->child_relid);
/*
* Reset cached derivative fields, since these might need to have