diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 36bf1dc92bb..3b54e3d80ce 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -2303,10 +2303,10 @@ _copyRangeTblEntry(const RangeTblEntry *from) COPY_STRING_FIELD(ctename); COPY_SCALAR_FIELD(ctelevelsup); COPY_SCALAR_FIELD(self_reference); - COPY_STRING_FIELD(enrname); COPY_NODE_FIELD(coltypes); COPY_NODE_FIELD(coltypmods); COPY_NODE_FIELD(colcollations); + COPY_STRING_FIELD(enrname); COPY_NODE_FIELD(alias); COPY_NODE_FIELD(eref); COPY_SCALAR_FIELD(lateral); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 5bcf0317dc8..696cd6e7e1b 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -2631,6 +2631,7 @@ _equalRangeTblEntry(const RangeTblEntry *a, const RangeTblEntry *b) COMPARE_NODE_FIELD(coltypes); COMPARE_NODE_FIELD(coltypmods); COMPARE_NODE_FIELD(colcollations); + COMPARE_STRING_FIELD(enrname); COMPARE_NODE_FIELD(alias); COMPARE_NODE_FIELD(eref); COMPARE_SCALAR_FIELD(lateral); diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index f062c6b9f1e..781cdf8ff99 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -4777,14 +4777,12 @@ set_namedtuplestore_size_estimates(PlannerInfo *root, RelOptInfo *rel) Assert(rte->rtekind == RTE_NAMEDTUPLESTORE); /* - * Use the estimate provided by the code which is generating the named - * tuplestore. In some cases, the actual number might be available; in - * others the same plan will be re-used, so a "typical" value might be - * estimated and used. + * XXX We could use the estimate provided by the code which is generating + * the named tuplestore in EphemeralNamedRelationMetadataData member + * 'enrtuples'. We don't have access to QueryEnvironment to look it up + * from here yet, so for now we'll use a bogus default estimate. */ - rel->tuples = rte->enrtuples; - if (rel->tuples < 0) - rel->tuples = 1000; + rel->tuples = 1000; /* Now estimate number of output rows, etc */ set_baserel_size_estimates(root, rel); diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index e412d0f9d30..f99e547745c 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -2020,7 +2020,6 @@ addRangeTableEntryForENR(ParseState *pstate, rte->eref = makeAlias(refname, NIL); buildRelationAliases(tupdesc, alias, rte->eref); rte->enrname = enrmd->name; - rte->enrtuples = enrmd->enrtuples; rte->coltypes = NIL; rte->coltypmods = NIL; rte->colcollations = NIL; diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 2d2e2c0fbc1..8be5c3a9c09 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -944,6 +944,11 @@ typedef struct RangeTblEntry /* * Fields valid for a plain relation RTE (else zero): + * + * As a special case, RTE_NAMEDTUPLESTORE can also set relid to indicate + * that the tuple format of the tuplestore is the same as the referenced + * relation. This allows plans referencing AFTER trigger transition + * tables to be invalidated if the underlying table is altered. */ Oid relid; /* OID of the relation */ char relkind; /* relation kind (see pg_class.relkind) */ @@ -1004,18 +1009,24 @@ typedef struct RangeTblEntry bool self_reference; /* is this a recursive self-reference? */ /* - * Fields valid for values and CTE RTEs (else NIL): + * Fields valid for table functions, values, CTE and ENR RTEs (else NIL): * * We need these for CTE RTEs so that the types of self-referential * columns are well-defined. For VALUES RTEs, storing these explicitly * saves having to re-determine the info by scanning the values_lists. + * For ENRs, we store the types explicitly here (we could get the + * information 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 info here). */ List *coltypes; /* OID list of column type OIDs */ List *coltypmods; /* integer list of column typmods */ List *colcollations; /* OID list of column collation OIDs */ + /* + * Fields valid for ENR RTEs (else NULL/zero): + */ char *enrname; /* name of ephemeral named relation */ - double enrtuples; /* estimated or actual from caller */ /* * Fields valid in all RTEs: diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out index 7ebbde60d30..66a9c9fc0c8 100644 --- a/src/test/regress/expected/plpgsql.out +++ b/src/test/regress/expected/plpgsql.out @@ -5757,13 +5757,17 @@ CREATE TRIGGER transition_table_base_upd_trig UPDATE transition_table_base SET val = '*' || val || '*' WHERE id BETWEEN 2 AND 3; -INFO: Hash Full Join +INFO: Merge Full Join Output: COALESCE(ot.id, nt.id), ot.val, nt.val - Hash Cond: (ot.id = nt.id) - -> Named Tuplestore Scan + Merge Cond: (ot.id = nt.id) + -> Sort Output: ot.id, ot.val - -> Hash + Sort Key: ot.id + -> Named Tuplestore Scan + Output: ot.id, ot.val + -> Sort Output: nt.id, nt.val + Sort Key: nt.id -> Named Tuplestore Scan Output: nt.id, nt.val