aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/spi.c
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2020-01-16 12:11:31 -0500
committerRobert Haas <rhaas@postgresql.org>2020-01-16 12:11:31 -0500
commit2eb34ac369741c110b593e2dc2195c57d29ab8e8 (patch)
tree5ea2cd571637ec3ed9fd357a4990b84c1f75f6c9 /src/backend/executor/spi.c
parent0db7c67051806f28a9129d50695efc19372d3af2 (diff)
downloadpostgresql-2eb34ac369741c110b593e2dc2195c57d29ab8e8.tar.gz
postgresql-2eb34ac369741c110b593e2dc2195c57d29ab8e8.zip
Fix problems with "read only query" checks, and refactor the code.
Previously, check_xact_readonly() was responsible for determining which types of queries could not be run in a read-only transaction, standard_ProcessUtility() was responsibility for prohibiting things which were allowed in read only transactions but not in recovery, and utility commands were basically prohibited in bulk in parallel mode by calls to CommandIsReadOnly() in functions.c and spi.c. This situation was confusing and error-prone. Accordingly, move all the checks to a new function ClassifyUtilityCommandAsReadOnly(), which determines the degree to which a given statement is read only. In the old code, check_xact_readonly() inadvertently failed to handle several statement types that actually should have been prohibited, specifically T_CreatePolicyStmt, T_AlterPolicyStmt, T_CreateAmStmt, T_CreateStatsStmt, T_AlterStatsStmt, and T_AlterCollationStmt. As a result, thes statements were erroneously allowed in read only transactions, parallel queries, and standby operation. Generally, they would fail anyway due to some lower-level error check, but we shouldn't rely on that. In the new code structure, future omissions of this type should cause ClassifyUtilityCommandAsReadOnly() to complain about an unrecognized node type. As a fringe benefit, this means we can allow certain types of utility commands in parallel mode, where it's safe to do so. This allows ALTER SYSTEM, CALL, DO, CHECKPOINT, COPY FROM, EXPLAIN, and SHOW. It might be possible to allow additional commands with more work and thought. Along the way, document the thinking process behind the current set of checks, as per discussion especially with Peter Eisentraut. There is some interest in revising some of these rules, but that seems like a job for another patch. Patch by me, reviewed by Tom Lane, Stephen Frost, and Peter Eisentraut. Discussion: http://postgr.es/m/CA+TgmoZ_rLqJt5sYkvh+JpQnfX0Y+B2R+qfi820xNih6x-FQOQ@mail.gmail.com
Diffstat (limited to 'src/backend/executor/spi.c')
-rw-r--r--src/backend/executor/spi.c31
1 files changed, 11 insertions, 20 deletions
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 4a6e82b6056..c46764bf428 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -1450,14 +1450,13 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
portal->queryEnv = _SPI_current->queryEnv;
/*
- * If told to be read-only, or in parallel mode, verify that this query is
- * in fact read-only. This can't be done earlier because we need to look
- * at the finished, planned queries. (In particular, we don't want to do
- * it between GetCachedPlan and PortalDefineQuery, because throwing an
- * error between those steps would result in leaking our plancache
- * refcount.)
+ * If told to be read-only, we'd better check for read-only queries. This
+ * can't be done earlier because we need to look at the finished, planned
+ * queries. (In particular, we don't want to do it between GetCachedPlan
+ * and PortalDefineQuery, because throwing an error between those steps
+ * would result in leaking our plancache refcount.)
*/
- if (read_only || IsInParallelMode())
+ if (read_only)
{
ListCell *lc;
@@ -1466,16 +1465,11 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
PlannedStmt *pstmt = lfirst_node(PlannedStmt, lc);
if (!CommandIsReadOnly(pstmt))
- {
- if (read_only)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- /* translator: %s is a SQL statement name */
- errmsg("%s is not allowed in a non-volatile function",
- CreateCommandTag((Node *) pstmt))));
- else
- PreventCommandIfParallelMode(CreateCommandTag((Node *) pstmt));
- }
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ /* translator: %s is a SQL statement name */
+ errmsg("%s is not allowed in a non-volatile function",
+ CreateCommandTag((Node *) pstmt))));
}
}
@@ -2263,9 +2257,6 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
errmsg("%s is not allowed in a non-volatile function",
CreateCommandTag((Node *) stmt))));
- if (IsInParallelMode() && !CommandIsReadOnly(stmt))
- PreventCommandIfParallelMode(CreateCommandTag((Node *) stmt));
-
/*
* If not read-only mode, advance the command counter before each
* command and update the snapshot.