From 17ac74797a12e85741436d27cd4ac6337a806c44 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 18 Nov 2002 01:17:39 +0000 Subject: [PATCH] Put back error test for DECLARE CURSOR outside a transaction block ... but do it correctly now. --- src/backend/access/transam/xact.c | 46 ++++++++++++++++++++++++++++++- src/backend/tcop/pquery.c | 4 ++- src/include/access/xact.h | 3 +- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 4711c091c7..607a47f124 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -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 diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c index 29909295f5..0919b03f45 100644 --- a/src/backend/tcop/pquery.c +++ b/src/backend/tcop/pquery.c @@ -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) { diff --git a/src/include/access/xact.h b/src/include/access/xact.h index dd609f19a1..fa30c3303b 100644 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@ -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);