mirror of
https://github.com/postgres/postgres.git
synced 2025-04-21 12:05:57 +03:00
plpgsql does exceptions.
There are still some things that need refinement; in particular I fear that the recognized set of error condition names probably has little in common with what Oracle recognizes. But it's a start.
This commit is contained in:
parent
b5d2821929
commit
beda4814c1
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.41 2004/07/11 23:26:51 momjian Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.42 2004/07/31 07:39:17 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<chapter id="plpgsql">
|
<chapter id="plpgsql">
|
||||||
@ -1797,6 +1797,101 @@ END LOOP;
|
|||||||
</para>
|
</para>
|
||||||
</note>
|
</note>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="plpgsql-error-trapping">
|
||||||
|
<title>Trapping Errors</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
By default, any error occurring in a <application>PL/pgSQL</>
|
||||||
|
function aborts execution of the function, and indeed of the
|
||||||
|
surrounding transaction as well. You can trap errors and recover
|
||||||
|
from them by using a <command>BEGIN</> block with an
|
||||||
|
<literal>EXCEPTION</> clause. The syntax is an extension of the
|
||||||
|
normal syntax for a <command>BEGIN</> block:
|
||||||
|
|
||||||
|
<synopsis>
|
||||||
|
<optional> <<<replaceable>label</replaceable>>> </optional>
|
||||||
|
<optional> DECLARE
|
||||||
|
<replaceable>declarations</replaceable> </optional>
|
||||||
|
BEGIN
|
||||||
|
<replaceable>statements</replaceable>
|
||||||
|
EXCEPTION
|
||||||
|
WHEN <replaceable>condition</replaceable> THEN
|
||||||
|
<replaceable>handler_statements</replaceable>
|
||||||
|
<optional> WHEN <replaceable>condition</replaceable> THEN
|
||||||
|
<replaceable>handler_statements</replaceable>
|
||||||
|
...
|
||||||
|
</optional>
|
||||||
|
END;
|
||||||
|
</synopsis>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If no error occurs, this form of block simply executes all the
|
||||||
|
<replaceable>statements</replaceable>, and then control passes
|
||||||
|
to the next statement after <literal>END</>. But if an error
|
||||||
|
occurs within the <replaceable>statements</replaceable>, further
|
||||||
|
processing of the <replaceable>statements</replaceable> is
|
||||||
|
abandoned, and control passes to the <literal>EXCEPTION</> list.
|
||||||
|
The list is searched for the first <replaceable>condition</replaceable>
|
||||||
|
matching the error that occurred. If a match is found, the
|
||||||
|
corresponding <replaceable>handler_statements</replaceable> are
|
||||||
|
executed, and then control passes to the next statement after
|
||||||
|
<literal>END</>. If no match is found, the error propagates out
|
||||||
|
as though the <literal>EXCEPTION</> clause were not there at all:
|
||||||
|
the error can be caught by an enclosing block with
|
||||||
|
<literal>EXCEPTION</>, or if there is none it aborts processing
|
||||||
|
of the function. The special condition name <literal>OTHERS</>
|
||||||
|
matches every error type except <literal>QUERY_CANCELED</>.
|
||||||
|
(It is possible, but usually not a good idea, to trap
|
||||||
|
<literal>QUERY_CANCELED</> by name.)
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If a new error occurs within the selected
|
||||||
|
<replaceable>handler_statements</replaceable>, it cannot be caught
|
||||||
|
by this <literal>EXCEPTION</> clause, but is propagated out.
|
||||||
|
A surrounding <literal>EXCEPTION</> clause could catch it.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
When an error is caught by an <literal>EXCEPTION</> clause,
|
||||||
|
the local variables of the <application>PL/pgSQL</> function
|
||||||
|
remain as they were when the error occurred, but all changes
|
||||||
|
to persistent database state within the block are rolled back.
|
||||||
|
As an example, consider this fragment:
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
INSERT INTO mytab(firstname, lastname) VALUES('Tom', 'Jones');
|
||||||
|
BEGIN
|
||||||
|
UPDATE mytab SET firstname = 'Joe' WHERE lastname = 'Jones';
|
||||||
|
x := x + 1;
|
||||||
|
y := x / 0;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN division_by_zero THEN
|
||||||
|
RAISE NOTICE 'caught division_by_zero';
|
||||||
|
RETURN x;
|
||||||
|
END;
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
When control reaches the assignment to <literal>y</>, it will
|
||||||
|
fail with a <literal>division_by_zero</> error. This will be caught by
|
||||||
|
the <literal>EXCEPTION</> clause. The value returned in the
|
||||||
|
<command>RETURN</> statement will be the incremented value of
|
||||||
|
<literal>x</>, but the effects of the <command>UPDATE</> command will
|
||||||
|
have been rolled back. The <command>INSERT</> command is not rolled
|
||||||
|
back, however, so the end result is that the database contains
|
||||||
|
<literal>Tom Jones</> not <literal>Joe Jones</>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<tip>
|
||||||
|
<para>
|
||||||
|
A block containing an <literal>EXCEPTION</> clause is significantly
|
||||||
|
more expensive to enter and exit than a block without one. Therefore,
|
||||||
|
don't use <literal>EXCEPTION</> without need.
|
||||||
|
</para>
|
||||||
|
</tip>
|
||||||
|
</sect2>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="plpgsql-cursors">
|
<sect1 id="plpgsql-cursors">
|
||||||
@ -2120,11 +2215,11 @@ RAISE <replaceable class="parameter">level</replaceable> '<replaceable class="pa
|
|||||||
</synopsis>
|
</synopsis>
|
||||||
|
|
||||||
Possible levels are <literal>DEBUG</literal>,
|
Possible levels are <literal>DEBUG</literal>,
|
||||||
<literal>LOG</literal>,
|
<literal>LOG</literal>, <literal>INFO</literal>,
|
||||||
<literal>NOTICE</literal>, <literal>WARNING</literal>,
|
<literal>NOTICE</literal>, <literal>WARNING</literal>,
|
||||||
and <literal>EXCEPTION</literal>.
|
and <literal>EXCEPTION</literal>.
|
||||||
<literal>EXCEPTION</literal> raises an error and aborts the current
|
<literal>EXCEPTION</literal> raises an error (which normally aborts the
|
||||||
transaction; the other levels only generate messages of different
|
current transaction); the other levels only generate messages of different
|
||||||
priority levels.
|
priority levels.
|
||||||
Whether messages of a particular priority are reported to the client,
|
Whether messages of a particular priority are reported to the client,
|
||||||
written to the server log, or both is controlled by the
|
written to the server log, or both is controlled by the
|
||||||
@ -2164,28 +2259,11 @@ RAISE EXCEPTION 'Nonexistent ID --> %', user_id;
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<productname>PostgreSQL</productname> does not have a very smart
|
<command>RAISE EXCEPTION</command> presently always generates
|
||||||
exception handling model. Whenever the parser, planner/optimizer
|
the same SQLSTATE code, <literal>P0001</>, no matter what message
|
||||||
or executor decide that a statement cannot be processed any longer,
|
it is invoked with. It is possible to trap this exception with
|
||||||
the whole transaction gets aborted and the system jumps back
|
<literal>EXCEPTION ... WHEN RAISE_EXCEPTION THEN ...</> but there
|
||||||
into the main loop to get the next command from the client application.
|
is no way to tell one <command>RAISE</> from another.
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
It is possible to hook into the error mechanism to notice that this
|
|
||||||
happens. But currently it is impossible to tell what really
|
|
||||||
caused the abort (data type format error, floating-point
|
|
||||||
error, parse error, etc.). And it is possible that the database server
|
|
||||||
is in an inconsistent state at this point so returning to the upper
|
|
||||||
executor or issuing more commands might corrupt the whole database.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Thus, the only thing <application>PL/pgSQL</application>
|
|
||||||
currently does when it encounters an abort during execution of a
|
|
||||||
function or trigger procedure is to add some fields to the message
|
|
||||||
telling in which function and where (line number and type of statement)
|
|
||||||
the error happened. The error always stops execution of the function.
|
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.173 2004/07/28 14:23:27 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.174 2004/07/31 07:39:18 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Transaction aborts can now occur two ways:
|
* Transaction aborts can now occur two ways:
|
||||||
@ -1589,7 +1589,8 @@ CleanupTransaction(void)
|
|||||||
* State should still be TRANS_ABORT from AbortTransaction().
|
* State should still be TRANS_ABORT from AbortTransaction().
|
||||||
*/
|
*/
|
||||||
if (s->state != TRANS_ABORT)
|
if (s->state != TRANS_ABORT)
|
||||||
elog(FATAL, "CleanupTransaction and not in abort state");
|
elog(FATAL, "CleanupTransaction: unexpected state %s",
|
||||||
|
TransStateAsString(s->state));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* do abort cleanup processing
|
* do abort cleanup processing
|
||||||
@ -1773,7 +1774,7 @@ CommitTransactionCommand(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* We were just issued a SAVEPOINT inside a transaction block.
|
* We were just issued a SAVEPOINT inside a transaction block.
|
||||||
* Start a subtransaction. (BeginTransactionBlock already
|
* Start a subtransaction. (DefineSavepoint already
|
||||||
* did PushTransaction, so as to have someplace to put the
|
* did PushTransaction, so as to have someplace to put the
|
||||||
* SUBBEGIN state.)
|
* SUBBEGIN state.)
|
||||||
*/
|
*/
|
||||||
@ -1853,6 +1854,7 @@ CleanupAbortedSubTransactions(bool returnName)
|
|||||||
AssertState(PointerIsValid(s->parent));
|
AssertState(PointerIsValid(s->parent));
|
||||||
Assert(s->parent->blockState == TBLOCK_SUBINPROGRESS ||
|
Assert(s->parent->blockState == TBLOCK_SUBINPROGRESS ||
|
||||||
s->parent->blockState == TBLOCK_INPROGRESS ||
|
s->parent->blockState == TBLOCK_INPROGRESS ||
|
||||||
|
s->parent->blockState == TBLOCK_STARTED ||
|
||||||
s->parent->blockState == TBLOCK_SUBABORT_PENDING);
|
s->parent->blockState == TBLOCK_SUBABORT_PENDING);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1878,7 +1880,8 @@ CleanupAbortedSubTransactions(bool returnName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
AssertState(s->blockState == TBLOCK_SUBINPROGRESS ||
|
AssertState(s->blockState == TBLOCK_SUBINPROGRESS ||
|
||||||
s->blockState == TBLOCK_INPROGRESS);
|
s->blockState == TBLOCK_INPROGRESS ||
|
||||||
|
s->blockState == TBLOCK_STARTED);
|
||||||
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@ -2468,7 +2471,7 @@ DefineSavepoint(char *name)
|
|||||||
case TBLOCK_SUBABORT_PENDING:
|
case TBLOCK_SUBABORT_PENDING:
|
||||||
case TBLOCK_SUBENDABORT_RELEASE:
|
case TBLOCK_SUBENDABORT_RELEASE:
|
||||||
case TBLOCK_SUBEND:
|
case TBLOCK_SUBEND:
|
||||||
elog(FATAL, "BeginTransactionBlock: unexpected state %s",
|
elog(FATAL, "DefineSavepoint: unexpected state %s",
|
||||||
BlockStateAsString(s->blockState));
|
BlockStateAsString(s->blockState));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2657,20 +2660,126 @@ RollbackToSavepoint(List *options)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RollbackAndReleaseSavepoint
|
* BeginInternalSubTransaction
|
||||||
|
* This is the same as DefineSavepoint except it allows TBLOCK_STARTED
|
||||||
|
* state, and therefore it can safely be used in a function that might
|
||||||
|
* be called when not inside a BEGIN block. Also, we automatically
|
||||||
|
* cycle through CommitTransactionCommand/StartTransactionCommand
|
||||||
|
* instead of expecting the caller to do it.
|
||||||
*
|
*
|
||||||
* Executes a ROLLBACK TO command, immediately followed by a RELEASE
|
* Optionally, name can be NULL to create an unnamed savepoint.
|
||||||
* of the same savepoint.
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
RollbackAndReleaseSavepoint(List *options)
|
BeginInternalSubTransaction(char *name)
|
||||||
{
|
{
|
||||||
TransactionState s;
|
TransactionState s = CurrentTransactionState;
|
||||||
|
|
||||||
RollbackToSavepoint(options);
|
switch (s->blockState)
|
||||||
s = CurrentTransactionState;
|
{
|
||||||
Assert(s->blockState == TBLOCK_SUBENDABORT);
|
case TBLOCK_STARTED:
|
||||||
|
case TBLOCK_INPROGRESS:
|
||||||
|
case TBLOCK_SUBINPROGRESS:
|
||||||
|
/* Normal subtransaction start */
|
||||||
|
PushTransaction();
|
||||||
|
s = CurrentTransactionState; /* changed by push */
|
||||||
|
/*
|
||||||
|
* Note that we are allocating the savepoint name in the
|
||||||
|
* parent transaction's CurTransactionContext, since we
|
||||||
|
* don't yet have a transaction context for the new guy.
|
||||||
|
*/
|
||||||
|
if (name)
|
||||||
|
s->name = MemoryContextStrdup(CurTransactionContext, name);
|
||||||
|
s->blockState = TBLOCK_SUBBEGIN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* These cases are invalid. Reject them altogether. */
|
||||||
|
case TBLOCK_DEFAULT:
|
||||||
|
case TBLOCK_BEGIN:
|
||||||
|
case TBLOCK_SUBBEGIN:
|
||||||
|
case TBLOCK_ABORT:
|
||||||
|
case TBLOCK_SUBABORT:
|
||||||
|
case TBLOCK_ENDABORT:
|
||||||
|
case TBLOCK_END:
|
||||||
|
case TBLOCK_SUBENDABORT_ALL:
|
||||||
|
case TBLOCK_SUBENDABORT:
|
||||||
|
case TBLOCK_SUBABORT_PENDING:
|
||||||
|
case TBLOCK_SUBENDABORT_RELEASE:
|
||||||
|
case TBLOCK_SUBEND:
|
||||||
|
elog(FATAL, "BeginInternalSubTransaction: unexpected state %s",
|
||||||
|
BlockStateAsString(s->blockState));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommitTransactionCommand();
|
||||||
|
StartTransactionCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ReleaseCurrentSubTransaction
|
||||||
|
*
|
||||||
|
* RELEASE (ie, commit) the innermost subtransaction, regardless of its
|
||||||
|
* savepoint name (if any).
|
||||||
|
* NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ReleaseCurrentSubTransaction(void)
|
||||||
|
{
|
||||||
|
TransactionState s = CurrentTransactionState;
|
||||||
|
|
||||||
|
if (s->blockState != TBLOCK_SUBINPROGRESS)
|
||||||
|
elog(ERROR, "ReleaseCurrentSubTransaction: unexpected state %s",
|
||||||
|
BlockStateAsString(s->blockState));
|
||||||
|
MemoryContextSwitchTo(CurTransactionContext);
|
||||||
|
CommitTransactionToLevel(GetCurrentTransactionNestLevel());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RollbackAndReleaseCurrentSubTransaction
|
||||||
|
*
|
||||||
|
* ROLLBACK and RELEASE (ie, abort) the innermost subtransaction, regardless
|
||||||
|
* of its savepoint name (if any).
|
||||||
|
* NB: do NOT use CommitTransactionCommand/StartTransactionCommand with this.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
RollbackAndReleaseCurrentSubTransaction(void)
|
||||||
|
{
|
||||||
|
TransactionState s = CurrentTransactionState;
|
||||||
|
|
||||||
|
switch (s->blockState)
|
||||||
|
{
|
||||||
|
/* Must be in a subtransaction */
|
||||||
|
case TBLOCK_SUBABORT:
|
||||||
|
case TBLOCK_SUBINPROGRESS:
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* these cases are invalid. */
|
||||||
|
case TBLOCK_DEFAULT:
|
||||||
|
case TBLOCK_STARTED:
|
||||||
|
case TBLOCK_ABORT:
|
||||||
|
case TBLOCK_INPROGRESS:
|
||||||
|
case TBLOCK_BEGIN:
|
||||||
|
case TBLOCK_END:
|
||||||
|
case TBLOCK_ENDABORT:
|
||||||
|
case TBLOCK_SUBEND:
|
||||||
|
case TBLOCK_SUBENDABORT_ALL:
|
||||||
|
case TBLOCK_SUBENDABORT:
|
||||||
|
case TBLOCK_SUBABORT_PENDING:
|
||||||
|
case TBLOCK_SUBENDABORT_RELEASE:
|
||||||
|
case TBLOCK_SUBBEGIN:
|
||||||
|
elog(FATAL, "RollbackAndReleaseCurrentSubTransaction: unexpected state %s",
|
||||||
|
BlockStateAsString(s->blockState));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Abort the current subtransaction, if needed.
|
||||||
|
*/
|
||||||
|
if (s->blockState == TBLOCK_SUBINPROGRESS)
|
||||||
|
AbortSubTransaction();
|
||||||
s->blockState = TBLOCK_SUBENDABORT_RELEASE;
|
s->blockState = TBLOCK_SUBENDABORT_RELEASE;
|
||||||
|
|
||||||
|
/* And clean it up, too */
|
||||||
|
CleanupAbortedSubTransactions(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2748,7 +2857,7 @@ AbortOutOfAnyTransaction(void)
|
|||||||
* Commit everything from the current transaction level
|
* Commit everything from the current transaction level
|
||||||
* up to the specified level (inclusive).
|
* up to the specified level (inclusive).
|
||||||
*/
|
*/
|
||||||
void
|
static void
|
||||||
CommitTransactionToLevel(int level)
|
CommitTransactionToLevel(int level)
|
||||||
{
|
{
|
||||||
TransactionState s = CurrentTransactionState;
|
TransactionState s = CurrentTransactionState;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/access/xact.h,v 1.67 2004/07/27 05:11:24 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/access/xact.h,v 1.68 2004/07/31 07:39:19 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -107,7 +107,9 @@ extern void UserAbortTransactionBlock(void);
|
|||||||
extern void ReleaseSavepoint(List *options);
|
extern void ReleaseSavepoint(List *options);
|
||||||
extern void DefineSavepoint(char *name);
|
extern void DefineSavepoint(char *name);
|
||||||
extern void RollbackToSavepoint(List *options);
|
extern void RollbackToSavepoint(List *options);
|
||||||
extern void RollbackAndReleaseSavepoint(List *options);
|
extern void BeginInternalSubTransaction(char *name);
|
||||||
|
extern void ReleaseCurrentSubTransaction(void);
|
||||||
|
extern void RollbackAndReleaseCurrentSubTransaction(void);
|
||||||
extern bool IsSubTransaction(void);
|
extern bool IsSubTransaction(void);
|
||||||
extern bool IsTransactionBlock(void);
|
extern bool IsTransactionBlock(void);
|
||||||
extern bool IsTransactionOrTransactionBlock(void);
|
extern bool IsTransactionOrTransactionBlock(void);
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2003, PostgreSQL Global Development Group
|
* Copyright (c) 2003, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/utils/errcodes.h,v 1.13 2004/07/27 05:11:35 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/utils/errcodes.h,v 1.14 2004/07/31 07:39:20 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -326,6 +326,10 @@
|
|||||||
#define ERRCODE_CONFIG_FILE_ERROR MAKE_SQLSTATE('F','0', '0','0','0')
|
#define ERRCODE_CONFIG_FILE_ERROR MAKE_SQLSTATE('F','0', '0','0','0')
|
||||||
#define ERRCODE_LOCK_FILE_EXISTS MAKE_SQLSTATE('F','0', '0','0','1')
|
#define ERRCODE_LOCK_FILE_EXISTS MAKE_SQLSTATE('F','0', '0','0','1')
|
||||||
|
|
||||||
|
/* Class P0 - PL/pgSQL Error (PostgreSQL-specific error class) */
|
||||||
|
#define ERRCODE_PLPGSQL_ERROR MAKE_SQLSTATE('P','0', '0','0','0')
|
||||||
|
#define ERRCODE_RAISE_EXCEPTION MAKE_SQLSTATE('P','0', '0','0','1')
|
||||||
|
|
||||||
/* Class XX - Internal Error (PostgreSQL-specific error class) */
|
/* Class XX - Internal Error (PostgreSQL-specific error class) */
|
||||||
/* (this is for "can't-happen" conditions and software bugs) */
|
/* (this is for "can't-happen" conditions and software bugs) */
|
||||||
#define ERRCODE_INTERNAL_ERROR MAKE_SQLSTATE('X','X', '0','0','0')
|
#define ERRCODE_INTERNAL_ERROR MAKE_SQLSTATE('X','X', '0','0','0')
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.57 2004/07/04 02:49:04 tgl Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.58 2004/07/31 07:39:20 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -96,6 +96,8 @@ static void check_assignable(PLpgSQL_datum *datum);
|
|||||||
PLpgSQL_stmt *stmt;
|
PLpgSQL_stmt *stmt;
|
||||||
PLpgSQL_stmts *stmts;
|
PLpgSQL_stmts *stmts;
|
||||||
PLpgSQL_stmt_block *program;
|
PLpgSQL_stmt_block *program;
|
||||||
|
PLpgSQL_exception *exception;
|
||||||
|
PLpgSQL_exceptions *exceptions;
|
||||||
PLpgSQL_nsitem *nsitem;
|
PLpgSQL_nsitem *nsitem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,6 +133,9 @@ static void check_assignable(PLpgSQL_datum *datum);
|
|||||||
%type <stmt> stmt_dynexecute stmt_getdiag
|
%type <stmt> stmt_dynexecute stmt_getdiag
|
||||||
%type <stmt> stmt_open stmt_fetch stmt_close
|
%type <stmt> stmt_open stmt_fetch stmt_close
|
||||||
|
|
||||||
|
%type <exceptions> exception_sect proc_exceptions
|
||||||
|
%type <exception> proc_exception
|
||||||
|
|
||||||
%type <intlist> raise_params
|
%type <intlist> raise_params
|
||||||
%type <ival> raise_level raise_param
|
%type <ival> raise_level raise_param
|
||||||
%type <str> raise_msg
|
%type <str> raise_msg
|
||||||
@ -240,7 +245,7 @@ opt_semi :
|
|||||||
| ';'
|
| ';'
|
||||||
;
|
;
|
||||||
|
|
||||||
pl_block : decl_sect K_BEGIN lno proc_sect K_END
|
pl_block : decl_sect K_BEGIN lno proc_sect exception_sect K_END
|
||||||
{
|
{
|
||||||
PLpgSQL_stmt_block *new;
|
PLpgSQL_stmt_block *new;
|
||||||
|
|
||||||
@ -253,6 +258,7 @@ pl_block : decl_sect K_BEGIN lno proc_sect K_END
|
|||||||
new->n_initvars = $1.n_initvars;
|
new->n_initvars = $1.n_initvars;
|
||||||
new->initvarnos = $1.initvarnos;
|
new->initvarnos = $1.initvarnos;
|
||||||
new->body = $4;
|
new->body = $4;
|
||||||
|
new->exceptions = $5;
|
||||||
|
|
||||||
plpgsql_ns_pop();
|
plpgsql_ns_pop();
|
||||||
|
|
||||||
@ -588,7 +594,7 @@ proc_stmts : proc_stmts proc_stmt
|
|||||||
$1->stmts_alloc *= 2;
|
$1->stmts_alloc *= 2;
|
||||||
$1->stmts = realloc($1->stmts, sizeof(PLpgSQL_stmt *) * $1->stmts_alloc);
|
$1->stmts = realloc($1->stmts, sizeof(PLpgSQL_stmt *) * $1->stmts_alloc);
|
||||||
}
|
}
|
||||||
$1->stmts[$1->stmts_used++] = (struct PLpgSQL_stmt *)$2;
|
$1->stmts[$1->stmts_used++] = $2;
|
||||||
|
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
@ -602,7 +608,7 @@ proc_stmts : proc_stmts proc_stmt
|
|||||||
new->stmts_alloc = 64;
|
new->stmts_alloc = 64;
|
||||||
new->stmts_used = 1;
|
new->stmts_used = 1;
|
||||||
new->stmts = malloc(sizeof(PLpgSQL_stmt *) * new->stmts_alloc);
|
new->stmts = malloc(sizeof(PLpgSQL_stmt *) * new->stmts_alloc);
|
||||||
new->stmts[0] = (struct PLpgSQL_stmt *)$1;
|
new->stmts[0] = $1;
|
||||||
|
|
||||||
$$ = new;
|
$$ = new;
|
||||||
|
|
||||||
@ -832,7 +838,7 @@ stmt_else :
|
|||||||
new->stmts_alloc = 64;
|
new->stmts_alloc = 64;
|
||||||
new->stmts_used = 1;
|
new->stmts_used = 1;
|
||||||
new->stmts = malloc(sizeof(PLpgSQL_stmt *) * new->stmts_alloc);
|
new->stmts = malloc(sizeof(PLpgSQL_stmt *) * new->stmts_alloc);
|
||||||
new->stmts[0] = (struct PLpgSQL_stmt *)new_if;
|
new->stmts[0] = (PLpgSQL_stmt *) new_if;
|
||||||
|
|
||||||
$$ = new;
|
$$ = new;
|
||||||
|
|
||||||
@ -1524,6 +1530,54 @@ execsql_start : T_WORD
|
|||||||
{ $$ = strdup(yytext); }
|
{ $$ = strdup(yytext); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
exception_sect :
|
||||||
|
{ $$ = NULL; }
|
||||||
|
| K_EXCEPTION proc_exceptions
|
||||||
|
{ $$ = $2; }
|
||||||
|
;
|
||||||
|
|
||||||
|
proc_exceptions : proc_exceptions proc_exception
|
||||||
|
{
|
||||||
|
if ($1->exceptions_used == $1->exceptions_alloc)
|
||||||
|
{
|
||||||
|
$1->exceptions_alloc *= 2;
|
||||||
|
$1->exceptions = realloc($1->exceptions, sizeof(PLpgSQL_exception *) * $1->exceptions_alloc);
|
||||||
|
}
|
||||||
|
$1->exceptions[$1->exceptions_used++] = $2;
|
||||||
|
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
|
| proc_exception
|
||||||
|
{
|
||||||
|
PLpgSQL_exceptions *new;
|
||||||
|
|
||||||
|
new = malloc(sizeof(PLpgSQL_exceptions));
|
||||||
|
memset(new, 0, sizeof(PLpgSQL_exceptions));
|
||||||
|
|
||||||
|
new->exceptions_alloc = 64;
|
||||||
|
new->exceptions_used = 1;
|
||||||
|
new->exceptions = malloc(sizeof(PLpgSQL_exception *) * new->exceptions_alloc);
|
||||||
|
new->exceptions[0] = $1;
|
||||||
|
|
||||||
|
$$ = new;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
proc_exception : K_WHEN lno opt_lblname K_THEN proc_sect
|
||||||
|
{
|
||||||
|
PLpgSQL_exception *new;
|
||||||
|
|
||||||
|
new = malloc(sizeof(PLpgSQL_exception));
|
||||||
|
memset(new, 0, sizeof(PLpgSQL_exception));
|
||||||
|
|
||||||
|
new->lineno = $2;
|
||||||
|
new->label = $3;
|
||||||
|
new->action = $5;
|
||||||
|
|
||||||
|
$$ = new;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
expr_until_semi :
|
expr_until_semi :
|
||||||
{ $$ = plpgsql_read_expression(';', ";"); }
|
{ $$ = plpgsql_read_expression(';', ";"); }
|
||||||
;
|
;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.108 2004/07/31 00:45:46 tgl Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.109 2004/07/31 07:39:20 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -56,6 +56,16 @@
|
|||||||
|
|
||||||
static const char *const raise_skip_msg = "RAISE";
|
static const char *const raise_skip_msg = "RAISE";
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *label;
|
||||||
|
int sqlerrstate;
|
||||||
|
} ExceptionLabelMap;
|
||||||
|
|
||||||
|
static const ExceptionLabelMap exception_label_map[] = {
|
||||||
|
#include "plerrcodes.h"
|
||||||
|
{ NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All plpgsql function executions within a single transaction share
|
* All plpgsql function executions within a single transaction share
|
||||||
* the same executor EState for evaluating "simple" expressions. Each
|
* the same executor EState for evaluating "simple" expressions. Each
|
||||||
@ -784,6 +794,32 @@ copy_rec(PLpgSQL_rec * rec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
exception_matches_label(ErrorData *edata, const char *label)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OTHERS matches everything *except* query-canceled;
|
||||||
|
* if you're foolish enough, you can match that explicitly.
|
||||||
|
*/
|
||||||
|
if (pg_strcasecmp(label, "OTHERS") == 0)
|
||||||
|
{
|
||||||
|
if (edata->sqlerrcode == ERRCODE_QUERY_CANCELED)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (i = 0; exception_label_map[i].label != NULL; i++)
|
||||||
|
{
|
||||||
|
if (pg_strcasecmp(label, exception_label_map[i].label) == 0)
|
||||||
|
return (edata->sqlerrcode == exception_label_map[i].sqlerrstate);
|
||||||
|
}
|
||||||
|
/* Should we raise an error if label is unrecognized?? */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* exec_stmt_block Execute a block of statements
|
* exec_stmt_block Execute a block of statements
|
||||||
* ----------
|
* ----------
|
||||||
@ -791,7 +827,7 @@ copy_rec(PLpgSQL_rec * rec)
|
|||||||
static int
|
static int
|
||||||
exec_stmt_block(PLpgSQL_execstate * estate, PLpgSQL_stmt_block * block)
|
exec_stmt_block(PLpgSQL_execstate * estate, PLpgSQL_stmt_block * block)
|
||||||
{
|
{
|
||||||
int rc;
|
volatile int rc = -1;
|
||||||
int i;
|
int i;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
@ -859,13 +895,86 @@ exec_stmt_block(PLpgSQL_execstate * estate, PLpgSQL_stmt_block * block)
|
|||||||
elog(ERROR, "unrecognized dtype: %d",
|
elog(ERROR, "unrecognized dtype: %d",
|
||||||
estate->datums[n]->dtype);
|
estate->datums[n]->dtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (block->exceptions)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Execute the statements in the block's body
|
* Execute the statements in the block's body inside a sub-transaction
|
||||||
|
*/
|
||||||
|
MemoryContext oldcontext = CurrentMemoryContext;
|
||||||
|
volatile bool caught = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start a subtransaction, and re-connect to SPI within it
|
||||||
|
*/
|
||||||
|
SPI_push();
|
||||||
|
BeginInternalSubTransaction(NULL);
|
||||||
|
/* Want to run statements inside function's memory context */
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
if (SPI_connect() != SPI_OK_CONNECT)
|
||||||
|
elog(ERROR, "SPI_connect failed");
|
||||||
|
|
||||||
|
PG_TRY();
|
||||||
|
{
|
||||||
|
rc = exec_stmts(estate, block->body);
|
||||||
|
}
|
||||||
|
PG_CATCH();
|
||||||
|
{
|
||||||
|
ErrorData *edata;
|
||||||
|
PLpgSQL_exceptions *exceptions;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
/* Save error info */
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
edata = CopyErrorData();
|
||||||
|
FlushErrorState();
|
||||||
|
|
||||||
|
/* Abort the inner transaction (and inner SPI connection) */
|
||||||
|
RollbackAndReleaseCurrentSubTransaction();
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
|
SPI_pop();
|
||||||
|
|
||||||
|
/* Look for a matching exception handler */
|
||||||
|
exceptions = block->exceptions;
|
||||||
|
for (j = 0; j < exceptions->exceptions_used; j++)
|
||||||
|
{
|
||||||
|
PLpgSQL_exception *exception = exceptions->exceptions[j];
|
||||||
|
|
||||||
|
if (exception_matches_label(edata, exception->label))
|
||||||
|
{
|
||||||
|
rc = exec_stmts(estate, exception->action);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If no match found, re-throw the error */
|
||||||
|
if (j >= exceptions->exceptions_used)
|
||||||
|
ReThrowError(edata);
|
||||||
|
else
|
||||||
|
FreeErrorData(edata);
|
||||||
|
caught = true;
|
||||||
|
}
|
||||||
|
PG_END_TRY();
|
||||||
|
|
||||||
|
/* Commit the inner transaction, return to outer xact context */
|
||||||
|
if (!caught)
|
||||||
|
{
|
||||||
|
if (SPI_finish() != SPI_OK_FINISH)
|
||||||
|
elog(ERROR, "SPI_finish failed");
|
||||||
|
ReleaseCurrentSubTransaction();
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
SPI_pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Just execute the statements in the block's body
|
||||||
*/
|
*/
|
||||||
rc = exec_stmts(estate, block->body);
|
rc = exec_stmts(estate, block->body);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle the return code.
|
* Handle the return code.
|
||||||
@ -909,7 +1018,7 @@ exec_stmts(PLpgSQL_execstate * estate, PLpgSQL_stmts * stmts)
|
|||||||
|
|
||||||
for (i = 0; i < stmts->stmts_used; i++)
|
for (i = 0; i < stmts->stmts_used; i++)
|
||||||
{
|
{
|
||||||
rc = exec_stmt(estate, (PLpgSQL_stmt *) (stmts->stmts[i]));
|
rc = exec_stmt(estate, stmts->stmts[i]);
|
||||||
if (rc != PLPGSQL_RC_OK)
|
if (rc != PLPGSQL_RC_OK)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -1852,7 +1961,8 @@ exec_stmt_raise(PLpgSQL_execstate * estate, PLpgSQL_stmt_raise * stmt)
|
|||||||
estate->err_text = raise_skip_msg; /* suppress traceback of raise */
|
estate->err_text = raise_skip_msg; /* suppress traceback of raise */
|
||||||
|
|
||||||
ereport(stmt->elog_level,
|
ereport(stmt->elog_level,
|
||||||
(errmsg_internal("%s", plpgsql_dstring_get(&ds))));
|
((stmt->elog_level >= ERROR) ? errcode(ERRCODE_RAISE_EXCEPTION) : 0,
|
||||||
|
errmsg_internal("%s", plpgsql_dstring_get(&ds))));
|
||||||
|
|
||||||
estate->err_text = NULL; /* un-suppress... */
|
estate->err_text = NULL; /* un-suppress... */
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.32 2004/02/21 00:34:53 tgl Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.33 2004/07/31 07:39:20 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -583,6 +583,17 @@ dump_stmt(PLpgSQL_stmt * stmt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dump_stmts(PLpgSQL_stmts * stmts)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
dump_indent += 2;
|
||||||
|
for (i = 0; i < stmts->stmts_used; i++)
|
||||||
|
dump_stmt(stmts->stmts[i]);
|
||||||
|
dump_indent -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_block(PLpgSQL_stmt_block * block)
|
dump_block(PLpgSQL_stmt_block * block)
|
||||||
{
|
{
|
||||||
@ -597,10 +608,19 @@ dump_block(PLpgSQL_stmt_block * block)
|
|||||||
dump_ind();
|
dump_ind();
|
||||||
printf("BLOCK <<%s>>\n", name);
|
printf("BLOCK <<%s>>\n", name);
|
||||||
|
|
||||||
dump_indent += 2;
|
dump_stmts(block->body);
|
||||||
for (i = 0; i < block->body->stmts_used; i++)
|
|
||||||
dump_stmt((PLpgSQL_stmt *) (block->body->stmts[i]));
|
if (block->exceptions)
|
||||||
dump_indent -= 2;
|
{
|
||||||
|
for (i = 0; i < block->exceptions->exceptions_used; i++)
|
||||||
|
{
|
||||||
|
PLpgSQL_exception *exc = block->exceptions->exceptions[i];
|
||||||
|
|
||||||
|
dump_ind();
|
||||||
|
printf(" EXCEPTION WHEN %s THEN\n", exc->label);
|
||||||
|
dump_stmts(exc->action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dump_ind();
|
dump_ind();
|
||||||
printf(" END -- %s\n", name);
|
printf(" END -- %s\n", name);
|
||||||
@ -618,25 +638,17 @@ dump_assign(PLpgSQL_stmt_assign * stmt)
|
|||||||
static void
|
static void
|
||||||
dump_if(PLpgSQL_stmt_if * stmt)
|
dump_if(PLpgSQL_stmt_if * stmt)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
dump_ind();
|
dump_ind();
|
||||||
printf("IF ");
|
printf("IF ");
|
||||||
dump_expr(stmt->cond);
|
dump_expr(stmt->cond);
|
||||||
printf(" THEN\n");
|
printf(" THEN\n");
|
||||||
|
|
||||||
dump_indent += 2;
|
dump_stmts(stmt->true_body);
|
||||||
for (i = 0; i < stmt->true_body->stmts_used; i++)
|
|
||||||
dump_stmt((PLpgSQL_stmt *) (stmt->true_body->stmts[i]));
|
|
||||||
dump_indent -= 2;
|
|
||||||
|
|
||||||
dump_ind();
|
dump_ind();
|
||||||
printf(" ELSE\n");
|
printf(" ELSE\n");
|
||||||
|
|
||||||
dump_indent += 2;
|
dump_stmts(stmt->false_body);
|
||||||
for (i = 0; i < stmt->false_body->stmts_used; i++)
|
|
||||||
dump_stmt((PLpgSQL_stmt *) (stmt->false_body->stmts[i]));
|
|
||||||
dump_indent -= 2;
|
|
||||||
|
|
||||||
dump_ind();
|
dump_ind();
|
||||||
printf(" ENDIF\n");
|
printf(" ENDIF\n");
|
||||||
@ -645,15 +657,10 @@ dump_if(PLpgSQL_stmt_if * stmt)
|
|||||||
static void
|
static void
|
||||||
dump_loop(PLpgSQL_stmt_loop * stmt)
|
dump_loop(PLpgSQL_stmt_loop * stmt)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
dump_ind();
|
dump_ind();
|
||||||
printf("LOOP\n");
|
printf("LOOP\n");
|
||||||
|
|
||||||
dump_indent += 2;
|
dump_stmts(stmt->body);
|
||||||
for (i = 0; i < stmt->body->stmts_used; i++)
|
|
||||||
dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
|
|
||||||
dump_indent -= 2;
|
|
||||||
|
|
||||||
dump_ind();
|
dump_ind();
|
||||||
printf(" ENDLOOP\n");
|
printf(" ENDLOOP\n");
|
||||||
@ -662,17 +669,12 @@ dump_loop(PLpgSQL_stmt_loop * stmt)
|
|||||||
static void
|
static void
|
||||||
dump_while(PLpgSQL_stmt_while * stmt)
|
dump_while(PLpgSQL_stmt_while * stmt)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
dump_ind();
|
dump_ind();
|
||||||
printf("WHILE ");
|
printf("WHILE ");
|
||||||
dump_expr(stmt->cond);
|
dump_expr(stmt->cond);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
dump_indent += 2;
|
dump_stmts(stmt->body);
|
||||||
for (i = 0; i < stmt->body->stmts_used; i++)
|
|
||||||
dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
|
|
||||||
dump_indent -= 2;
|
|
||||||
|
|
||||||
dump_ind();
|
dump_ind();
|
||||||
printf(" ENDWHILE\n");
|
printf(" ENDWHILE\n");
|
||||||
@ -681,8 +683,6 @@ dump_while(PLpgSQL_stmt_while * stmt)
|
|||||||
static void
|
static void
|
||||||
dump_fori(PLpgSQL_stmt_fori * stmt)
|
dump_fori(PLpgSQL_stmt_fori * stmt)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
dump_ind();
|
dump_ind();
|
||||||
printf("FORI %s %s\n", stmt->var->refname, (stmt->reverse) ? "REVERSE" : "NORMAL");
|
printf("FORI %s %s\n", stmt->var->refname, (stmt->reverse) ? "REVERSE" : "NORMAL");
|
||||||
|
|
||||||
@ -695,11 +695,10 @@ dump_fori(PLpgSQL_stmt_fori * stmt)
|
|||||||
printf(" upper = ");
|
printf(" upper = ");
|
||||||
dump_expr(stmt->upper);
|
dump_expr(stmt->upper);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
for (i = 0; i < stmt->body->stmts_used; i++)
|
|
||||||
dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
|
|
||||||
dump_indent -= 2;
|
dump_indent -= 2;
|
||||||
|
|
||||||
|
dump_stmts(stmt->body);
|
||||||
|
|
||||||
dump_ind();
|
dump_ind();
|
||||||
printf(" ENDFORI\n");
|
printf(" ENDFORI\n");
|
||||||
}
|
}
|
||||||
@ -707,17 +706,12 @@ dump_fori(PLpgSQL_stmt_fori * stmt)
|
|||||||
static void
|
static void
|
||||||
dump_fors(PLpgSQL_stmt_fors * stmt)
|
dump_fors(PLpgSQL_stmt_fors * stmt)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
dump_ind();
|
dump_ind();
|
||||||
printf("FORS %s ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
|
printf("FORS %s ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
|
||||||
dump_expr(stmt->query);
|
dump_expr(stmt->query);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
dump_indent += 2;
|
dump_stmts(stmt->body);
|
||||||
for (i = 0; i < stmt->body->stmts_used; i++)
|
|
||||||
dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
|
|
||||||
dump_indent -= 2;
|
|
||||||
|
|
||||||
dump_ind();
|
dump_ind();
|
||||||
printf(" ENDFORS\n");
|
printf(" ENDFORS\n");
|
||||||
@ -891,17 +885,12 @@ dump_dynexecute(PLpgSQL_stmt_dynexecute * stmt)
|
|||||||
static void
|
static void
|
||||||
dump_dynfors(PLpgSQL_stmt_dynfors * stmt)
|
dump_dynfors(PLpgSQL_stmt_dynfors * stmt)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
dump_ind();
|
dump_ind();
|
||||||
printf("FORS %s EXECUTE ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
|
printf("FORS %s EXECUTE ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
|
||||||
dump_expr(stmt->query);
|
dump_expr(stmt->query);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
dump_indent += 2;
|
dump_stmts(stmt->body);
|
||||||
for (i = 0; i < stmt->body->stmts_used; i++)
|
|
||||||
dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
|
|
||||||
dump_indent -= 2;
|
|
||||||
|
|
||||||
dump_ind();
|
dump_ind();
|
||||||
printf(" ENDFORS\n");
|
printf(" ENDFORS\n");
|
||||||
@ -1051,4 +1040,5 @@ plpgsql_dumptree(PLpgSQL_function * func)
|
|||||||
printf("%3d:", func->action->lineno);
|
printf("%3d:", func->action->lineno);
|
||||||
dump_block(func->action);
|
dump_block(func->action);
|
||||||
printf("\nEnd of execution tree of function %s\n\n", func->fn_name);
|
printf("\nEnd of execution tree of function %s\n\n", func->fn_name);
|
||||||
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
203
src/pl/plpgsql/src/plerrcodes.h
Normal file
203
src/pl/plpgsql/src/plerrcodes.h
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* plerrcodes.h
|
||||||
|
* PL/pgSQL error codes (mapping of exception labels to SQLSTATEs)
|
||||||
|
*
|
||||||
|
* Eventually this header file should be auto-generated from errcodes.h
|
||||||
|
* with some sort of sed hackery, but no time for that now. It's likely
|
||||||
|
* that an exact mapping will not be what's wanted anyhow ...
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003, PostgreSQL Global Development Group
|
||||||
|
*
|
||||||
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plerrcodes.h,v 1.1 2004/07/31 07:39:20 tgl Exp $
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
{ "SUCCESSFUL_COMPLETION", ERRCODE_SUCCESSFUL_COMPLETION },
|
||||||
|
{ "WARNING", ERRCODE_WARNING },
|
||||||
|
{ "WARNING_DYNAMIC_RESULT_SETS_RETURNED", ERRCODE_WARNING_DYNAMIC_RESULT_SETS_RETURNED },
|
||||||
|
{ "WARNING_IMPLICIT_ZERO_BIT_PADDING", ERRCODE_WARNING_IMPLICIT_ZERO_BIT_PADDING },
|
||||||
|
{ "WARNING_NULL_VALUE_ELIMINATED_IN_SET_FUNCTION", ERRCODE_WARNING_NULL_VALUE_ELIMINATED_IN_SET_FUNCTION },
|
||||||
|
{ "WARNING_PRIVILEGE_NOT_GRANTED", ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED },
|
||||||
|
{ "WARNING_PRIVILEGE_NOT_REVOKED", ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED },
|
||||||
|
{ "WARNING_STRING_DATA_RIGHT_TRUNCATION", ERRCODE_WARNING_STRING_DATA_RIGHT_TRUNCATION },
|
||||||
|
{ "WARNING_DEPRECATED_FEATURE", ERRCODE_WARNING_DEPRECATED_FEATURE },
|
||||||
|
{ "NO_DATA", ERRCODE_NO_DATA },
|
||||||
|
{ "NO_ADDITIONAL_DYNAMIC_RESULT_SETS_RETURNED", ERRCODE_NO_ADDITIONAL_DYNAMIC_RESULT_SETS_RETURNED },
|
||||||
|
{ "SQL_STATEMENT_NOT_YET_COMPLETE", ERRCODE_SQL_STATEMENT_NOT_YET_COMPLETE },
|
||||||
|
{ "CONNECTION_EXCEPTION", ERRCODE_CONNECTION_EXCEPTION },
|
||||||
|
{ "CONNECTION_DOES_NOT_EXIST", ERRCODE_CONNECTION_DOES_NOT_EXIST },
|
||||||
|
{ "CONNECTION_FAILURE", ERRCODE_CONNECTION_FAILURE },
|
||||||
|
{ "SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION", ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION },
|
||||||
|
{ "SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION", ERRCODE_SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION },
|
||||||
|
{ "TRANSACTION_RESOLUTION_UNKNOWN", ERRCODE_TRANSACTION_RESOLUTION_UNKNOWN },
|
||||||
|
{ "PROTOCOL_VIOLATION", ERRCODE_PROTOCOL_VIOLATION },
|
||||||
|
{ "TRIGGERED_ACTION_EXCEPTION", ERRCODE_TRIGGERED_ACTION_EXCEPTION },
|
||||||
|
{ "FEATURE_NOT_SUPPORTED", ERRCODE_FEATURE_NOT_SUPPORTED },
|
||||||
|
{ "INVALID_TRANSACTION_INITIATION", ERRCODE_INVALID_TRANSACTION_INITIATION },
|
||||||
|
{ "LOCATOR_EXCEPTION", ERRCODE_LOCATOR_EXCEPTION },
|
||||||
|
{ "L_E_INVALID_SPECIFICATION", ERRCODE_L_E_INVALID_SPECIFICATION },
|
||||||
|
{ "INVALID_GRANTOR", ERRCODE_INVALID_GRANTOR },
|
||||||
|
{ "INVALID_GRANT_OPERATION", ERRCODE_INVALID_GRANT_OPERATION },
|
||||||
|
{ "INVALID_ROLE_SPECIFICATION", ERRCODE_INVALID_ROLE_SPECIFICATION },
|
||||||
|
{ "CARDINALITY_VIOLATION", ERRCODE_CARDINALITY_VIOLATION },
|
||||||
|
{ "DATA_EXCEPTION", ERRCODE_DATA_EXCEPTION },
|
||||||
|
{ "ARRAY_ELEMENT_ERROR", ERRCODE_ARRAY_ELEMENT_ERROR },
|
||||||
|
{ "ARRAY_SUBSCRIPT_ERROR", ERRCODE_ARRAY_SUBSCRIPT_ERROR },
|
||||||
|
{ "CHARACTER_NOT_IN_REPERTOIRE", ERRCODE_CHARACTER_NOT_IN_REPERTOIRE },
|
||||||
|
{ "DATETIME_FIELD_OVERFLOW", ERRCODE_DATETIME_FIELD_OVERFLOW },
|
||||||
|
{ "DATETIME_VALUE_OUT_OF_RANGE", ERRCODE_DATETIME_VALUE_OUT_OF_RANGE },
|
||||||
|
{ "DIVISION_BY_ZERO", ERRCODE_DIVISION_BY_ZERO },
|
||||||
|
{ "ERROR_IN_ASSIGNMENT", ERRCODE_ERROR_IN_ASSIGNMENT },
|
||||||
|
{ "ESCAPE_CHARACTER_CONFLICT", ERRCODE_ESCAPE_CHARACTER_CONFLICT },
|
||||||
|
{ "INDICATOR_OVERFLOW", ERRCODE_INDICATOR_OVERFLOW },
|
||||||
|
{ "INTERVAL_FIELD_OVERFLOW", ERRCODE_INTERVAL_FIELD_OVERFLOW },
|
||||||
|
{ "INVALID_ARGUMENT_FOR_LOG", ERRCODE_INVALID_ARGUMENT_FOR_LOG },
|
||||||
|
{ "INVALID_ARGUMENT_FOR_POWER_FUNCTION", ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION },
|
||||||
|
{ "INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION", ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION },
|
||||||
|
{ "INVALID_CHARACTER_VALUE_FOR_CAST", ERRCODE_INVALID_CHARACTER_VALUE_FOR_CAST },
|
||||||
|
{ "INVALID_DATETIME_FORMAT", ERRCODE_INVALID_DATETIME_FORMAT },
|
||||||
|
{ "INVALID_ESCAPE_CHARACTER", ERRCODE_INVALID_ESCAPE_CHARACTER },
|
||||||
|
{ "INVALID_ESCAPE_OCTET", ERRCODE_INVALID_ESCAPE_OCTET },
|
||||||
|
{ "INVALID_ESCAPE_SEQUENCE", ERRCODE_INVALID_ESCAPE_SEQUENCE },
|
||||||
|
{ "INVALID_INDICATOR_PARAMETER_VALUE", ERRCODE_INVALID_INDICATOR_PARAMETER_VALUE },
|
||||||
|
{ "INVALID_LIMIT_VALUE", ERRCODE_INVALID_LIMIT_VALUE },
|
||||||
|
{ "INVALID_PARAMETER_VALUE", ERRCODE_INVALID_PARAMETER_VALUE },
|
||||||
|
{ "INVALID_REGULAR_EXPRESSION", ERRCODE_INVALID_REGULAR_EXPRESSION },
|
||||||
|
{ "INVALID_TIME_ZONE_DISPLACEMENT_VALUE", ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE },
|
||||||
|
{ "INVALID_USE_OF_ESCAPE_CHARACTER", ERRCODE_INVALID_USE_OF_ESCAPE_CHARACTER },
|
||||||
|
{ "MOST_SPECIFIC_TYPE_MISMATCH", ERRCODE_MOST_SPECIFIC_TYPE_MISMATCH },
|
||||||
|
{ "NULL_VALUE_NOT_ALLOWED", ERRCODE_NULL_VALUE_NOT_ALLOWED },
|
||||||
|
{ "NULL_VALUE_NO_INDICATOR_PARAMETER", ERRCODE_NULL_VALUE_NO_INDICATOR_PARAMETER },
|
||||||
|
{ "NUMERIC_VALUE_OUT_OF_RANGE", ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE },
|
||||||
|
{ "STRING_DATA_LENGTH_MISMATCH", ERRCODE_STRING_DATA_LENGTH_MISMATCH },
|
||||||
|
{ "STRING_DATA_RIGHT_TRUNCATION", ERRCODE_STRING_DATA_RIGHT_TRUNCATION },
|
||||||
|
{ "SUBSTRING_ERROR", ERRCODE_SUBSTRING_ERROR },
|
||||||
|
{ "TRIM_ERROR", ERRCODE_TRIM_ERROR },
|
||||||
|
{ "UNTERMINATED_C_STRING", ERRCODE_UNTERMINATED_C_STRING },
|
||||||
|
{ "ZERO_LENGTH_CHARACTER_STRING", ERRCODE_ZERO_LENGTH_CHARACTER_STRING },
|
||||||
|
{ "FLOATING_POINT_EXCEPTION", ERRCODE_FLOATING_POINT_EXCEPTION },
|
||||||
|
{ "INVALID_TEXT_REPRESENTATION", ERRCODE_INVALID_TEXT_REPRESENTATION },
|
||||||
|
{ "INVALID_BINARY_REPRESENTATION", ERRCODE_INVALID_BINARY_REPRESENTATION },
|
||||||
|
{ "BAD_COPY_FILE_FORMAT", ERRCODE_BAD_COPY_FILE_FORMAT },
|
||||||
|
{ "UNTRANSLATABLE_CHARACTER", ERRCODE_UNTRANSLATABLE_CHARACTER },
|
||||||
|
{ "INTEGRITY_CONSTRAINT_VIOLATION", ERRCODE_INTEGRITY_CONSTRAINT_VIOLATION },
|
||||||
|
{ "RESTRICT_VIOLATION", ERRCODE_RESTRICT_VIOLATION },
|
||||||
|
{ "NOT_NULL_VIOLATION", ERRCODE_NOT_NULL_VIOLATION },
|
||||||
|
{ "FOREIGN_KEY_VIOLATION", ERRCODE_FOREIGN_KEY_VIOLATION },
|
||||||
|
{ "UNIQUE_VIOLATION", ERRCODE_UNIQUE_VIOLATION },
|
||||||
|
{ "CHECK_VIOLATION", ERRCODE_CHECK_VIOLATION },
|
||||||
|
{ "INVALID_CURSOR_STATE", ERRCODE_INVALID_CURSOR_STATE },
|
||||||
|
{ "INVALID_TRANSACTION_STATE", ERRCODE_INVALID_TRANSACTION_STATE },
|
||||||
|
{ "ACTIVE_SQL_TRANSACTION", ERRCODE_ACTIVE_SQL_TRANSACTION },
|
||||||
|
{ "BRANCH_TRANSACTION_ALREADY_ACTIVE", ERRCODE_BRANCH_TRANSACTION_ALREADY_ACTIVE },
|
||||||
|
{ "HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL", ERRCODE_HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL },
|
||||||
|
{ "INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION", ERRCODE_INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION },
|
||||||
|
{ "INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION", ERRCODE_INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION },
|
||||||
|
{ "NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION", ERRCODE_NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION },
|
||||||
|
{ "READ_ONLY_SQL_TRANSACTION", ERRCODE_READ_ONLY_SQL_TRANSACTION },
|
||||||
|
{ "SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED", ERRCODE_SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED },
|
||||||
|
{ "NO_ACTIVE_SQL_TRANSACTION", ERRCODE_NO_ACTIVE_SQL_TRANSACTION },
|
||||||
|
{ "IN_FAILED_SQL_TRANSACTION", ERRCODE_IN_FAILED_SQL_TRANSACTION },
|
||||||
|
{ "INVALID_SQL_STATEMENT_NAME", ERRCODE_INVALID_SQL_STATEMENT_NAME },
|
||||||
|
{ "TRIGGERED_DATA_CHANGE_VIOLATION", ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION },
|
||||||
|
{ "INVALID_AUTHORIZATION_SPECIFICATION", ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION },
|
||||||
|
{ "DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST", ERRCODE_DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST },
|
||||||
|
{ "DEPENDENT_OBJECTS_STILL_EXIST", ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST },
|
||||||
|
{ "INVALID_TRANSACTION_TERMINATION", ERRCODE_INVALID_TRANSACTION_TERMINATION },
|
||||||
|
{ "SQL_ROUTINE_EXCEPTION", ERRCODE_SQL_ROUTINE_EXCEPTION },
|
||||||
|
{ "S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT", ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT },
|
||||||
|
{ "S_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED", ERRCODE_S_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED },
|
||||||
|
{ "S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED", ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED },
|
||||||
|
{ "S_R_E_READING_SQL_DATA_NOT_PERMITTED", ERRCODE_S_R_E_READING_SQL_DATA_NOT_PERMITTED },
|
||||||
|
{ "INVALID_CURSOR_NAME", ERRCODE_INVALID_CURSOR_NAME },
|
||||||
|
{ "EXTERNAL_ROUTINE_EXCEPTION", ERRCODE_EXTERNAL_ROUTINE_EXCEPTION },
|
||||||
|
{ "E_R_E_CONTAINING_SQL_NOT_PERMITTED", ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED },
|
||||||
|
{ "E_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED", ERRCODE_E_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED },
|
||||||
|
{ "E_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED", ERRCODE_E_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED },
|
||||||
|
{ "E_R_E_READING_SQL_DATA_NOT_PERMITTED", ERRCODE_E_R_E_READING_SQL_DATA_NOT_PERMITTED },
|
||||||
|
{ "EXTERNAL_ROUTINE_INVOCATION_EXCEPTION", ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION },
|
||||||
|
{ "E_R_I_E_INVALID_SQLSTATE_RETURNED", ERRCODE_E_R_I_E_INVALID_SQLSTATE_RETURNED },
|
||||||
|
{ "E_R_I_E_NULL_VALUE_NOT_ALLOWED", ERRCODE_E_R_I_E_NULL_VALUE_NOT_ALLOWED },
|
||||||
|
{ "E_R_I_E_TRIGGER_PROTOCOL_VIOLATED", ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED },
|
||||||
|
{ "E_R_I_E_SRF_PROTOCOL_VIOLATED", ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED },
|
||||||
|
{ "SAVEPOINT_EXCEPTION", ERRCODE_SAVEPOINT_EXCEPTION },
|
||||||
|
{ "S_E_INVALID_SPECIFICATION", ERRCODE_S_E_INVALID_SPECIFICATION },
|
||||||
|
{ "INVALID_CATALOG_NAME", ERRCODE_INVALID_CATALOG_NAME },
|
||||||
|
{ "INVALID_SCHEMA_NAME", ERRCODE_INVALID_SCHEMA_NAME },
|
||||||
|
{ "TRANSACTION_ROLLBACK", ERRCODE_TRANSACTION_ROLLBACK },
|
||||||
|
{ "T_R_INTEGRITY_CONSTRAINT_VIOLATION", ERRCODE_T_R_INTEGRITY_CONSTRAINT_VIOLATION },
|
||||||
|
{ "T_R_SERIALIZATION_FAILURE", ERRCODE_T_R_SERIALIZATION_FAILURE },
|
||||||
|
{ "T_R_STATEMENT_COMPLETION_UNKNOWN", ERRCODE_T_R_STATEMENT_COMPLETION_UNKNOWN },
|
||||||
|
{ "T_R_DEADLOCK_DETECTED", ERRCODE_T_R_DEADLOCK_DETECTED },
|
||||||
|
{ "SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION", ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION },
|
||||||
|
{ "SYNTAX_ERROR", ERRCODE_SYNTAX_ERROR },
|
||||||
|
{ "INSUFFICIENT_PRIVILEGE", ERRCODE_INSUFFICIENT_PRIVILEGE },
|
||||||
|
{ "CANNOT_COERCE", ERRCODE_CANNOT_COERCE },
|
||||||
|
{ "GROUPING_ERROR", ERRCODE_GROUPING_ERROR },
|
||||||
|
{ "INVALID_FOREIGN_KEY", ERRCODE_INVALID_FOREIGN_KEY },
|
||||||
|
{ "INVALID_NAME", ERRCODE_INVALID_NAME },
|
||||||
|
{ "NAME_TOO_LONG", ERRCODE_NAME_TOO_LONG },
|
||||||
|
{ "RESERVED_NAME", ERRCODE_RESERVED_NAME },
|
||||||
|
{ "DATATYPE_MISMATCH", ERRCODE_DATATYPE_MISMATCH },
|
||||||
|
{ "INDETERMINATE_DATATYPE", ERRCODE_INDETERMINATE_DATATYPE },
|
||||||
|
{ "WRONG_OBJECT_TYPE", ERRCODE_WRONG_OBJECT_TYPE },
|
||||||
|
{ "UNDEFINED_COLUMN", ERRCODE_UNDEFINED_COLUMN },
|
||||||
|
{ "UNDEFINED_CURSOR", ERRCODE_UNDEFINED_CURSOR },
|
||||||
|
{ "UNDEFINED_DATABASE", ERRCODE_UNDEFINED_DATABASE },
|
||||||
|
{ "UNDEFINED_FUNCTION", ERRCODE_UNDEFINED_FUNCTION },
|
||||||
|
{ "UNDEFINED_PSTATEMENT", ERRCODE_UNDEFINED_PSTATEMENT },
|
||||||
|
{ "UNDEFINED_SCHEMA", ERRCODE_UNDEFINED_SCHEMA },
|
||||||
|
{ "UNDEFINED_TABLE", ERRCODE_UNDEFINED_TABLE },
|
||||||
|
{ "UNDEFINED_PARAMETER", ERRCODE_UNDEFINED_PARAMETER },
|
||||||
|
{ "UNDEFINED_OBJECT", ERRCODE_UNDEFINED_OBJECT },
|
||||||
|
{ "DUPLICATE_COLUMN", ERRCODE_DUPLICATE_COLUMN },
|
||||||
|
{ "DUPLICATE_CURSOR", ERRCODE_DUPLICATE_CURSOR },
|
||||||
|
{ "DUPLICATE_DATABASE", ERRCODE_DUPLICATE_DATABASE },
|
||||||
|
{ "DUPLICATE_FUNCTION", ERRCODE_DUPLICATE_FUNCTION },
|
||||||
|
{ "DUPLICATE_PSTATEMENT", ERRCODE_DUPLICATE_PSTATEMENT },
|
||||||
|
{ "DUPLICATE_SCHEMA", ERRCODE_DUPLICATE_SCHEMA },
|
||||||
|
{ "DUPLICATE_TABLE", ERRCODE_DUPLICATE_TABLE },
|
||||||
|
{ "DUPLICATE_ALIAS", ERRCODE_DUPLICATE_ALIAS },
|
||||||
|
{ "DUPLICATE_OBJECT", ERRCODE_DUPLICATE_OBJECT },
|
||||||
|
{ "AMBIGUOUS_COLUMN", ERRCODE_AMBIGUOUS_COLUMN },
|
||||||
|
{ "AMBIGUOUS_FUNCTION", ERRCODE_AMBIGUOUS_FUNCTION },
|
||||||
|
{ "AMBIGUOUS_PARAMETER", ERRCODE_AMBIGUOUS_PARAMETER },
|
||||||
|
{ "AMBIGUOUS_ALIAS", ERRCODE_AMBIGUOUS_ALIAS },
|
||||||
|
{ "INVALID_COLUMN_REFERENCE", ERRCODE_INVALID_COLUMN_REFERENCE },
|
||||||
|
{ "INVALID_COLUMN_DEFINITION", ERRCODE_INVALID_COLUMN_DEFINITION },
|
||||||
|
{ "INVALID_CURSOR_DEFINITION", ERRCODE_INVALID_CURSOR_DEFINITION },
|
||||||
|
{ "INVALID_DATABASE_DEFINITION", ERRCODE_INVALID_DATABASE_DEFINITION },
|
||||||
|
{ "INVALID_FUNCTION_DEFINITION", ERRCODE_INVALID_FUNCTION_DEFINITION },
|
||||||
|
{ "INVALID_PSTATEMENT_DEFINITION", ERRCODE_INVALID_PSTATEMENT_DEFINITION },
|
||||||
|
{ "INVALID_SCHEMA_DEFINITION", ERRCODE_INVALID_SCHEMA_DEFINITION },
|
||||||
|
{ "INVALID_TABLE_DEFINITION", ERRCODE_INVALID_TABLE_DEFINITION },
|
||||||
|
{ "INVALID_OBJECT_DEFINITION", ERRCODE_INVALID_OBJECT_DEFINITION },
|
||||||
|
{ "WITH_CHECK_OPTION_VIOLATION", ERRCODE_WITH_CHECK_OPTION_VIOLATION },
|
||||||
|
{ "INSUFFICIENT_RESOURCES", ERRCODE_INSUFFICIENT_RESOURCES },
|
||||||
|
{ "DISK_FULL", ERRCODE_DISK_FULL },
|
||||||
|
{ "OUT_OF_MEMORY", ERRCODE_OUT_OF_MEMORY },
|
||||||
|
{ "TOO_MANY_CONNECTIONS", ERRCODE_TOO_MANY_CONNECTIONS },
|
||||||
|
{ "PROGRAM_LIMIT_EXCEEDED", ERRCODE_PROGRAM_LIMIT_EXCEEDED },
|
||||||
|
{ "STATEMENT_TOO_COMPLEX", ERRCODE_STATEMENT_TOO_COMPLEX },
|
||||||
|
{ "TOO_MANY_COLUMNS", ERRCODE_TOO_MANY_COLUMNS },
|
||||||
|
{ "TOO_MANY_ARGUMENTS", ERRCODE_TOO_MANY_ARGUMENTS },
|
||||||
|
{ "OBJECT_NOT_IN_PREREQUISITE_STATE", ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE },
|
||||||
|
{ "OBJECT_IN_USE", ERRCODE_OBJECT_IN_USE },
|
||||||
|
{ "CANT_CHANGE_RUNTIME_PARAM", ERRCODE_CANT_CHANGE_RUNTIME_PARAM },
|
||||||
|
{ "OPERATOR_INTERVENTION", ERRCODE_OPERATOR_INTERVENTION },
|
||||||
|
{ "QUERY_CANCELED", ERRCODE_QUERY_CANCELED },
|
||||||
|
{ "ADMIN_SHUTDOWN", ERRCODE_ADMIN_SHUTDOWN },
|
||||||
|
{ "CRASH_SHUTDOWN", ERRCODE_CRASH_SHUTDOWN },
|
||||||
|
{ "CANNOT_CONNECT_NOW", ERRCODE_CANNOT_CONNECT_NOW },
|
||||||
|
{ "IO_ERROR", ERRCODE_IO_ERROR },
|
||||||
|
{ "UNDEFINED_FILE", ERRCODE_UNDEFINED_FILE },
|
||||||
|
{ "DUPLICATE_FILE", ERRCODE_DUPLICATE_FILE },
|
||||||
|
{ "CONFIG_FILE_ERROR", ERRCODE_CONFIG_FILE_ERROR },
|
||||||
|
{ "LOCK_FILE_EXISTS", ERRCODE_LOCK_FILE_EXISTS },
|
||||||
|
{ "PLPGSQL_ERROR", ERRCODE_PLPGSQL_ERROR },
|
||||||
|
{ "RAISE_EXCEPTION", ERRCODE_RAISE_EXCEPTION },
|
||||||
|
{ "INTERNAL_ERROR", ERRCODE_INTERNAL_ERROR },
|
||||||
|
{ "DATA_CORRUPTED", ERRCODE_DATA_CORRUPTED },
|
||||||
|
{ "INDEX_CORRUPTED", ERRCODE_INDEX_CORRUPTED },
|
@ -3,7 +3,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.47 2004/06/06 00:41:28 tgl Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.48 2004/07/31 07:39:20 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -307,14 +307,6 @@ typedef struct PLpgSQL_ns
|
|||||||
} PLpgSQL_ns;
|
} PLpgSQL_ns;
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{ /* List of execution nodes */
|
|
||||||
int stmts_alloc;
|
|
||||||
int stmts_used;
|
|
||||||
struct PLpgSQL_stmt **stmts;
|
|
||||||
} PLpgSQL_stmts;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{ /* Generic execution node */
|
{ /* Generic execution node */
|
||||||
int cmd_type;
|
int cmd_type;
|
||||||
@ -322,12 +314,37 @@ typedef struct
|
|||||||
} PLpgSQL_stmt;
|
} PLpgSQL_stmt;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{ /* List of execution nodes */
|
||||||
|
int stmts_alloc; /* XXX this oughta just be a List ... */
|
||||||
|
int stmts_used;
|
||||||
|
PLpgSQL_stmt **stmts;
|
||||||
|
} PLpgSQL_stmts;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{ /* One EXCEPTION ... WHEN clause */
|
||||||
|
int lineno;
|
||||||
|
char *label;
|
||||||
|
PLpgSQL_stmts *action;
|
||||||
|
} PLpgSQL_exception;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{ /* List of WHEN clauses */
|
||||||
|
int exceptions_alloc; /* XXX this oughta just be a List ... */
|
||||||
|
int exceptions_used;
|
||||||
|
PLpgSQL_exception **exceptions;
|
||||||
|
} PLpgSQL_exceptions;
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{ /* Block of statements */
|
{ /* Block of statements */
|
||||||
int cmd_type;
|
int cmd_type;
|
||||||
int lineno;
|
int lineno;
|
||||||
char *label;
|
char *label;
|
||||||
PLpgSQL_stmts *body;
|
PLpgSQL_stmts *body;
|
||||||
|
PLpgSQL_exceptions *exceptions;
|
||||||
int n_initvars;
|
int n_initvars;
|
||||||
int *initvarnos;
|
int *initvarnos;
|
||||||
} PLpgSQL_stmt_block;
|
} PLpgSQL_stmt_block;
|
||||||
|
@ -1793,3 +1793,60 @@ SELECT * FROM perform_test;
|
|||||||
(3 rows)
|
(3 rows)
|
||||||
|
|
||||||
drop table perform_test;
|
drop table perform_test;
|
||||||
|
--
|
||||||
|
-- Test error trapping
|
||||||
|
--
|
||||||
|
create function trap_zero_divide(int) returns int as $$
|
||||||
|
declare x int;
|
||||||
|
declare sx smallint;
|
||||||
|
begin
|
||||||
|
begin -- start a subtransaction
|
||||||
|
raise notice 'should see this';
|
||||||
|
x := 100 / $1;
|
||||||
|
raise notice 'should see this only if % <> 0', $1;
|
||||||
|
sx := $1;
|
||||||
|
raise notice 'should see this only if % fits in smallint', $1;
|
||||||
|
if $1 < 0 then
|
||||||
|
raise exception '% is less than zero', $1;
|
||||||
|
end if;
|
||||||
|
exception
|
||||||
|
when division_by_zero then
|
||||||
|
raise notice 'caught division_by_zero';
|
||||||
|
x := -1;
|
||||||
|
when NUMERIC_VALUE_OUT_OF_RANGE then
|
||||||
|
raise notice 'caught numeric_value_out_of_range';
|
||||||
|
x := -2;
|
||||||
|
end;
|
||||||
|
return x;
|
||||||
|
end$$ language plpgsql;
|
||||||
|
select trap_zero_divide(50);
|
||||||
|
NOTICE: should see this
|
||||||
|
NOTICE: should see this only if 50 <> 0
|
||||||
|
NOTICE: should see this only if 50 fits in smallint
|
||||||
|
trap_zero_divide
|
||||||
|
------------------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
select trap_zero_divide(0);
|
||||||
|
NOTICE: should see this
|
||||||
|
NOTICE: caught division_by_zero
|
||||||
|
trap_zero_divide
|
||||||
|
------------------
|
||||||
|
-1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
select trap_zero_divide(100000);
|
||||||
|
NOTICE: should see this
|
||||||
|
NOTICE: should see this only if 100000 <> 0
|
||||||
|
NOTICE: caught numeric_value_out_of_range
|
||||||
|
trap_zero_divide
|
||||||
|
------------------
|
||||||
|
-2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
select trap_zero_divide(-100);
|
||||||
|
NOTICE: should see this
|
||||||
|
NOTICE: should see this only if -100 <> 0
|
||||||
|
NOTICE: should see this only if -100 fits in smallint
|
||||||
|
ERROR: -100 is less than zero
|
||||||
|
@ -1608,3 +1608,36 @@ SELECT perform_test_func();
|
|||||||
SELECT * FROM perform_test;
|
SELECT * FROM perform_test;
|
||||||
|
|
||||||
drop table perform_test;
|
drop table perform_test;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Test error trapping
|
||||||
|
--
|
||||||
|
|
||||||
|
create function trap_zero_divide(int) returns int as $$
|
||||||
|
declare x int;
|
||||||
|
declare sx smallint;
|
||||||
|
begin
|
||||||
|
begin -- start a subtransaction
|
||||||
|
raise notice 'should see this';
|
||||||
|
x := 100 / $1;
|
||||||
|
raise notice 'should see this only if % <> 0', $1;
|
||||||
|
sx := $1;
|
||||||
|
raise notice 'should see this only if % fits in smallint', $1;
|
||||||
|
if $1 < 0 then
|
||||||
|
raise exception '% is less than zero', $1;
|
||||||
|
end if;
|
||||||
|
exception
|
||||||
|
when division_by_zero then
|
||||||
|
raise notice 'caught division_by_zero';
|
||||||
|
x := -1;
|
||||||
|
when NUMERIC_VALUE_OUT_OF_RANGE then
|
||||||
|
raise notice 'caught numeric_value_out_of_range';
|
||||||
|
x := -2;
|
||||||
|
end;
|
||||||
|
return x;
|
||||||
|
end$$ language plpgsql;
|
||||||
|
|
||||||
|
select trap_zero_divide(50);
|
||||||
|
select trap_zero_divide(0);
|
||||||
|
select trap_zero_divide(100000);
|
||||||
|
select trap_zero_divide(-100);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user