mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
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
This commit is contained in:
@ -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,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 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,
|
|||||||
{
|
{
|
||||||
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 */
|
||||||
rv->relname);
|
rte->coltypes = lappend_oid(rte->coltypes, InvalidOid);
|
||||||
rte->coltypes =
|
rte->coltypmods = lappend_int(rte->coltypmods, 0);
|
||||||
lappend_oid(rte->coltypes, att->atttypid);
|
rte->colcollations = lappend_oid(rte->colcollations, InvalidOid);
|
||||||
rte->coltypmods =
|
}
|
||||||
lappend_int(rte->coltypmods, att->atttypmod);
|
else
|
||||||
rte->colcollations =
|
{
|
||||||
lappend_oid(rte->colcollations, att->attcollation);
|
/* 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);
|
||||||
|
rte->coltypes = lappend_oid(rte->coltypes, att->atttypid);
|
||||||
|
rte->coltypmods = lappend_int(rte->coltypmods, att->atttypmod);
|
||||||
|
rte->colcollations = lappend_oid(rte->colcollations,
|
||||||
|
att->attcollation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -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,23 +2446,43 @@ 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 */
|
||||||
char *label = strVal(lfirst(aliasp_item));
|
if (OidIsValid(coltype))
|
||||||
|
{
|
||||||
|
char *label = strVal(lfirst(aliasp_item));
|
||||||
|
|
||||||
|
*colnames = lappend(*colnames,
|
||||||
|
makeString(pstrdup(label)));
|
||||||
|
}
|
||||||
|
else if (include_dropped)
|
||||||
|
*colnames = lappend(*colnames,
|
||||||
|
makeString(pstrdup("")));
|
||||||
|
|
||||||
*colnames = lappend(*colnames,
|
|
||||||
makeString(pstrdup(label)));
|
|
||||||
aliasp_item = lnext(aliasp_item);
|
aliasp_item = lnext(aliasp_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (colvars)
|
if (colvars)
|
||||||
{
|
{
|
||||||
Var *varnode;
|
if (OidIsValid(coltype))
|
||||||
|
{
|
||||||
|
Var *varnode;
|
||||||
|
|
||||||
varnode = makeVar(rtindex, varattno,
|
varnode = makeVar(rtindex, varattno,
|
||||||
coltype, coltypmod, colcoll,
|
coltype, coltypmod, colcoll,
|
||||||
sublevels_up);
|
sublevels_up);
|
||||||
varnode->location = location;
|
varnode->location = location;
|
||||||
|
|
||||||
*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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
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
|
|||||||
* 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 */
|
||||||
|
Reference in New Issue
Block a user