diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 7a34add7105b27e69dfe08511434ad01971f1a86..e0856a3d8f2bcc93fb029da301db2b8ceb275890 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.)