Commit 8689e382 authored by Tom Lane's avatar Tom Lane

Clean up handling of dropped columns in NAMEDTUPLESTORE RTEs.

The NAMEDTUPLESTORE patch piggybacked on the infrastructure for
TABLEFUNC/VALUES/CTE RTEs, none of which can ever have dropped columns,
so the possibility was ignored most places.  Fix that, including adding a
specification to parsenodes.h about what it's supposed to look like.

In passing, clean up assorted comments that hadn't been maintained
properly by said patch.

Per bug #14799 from Philippe Beaudoin.  Back-patch to v10.

Discussion: https://postgr.es/m/20170906120005.25630.84360@wrigleys.postgresql.org
parent 0b554e4e
...@@ -178,8 +178,8 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent) ...@@ -178,8 +178,8 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
case RTE_NAMEDTUPLESTORE: case RTE_NAMEDTUPLESTORE:
/* /*
* Subquery, function, tablefunc, or values list --- set up attr * Subquery, function, tablefunc, values list, CTE, or ENR --- set
* range and arrays * up attr range and arrays
* *
* Note: 0 is included in range to support whole-row Vars * Note: 0 is included in range to support whole-row Vars
*/ */
......
...@@ -2014,11 +2014,13 @@ addRangeTableEntryForENR(ParseState *pstate, ...@@ -2014,11 +2014,13 @@ addRangeTableEntryForENR(ParseState *pstate,
/* /*
* Build the list of effective column names using user-supplied aliases * Build the list of effective column names using user-supplied aliases
* and/or actual column names. Also build the cannibalized fields. * and/or actual column names.
*/ */
tupdesc = ENRMetadataGetTupDesc(enrmd); tupdesc = ENRMetadataGetTupDesc(enrmd);
rte->eref = makeAlias(refname, NIL); rte->eref = makeAlias(refname, NIL);
buildRelationAliases(tupdesc, alias, rte->eref); buildRelationAliases(tupdesc, alias, rte->eref);
/* Record additional data for ENR, including column type info */
rte->enrname = enrmd->name; rte->enrname = enrmd->name;
rte->enrtuples = enrmd->enrtuples; rte->enrtuples = enrmd->enrtuples;
rte->coltypes = NIL; rte->coltypes = NIL;
...@@ -2028,16 +2030,24 @@ addRangeTableEntryForENR(ParseState *pstate, ...@@ -2028,16 +2030,24 @@ addRangeTableEntryForENR(ParseState *pstate,
{ {
Form_pg_attribute att = TupleDescAttr(tupdesc, attno - 1); Form_pg_attribute att = TupleDescAttr(tupdesc, attno - 1);
if (att->atttypid == InvalidOid && if (att->attisdropped)
!(att->attisdropped)) {
elog(ERROR, "atttypid was invalid for column which has not been dropped from \"%s\"", /* Record zeroes for a dropped column */
rte->coltypes = lappend_oid(rte->coltypes, InvalidOid);
rte->coltypmods = lappend_int(rte->coltypmods, 0);
rte->colcollations = lappend_oid(rte->colcollations, InvalidOid);
}
else
{
/* Let's just make sure we can tell this isn't dropped */
if (att->atttypid == InvalidOid)
elog(ERROR, "atttypid is invalid for non-dropped column in \"%s\"",
rv->relname); rv->relname);
rte->coltypes = rte->coltypes = lappend_oid(rte->coltypes, att->atttypid);
lappend_oid(rte->coltypes, att->atttypid); rte->coltypmods = lappend_int(rte->coltypmods, att->atttypmod);
rte->coltypmods = rte->colcollations = lappend_oid(rte->colcollations,
lappend_int(rte->coltypmods, att->atttypmod); att->attcollation);
rte->colcollations = }
lappend_oid(rte->colcollations, att->attcollation);
} }
/* /*
...@@ -2416,7 +2426,7 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, ...@@ -2416,7 +2426,7 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
case RTE_CTE: case RTE_CTE:
case RTE_NAMEDTUPLESTORE: case RTE_NAMEDTUPLESTORE:
{ {
/* Tablefunc, Values or CTE RTE */ /* Tablefunc, Values, CTE, or ENR RTE */
ListCell *aliasp_item = list_head(rte->eref->colnames); ListCell *aliasp_item = list_head(rte->eref->colnames);
ListCell *lct; ListCell *lct;
ListCell *lcm; ListCell *lcm;
...@@ -2436,14 +2446,23 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, ...@@ -2436,14 +2446,23 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
if (colnames) if (colnames)
{ {
/* Assume there is one alias per output column */ /* Assume there is one alias per output column */
if (OidIsValid(coltype))
{
char *label = strVal(lfirst(aliasp_item)); char *label = strVal(lfirst(aliasp_item));
*colnames = lappend(*colnames, *colnames = lappend(*colnames,
makeString(pstrdup(label))); makeString(pstrdup(label)));
}
else if (include_dropped)
*colnames = lappend(*colnames,
makeString(pstrdup("")));
aliasp_item = lnext(aliasp_item); aliasp_item = lnext(aliasp_item);
} }
if (colvars) if (colvars)
{
if (OidIsValid(coltype))
{ {
Var *varnode; Var *varnode;
...@@ -2454,6 +2473,17 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, ...@@ -2454,6 +2473,17 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
*colvars = lappend(*colvars, varnode); *colvars = lappend(*colvars, varnode);
} }
else if (include_dropped)
{
/*
* It doesn't really matter what type the Const
* claims to be.
*/
*colvars = lappend(*colvars,
makeNullConst(INT4OID, -1,
InvalidOid));
}
}
} }
} }
break; break;
...@@ -2831,13 +2861,21 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum, ...@@ -2831,13 +2861,21 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
case RTE_NAMEDTUPLESTORE: case RTE_NAMEDTUPLESTORE:
{ {
/* /*
* tablefunc, VALUES or CTE RTE --- get type info from lists * tablefunc, VALUES, CTE, or ENR RTE --- get type info from
* in the RTE * lists in the RTE
*/ */
Assert(attnum > 0 && attnum <= list_length(rte->coltypes)); Assert(attnum > 0 && attnum <= list_length(rte->coltypes));
*vartype = list_nth_oid(rte->coltypes, attnum - 1); *vartype = list_nth_oid(rte->coltypes, attnum - 1);
*vartypmod = list_nth_int(rte->coltypmods, attnum - 1); *vartypmod = list_nth_int(rte->coltypmods, attnum - 1);
*varcollid = list_nth_oid(rte->colcollations, attnum - 1); *varcollid = list_nth_oid(rte->colcollations, attnum - 1);
/* For ENR, better check for dropped column */
if (!OidIsValid(*vartype))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column %d of relation \"%s\" does not exist",
attnum,
rte->eref->aliasname)));
} }
break; break;
default: default:
...@@ -2888,15 +2926,11 @@ get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum) ...@@ -2888,15 +2926,11 @@ get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum)
break; break;
case RTE_NAMEDTUPLESTORE: case RTE_NAMEDTUPLESTORE:
{ {
Assert(rte->enrname); /* Check dropped-ness by testing for valid coltype */
if (attnum <= 0 ||
/* attnum > list_length(rte->coltypes))
* We checked when we loaded coltypes for the tuplestore that elog(ERROR, "invalid varattno %d", attnum);
* InvalidOid was only used for dropped columns, so it is safe result = !OidIsValid((list_nth_oid(rte->coltypes, attnum - 1)));
* to count on that here.
*/
result =
((list_nth_oid(rte->coltypes, attnum - 1) == InvalidOid));
} }
break; break;
case RTE_JOIN: case RTE_JOIN:
......
...@@ -1511,8 +1511,8 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup) ...@@ -1511,8 +1511,8 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
case RTE_NAMEDTUPLESTORE: case RTE_NAMEDTUPLESTORE:
/* /*
* This case should not occur: a column of a table or values list * This case should not occur: a column of a table, values list,
* shouldn't have type RECORD. Fall through and fail (most * or ENR shouldn't have type RECORD. Fall through and fail (most
* likely) at the bottom. * likely) at the bottom.
*/ */
break; break;
......
...@@ -6846,8 +6846,8 @@ get_name_for_var_field(Var *var, int fieldno, ...@@ -6846,8 +6846,8 @@ get_name_for_var_field(Var *var, int fieldno,
case RTE_NAMEDTUPLESTORE: case RTE_NAMEDTUPLESTORE:
/* /*
* This case should not occur: a column of a table or values list * This case should not occur: a column of a table, values list,
* shouldn't have type RECORD. Fall through and fail (most * or ENR shouldn't have type RECORD. Fall through and fail (most
* likely) at the bottom. * likely) at the bottom.
*/ */
break; break;
......
...@@ -1025,6 +1025,11 @@ typedef struct RangeTblEntry ...@@ -1025,6 +1025,11 @@ typedef struct RangeTblEntry
* from the catalogs if 'relid' was supplied, but we'd still need these * from the catalogs if 'relid' was supplied, but we'd still need these
* for TupleDesc-based ENRs, so we might as well always store the type * for TupleDesc-based ENRs, so we might as well always store the type
* info here). * info here).
*
* For ENRs only, we have to consider the possibility of dropped columns.
* A dropped column is included in these lists, but it will have zeroes in
* all three lists (as well as an empty-string entry in eref). Testing
* for zero coltype is the standard way to detect a dropped column.
*/ */
List *coltypes; /* OID list of column type OIDs */ List *coltypes; /* OID list of column type OIDs */
List *coltypmods; /* integer list of column typmods */ List *coltypmods; /* integer list of column typmods */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment