From cdf8b56d5463815244467ea8f5ec6e72b6c65a6c Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 17 Mar 2007 03:15:38 +0000 Subject: [PATCH] SPI_cursor_open failed to enforce that only read-only queries could be executed in read_only mode. This could lead to various relatively-subtle failures, such as an allegedly stable function returning non-stable results. Bug goes all the way back to the introduction of read-only mode in 8.0. Per report from Gaetano Mendola. --- src/backend/executor/spi.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 7a34add7105b2..e0856a3d8f2bc 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.172 2007/03/15 23:12:06 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.173 2007/03/17 03:15:38 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -964,6 +964,30 @@ SPI_cursor_open(const char *name, SPIPlanPtr plan, else portal->cursorOptions |= CURSOR_OPT_NO_SCROLL; + /* + * 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 + * RevalidateCachedPlan and PortalDefineQuery, because throwing an error + * between those steps would result in leaking our plancache refcount.) + */ + if (read_only) + { + ListCell *lc; + + foreach(lc, stmt_list) + { + Node *pstmt = (Node *) lfirst(lc); + + if (!CommandIsReadOnly(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(pstmt)))); + } + } + /* * Set up the snapshot to use. (PortalStart will do CopySnapshot, so we * skip that here.)