aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/optimizer/prep/prepjointree.c18
-rw-r--r--src/test/regress/expected/join.out37
-rw-r--r--src/test/regress/sql/join.sql19
3 files changed, 74 insertions, 0 deletions
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index d13cb582272..f489f140e37 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -26,6 +26,7 @@
#include "postgres.h"
#include "catalog/pg_type.h"
+#include "funcapi.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
@@ -1683,6 +1684,9 @@ pull_up_constant_function(PlannerInfo *root, Node *jtnode,
{
Query *parse = root->parse;
RangeTblFunction *rtf;
+ TypeFuncClass functypclass;
+ Oid funcrettype;
+ TupleDesc tupdesc;
pullup_replace_vars_context rvcontext;
/* Fail if the RTE has ORDINALITY - we don't implement that here. */
@@ -1696,6 +1700,20 @@ pull_up_constant_function(PlannerInfo *root, Node *jtnode,
if (!IsA(rtf->funcexpr, Const))
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 */
rvcontext.root = root;
rvcontext.targetlist = list_make1(makeTargetEntry((Expr *) rtf->funcexpr,
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index 9b407bc4854..b58d560163b 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -3365,6 +3365,43 @@ where nt3.id = 1 and ss2.b3;
(9 rows)
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
-- (we used to only do this for indexable clauses)
diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql
index 145accca86f..57481d04117 100644
--- a/src/test/regress/sql/join.sql
+++ b/src/test/regress/sql/join.sql
@@ -1072,6 +1072,25 @@ where nt3.id = 1 and ss2.b3;
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
-- (we used to only do this for indexable clauses)