aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2021-11-17 11:31:31 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2021-11-17 11:31:31 -0500
commita8d8445a7b2f80f6d0bfe97b19f90bd2cbef8759 (patch)
treebe16d64dded5abf9f9baaecf28a825e20389a76e
parentaa12781b0d039d93e1a851ece4bc75c3746cbd43 (diff)
downloadpostgresql-a8d8445a7b2f80f6d0bfe97b19f90bd2cbef8759.tar.gz
postgresql-a8d8445a7b2f80f6d0bfe97b19f90bd2cbef8759.zip
Fix display of SQL-standard function's arguments in INSERT/SELECT.
If a SQL-standard function body contains an INSERT ... SELECT statement, any function parameters referenced within the SELECT were always printed in $N style, rather than using the parameter name if any. While not strictly incorrect, this wasn't the intention, and it's inconsistent with the way that such parameters would be printed in any other kind of statement. The cause is that the recursion to get_query_def from get_insert_query_def neglected to pass down the context->namespaces list, passing constant NIL instead. This is a very ancient oversight, but AFAICT it had no visible consequences before commit e717a9a18 added an outermost namespace with function parameters. We don't allow INSERT ... SELECT as a sub-query, except in a top-level WITH clause, where it couldn't contain any outer references that might need to access upper namespaces. So although that's arguably a bug, I don't see any point in changing it before v14. In passing, harden the code added to get_parameter by e717a9a18 so that it won't crash if a PARAM_EXTERN Param appears in an unexpected place. Per report from Erki Eessaar. Code fix by me, regression test case by Masahiko Sawada. Discussion: https://postgr.es/m/AM9PR01MB8268347BED344848555167FAFE949@AM9PR01MB8268.eurprd01.prod.exchangelabs.com
-rw-r--r--src/backend/utils/adt/ruleutils.c10
-rw-r--r--src/test/regress/expected/create_function_3.out21
-rw-r--r--src/test/regress/sql/create_function_3.sql11
3 files changed, 38 insertions, 4 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 1bb25738a52..6b4022c3bcc 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -6566,7 +6566,7 @@ get_insert_query_def(Query *query, deparse_context *context)
if (select_rte)
{
/* Add the SELECT */
- get_query_def(select_rte->subquery, buf, NIL, NULL,
+ get_query_def(select_rte->subquery, buf, context->namespaces, NULL,
context->prettyFlags, context->wrapColumn,
context->indentLevel);
}
@@ -7919,10 +7919,12 @@ get_parameter(Param *param, deparse_context *context)
* If it's an external parameter, see if the outermost namespace provides
* function argument names.
*/
- if (param->paramkind == PARAM_EXTERN)
+ if (param->paramkind == PARAM_EXTERN && context->namespaces != NIL)
{
- dpns = lfirst(list_tail(context->namespaces));
- if (dpns->argnames)
+ dpns = llast(context->namespaces);
+ if (dpns->argnames &&
+ param->paramid > 0 &&
+ param->paramid <= dpns->numargs)
{
char *argname = dpns->argnames[param->paramid - 1];
diff --git a/src/test/regress/expected/create_function_3.out b/src/test/regress/expected/create_function_3.out
index a77df01042e..3a4fd451471 100644
--- a/src/test/regress/expected/create_function_3.out
+++ b/src/test/regress/expected/create_function_3.out
@@ -279,6 +279,13 @@ CREATE FUNCTION functest_S_13() RETURNS boolean
SELECT 1;
SELECT false;
END;
+-- check display of function argments in sub-SELECT
+CREATE TABLE functest1 (i int);
+CREATE FUNCTION functest_S_16(a int, b int) RETURNS void
+ LANGUAGE SQL
+ BEGIN ATOMIC
+ INSERT INTO functest1 SELECT a + $2;
+ END;
-- error: duplicate function body
CREATE FUNCTION functest_S_xxx(x int) RETURNS int
LANGUAGE SQL
@@ -417,6 +424,20 @@ SELECT pg_get_functiondef('functest_S_15'::regproc);
(1 row)
+SELECT pg_get_functiondef('functest_S_16'::regproc);
+ pg_get_functiondef
+-------------------------------------------------------------------------------
+ CREATE OR REPLACE FUNCTION temp_func_test.functest_s_16(a integer, b integer)+
+ RETURNS void +
+ LANGUAGE sql +
+ BEGIN ATOMIC +
+ INSERT INTO functest1 (i) SELECT (functest_s_16.a + functest_s_16.b); +
+ END +
+
+(1 row)
+
+DROP TABLE functest1 CASCADE;
+NOTICE: drop cascades to function functest_s_16(integer,integer)
-- test with views
CREATE TABLE functest3 (a int);
INSERT INTO functest3 VALUES (1), (2);
diff --git a/src/test/regress/sql/create_function_3.sql b/src/test/regress/sql/create_function_3.sql
index 23a46b0b114..7edd757b8f3 100644
--- a/src/test/regress/sql/create_function_3.sql
+++ b/src/test/regress/sql/create_function_3.sql
@@ -180,6 +180,14 @@ CREATE FUNCTION functest_S_13() RETURNS boolean
SELECT false;
END;
+-- check display of function argments in sub-SELECT
+CREATE TABLE functest1 (i int);
+CREATE FUNCTION functest_S_16(a int, b int) RETURNS void
+ LANGUAGE SQL
+ BEGIN ATOMIC
+ INSERT INTO functest1 SELECT a + $2;
+ END;
+
-- error: duplicate function body
CREATE FUNCTION functest_S_xxx(x int) RETURNS int
LANGUAGE SQL
@@ -217,6 +225,9 @@ SELECT pg_get_functiondef('functest_S_3a'::regproc);
SELECT pg_get_functiondef('functest_S_10'::regproc);
SELECT pg_get_functiondef('functest_S_13'::regproc);
SELECT pg_get_functiondef('functest_S_15'::regproc);
+SELECT pg_get_functiondef('functest_S_16'::regproc);
+
+DROP TABLE functest1 CASCADE;
-- test with views
CREATE TABLE functest3 (a int);