diff --git a/doc/src/sgml/errcodes.sgml b/doc/src/sgml/errcodes.sgml index 5d1a770bf87f1c47e7e91d3640c641dcab947387..ca3bc9ca4f1e8e6f4aca28faa2114d9195015b92 100644 --- a/doc/src/sgml/errcodes.sgml +++ b/doc/src/sgml/errcodes.sgml @@ -1,4 +1,4 @@ -<!-- $PostgreSQL: pgsql/doc/src/sgml/errcodes.sgml,v 1.6 2004/05/16 23:18:52 neilc Exp $ --> +<!-- $PostgreSQL: pgsql/doc/src/sgml/errcodes.sgml,v 1.7 2004/07/31 23:04:54 tgl Exp $ --> <appendix id="errcodes-appendix"> <title><productname>PostgreSQL</productname> Error Codes</title> @@ -41,10 +41,18 @@ within the class but do not have any more-specific code assigned. </para> + <para> + The <application>PL/pgSQL</> condition name for each error code is the + same as the phrase shown in the table, with underscores substituted + for spaces. For example, code <literal>22012</>, DIVISION BY ZERO, + has condition name <literal>DIVISION_BY_ZERO</>. Condition names can + be written in either upper or lower case. + </para> + <!-- The following table should correspond to the contents of - src/include/utils/errcodes.h. + src/include/utils/errcodes.h and src/pl/plpgsql/src/plerrcodes.h. --> <table id="errcodes-table"> @@ -82,27 +90,37 @@ <row> <entry><literal>0100C</literal></entry> -<entry>WARNING DYNAMIC RESULT SETS RETURNED</entry> +<entry>DYNAMIC RESULT SETS RETURNED</entry> </row> <row> <entry><literal>01008</literal></entry> -<entry>WARNING IMPLICIT ZERO BIT PADDING</entry> +<entry>IMPLICIT ZERO BIT PADDING</entry> </row> <row> <entry><literal>01003</literal></entry> -<entry>WARNING NULL VALUE ELIMINATED IN SET FUNCTION</entry> +<entry>NULL VALUE ELIMINATED IN SET FUNCTION</entry> +</row> + +<row> +<entry><literal>01007</literal></entry> +<entry>PRIVILEGE NOT GRANTED</entry> +</row> + +<row> +<entry><literal>01006</literal></entry> +<entry>PRIVILEGE NOT REVOKED</entry> </row> <row> <entry><literal>01004</literal></entry> -<entry>WARNING STRING DATA RIGHT TRUNCATION</entry> +<entry>STRING DATA RIGHT TRUNCATION</entry> </row> <row> <entry><literal>01P01</literal></entry> -<entry>WARNING DEPRECATED FEATURE</entry> +<entry>DEPRECATED FEATURE</entry> </row> <row> @@ -218,7 +236,7 @@ <row> <entry><literal>0F001</literal></entry> -<entry>INVALID SPECIFICATION</entry> +<entry>INVALID LOCATOR SPECIFICATION</entry> </row> @@ -272,7 +290,7 @@ <row> <entry><literal>2202E</literal></entry> -<entry>ARRAY ELEMENT ERROR</entry> +<entry>ARRAY SUBSCRIPT ERROR</entry> </row> <row> @@ -728,6 +746,22 @@ </row> +<row> +<entry>Class 3B</entry> +<entry>Savepoint Exception</entry> +</row> + +<row> +<entry><literal>3B000</literal></entry> +<entry>SAVEPOINT EXCEPTION</entry> +</row> + +<row> +<entry><literal>3B001</literal></entry> +<entry>INVALID SAVEPOINT SPECIFICATION</entry> +</row> + + <row> <entry>Class 3D</entry> <entry>Invalid Catalog Name</entry> @@ -762,7 +796,7 @@ <row> <entry><literal>40002</literal></entry> -<entry>INTEGRITY CONSTRAINT VIOLATION</entry> +<entry>TRANSACTION INTEGRITY CONSTRAINT VIOLATION</entry> </row> <row> @@ -893,7 +927,7 @@ <row> <entry><literal>42P05</literal></entry> -<entry>DUPLICATE PSTATEMENT</entry> +<entry>DUPLICATE PREPARED STATEMENT</entry> </row> <row> @@ -963,7 +997,7 @@ <row> <entry><literal>42P14</literal></entry> -<entry>INVALID PSTATEMENT DEFINITION</entry> +<entry>INVALID PREPARED STATEMENT DEFINITION</entry> </row> <row> @@ -1134,6 +1168,22 @@ </row> +<row> +<entry>Class P0</entry> +<entry><application>PL/pgSQL</> Error</entry> +</row> + +<row> +<entry><literal>P0000</literal></entry> +<entry>PLPGSQL ERROR</entry> +</row> + +<row> +<entry><literal>P0001</literal></entry> +<entry>RAISE EXCEPTION</entry> +</row> + + <row> <entry>Class XX</entry> <entry>Internal Error</entry> diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml index 7f3f84448d789ce47cbc3027dc50fe399d50298b..e44b886214b06acf7829fd71e5e4e54de62fb85d 100644 --- a/doc/src/sgml/plpgsql.sgml +++ b/doc/src/sgml/plpgsql.sgml @@ -1,5 +1,5 @@ <!-- -$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.42 2004/07/31 07:39:17 tgl Exp $ +$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.43 2004/07/31 23:04:54 tgl Exp $ --> <chapter id="plpgsql"> @@ -1816,12 +1816,11 @@ END LOOP; BEGIN <replaceable>statements</replaceable> EXCEPTION - WHEN <replaceable>condition</replaceable> THEN + WHEN <replaceable>condition</replaceable> <optional> OR <replaceable>condition</replaceable> ... </optional> THEN <replaceable>handler_statements</replaceable> - <optional> WHEN <replaceable>condition</replaceable> THEN - <replaceable>handler_statements</replaceable> - ... - </optional> + <optional> WHEN <replaceable>condition</replaceable> <optional> OR <replaceable>condition</replaceable> ... </optional> THEN + <replaceable>handler_statements</replaceable> + ... </optional> END; </synopsis> </para> @@ -1841,10 +1840,18 @@ END; 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</> + of the function. + </para> + + <para> + The <replaceable>condition</replaceable> names can be any of those + shown in <xref linkend="errcodes-appendix">. A category name matches + any error within its category. + 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 + (It is possible, but often unwise, to trap <literal>QUERY_CANCELED</> by name.) + Condition names are not case-sensitive. </para> <para> @@ -1879,9 +1886,9 @@ END; 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</>. + have been rolled back. The <command>INSERT</> command preceding the + block is not rolled back, however, so the end result is that the database + contains <literal>Tom Jones</> not <literal>Joe Jones</>. </para> <tip> diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index e9f2b0e879f296d894674776f3c3e2ce21308ee4..4a2d26ddb9d97a291cb33b74a563bf420b5b97cf 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/elog.h,v 1.71 2004/07/31 00:45:43 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/elog.h,v 1.72 2004/07/31 23:04:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -61,6 +61,10 @@ (PGSIXBIT(ch1) + (PGSIXBIT(ch2) << 6) + (PGSIXBIT(ch3) << 12) + \ (PGSIXBIT(ch4) << 18) + (PGSIXBIT(ch5) << 24)) +/* These macros depend on the fact that '0' becomes a zero in SIXBIT */ +#define ERRCODE_TO_CATEGORY(ec) ((ec) & ((1 << 12) - 1)) +#define ERRCODE_IS_CATEGORY(ec) (((ec) & ~((1 << 12) - 1)) == 0) + /* SQLSTATE codes for errors are defined in a separate file */ #include "utils/errcodes.h" diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y index 628c81b570bc7d1cf3269277fb1581762154639c..96c5c61725dcdad56537f577d5c68f6b7dd3270f 100644 --- a/src/pl/plpgsql/src/gram.y +++ b/src/pl/plpgsql/src/gram.y @@ -4,7 +4,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.58 2004/07/31 07:39:20 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.59 2004/07/31 23:04:56 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -96,6 +96,7 @@ static void check_assignable(PLpgSQL_datum *datum); PLpgSQL_stmt *stmt; PLpgSQL_stmts *stmts; PLpgSQL_stmt_block *program; + PLpgSQL_condition *condition; PLpgSQL_exception *exception; PLpgSQL_exceptions *exceptions; PLpgSQL_nsitem *nsitem; @@ -135,6 +136,7 @@ static void check_assignable(PLpgSQL_datum *datum); %type <exceptions> exception_sect proc_exceptions %type <exception> proc_exception +%type <condition> proc_conditions %type <intlist> raise_params %type <ival> raise_level raise_param @@ -181,6 +183,7 @@ static void check_assignable(PLpgSQL_datum *datum); %token K_NOTICE %token K_NULL %token K_OPEN +%token K_OR %token K_PERFORM %token K_ROW_COUNT %token K_RAISE @@ -1563,21 +1566,52 @@ proc_exceptions : proc_exceptions proc_exception } ; -proc_exception : K_WHEN lno opt_lblname K_THEN proc_sect +proc_exception : K_WHEN lno proc_conditions 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->lineno = $2; + new->conditions = $3; + new->action = $5; $$ = new; } ; +proc_conditions : proc_conditions K_OR opt_lblname + { + PLpgSQL_condition *new; + PLpgSQL_condition *old; + + new = malloc(sizeof(PLpgSQL_condition)); + memset(new, 0, sizeof(PLpgSQL_condition)); + + new->condname = $3; + new->next = NULL; + + for (old = $1; old->next != NULL; old = old->next) + /* skip */ ; + old->next = new; + + $$ = $1; + } + | opt_lblname + { + PLpgSQL_condition *new; + + new = malloc(sizeof(PLpgSQL_condition)); + memset(new, 0, sizeof(PLpgSQL_condition)); + + new->condname = $1; + new->next = NULL; + + $$ = new; + } + ; + expr_until_semi : { $$ = plpgsql_read_expression(';', ";"); } ; diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 0950149a494763ef6d025b433a897b0f12872153..4c579223d91a0fff0bd8c0fafc30ab1442f44f83 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -3,7 +3,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.110 2004/07/31 20:55:44 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.111 2004/07/31 23:04:56 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -795,27 +795,45 @@ copy_rec(PLpgSQL_rec * rec) static bool -exception_matches_label(ErrorData *edata, const char *label) +exception_matches_conditions(ErrorData *edata, PLpgSQL_condition *cond) { - 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++) + for (; cond != NULL; cond = cond->next) { - if (pg_strcasecmp(label, exception_label_map[i].label) == 0) - return (edata->sqlerrcode == exception_label_map[i].sqlerrstate); + const char *condname = cond->condname; + int i; + + /* + * OTHERS matches everything *except* query-canceled; + * if you're foolish enough, you can match that explicitly. + */ + if (pg_strcasecmp(condname, "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(condname, exception_label_map[i].label) == 0) + { + int labelerrcode = exception_label_map[i].sqlerrstate; + + /* Exact match? */ + if (edata->sqlerrcode == labelerrcode) + return true; + /* Category match? */ + if (ERRCODE_IS_CATEGORY(labelerrcode) && + ERRCODE_TO_CATEGORY(edata->sqlerrcode) == labelerrcode) + return true; + /* + * You would think we should "break" here, but there are some + * duplicate names in the table, so keep looking. + */ + } + } + /* Should we raise an error if condname is unrecognized?? */ } - /* Should we raise an error if label is unrecognized?? */ return false; } @@ -944,7 +962,7 @@ exec_stmt_block(PLpgSQL_execstate * estate, PLpgSQL_stmt_block * block) { PLpgSQL_exception *exception = exceptions->exceptions[j]; - if (exception_matches_label(edata, exception->label)) + if (exception_matches_conditions(edata, exception->conditions)) { rc = exec_stmts(estate, exception->action); break; diff --git a/src/pl/plpgsql/src/pl_funcs.c b/src/pl/plpgsql/src/pl_funcs.c index b4649067522a2bb2a88ec26ede4ffddb8f743dc9..028bc3836cbb6b8d68f3193b975a79740eac3710 100644 --- a/src/pl/plpgsql/src/pl_funcs.c +++ b/src/pl/plpgsql/src/pl_funcs.c @@ -3,7 +3,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.33 2004/07/31 07:39:20 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.34 2004/07/31 23:04:56 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -615,9 +615,17 @@ dump_block(PLpgSQL_stmt_block * block) for (i = 0; i < block->exceptions->exceptions_used; i++) { PLpgSQL_exception *exc = block->exceptions->exceptions[i]; + PLpgSQL_condition *cond; dump_ind(); - printf(" EXCEPTION WHEN %s THEN\n", exc->label); + printf(" EXCEPTION WHEN "); + for (cond = exc->conditions; cond; cond = cond->next) + { + if (cond != exc->conditions) + printf(" OR "); + printf("%s", cond->condname); + } + printf(" THEN\n"); dump_stmts(exc->action); } } diff --git a/src/pl/plpgsql/src/plerrcodes.h b/src/pl/plpgsql/src/plerrcodes.h index 4e76bde6739945d5e3efaefe95698ad039e36351..2448701d906d57e85dd26d1c4d4e215f229c7079 100644 --- a/src/pl/plpgsql/src/plerrcodes.h +++ b/src/pl/plpgsql/src/plerrcodes.h @@ -9,22 +9,12 @@ * * 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 $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/plerrcodes.h,v 1.2 2004/07/31 23:04:56 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 }, +/* Success and warnings can't be caught, so omit them from table */ { "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 }, @@ -37,7 +27,7 @@ { "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_LOCATOR_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 }, @@ -53,7 +43,7 @@ { "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_LOGARITHM", 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 }, @@ -107,30 +97,30 @@ { "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 }, +{ "FUNCTION_EXECUTED_NO_RETURN_STATEMENT", ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT }, +{ "MODIFYING_SQL_DATA_NOT_PERMITTED", ERRCODE_S_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED }, +{ "PROHIBITED_SQL_STATEMENT_ATTEMPTED", ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED }, +{ "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 }, +{ "CONTAINING_SQL_NOT_PERMITTED", ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED }, +{ "MODIFYING_SQL_DATA_NOT_PERMITTED", ERRCODE_E_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED }, +{ "PROHIBITED_SQL_STATEMENT_ATTEMPTED", ERRCODE_E_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED }, +{ "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 }, +{ "INVALID_SQLSTATE_RETURNED", ERRCODE_E_R_I_E_INVALID_SQLSTATE_RETURNED }, +{ "NULL_VALUE_NOT_ALLOWED", ERRCODE_E_R_I_E_NULL_VALUE_NOT_ALLOWED }, +{ "TRIGGER_PROTOCOL_VIOLATED", ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED }, +{ "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_SAVEPOINT_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 }, +{ "TRANSACTION_INTEGRITY_CONSTRAINT_VIOLATION", ERRCODE_T_R_INTEGRITY_CONSTRAINT_VIOLATION }, +{ "SERIALIZATION_FAILURE", ERRCODE_T_R_SERIALIZATION_FAILURE }, +{ "STATEMENT_COMPLETION_UNKNOWN", ERRCODE_T_R_STATEMENT_COMPLETION_UNKNOWN }, +{ "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 }, @@ -156,7 +146,7 @@ { "DUPLICATE_CURSOR", ERRCODE_DUPLICATE_CURSOR }, { "DUPLICATE_DATABASE", ERRCODE_DUPLICATE_DATABASE }, { "DUPLICATE_FUNCTION", ERRCODE_DUPLICATE_FUNCTION }, -{ "DUPLICATE_PSTATEMENT", ERRCODE_DUPLICATE_PSTATEMENT }, +{ "DUPLICATE_PREPARED_STATEMENT", ERRCODE_DUPLICATE_PSTATEMENT }, { "DUPLICATE_SCHEMA", ERRCODE_DUPLICATE_SCHEMA }, { "DUPLICATE_TABLE", ERRCODE_DUPLICATE_TABLE }, { "DUPLICATE_ALIAS", ERRCODE_DUPLICATE_ALIAS }, @@ -170,7 +160,7 @@ { "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_PREPARED_STATEMENT_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 }, diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index 28868cf731efbbc0a189f08aa7dd989ae8461972..d57d4a7025ecc85917543cdc7c33ddfdbbec71de 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -3,7 +3,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.48 2004/07/31 07:39:20 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.49 2004/07/31 23:04:56 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -322,10 +322,16 @@ typedef struct } PLpgSQL_stmts; +typedef struct PLpgSQL_condition +{ /* One EXCEPTION condition name */ + char *condname; + struct PLpgSQL_condition *next; +} PLpgSQL_condition; + typedef struct { /* One EXCEPTION ... WHEN clause */ int lineno; - char *label; + PLpgSQL_condition *conditions; PLpgSQL_stmts *action; } PLpgSQL_exception; diff --git a/src/pl/plpgsql/src/scan.l b/src/pl/plpgsql/src/scan.l index d369170cf3eafd9365e5bae212dcf1720785b68c..5e6ccd68d71f6b33e75b25cbb710f3ec1693c868 100644 --- a/src/pl/plpgsql/src/scan.l +++ b/src/pl/plpgsql/src/scan.l @@ -4,7 +4,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.35 2004/06/03 22:56:43 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.36 2004/07/31 23:04:56 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -165,6 +165,7 @@ not { return K_NOT; } notice { return K_NOTICE; } null { return K_NULL; } open { return K_OPEN; } +or { return K_OR; } perform { return K_PERFORM; } raise { return K_RAISE; } rename { return K_RENAME; } diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out index 6907905cc51ec1c2532b55e7069690ff6908eaef..73962dbb37a5c6a24cf79e797686538e8c9a5c5d 100644 --- a/src/test/regress/expected/plpgsql.out +++ b/src/test/regress/expected/plpgsql.out @@ -1798,7 +1798,7 @@ drop table perform_test; -- create function trap_zero_divide(int) returns int as $$ declare x int; -declare sx smallint; + sx smallint; begin begin -- start a subtransaction raise notice 'should see this'; @@ -1850,3 +1850,88 @@ 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 +create function trap_matching_test(int) returns int as $$ +declare x int; + sx smallint; + y int; +begin + begin -- start a subtransaction + x := 100 / $1; + sx := $1; + select into y unique1 from tenk1 where unique2 = + (select unique2 from tenk1 b where ten = $1); + exception + when data_exception then -- category match + raise notice 'caught data_exception'; + x := -1; + when NUMERIC_VALUE_OUT_OF_RANGE OR CARDINALITY_VIOLATION then + raise notice 'caught numeric_value_out_of_range or cardinality_violation'; + x := -2; + end; + return x; +end$$ language plpgsql; +select trap_matching_test(50); + trap_matching_test +-------------------- + 2 +(1 row) + +select trap_matching_test(0); +NOTICE: caught data_exception + trap_matching_test +-------------------- + -1 +(1 row) + +select trap_matching_test(100000); +NOTICE: caught data_exception + trap_matching_test +-------------------- + -1 +(1 row) + +select trap_matching_test(1); +NOTICE: caught numeric_value_out_of_range or cardinality_violation + trap_matching_test +-------------------- + -2 +(1 row) + +create temp table foo (f1 int); +create function blockme() returns int as $$ +declare x int; +begin + x := 1; + insert into foo values(x); + begin + x := x + 1; + insert into foo values(x); + -- we assume this will take longer than 1 second: + select count(*) into x from tenk1 a, tenk1 b, tenk1 c; + exception + when others then + raise notice 'caught others?'; + return -1; + when query_canceled then + raise notice 'nyeah nyeah, can''t stop me'; + x := x * 10; + end; + insert into foo values(x); + return x; +end$$ language plpgsql; +set statement_timeout to 1000; +select blockme(); +NOTICE: nyeah nyeah, can't stop me + blockme +--------- + 20 +(1 row) + +reset statement_timeout; +select * from foo; + f1 +---- + 1 + 20 +(2 rows) + diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql index 48a78196a892efeb7b53bf905b42d47af0857676..948a02ac0e214c833c9727055274d752b8c3fd67 100644 --- a/src/test/regress/sql/plpgsql.sql +++ b/src/test/regress/sql/plpgsql.sql @@ -1615,7 +1615,7 @@ drop table perform_test; create function trap_zero_divide(int) returns int as $$ declare x int; -declare sx smallint; + sx smallint; begin begin -- start a subtransaction raise notice 'should see this'; @@ -1641,3 +1641,61 @@ select trap_zero_divide(50); select trap_zero_divide(0); select trap_zero_divide(100000); select trap_zero_divide(-100); + +create function trap_matching_test(int) returns int as $$ +declare x int; + sx smallint; + y int; +begin + begin -- start a subtransaction + x := 100 / $1; + sx := $1; + select into y unique1 from tenk1 where unique2 = + (select unique2 from tenk1 b where ten = $1); + exception + when data_exception then -- category match + raise notice 'caught data_exception'; + x := -1; + when NUMERIC_VALUE_OUT_OF_RANGE OR CARDINALITY_VIOLATION then + raise notice 'caught numeric_value_out_of_range or cardinality_violation'; + x := -2; + end; + return x; +end$$ language plpgsql; + +select trap_matching_test(50); +select trap_matching_test(0); +select trap_matching_test(100000); +select trap_matching_test(1); + +create temp table foo (f1 int); + +create function blockme() returns int as $$ +declare x int; +begin + x := 1; + insert into foo values(x); + begin + x := x + 1; + insert into foo values(x); + -- we assume this will take longer than 1 second: + select count(*) into x from tenk1 a, tenk1 b, tenk1 c; + exception + when others then + raise notice 'caught others?'; + return -1; + when query_canceled then + raise notice 'nyeah nyeah, can''t stop me'; + x := x * 10; + end; + insert into foo values(x); + return x; +end$$ language plpgsql; + +set statement_timeout to 1000; + +select blockme(); + +reset statement_timeout; + +select * from foo;