agora inbox for pgsql-bugs@postgresql.org
help / color / mirror / Atom feedBUG #19689: MERGE INSERT accepts a set-returning function during PREPARE but fails at EXECUTE
2+ messages / 2 participants
[nested] [flat]
* BUG #19689: MERGE INSERT accepts a set-returning function during PREPARE but fails at EXECUTE
@ 2026-09-15 06:46 PG Bug reporting form <noreply@postgresql.org>
2026-09-16 02:56 ` Re: BUG #19689: MERGE INSERT accepts a set-returning function during PREPARE but fails at EXECUTE Tender Wang <tndrwang@gmail.com>
0 siblings, 1 reply; 2+ messages in thread
From: PG Bug reporting form @ 2026-09-15 06:46 UTC (permalink / raw)
To: pgsql-bugs@lists.postgresql.org; +Cc: imchifan@163.com
The following bug has been logged on the website:
Bug reference: 19689
Logged by: Qifan Liu
Email address: imchifan@163.com
PostgreSQL version: 18.6
Operating system: Linux x86-64
Description:
Description
-----------
A set-returning function can be placed in the VALUES expression of a MERGE
WHEN NOT MATCHED INSERT action. PREPARE accepts the statement, but EXECUTE
fails with "set-valued function called in context that cannot accept a set"
and inserts no rows. This violates the analysis/execution contract: an
expression that the MERGE action cannot execute should be rejected while the
statement is analyzed, rather than being accepted into a prepared plan that
deterministically fails only when executed.
Impact: Applications can successfully prepare an unusable MERGE statement
and encounter a localized execution failure later. The statement inserts no
rows. This was reproduced consistently on all tested versions.
Steps to reproduce
------------------
```sql
CREATE TABLE merge_target (id integer);
CREATE TABLE merge_source (id integer);
INSERT INTO merge_source VALUES (1);
PREPARE merge_srf AS
MERGE INTO merge_target AS t
USING merge_source AS s
ON false
WHEN NOT MATCHED THEN
INSERT VALUES (generate_series(1, 2));
EXECUTE merge_srf;
SELECT count(*) AS rows_after_execution
FROM merge_target;
```
Actual result
-------------
```text
ERROR: set-valued function called in context that cannot accept a set
rows_after_execution
----------------------
0
(1 row)
```
Expected result
---------------
PREPARE should reject the set-returning function because a MERGE INSERT
action cannot execute that expression in this context. It should not create
a prepared statement that is accepted successfully and then
deterministically fails during EXECUTE.
Additional information
----------------------
The issue was reproduced on PostgreSQL 20devel, PostgreSQL 18.6, and
PostgreSQL 17.11. Inference: the MERGE INSERT action's specialized
expression handling does not propagate or enforce the restriction on
set-returning functions during analysis, leaving the executor to detect the
unsupported context.
^ permalink raw reply [nested|flat] 2+ messages in thread
* Re: BUG #19689: MERGE INSERT accepts a set-returning function during PREPARE but fails at EXECUTE
2026-09-15 06:46 BUG #19689: MERGE INSERT accepts a set-returning function during PREPARE but fails at EXECUTE PG Bug reporting form <noreply@postgresql.org>
@ 2026-09-16 02:56 ` Tender Wang <tndrwang@gmail.com>
0 siblings, 0 replies; 2+ messages in thread
From: Tender Wang @ 2026-09-16 02:56 UTC (permalink / raw)
To: imchifan@163.com; pgsql-bugs@lists.postgresql.org
PG Bug reporting form <noreply@postgresql.org> 于2026年9月15日周二 17:36写道:
>
> Additional information
> ----------------------
> The issue was reproduced on PostgreSQL 20devel, PostgreSQL 18.6, and
> PostgreSQL 17.11. Inference: the MERGE INSERT action's specialized
> expression handling does not propagate or enforce the restriction on
> set-returning functions during analysis, leaving the executor to detect the
> unsupported context.
I looked into this issue.
MERGE INSERT values are transformed using EXPR_KIND_VALUES_SINGLE,
which permits set-returning functions and sets
pstate->p_hasTargetSRFs. However, transformMergeStmt() later
unconditionally sets qry->hasTargetSRFs to false, and a MERGE action
target list is not expanded using a ProjectSet plan node.
Consequently, the SRF is accepted during PREPARE, but later fails
during executor expression initialization with:
ERROR: set-valued function called in context that cannot accept a set
The attached patch is one possible fix. It checks
pstate->p_hasTargetSRFs immediately after transforming the MERGE
INSERT values and reports an error during parse analysis. The check
is placed specifically in the CMD_INSERT case, so it does not affect
the other MERGE actions or set-returning functions used as the MERGE
data source.
I have not included a regression test in this version, since I would
first like to confirm whether rejecting SRFs in MERGE INSERT actions
is the intended behavior. If so, I can add a test in the next
version.
Thoughts?
--
Thanks,
Tender Wang
From 06ea984af3096589ee324f91a7d9d3d6e66af981 Mon Sep 17 00:00:00 2001
From: Tender Wang <tndrwang@gmail.com>
Date: Wed, 16 Sep 2026 10:49:33 +0800
Subject: [PATCH] Reject set-returning functions in MERGE INSERT actions
MERGE INSERT values are transformed using EXPR_KIND_VALUES_SINGLE,
which allows set-returning functions and sets p_hasTargetSRFs. However,
a MERGE INSERT action is supposed to insert one row for each candidate
change row, and its target list cannot be expanded using a ProjectSet
plan node.
As a result, an SRF in a MERGE INSERT action was accepted during parse
analysis, but failed during executor initialization with "set-valued
function called in context that cannot accept a set". In particular,
this allowed PREPARE to succeed for a statement that would always fail
when executed.
Reject such functions while transforming the MERGE INSERT action, so
the error is reported during parse analysis.
---
src/backend/parser/parse_merge.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/backend/parser/parse_merge.c b/src/backend/parser/parse_merge.c
index 0a70d48fd4c..daa89e199a5 100644
--- a/src/backend/parser/parse_merge.c
+++ b/src/backend/parser/parse_merge.c
@@ -17,6 +17,7 @@
#include "access/sysattr.h"
#include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
#include "parser/analyze.h"
#include "parser/parse_clause.h"
#include "parser/parse_collate.h"
@@ -345,6 +346,11 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
mergeWhenClause->values,
EXPR_KIND_VALUES_SINGLE,
true);
+ if (pstate->p_hasTargetSRFs)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-returning functions are not allowed in MERGE INSERT actions"),
+ parser_errposition(pstate, exprLocation(pstate->p_last_srf))));
/* Prepare row for assignment to target table */
exprList = transformInsertRow(pstate, exprList,
--
2.43.0
Attachments:
[text/plain] 0001-Reject-set-returning-functions-in-MERGE-INSERT-actio.patch (1.9K, ../../CAHewXN=t2OW_gehDsso17CLgqRfMfnhzDsby7pXWpzSy_-e9Tg@mail.gmail.com/2-0001-Reject-set-returning-functions-in-MERGE-INSERT-actio.patch)
download | inline diff:
From 06ea984af3096589ee324f91a7d9d3d6e66af981 Mon Sep 17 00:00:00 2001
From: Tender Wang <tndrwang@gmail.com>
Date: Wed, 16 Sep 2026 10:49:33 +0800
Subject: [PATCH] Reject set-returning functions in MERGE INSERT actions
MERGE INSERT values are transformed using EXPR_KIND_VALUES_SINGLE,
which allows set-returning functions and sets p_hasTargetSRFs. However,
a MERGE INSERT action is supposed to insert one row for each candidate
change row, and its target list cannot be expanded using a ProjectSet
plan node.
As a result, an SRF in a MERGE INSERT action was accepted during parse
analysis, but failed during executor initialization with "set-valued
function called in context that cannot accept a set". In particular,
this allowed PREPARE to succeed for a statement that would always fail
when executed.
Reject such functions while transforming the MERGE INSERT action, so
the error is reported during parse analysis.
---
src/backend/parser/parse_merge.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/backend/parser/parse_merge.c b/src/backend/parser/parse_merge.c
index 0a70d48fd4c..daa89e199a5 100644
--- a/src/backend/parser/parse_merge.c
+++ b/src/backend/parser/parse_merge.c
@@ -17,6 +17,7 @@
#include "access/sysattr.h"
#include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
#include "parser/analyze.h"
#include "parser/parse_clause.h"
#include "parser/parse_collate.h"
@@ -345,6 +346,11 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
mergeWhenClause->values,
EXPR_KIND_VALUES_SINGLE,
true);
+ if (pstate->p_hasTargetSRFs)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-returning functions are not allowed in MERGE INSERT actions"),
+ parser_errposition(pstate, exprLocation(pstate->p_last_srf))));
/* Prepare row for assignment to target table */
exprList = transformInsertRow(pstate, exprList,
--
2.43.0
^ permalink raw reply [nested|flat] 2+ messages in thread
end of thread, other threads:[~2026-09-16 02:56 UTC | newest]
Thread overview: 2+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-09-15 06:46 BUG #19689: MERGE INSERT accepts a set-returning function during PREPARE but fails at EXECUTE PG Bug reporting form <noreply@postgresql.org>
2026-09-16 02:56 ` Tender Wang <tndrwang@gmail.com>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox