]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix mishandling of after-trigger state when a SQL function returns multiple
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 12 Oct 2006 17:02:34 +0000 (17:02 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 12 Oct 2006 17:02:34 +0000 (17:02 +0000)
rows --- if the surrounding query queued any trigger events between the rows,
the events would be fired at the wrong time, leading to bizarre behavior.
Per report from Merlin Moncure.

This is a simple patch that should solve the problem fully in the back
branches, but in HEAD we also need to consider the possibility of queries
with RETURNING clauses.  Will look into a fix for that separately.

src/backend/executor/functions.c

index ae6a0fc537cb6fca2bfe65db391f14590243b14f..d08955163e9dc9aa93b09c7d0ebdd0e93954403c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.91.4.1 2005/04/10 18:04:31 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.91.4.2 2006/10/12 17:02:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -328,7 +328,14 @@ postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
        /* Utility commands don't need Executor. */
        if (es->qd->operation != CMD_UTILITY)
        {
-               AfterTriggerBeginQuery();
+               /*
+                * Only set up to collect queued triggers if it's not a SELECT.
+                * This isn't just an optimization, but is necessary in case a SELECT
+                * returns multiple rows to caller --- we mustn't exit from the
+                * function execution with a stacked AfterTrigger level still active.
+                */
+               if (es->qd->operation != CMD_SELECT)
+                       AfterTriggerBeginQuery();
                ExecutorStart(es->qd, false);
        }
 
@@ -401,7 +408,8 @@ postquel_end(execution_state *es)
                        ActiveSnapshot = es->qd->snapshot;
 
                        ExecutorEnd(es->qd);
-                       AfterTriggerEndQuery();
+                       if (es->qd->operation != CMD_SELECT)
+                               AfterTriggerEndQuery();
                }
                PG_CATCH();
                {