]> granicus.if.org Git - postgresql/commitdiff
Fix pg_plan_queries() to restore the previous setting of ActiveSnapshot
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 12 Mar 2008 23:58:27 +0000 (23:58 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 12 Mar 2008 23:58:27 +0000 (23:58 +0000)
(probably NULL) before exiting.  Up to now it's just left the variable as it
set it, which means that after we're done processing the current client
message, ActiveSnapshot is probably pointing at garbage (because this function
is typically run in MessageContext which will get reset).  There doesn't seem
to have been any code path in which that mattered before 8.3, but now the
plancache module might try to use the stale value if the next client message
is a Bind for a prepared statement that is in need of replanning.  Per report
from Alex Hunsaker.

src/backend/tcop/postgres.c

index 9fc0389d96bcf12f4118946a93cb59cf2316c4e0..19e7c0b070c0a003068e4798ce7f321fc5ec3a6b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.544 2008/03/10 12:55:13 mha Exp $
+ *       $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.545 2008/03/12 23:58:27 tgl Exp $
  *
  * NOTES
  *       this is the "main" module of the postgres backend and
@@ -730,31 +730,49 @@ List *
 pg_plan_queries(List *querytrees, int cursorOptions, ParamListInfo boundParams,
                                bool needSnapshot)
 {
-       List       *stmt_list = NIL;
-       ListCell   *query_list;
+       List       * volatile stmt_list = NIL;
+       Snapshot        saveActiveSnapshot = ActiveSnapshot;
 
-       foreach(query_list, querytrees)
+       /* PG_TRY to ensure previous ActiveSnapshot is restored on error */
+       PG_TRY();
        {
-               Query      *query = (Query *) lfirst(query_list);
-               Node       *stmt;
+               Snapshot        mySnapshot = NULL;
+               ListCell   *query_list;
 
-               if (query->commandType == CMD_UTILITY)
+               foreach(query_list, querytrees)
                {
-                       /* Utility commands have no plans. */
-                       stmt = query->utilityStmt;
-               }
-               else
-               {
-                       if (needSnapshot)
+                       Query      *query = (Query *) lfirst(query_list);
+                       Node       *stmt;
+
+                       if (query->commandType == CMD_UTILITY)
+                       {
+                               /* Utility commands have no plans. */
+                               stmt = query->utilityStmt;
+                       }
+                       else
                        {
-                               ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
-                               needSnapshot = false;
+                               if (needSnapshot && mySnapshot == NULL)
+                               {
+                                       mySnapshot = CopySnapshot(GetTransactionSnapshot());
+                                       ActiveSnapshot = mySnapshot;
+                               }
+                               stmt = (Node *) pg_plan_query(query, cursorOptions,
+                                                                                         boundParams);
                        }
-                       stmt = (Node *) pg_plan_query(query, cursorOptions, boundParams);
+
+                       stmt_list = lappend(stmt_list, stmt);
                }
 
-               stmt_list = lappend(stmt_list, stmt);
+               if (mySnapshot)
+                       FreeSnapshot(mySnapshot);
+       }
+       PG_CATCH();
+       {
+               ActiveSnapshot = saveActiveSnapshot;
+               PG_RE_THROW();
        }
+       PG_END_TRY();
+       ActiveSnapshot = saveActiveSnapshot;
 
        return stmt_list;
 }