If a RowExpr is marked as returning a named composite type, we aren't
going to consult its colnames list; we'll use the attribute names
shown for the type in pg_attribute. Hence, skip storing that list,
to save a few nanoseconds when copying the expression tree around.
Discussion: https://postgr.es/m/
2950001.
1638729947@sss.pgh.pa.us
* 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. Either way, attach column names to the
- * RowExpr for use of ruleutils.c.
+ * omit dropped columns. In the latter case, attach column names to
+ * the RowExpr for use of the executor and ruleutils.c.
*
* In order to be able to cache the results, we always generate the
* expansion with varlevelsup = 0, and then adjust if needed.
rowexpr->args = fields;
rowexpr->row_typeid = var->vartype;
rowexpr->row_format = COERCE_IMPLICIT_CAST;
- rowexpr->colnames = colnames;
+ rowexpr->colnames = (var->vartype == RECORDOID) ? colnames : NIL;
rowexpr->location = var->location;
newnode = (Node *) rowexpr;
rowexpr->args = fields;
rowexpr->row_typeid = var->vartype;
rowexpr->row_format = COERCE_IMPLICIT_CAST;
+ /* vartype will always be RECORDOID, so we always need colnames */
rowexpr->colnames = colnames;
rowexpr->location = var->location;
* 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. Either way, attach column names to the
- * RowExpr for use of ruleutils.c.
+ * omit dropped columns. In the latter case, attach column names to
+ * the RowExpr for use of the executor and ruleutils.c.
*/
expandRTE(rcon->target_rte,
var->varno, var->varlevelsup, var->location,
rowexpr->args = fields;
rowexpr->row_typeid = var->vartype;
rowexpr->row_format = COERCE_IMPLICIT_CAST;
- rowexpr->colnames = colnames;
+ rowexpr->colnames = (var->vartype == RECORDOID) ? colnames : NIL;
rowexpr->location = var->location;
return (Node *) rowexpr;
* 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 provides field names in cases where the names can't easily be
- * obtained otherwise. Names *must* be provided if row_typeid is RECORDOID.
- * If row_typeid identifies a known composite type, colnames can be NIL to
- * indicate the type's cataloged field names apply. Note that colnames can
- * be non-NIL even for a composite type, and typically is when the RowExpr
- * was created by expanding a whole-row Var. This is so that we can 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, colnames is one-for-one with physical fields of the rowtype.
+ * colnames provides field names if the ROW() result is of type RECORD.
+ * Names *must* be provided if row_typeid is RECORDOID; but if it is a
+ * named composite type, colnames will be ignored in favor of using the
+ * type's cataloged field names, so colnames should be NIL. Like the
+ * args list, colnames is defined to be one-for-one with physical fields
+ * of the rowtype (although dropped columns shouldn't appear in the
+ * RECORD case, so this fine point is currently moot).
*/
typedef struct RowExpr
{