]> granicus.if.org Git - postgresql/commitdiff
SPI_cursor_open failed to enforce that only read-only queries could be
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 17 Mar 2007 03:15:38 +0000 (03:15 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 17 Mar 2007 03:15:38 +0000 (03:15 +0000)
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

index 7a34add7105b27e69dfe08511434ad01971f1a86..e0856a3d8f2bcc93fb029da301db2b8ceb275890 100644 (file)
@@ -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.)