diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 11 | ||||
-rw-r--r-- | src/backend/parser/parse_relation.c | 19 | ||||
-rw-r--r-- | src/backend/utils/fmgr/funcapi.c | 10 | ||||
-rw-r--r-- | src/test/regress/expected/rangefuncs.out | 3 | ||||
-rw-r--r-- | src/test/regress/sql/rangefuncs.sql | 1 |
5 files changed, 32 insertions, 12 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index b2a7f6609a0..b902084e56b 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -4360,12 +4360,11 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, * Can't simplify if it returns RECORD. The immediate problem is that it * will be needing an expected tupdesc which we can't supply here. * - * In the case where it has OUT parameters, it could get by without an - * expected tupdesc, but we still have issues: get_expr_result_type() - * doesn't know how to extract type info from a RECORD constant, and in - * the case of a NULL function result there doesn't seem to be any clean - * way to fix that. In view of the likelihood of there being still other - * gotchas, seems best to leave the function call unreduced. + * In the case where it has OUT parameters, we could build an expected + * tupdesc from those, but there may be other gotchas lurking. In + * particular, if the function were to return NULL, we would produce a + * null constant with no remaining indication of which concrete record + * type it is. For now, seems best to leave the function call unreduced. */ if (funcform->prorettype == RECORDOID) return NULL; diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 4bc5340984f..2268981a8b5 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -2347,12 +2347,17 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, { RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc); TypeFuncClass functypclass; - Oid funcrettype; - TupleDesc tupdesc; + Oid funcrettype = InvalidOid; + TupleDesc tupdesc = NULL; + + /* If it has a coldeflist, it returns RECORD */ + if (rtfunc->funccolnames != NIL) + functypclass = TYPEFUNC_RECORD; + else + functypclass = get_expr_result_type(rtfunc->funcexpr, + &funcrettype, + &tupdesc); - functypclass = get_expr_result_type(rtfunc->funcexpr, - &funcrettype, - &tupdesc); if (functypclass == TYPEFUNC_COMPOSITE || functypclass == TYPEFUNC_COMPOSITE_DOMAIN) { @@ -3092,6 +3097,10 @@ get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum) { TupleDesc tupdesc; + /* If it has a coldeflist, it returns RECORD */ + if (rtfunc->funccolnames != NIL) + return false; /* can't have any dropped columns */ + tupdesc = get_expr_result_tupdesc(rtfunc->funcexpr, true); if (tupdesc) diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c index dafccc1d0b6..f2a1cb5185c 100644 --- a/src/backend/utils/fmgr/funcapi.c +++ b/src/backend/utils/fmgr/funcapi.c @@ -216,6 +216,13 @@ get_call_result_type(FunctionCallInfo fcinfo, /* * get_expr_result_type * As above, but work from a calling expression node tree + * + * Beware of using this on the funcexpr of a RTE that has a coldeflist. + * The correct conclusion in such cases is always that the function returns + * RECORD with the columns defined by the coldeflist fields (funccolnames etc). + * If it does not, it's the executor's responsibility to catch the discrepancy + * at runtime; but code processing the query in advance of that point might + * come to inconsistent conclusions if it checks the actual expression. */ TypeFuncClass get_expr_result_type(Node *expr, @@ -466,7 +473,8 @@ internal_get_result_type(Oid funcid, * if noError is true, else throws error. * * This is a simpler version of get_expr_result_type() for use when the caller - * is only interested in determinate rowtype results. + * is only interested in determinate rowtype results. As with that function, + * beware of using this on the funcexpr of a RTE that has a coldeflist. */ TupleDesc get_expr_result_tupdesc(Node *expr, bool noError) diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out index e7b569ed314..e8318eb9143 100644 --- a/src/test/regress/expected/rangefuncs.out +++ b/src/test/regress/expected/rangefuncs.out @@ -2111,3 +2111,6 @@ with a(b) as (values (row(1,2,3))) select * from a, coalesce(b) as c(d int, e int, f float); -- fail ERROR: function return row and query-specified return row do not match DETAIL: Returned type integer at ordinal position 3, but query expects double precision. +select * from int8_tbl, coalesce(row(1)) as (a int, b int); -- fail +ERROR: function return row and query-specified return row do not match +DETAIL: Returned row contains 1 attribute, but query expects 2. diff --git a/src/test/regress/sql/rangefuncs.sql b/src/test/regress/sql/rangefuncs.sql index 6a56aedac16..00ac8d579a8 100644 --- a/src/test/regress/sql/rangefuncs.sql +++ b/src/test/regress/sql/rangefuncs.sql @@ -665,3 +665,4 @@ with a(b) as (values (row(1,2,3))) select * from a, coalesce(b) as c(d int, e int, f int, g int); -- fail with a(b) as (values (row(1,2,3))) select * from a, coalesce(b) as c(d int, e int, f float); -- fail +select * from int8_tbl, coalesce(row(1)) as (a int, b int); -- fail |