aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/optimizer/util/clauses.c11
-rw-r--r--src/backend/parser/parse_relation.c19
-rw-r--r--src/backend/utils/fmgr/funcapi.c10
-rw-r--r--src/test/regress/expected/rangefuncs.out3
-rw-r--r--src/test/regress/sql/rangefuncs.sql1
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