summaryrefslogtreecommitdiff
path: root/src/pl/plpgsql
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2021-10-03 13:21:20 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2021-10-03 13:21:20 -0400
commita0558cfa395b47adb245972f5eba7978461e7baa (patch)
treeabb2433cfcbe12b1d65c304d9fcb199703b6a755 /src/pl/plpgsql
parent2903f1404df37e11ecc303dbc164826c4717194b (diff)
downloadpostgresql-a0558cfa395b47adb245972f5eba7978461e7baa.tar.gz
Fix checking of query type in plpgsql's RETURN QUERY command.
Prior to v14, we insisted that the query in RETURN QUERY be of a type that returns tuples. (For instance, INSERT RETURNING was allowed, but not plain INSERT.) That happened indirectly because we opened a cursor for the query, so spi.c checked SPI_is_cursor_plan(). As a consequence, the error message wasn't terribly on-point, but at least it was there. Commit 2f48ede08 lost this detail. Instead, plain RETURN QUERY insisted that the query be a SELECT (by checking for SPI_OK_SELECT) while RETURN QUERY EXECUTE failed to check the query type at all. Neither of these changes was intended. The only convenient place to check this in the EXECUTE case is inside _SPI_execute_plan, because we haven't done parse analysis until then. So we need to pass down a flag saying whether to enforce that the query returns tuples. Fortunately, we can squeeze another boolean into struct SPIExecuteOptions without an ABI break, since there's padding space there. (It's unlikely that any extensions would already be using this new struct, but preserving ABI in v14 seems like a smart idea anyway.) Within spi.c, it seemed like _SPI_execute_plan's parameter list was already ridiculously long, and I didn't want to make it longer. So I thought of passing SPIExecuteOptions down as-is, allowing that parameter list to become much shorter. This makes the patch a bit more invasive than it might otherwise be, but it's all internal to spi.c, so that seems fine. Per report from Marc Bachmann. Back-patch to v14 where the faulty code came in. Discussion: https://postgr.es/m/1F2F75F0-27DF-406F-848D-8B50C7EEF06A@gmail.com
Diffstat (limited to 'src/pl/plpgsql')
-rw-r--r--src/pl/plpgsql/src/pl_exec.c22
1 files changed, 5 insertions, 17 deletions
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 7c5bc63778..0e1cfa3df6 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -3553,26 +3553,13 @@ exec_stmt_return_query(PLpgSQL_execstate *estate,
memset(&options, 0, sizeof(options));
options.params = paramLI;
options.read_only = estate->readonly_func;
+ options.must_return_tuples = true;
options.dest = treceiver;
rc = SPI_execute_plan_extended(expr->plan, &options);
- if (rc != SPI_OK_SELECT)
- {
- /*
- * SELECT INTO deserves a special error message, because "query is
- * not a SELECT" is not very helpful in that case.
- */
- if (rc == SPI_OK_SELINTO)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("query is SELECT INTO, but it should be plain SELECT"),
- errcontext("query: %s", expr->query)));
- else
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("query is not a SELECT"),
- errcontext("query: %s", expr->query)));
- }
+ if (rc < 0)
+ elog(ERROR, "SPI_execute_plan_extended failed executing query \"%s\": %s",
+ expr->query, SPI_result_code_string(rc));
}
else
{
@@ -3609,6 +3596,7 @@ exec_stmt_return_query(PLpgSQL_execstate *estate,
options.params = exec_eval_using_params(estate,
stmt->params);
options.read_only = estate->readonly_func;
+ options.must_return_tuples = true;
options.dest = treceiver;
rc = SPI_execute_extended(querystr, &options);