From: Tom Lane Date: Mon, 18 Nov 2002 01:17:50 +0000 (+0000) Subject: Put back error test for DECLARE CURSOR outside a transaction block ... X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=72c4738fc79b06b39220fcc812875648dbe28899;p=users%2Fbernd%2Fpostgres.git Put back error test for DECLARE CURSOR outside a transaction block ... but do it correctly now. --- diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 04e2103a76..6e1d41e533 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -1497,6 +1497,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 9227b1b2fc..2d871de1d5 100644 --- a/src/backend/tcop/pquery.c +++ b/src/backend/tcop/pquery.c @@ -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 4fca596a6d..1e1e1b613c 100644 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@ -114,6 +114,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);