Hello

Per small recent discussion I corrected patch user's exception.

diff: User can choise any sqlstate (without class U0, which I reserve as 
range for default values sqlstates - if user don't spec sqlstate, is 
used value from this range). There is only basic changes in documentation 
and needs enhancing. I am not able to do (I am sorry, my english is poor).

Note: patch don't create deep changes in plpgsql core. Only enhance stmts 
DECLARE, RAISE and EXCEPTION condition.

Next ToDo (needs discussion): 
  + Optional message in raise stmt for user's or system exception
      raise exception division_by_zero; 
  + Possibility rethrown exception
      raise;

Regards
Pavel Stehule

diff -c -r --new-file pgsql.01/doc/src/sgml/plpgsql.sgml 
pgsql.02/doc/src/sgml/plpgsql.sgml
*** pgsql.01/doc/src/sgml/plpgsql.sgml  2005-06-25 15:29:27.000000000 +0200
--- pgsql.02/doc/src/sgml/plpgsql.sgml  2005-06-25 21:56:24.000000000 +0200
***************
*** 2116,2122 ****
      <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 often unwise, to trap
--- 2116,2124 ----
      <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. You can use exception variable as
!      condition name. Exception variable is declared with type 
!      <literal>EXCEPTION</literal>
       The special condition name <literal>OTHERS</>
       matches every error type except <literal>QUERY_CANCELED</>.
       (It is possible, but often unwise, to trap
***************
*** 2570,2576 ****
      raise errors.
  
  <synopsis>
! RAISE <replaceable class="parameter">level</replaceable> '<replaceable 
class="parameter">format</replaceable>' <optional>, <replaceable 
class="parameter">expression</replaceable> <optional>, 
...</optional></optional>;
  </synopsis>
  
      Possible levels are <literal>DEBUG</literal>,
--- 2572,2579 ----
      raise errors.
  
  <synopsis>
! RAISE <replaceable class="parameter">level</replaceable> 
! <optional>system exception|exception variable</optional> '<replaceable 
class="parameter">format</replaceable>' <optional>, <replaceable 
class="parameter">expression</replaceable> <optional>, 
...</optional></optional>;
  </synopsis>
  
      Possible levels are <literal>DEBUG</literal>,
***************
*** 2587,2592 ****
--- 2590,2599 ----
      variables. See <xref linkend="runtime-config"> for more
      information.
     </para>
+     
+    <para>
+    You can specify any system exception or any user exception.
+    </para>
  
     <para>
      Inside the format string, <literal>%</literal> is replaced by the
diff -c -r --new-file pgsql.01/src/pl/plpgsql/src/gram.y 
pgsql.02/src/pl/plpgsql/src/gram.y
*** pgsql.01/src/pl/plpgsql/src/gram.y  2005-06-25 15:21:22.000000000 +0200
--- pgsql.02/src/pl/plpgsql/src/gram.y  2005-06-25 19:57:42.000000000 +0200
***************
*** 39,44 ****
--- 39,45 ----
  #include "plpgsql.h"
  
  #include "parser/parser.h"
+ #include "utils/elog.h"
  
  static PLpgSQL_expr           *read_sql_construct(int until,
                                                                                
        int until2,
***************
*** 78,83 ****
--- 79,90 ----
                }                                               forvariable;
                struct
                {
+                       bool nospec;
+                       int sqlstate;
+                       char *refname;
+               }                                               opt_excptspec;
+               struct
+               {
                        char *label;
                        int  n_initvars;
                        int  *initvarnos;
***************
*** 103,108 ****
--- 110,116 ----
                PLpgSQL_exception_block *exception_block;
                PLpgSQL_nsitem                  *nsitem;
                PLpgSQL_diag_item               *diagitem;
+               PLpgSQL_usrexcpt                *usrexcpt;
  }
  
  %type <declhdr> decl_sect
***************
*** 115,125 ****
--- 123,135 ----
  %type <list>  decl_cursor_arglist
  %type <nsitem>        decl_aliasitem
  %type <str>           decl_stmts decl_stmt
+ %type <str>   decl_defsqlstate
  
  %type <expr>  expr_until_semi expr_until_rightbracket
  %type <expr>  expr_until_then expr_until_loop
  %type <expr>  opt_exitcond
  
+ 
  %type <ival>  assign_var cursor_variable
  %type <var>           cursor_varptr
  %type <variable>      decl_cursor_arg
***************
*** 144,150 ****
  %type <exception_block> exception_sect
  %type <exception>     proc_exception
  %type <condition>     proc_conditions
! 
  
  %type <ival>  raise_level
  %type <str>           raise_msg
--- 154,161 ----
  %type <exception_block> exception_sect
  %type <exception>     proc_exception
  %type <condition>     proc_conditions
! %type <opt_excptspec> opt_excptspec
! %type <str>   excpt_name
  
  %type <ival>  raise_level
  %type <str>           raise_msg
***************
*** 223,228 ****
--- 234,240 ----
  %token        T_LABEL
  %token        T_WORD
  %token        T_ERROR
+ %token  T_EXCEPTION
  
  %token        O_OPTION
  %token        O_DUMP
***************
*** 332,338 ****
                                                PLpgSQL_variable        *var;
  
                                                var = 
plpgsql_build_variable($1.name, $1.lineno,
!                                                                               
                         $3, true);
                                                if ($2)
                                                {
                                                        if (var->dtype == 
PLPGSQL_DTYPE_VAR)
--- 344,351 ----
                                                PLpgSQL_variable        *var;
  
                                                var = 
plpgsql_build_variable($1.name, $1.lineno,
!                                                       
!                                                                               
                 $3, true);
                                                if ($2)
                                                {
                                                        if (var->dtype == 
PLPGSQL_DTYPE_VAR)
***************
*** 361,366 ****
--- 374,408 ----
                                                                                
 errmsg("default value for row or record variable is not supported")));
                                                }
                                        }
+                               | decl_varname K_EXCEPTION decl_defsqlstate
+                                       {
+                                               PLpgSQL_usrexcpt *ue;
+                                               PLpgSQL_type *dtype;
+                                               
+                                               dtype = (PLpgSQL_type *) 
palloc(sizeof(PLpgSQL_type));
+                                               dtype->typname = "exception";
+                                               dtype->ttype = 
PLPGSQL_TTYPE_EXCEPTION;
+     
+                                               
+                                               ue = (PLpgSQL_usrexcpt *) 
plpgsql_build_variable($1.name, $1.lineno,
+                                                                               
                 dtype, true);
+                                               if ($3)
+                                               {
+                                                       if (strlen($3) != 5)
+                                                               
yyerror("Sqlstate has five chars");
+ 
+                                                       if (strncmp($3,"U0",2) 
== 0)
+                                                               ereport(ERROR,
+                                                                   
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                                                   
errmsg("Invalid class for SQLSTATE value '%s' for user's exception.", $3),
+                                                                   
errhint("Class 'U0' is reserved for default values user's exceptions.")));
+                                                                               
                                
+                                                       ue->sqlstate = 
MAKE_SQLSTATE($3[0],$3[1],$3[2],$3[3],$3[4]);
+                                               } else
+                                                       ue->sqlstate = 
plpgsql_newUsrExceptions();
+                                               
+                                               pfree(dtype);
+                                       }
                                | decl_varname K_ALIAS K_FOR decl_aliasitem ';'
                                        {
                                                plpgsql_ns_additem($4->itemtype,
***************
*** 563,568 ****
--- 605,626 ----
                                | K_DEFAULT
                                ;
  
+ decl_defsqlstate      : ';'
+                                       { $$ = NULL; }
+                               | decl_defkey
+                                       {
+                                           if (yylex() != T_STRING)
+                                                     ereport(ERROR,
+                                                         
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                                          errmsg("Default 
value for exception type have to be string constant")));
+                                           $$ = plpgsql_get_string_value();
+                                           if (yylex() != ';')
+                                                   yyerror("syntax error");
+                                           
+                                       }
+                               ;
+                               
+ 
  proc_sect             :
                                        {
                                                $$ = NIL;
***************
*** 1185,1191 ****
                                        }
                                ;
  
! stmt_raise            : K_RAISE lno raise_level raise_msg
                                        {
                                                PLpgSQL_stmt_raise              
*new;
                                                int     tok;
--- 1243,1249 ----
                                        }
                                ;
  
! stmt_raise            : K_RAISE lno raise_level opt_excptspec raise_msg
                                        {
                                                PLpgSQL_stmt_raise              
*new;
                                                int     tok;
***************
*** 1195,1203 ****
                                                new->cmd_type   = 
PLPGSQL_STMT_RAISE;
                                                new->lineno             = $2;
                                                new->elog_level = $3;
!                                               new->message    = $4;
                                                new->params             = NIL;
  
                                                tok = yylex();
  
                                                /*
--- 1253,1273 ----
                                                new->cmd_type   = 
PLPGSQL_STMT_RAISE;
                                                new->lineno             = $2;
                                                new->elog_level = $3;
!                                               new->message    = $5;
                                                new->params             = NIL;
  
+                                                 if ($4.nospec == false)
+                                                 {
+                                                     new->sqlstate = 
$4.sqlstate;
+                                                     new->refname = $4.refname;
+                                                 }
+                                                 else
+                                               {
+                                                     new->sqlstate = 
(new->elog_level >= ERROR)?ERRCODE_RAISE_EXCEPTION:0;
+                                                   new->refname = NULL;
+                                               }
+ 
+ 
                                                tok = yylex();
  
                                                /*
***************
*** 1260,1265 ****
--- 1330,1358 ----
                                        }
                                ;
  
+ opt_excptspec          : T_EXCEPTION
+                                         {
+                                                 $$.nospec = false;
+                                                 $$.sqlstate = 
yylval.usrexcpt->sqlstate;
+                                                 $$.refname = 
yylval.usrexcpt->refname;
+                                         }
+                         | T_WORD
+                                         {
+ 
+                                                 PLpgSQL_condition *c = 
plpgsql_parse_err_condition(yytext);
+                                                 if (c->sqlerrstate == 0) /* 
others */
+                                                         yyerror("You have to 
use exception's variable or system exception");
+ 
+                                                 $$.nospec = false;
+                                                 $$.sqlstate = c->sqlerrstate;
+                                                 $$.refname = c->condname;
+                                         }
+                         | /* EMPTY */
+                                         {
+                                                 $$.nospec = true;
+                                         }
+ 
+ 
  loop_body             : proc_sect lno K_END K_LOOP opt_endlabel ';'
                                        { 
                                                $$.list = $1;
***************
*** 1583,1589 ****
                                        }
                                ;
  
! proc_conditions       : proc_conditions K_OR opt_lblname
                                                {
                                                        PLpgSQL_condition       
*old;
  
--- 1676,1682 ----
                                        }
                                ;
  
! proc_conditions       : proc_conditions K_OR excpt_name
                                                {
                                                        PLpgSQL_condition       
*old;
  
***************
*** 1593,1604 ****
  
                                                        $$ = $1;
                                                }
!                               | opt_lblname
                                                {
                                                        $$ = 
plpgsql_parse_err_condition($1);
                                                }
                                ;
  
  expr_until_semi :
                                        { $$ = plpgsql_read_expression(';', 
";"); }
                                ;
--- 1686,1711 ----
  
                                                        $$ = $1;
                                                }
!                               | excpt_name
                                                {
                                                        $$ = 
plpgsql_parse_err_condition($1);
                                                }
                                ;
  
+ excpt_name:                   T_WORD  
+                                               {
+                                                       char    *name;
+ 
+                                                       
plpgsql_convert_ident(yytext, &name, 1);
+                                                       $$ = name;
+                                               }
+                               | T_EXCEPTION
+                                               {
+                                                       $$ = 
yylval.usrexcpt->refname;
+                                               }
+                               ;
+                           
+ 
  expr_until_semi :
                                        { $$ = plpgsql_read_expression(';', 
";"); }
                                ;
diff -c -r --new-file pgsql.01/src/pl/plpgsql/src/pl_comp.c 
pgsql.02/src/pl/plpgsql/src/pl_comp.c
*** pgsql.01/src/pl/plpgsql/src/pl_comp.c       2005-06-24 13:11:25.000000000 
+0200
--- pgsql.02/src/pl/plpgsql/src/pl_comp.c       2005-06-25 20:03:14.000000000 
+0200
***************
*** 80,85 ****
--- 80,87 ----
  bool          plpgsql_DumpExecTree = false;
  bool          plpgsql_check_syntax = false;
  
+ int     plpgsql_user_excpt;
+ 
  PLpgSQL_function *plpgsql_curr_compile;
  
  /* A context appropriate for short-term allocs during compilation */
***************
*** 315,320 ****
--- 317,324 ----
        /* This is short-lived, so needn't allocate in function's cxt */
        plpgsql_Datums = palloc(sizeof(PLpgSQL_datum *) * datums_alloc);
        datums_last = 0;
+       
+       plpgsql_user_excpt = 0;
  
        /*
         * Do extra syntax checks when validating the function
***************
*** 904,910 ****
                        case PLPGSQL_NSTYPE_ROW:
                                plpgsql_yylval.row = (PLpgSQL_row *) 
(plpgsql_Datums[nse->itemno]);
                                return T_ROW;
! 
                        default:
                                return T_ERROR;
                }
--- 908,918 ----
                        case PLPGSQL_NSTYPE_ROW:
                                plpgsql_yylval.row = (PLpgSQL_row *) 
(plpgsql_Datums[nse->itemno]);
                                return T_ROW;
!                               
!                       case PLPGSQL_NSTYPE_EXCEPTION:
!                               plpgsql_yylval.usrexcpt = (PLpgSQL_usrexcpt *) 
(plpgsql_Datums[nse->itemno]);
!                               return T_EXCEPTION;
!                               
                        default:
                                return T_ERROR;
                }
***************
*** 1626,1631 ****
--- 1634,1658 ----
                                result = (PLpgSQL_variable *) rec;
                                break;
                        }
+                 case PLPGSQL_TTYPE_EXCEPTION:
+                         {
+                             /* Exception pseudo type */
+                             PLpgSQL_usrexcpt *excpt;
+ 
+                             excpt = palloc0(sizeof(PLpgSQL_usrexcpt));
+                             excpt->dtype = PLPGSQL_DTYPE_EXCEPTION;
+                             excpt->refname = pstrdup(refname);
+                             excpt->lineno = lineno;
+ 
+                             plpgsql_adddatum((PLpgSQL_datum *) excpt);
+                             if (add2namespace)
+                                     
plpgsql_ns_additem(PLPGSQL_NSTYPE_EXCEPTION,
+                                                                     
excpt->eno,
+                                                                     refname);
+                             result = (PLpgSQL_variable *) excpt;
+                             break;
+                         }
+ 
                case PLPGSQL_TTYPE_PSEUDO:
                        ereport(ERROR,
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
***************
*** 1893,1898 ****
--- 1920,1928 ----
        PLpgSQL_condition *new;
        PLpgSQL_condition *prev;
  
+         PLpgSQL_nsitem *nse;
+         char       *cp[1];
+ 
        /*
         * XXX Eventually we will want to look for user-defined exception
         * names here.
***************
*** 1924,1929 ****
--- 1954,1986 ----
                }
        }
  
+         if (!prev)
+         {
+             /* Do case conversion and word separation */
+             plpgsql_convert_ident(condname, cp, 1);
+ 
+             /*
+             * Do a lookup on the compiler's namestack
+             */
+             nse = plpgsql_ns_lookup(cp[0], NULL);
+ 
+             if (nse != NULL)
+             {
+                 PLpgSQL_usrexcpt *excpt = (PLpgSQL_usrexcpt *) 
(plpgsql_Datums[nse->itemno]);
+                 if (nse->itemtype == PLPGSQL_NSTYPE_EXCEPTION)
+                 {
+                     new = palloc(sizeof(PLpgSQL_condition));
+                     new->sqlerrstate = excpt->sqlstate;
+                     new->condname = condname;
+                     new->next = prev;
+                     prev = new;
+                 }
+             }
+             pfree(cp[0]);
+         }
+ 
+ 
+ 
        if (!prev)
                ereport(ERROR,
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
***************
*** 2177,2179 ****
--- 2234,2251 ----
        if (hentry == NULL)
                elog(WARNING, "trying to delete function that does not exist");
  }
+ 
+ #define MAX_USER_EXCPT 999
+ 
+ int
+ plpgsql_newUsrExceptions(void)
+ {
+     char rs[4];
+ 
+     if (plpgsql_user_excpt == MAX_USER_EXCPT)
+             ereport(ERROR,
+                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                                  errmsg("Too much user's exception")));
+     sprintf(rs,"%03d", ++plpgsql_user_excpt);
+     return MAKE_SQLSTATE('U','0', rs[0],rs[1],rs[2]);
+ }
diff -c -r --new-file pgsql.01/src/pl/plpgsql/src/pl_exec.c 
pgsql.02/src/pl/plpgsql/src/pl_exec.c
*** pgsql.01/src/pl/plpgsql/src/pl_exec.c       2005-06-24 13:11:25.000000000 
+0200
--- pgsql.02/src/pl/plpgsql/src/pl_exec.c       2005-06-25 19:36:02.000000000 
+0200
***************
*** 722,727 ****
--- 722,730 ----
                         */
                        result = datum;
                        break;
+               case PLPGSQL_DTYPE_EXCEPTION:
+                       result = NULL;
+                       break;
  
                default:
                        elog(ERROR, "unrecognized dtype: %d", datum->dtype);
***************
*** 825,830 ****
--- 828,834 ----
  
                        case PLPGSQL_DTYPE_RECFIELD:
                        case PLPGSQL_DTYPE_ARRAYELEM:
+                       case PLPGSQL_DTYPE_EXCEPTION:
                                break;
  
                        default:
***************
*** 2061,2069 ****
         */
        estate->err_text = raise_skip_msg;      /* suppress traceback of raise 
*/
  
!       ereport(stmt->elog_level,
!        ((stmt->elog_level >= ERROR) ? errcode(ERRCODE_RAISE_EXCEPTION) : 0,
!         errmsg_internal("%s", plpgsql_dstring_get(&ds))));
  
        estate->err_text = NULL;        /* un-suppress... */
  
--- 2065,2081 ----
         */
        estate->err_text = raise_skip_msg;      /* suppress traceback of raise 
*/
  
! 
!         if (stmt->refname != NULL)
!             ereport(stmt->elog_level,           /* User's exception */
!                 (errcode(stmt->sqlstate),
!                  errdetail("User's exception/notice - sqlstate: '%s', name: 
'%s'", unpack_sql_state(stmt->sqlstate), stmt->refname),
!                errhint("from RAISE stmt on line %d", stmt->lineno),
!                     errmsg_internal("%s", plpgsql_dstring_get(&ds))));
!         else
!             ereport(stmt->elog_level,
!                 (errcode(stmt->sqlstate), 
!                     errmsg_internal("%s", plpgsql_dstring_get(&ds))));
  
        estate->err_text = NULL;        /* un-suppress... */
  
diff -c -r --new-file pgsql.01/src/pl/plpgsql/src/plpgsql.h 
pgsql.02/src/pl/plpgsql/src/plpgsql.h
*** pgsql.01/src/pl/plpgsql/src/plpgsql.h       2005-06-24 13:11:25.000000000 
+0200
--- pgsql.02/src/pl/plpgsql/src/plpgsql.h       2005-06-25 19:27:28.000000000 
+0200
***************
*** 58,64 ****
        PLPGSQL_NSTYPE_LABEL,
        PLPGSQL_NSTYPE_VAR,
        PLPGSQL_NSTYPE_ROW,
!       PLPGSQL_NSTYPE_REC
  };
  
  /* ----------
--- 58,65 ----
        PLPGSQL_NSTYPE_LABEL,
        PLPGSQL_NSTYPE_VAR,
        PLPGSQL_NSTYPE_ROW,
!       PLPGSQL_NSTYPE_REC,
!       PLPGSQL_NSTYPE_EXCEPTION
  };
  
  /* ----------
***************
*** 73,79 ****
        PLPGSQL_DTYPE_RECFIELD,
        PLPGSQL_DTYPE_ARRAYELEM,
        PLPGSQL_DTYPE_EXPR,
!       PLPGSQL_DTYPE_TRIGARG
  };
  
  /* ----------
--- 74,81 ----
        PLPGSQL_DTYPE_RECFIELD,
        PLPGSQL_DTYPE_ARRAYELEM,
        PLPGSQL_DTYPE_EXPR,
!       PLPGSQL_DTYPE_TRIGARG,
!       PLPGSQL_DTYPE_EXCEPTION
  };
  
  /* ----------
***************
*** 85,91 ****
        PLPGSQL_TTYPE_SCALAR,           /* scalar types and domains */
        PLPGSQL_TTYPE_ROW,                      /* composite types */
        PLPGSQL_TTYPE_REC,                      /* RECORD pseudotype */
!       PLPGSQL_TTYPE_PSEUDO            /* other pseudotypes */
  };
  
  /* ----------
--- 87,94 ----
        PLPGSQL_TTYPE_SCALAR,           /* scalar types and domains */
        PLPGSQL_TTYPE_ROW,                      /* composite types */
        PLPGSQL_TTYPE_REC,                      /* RECORD pseudotype */
!       PLPGSQL_TTYPE_PSEUDO,           /* other pseudotypes */
!       PLPGSQL_TTYPE_EXCEPTION
  };
  
  /* ----------
***************
*** 190,195 ****
--- 193,207 ----
        int                     lineno;
  } PLpgSQL_variable;
  
+ typedef struct
+ {
+       int                     dtype;                          /* Exception 
variable */
+       int                     eno;
+       char    *refname;
+       int     lineno;
+       int     sqlstate;
+ } PLpgSQL_usrexcpt;
+ 
  typedef struct PLpgSQL_expr
  {                                                             /* SQL Query to 
plan and execute        */
        int                     dtype;
***************
*** 516,521 ****
--- 528,535 ----
        int                     cmd_type;
        int                     lineno;
        int                     elog_level;
+       int                     sqlstate;
+       char       *refname;
        char       *message;
        List       *params;                     /* list of expressions */
  } PLpgSQL_stmt_raise;
***************
*** 688,693 ****
--- 702,709 ----
  extern int    plpgsql_add_initdatums(int **varnos);
  extern void plpgsql_HashTableInit(void);
  extern void plpgsql_compile_error_callback(void *arg);
+ extern int plpgsql_newUsrExceptions(void);
+ 
  
  /* ----------
   * Functions in pl_handler.c
diff -c -r --new-file pgsql.01/src/test/regress/expected/plpgsql.out 
pgsql.02/src/test/regress/expected/plpgsql.out
*** pgsql.01/src/test/regress/expected/plpgsql.out      2005-06-25 
15:23:17.000000000 +0200
--- pgsql.02/src/test/regress/expected/plpgsql.out      2005-06-25 
20:34:05.000000000 +0200
***************
*** 2709,2711 ****
--- 2709,2770 ----
  DROP FUNCTION
  drop function vfoo2();
  ERROR:  function vfoo2() does not exist
+ 
+ -- user's exception
+ create function innerfx() returns integer as $$
+ declare my_excpt exception = 'U0001';
+ begin -- using msgtext as one param of exception
+   raise exception my_excpt '%', CURRENT_TIMESTAMP;
+   return 1;
+ end $$ language plpgsql;
+ ERROR:  Invalid class for SQLSTATE value 'U0001' for user's exception.
+ HINT:  Class 'U0' is reserved for default values user's exceptions.
+ CONTEXT:  compile of PL/pgSQL function "innerfx" near line 1
+ create function innerfx() returns integer as $$
+ declare my_excpt exception = 'U1001';
+ begin -- using msgtext as one param of exception
+   raise exception my_excpt '%', 100.34::numeric;
+   return 1;
+ end $$ language plpgsql;
+ CREATE FUNCTION
+ create function outerfx() returns integer as $$
+ declare 
+   my_excpt exception = 'U1001';
+   alias_div_by_zero exception = '22012';
+   my_excpt_def_sqlstate exception;
+ begin
+   begin
+     raise exception my_excpt_def_sqlstate 'foo';
+   exception when my_excpt_def_sqlstate then
+     raise notice '01 catch: %, %', sqlstate, sqlerrm;
+   end;
+   begin
+     raise notice '%', innerfx();
+   exception when my_excpt then
+     raise notice '02 catch: %, %', sqlstate, sqlerrm::numeric;
+   end;
+   begin
+     raise exception alias_div_by_zero 'testing';
+   exception when division_by_zero then
+     raise notice 'Divison by zero: %, %', sqlstate, sqlerrm;
+   end;
+   return 1;
+ end; $$ language plpgsql;
+ CREATE FUNCTION
+ select innerfx();
+ ERROR:  100.34
+ DETAIL:  User's exception/notice - sqlstate: 'U1001', name: 'my_excpt'
+ HINT:  from RAISE stmt on line 3
+ select outerfx();
+ NOTICE:  01 catch: U0001, foo
+ NOTICE:  02 catch: U1001, 100.34
+ NOTICE:  Divison by zero: 22012, testing
+  outerfx 
+ ---------
+        1
+ (1 row)
+ 
+ drop function outerfx();
+ DROP FUNCTION
+ drop function innerfx();
+ DROP FUNCTION
diff -c -r --new-file pgsql.01/src/test/regress/sql/plpgsql.sql 
pgsql.02/src/test/regress/sql/plpgsql.sql
*** pgsql.01/src/test/regress/sql/plpgsql.sql   2005-06-25 14:10:30.000000000 
+0200
--- pgsql.02/src/test/regress/sql/plpgsql.sql   2005-06-25 20:32:59.000000000 
+0200
***************
*** 2266,2268 ****
--- 2266,2314 ----
  
  drop function vfoo();
  drop function vfoo2();
+ 
+ -- user's exception
+ create function innerfx() returns integer as $$
+ declare my_excpt exception = 'U0001';
+ begin -- using msgtext as one param of exception
+   raise exception my_excpt '%', CURRENT_TIMESTAMP;
+   return 1;
+ end $$ language plpgsql;
+ 
+ 
+ create function innerfx() returns integer as $$
+ declare my_excpt exception = 'U1001';
+ begin -- using msgtext as one param of exception
+   raise exception my_excpt '%', 100.34::numeric;
+   return 1;
+ end $$ language plpgsql;
+ 
+ create function outerfx() returns integer as $$
+ declare 
+   my_excpt exception = 'U1001';
+   alias_div_by_zero exception = '22012';
+   my_excpt_def_sqlstate exception;
+ begin
+   begin
+     raise exception my_excpt_def_sqlstate 'foo';
+   exception when my_excpt_def_sqlstate then
+     raise notice '01 catch: %, %', sqlstate, sqlerrm;
+   end;
+   begin
+     raise notice '%', innerfx();
+   exception when my_excpt then
+     raise notice '02 catch: %, %', sqlstate, sqlerrm::numeric;
+   end;
+   begin
+     raise exception alias_div_by_zero 'testing';
+   exception when division_by_zero then
+     raise notice 'Divison by zero: %, %', sqlstate, sqlerrm;
+   end;
+   return 1;
+ end; $$ language plpgsql;
+ 
+ select innerfx();
+ select outerfx();
+ 
+ drop function outerfx();
+ drop function innerfx();
---------------------------(end of broadcast)---------------------------
TIP 5: Have you checked our extensive FAQ?

               http://www.postgresql.org/docs/faq

Reply via email to