aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2019-09-24 12:11:32 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2019-09-24 12:11:32 -0400
commita9ae99d0190960ce2d3dd3e5f10e7f4adc3cf203 (patch)
tree39d15b08493f95a414acab4d3282275e5364c368
parent6d05086c0a79e50d8e91ed953626ec7280cd2481 (diff)
downloadpostgresql-a9ae99d0190960ce2d3dd3e5f10e7f4adc3cf203.tar.gz
postgresql-a9ae99d0190960ce2d3dd3e5f10e7f4adc3cf203.zip
Prevent bogus pullup of constant-valued functions returning composite.
Fix an oversight in commit 7266d0997: 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
-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)