Commit a9ae99d0 authored by Tom Lane's avatar Tom Lane

Prevent bogus pullup of constant-valued functions returning composite.

Fix an oversight in commit 7266d099: as it stood, the code failed
when a function-in-FROM returns composite and can be simplified
to a composite constant.

For the moment, just test for composite result and abandon pullup
if we see one.  To make it actually work, we'd have to decompose
the composite constant into per-column constants; which is surely
do-able, but I'm not convinced it's worth the code space.

Per report from Raúl Marín Rodríguez.

Discussion: https://postgr.es/m/CAM6_UM4isP+buRA5sWodO_MUEgutms-KDfnkwGmryc5DGj9XuQ@mail.gmail.com
parent 6d05086c
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "postgres.h" #include "postgres.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "funcapi.h"
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h" #include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
...@@ -1683,6 +1684,9 @@ pull_up_constant_function(PlannerInfo *root, Node *jtnode, ...@@ -1683,6 +1684,9 @@ pull_up_constant_function(PlannerInfo *root, Node *jtnode,
{ {
Query *parse = root->parse; Query *parse = root->parse;
RangeTblFunction *rtf; RangeTblFunction *rtf;
TypeFuncClass functypclass;
Oid funcrettype;
TupleDesc tupdesc;
pullup_replace_vars_context rvcontext; pullup_replace_vars_context rvcontext;
/* Fail if the RTE has ORDINALITY - we don't implement that here. */ /* Fail if the RTE has ORDINALITY - we don't implement that here. */
...@@ -1696,6 +1700,20 @@ pull_up_constant_function(PlannerInfo *root, Node *jtnode, ...@@ -1696,6 +1700,20 @@ pull_up_constant_function(PlannerInfo *root, Node *jtnode,
if (!IsA(rtf->funcexpr, Const)) if (!IsA(rtf->funcexpr, Const))
return jtnode; return jtnode;
/*
* If the function's result is not a scalar, we punt. In principle we
* could break the composite constant value apart into per-column
* constants, but for now it seems not worth the work.
*/
if (rtf->funccolcount != 1)
return jtnode; /* definitely composite */
functypclass = get_expr_result_type(rtf->funcexpr,
&funcrettype,
&tupdesc);
if (functypclass != TYPEFUNC_SCALAR)
return jtnode; /* must be a one-column composite type */
/* Create context for applying pullup_replace_vars */ /* Create context for applying pullup_replace_vars */
rvcontext.root = root; rvcontext.root = root;
rvcontext.targetlist = list_make1(makeTargetEntry((Expr *) rtf->funcexpr, rvcontext.targetlist = list_make1(makeTargetEntry((Expr *) rtf->funcexpr,
......
...@@ -3365,6 +3365,43 @@ where nt3.id = 1 and ss2.b3; ...@@ -3365,6 +3365,43 @@ where nt3.id = 1 and ss2.b3;
(9 rows) (9 rows)
drop function f_immutable_int4(int); drop function f_immutable_int4(int);
-- test inlining when function returns composite
create function mki8(bigint, bigint) returns int8_tbl as
$$select row($1,$2)::int8_tbl$$ language sql;
create function mki4(int) returns int4_tbl as
$$select row($1)::int4_tbl$$ language sql;
explain (verbose, costs off)
select * from mki8(1,2);
QUERY PLAN
------------------------------------
Function Scan on mki8
Output: q1, q2
Function Call: '(1,2)'::int8_tbl
(3 rows)
select * from mki8(1,2);
q1 | q2
----+----
1 | 2
(1 row)
explain (verbose, costs off)
select * from mki4(42);
QUERY PLAN
-----------------------------------
Function Scan on mki4
Output: f1
Function Call: '(42)'::int4_tbl
(3 rows)
select * from mki4(42);
f1
----
42
(1 row)
drop function mki8(bigint, bigint);
drop function mki4(int);
-- --
-- test extraction of restriction OR clauses from join OR clause -- test extraction of restriction OR clauses from join OR clause
-- (we used to only do this for indexable clauses) -- (we used to only do this for indexable clauses)
......
...@@ -1072,6 +1072,25 @@ where nt3.id = 1 and ss2.b3; ...@@ -1072,6 +1072,25 @@ where nt3.id = 1 and ss2.b3;
drop function f_immutable_int4(int); drop function f_immutable_int4(int);
-- test inlining when function returns composite
create function mki8(bigint, bigint) returns int8_tbl as
$$select row($1,$2)::int8_tbl$$ language sql;
create function mki4(int) returns int4_tbl as
$$select row($1)::int4_tbl$$ language sql;
explain (verbose, costs off)
select * from mki8(1,2);
select * from mki8(1,2);
explain (verbose, costs off)
select * from mki4(42);
select * from mki4(42);
drop function mki8(bigint, bigint);
drop function mki4(int);
-- --
-- test extraction of restriction OR clauses from join OR clause -- test extraction of restriction OR clauses from join OR clause
-- (we used to only do this for indexable clauses) -- (we used to only do this for indexable clauses)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment