Bruce Momjian <[EMAIL PROTECTED]> writes:
> Let's just fix it and roll an RC2 with the fix.  If not, we can just fix
> it in 7.3.1 but I see little problem in rolling an RC2.

Here is the patch I am testing (in current sources; I don't think it
needs any adjustments for REL7_3, but haven't tried to apply it yet).
Basically it moves the test that was originally done in parse/analyze.c
into the execution-time setup of a cursor, and enlarges the test to
understand about autocommit-off and inside-a-function exceptions.
Anyone see a problem?

                        regards, tom lane

*** src/backend/access/transam/xact.c.orig      Wed Nov 13 10:51:46 2002
--- src/backend/access/transam/xact.c   Sun Nov 17 19:10:20 2002
***************
*** 1488,1493 ****
--- 1488,1537 ----
        }
  }
  
+ /* --------------------------------
+  *    RequireTransactionChain
+  *
+  *    This routine is to be called by statements that must run inside
+  *    a transaction block, because they have no effects that persist past
+  *    transaction end (and so calling them outside a transaction block
+  *    is presumably an error).  DECLARE CURSOR is an example.
+  *
+  *    If we appear to be running inside a user-defined function, we do not
+  *    issue an error, since the function could issue more commands that make
+  *    use of the current statement's results.  Thus this is an inverse for
+  *    PreventTransactionChain.
+  *
+  *    stmtNode: pointer to parameter block for statement; this is used in
+  *    a very klugy way to determine whether we are inside a function.
+  *    stmtType: statement type name for error messages.
+  * --------------------------------
+  */
+ void
+ RequireTransactionChain(void *stmtNode, const char *stmtType)
+ {
+       /*
+        * xact block already started?
+        */
+       if (IsTransactionBlock())
+               return;
+       /*
+        * Are we inside a function call?  If the statement's parameter block
+        * was allocated in QueryContext, assume it is an interactive command.
+        * Otherwise assume it is coming from a function.
+        */
+       if (!MemoryContextContains(QueryContext, stmtNode))
+               return;
+       /*
+        * If we are in autocommit-off mode then it's okay, because this
+        * statement will itself start a transaction block.
+        */
+       if (!autocommit && !suppressChain)
+               return;
+       /* translator: %s represents an SQL statement name */
+       elog(ERROR, "%s may only be used in begin/end transaction blocks",
+                stmtType);
+ }
+ 
  
  /* ----------------------------------------------------------------
   *                                       transaction block support
*** /home/postgres/pgsql/src/backend/tcop/pquery.c.orig Wed Sep  4 17:30:43 2002
--- /home/postgres/pgsql/src/backend/tcop/pquery.c      Sun Nov 17 19:10:26 2002
***************
*** 161,166 ****
--- 161,168 ----
                        /* If binary portal, switch to alternate output format */
                        if (dest == Remote && parsetree->isBinary)
                                dest = RemoteInternal;
+                       /* Check for invalid context (must be in transaction block) */
+                       RequireTransactionChain((void *) parsetree, "DECLARE CURSOR");
                }
                else if (parsetree->into != NULL)
                {
*** /home/postgres/pgsql/src/include/access/xact.h.orig Wed Nov 13 10:52:07 2002
--- /home/postgres/pgsql/src/include/access/xact.h      Sun Nov 17 19:10:13 2002
***************
*** 115,120 ****
--- 115,121 ----
  extern void UserAbortTransactionBlock(void);
  extern void AbortOutOfAnyTransaction(void);
  extern void PreventTransactionChain(void *stmtNode, const char *stmtType);
+ extern void RequireTransactionChain(void *stmtNode, const char *stmtType);
  
  extern void RecordTransactionCommit(void);
  

---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to [EMAIL PROTECTED]

Reply via email to