Put back error test for DECLARE CURSOR outside a transaction block ...
authorTom Lane
Mon, 18 Nov 2002 01:17:39 +0000 (01:17 +0000)
committerTom Lane
Mon, 18 Nov 2002 01:17:39 +0000 (01:17 +0000)
but do it correctly now.

src/backend/access/transam/xact.c
src/backend/tcop/pquery.c
src/include/access/xact.h

index 4711c091c78f906accf753228a02be0153a1adc8..607a47f1246c7d1e836f4b093170e821f43d0af6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.138 2002/11/13 03:12:05 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.139 2002/11/18 01:17:39 tgl Exp $
  *
  * NOTES
  *     Transaction aborts can now occur two ways:
@@ -1488,6 +1488,50 @@ PreventTransactionChain(void *stmtNode, const char *stmtType)
    }
 }
 
+/* --------------------------------
+ * 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
index 29909295f513cdb39f9937292404c35966685f78..0919b03f45a9a4e10ddfd7bbc93eae7013c7be46 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.55 2002/09/04 20:31:26 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.56 2002/11/18 01:17:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -161,6 +161,8 @@ ProcessQuery(Query *parsetree,
            /* 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)
        {
index dd609f19a14393a2b63a74006d956ffed9a4a592..fa30c3303b1b66618211dbdc8590a9dd75ec2a49 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: xact.h,v 1.47 2002/11/13 03:12:05 momjian Exp $
+ * $Id: xact.h,v 1.48 2002/11/18 01:17:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -115,6 +115,7 @@ extern bool IsTransactionBlock(void);
 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);