Hello,

I changed code by your and Neil's notes. The name SQLCODE isn't well,
better is SQLSTATE. It's very similar DB2 variable. I am not sure, so my 
solutions is best. Propably not. It's only particular solution for 
plpgsql. The files plpgsql.sql and plpgsql.out are diffs for regression 
tests.

 This patch is implementation of variables SQLERRM and SQLSTATE for plpgsql 
 language. Variable SQLSTATE contains five chars PostgreSQL Error Code, 
 SQLERRM contains relevant message last catched exception. All variables 
 are attached to plpgsql_block and have local scope. Default values are 
 '00000' for SQLSTATE and 'Sucessful completion' for SQLERRM.  
 
Regards
 
Pavel Stehule
 
*** test.old/plpgsql.sql        2005-02-22 08:18:27.000000000 +0100
--- test/plpgsql.sql    2005-03-08 09:58:23.419281208 +0100
***************
*** 1917,1920 ****
  create function void_return_expr() returns void as $$
  begin
      return 5;
! end;$$ language plpgsql;
--- 1917,1944 ----
  create function void_return_expr() returns void as $$
  begin
      return 5;
! end;$$ language plpgsql;
! 
! --
! -- Test of built variables SQLERRM and SQLSTATE
! --
! 
! create or replace function trap_exceptions() returns void as $_$
! begin
!   begin
!     raise exception 'first exception';
!   exception when others then
!     raise notice '% %', SQLSTATE, SQLERRM;
!   end;
!   raise notice '% %', SQLSTATE, SQLERRM;
!   begin
!     raise exception 'last exception';
!   exception when others then
!     raise notice '% %', SQLSTATE, SQLERRM;
!   end;
!   return;
! end; $_$ language plpgsql;
! 
! select trap_exceptions();
! 
! 
*** test.old/plpgsql.out        2005-02-22 08:18:25.000000000 +0100
--- test/plpgsql.out    2005-03-08 09:56:58.272225528 +0100
***************
*** 2242,2244 ****
--- 2242,2252 ----
  ERROR:  function returning void cannot specify RETURN expression at or near 
"5" at character 72
  LINE 3:     return 5;
                     ^
+ CREATE FUNCTION
+ psql:plpgsql.sql:1942: NOTICE:  P0001 first exception
+ psql:plpgsql.sql:1942: NOTICE:  000000 Sucessful completion
+ psql:plpgsql.sql:1942: NOTICE:  P0001 last exception
+  trap_exceptions 
+ -----------------
+  
+ (1 row)
diff -c -r src.old/gram.y src/gram.y
*** src.old/gram.y      2005-02-22 08:18:24.000000000 +0100
--- src/gram.y  2005-03-08 09:22:20.886036232 +0100
***************
*** 80,85 ****
--- 80,90 ----
                        int  n_initvars;
                        int  *initvarnos;
                }                                               declhdr;
+                 struct 
+               {
+                       int sqlstate_varno;
+                       int sqlerrm_varno;
+               }                                               fict_vars;
                List                                    *list;
                PLpgSQL_type                    *dtype;
                PLpgSQL_datum                   *scalar;        /* a VAR, 
RECFIELD, or TRIGARG */
***************
*** 95,101 ****
                PLpgSQL_nsitem                  *nsitem;
                PLpgSQL_diag_item               *diagitem;
  }
! 
  %type <declhdr> decl_sect
  %type <varname> decl_varname
  %type <str>           decl_renname
--- 100,106 ----
                PLpgSQL_nsitem                  *nsitem;
                PLpgSQL_diag_item               *diagitem;
  }
! %type <fict_vars> fict_vars_sect
  %type <declhdr> decl_sect
  %type <varname> decl_varname
  %type <str>           decl_renname
***************
*** 244,268 ****
                                | ';'
                                ;
  
! pl_block              : decl_sect K_BEGIN lno proc_sect exception_sect K_END
                                        {
                                                PLpgSQL_stmt_block *new;
  
                                                new = 
palloc0(sizeof(PLpgSQL_stmt_block));
  
                                                new->cmd_type   = 
PLPGSQL_STMT_BLOCK;
!                                               new->lineno             = $3;
                                                new->label              = 
$1.label;
                                                new->n_initvars = $1.n_initvars;
                                                new->initvarnos = $1.initvarnos;
!                                               new->body               = $4;
!                                               new->exceptions = $5;
  
                                                plpgsql_ns_pop();
  
                                                $$ = (PLpgSQL_stmt *)new;
                                        }
                                ;
  
  
  decl_sect             : opt_label
--- 249,288 ----
                                | ';'
                                ;
  
! pl_block              : decl_sect fict_vars_sect K_BEGIN lno proc_sect 
exception_sect K_END
                                        {
                                                PLpgSQL_stmt_block *new;
  
                                                new = 
palloc0(sizeof(PLpgSQL_stmt_block));
  
                                                new->cmd_type   = 
PLPGSQL_STMT_BLOCK;
!                                               new->lineno             = $4;
                                                new->label              = 
$1.label;
                                                new->n_initvars = $1.n_initvars;
                                                new->initvarnos = $1.initvarnos;
!                                               new->body               = $5;
!                                               new->exceptions = $6;
! 
!                                               new->sqlstate_varno = 
$2.sqlstate_varno;
!                                               new->sqlerrm_varno = 
$2.sqlerrm_varno;
  
                                                plpgsql_ns_pop();
  
                                                $$ = (PLpgSQL_stmt *)new;
                                        }
                                ;
+ fict_vars_sect            :
+                                       {
+                                               plpgsql_ns_setlocal(false);
+                                               PLpgSQL_variable        *var;
+                                               var = 
plpgsql_build_variable("sqlstate", 0,
+                                                                            
plpgsql_build_datatype(TEXTOID, -1), true);  
+                                               $$.sqlstate_varno = var->dno;
+                                               var = 
plpgsql_build_variable("sqlerrm", 0,
+                                                                            
plpgsql_build_datatype(TEXTOID, -1), true);  
+                                               $$.sqlerrm_varno = var->dno;
+                                               plpgsql_add_initdatums(NULL);
+                                       };
  
  
  decl_sect             : opt_label
diff -c -r src.old/pl_exec.c src/pl_exec.c
*** src.old/pl_exec.c   2005-02-24 02:11:40.000000000 +0100
--- src/pl_exec.c       2005-03-08 09:40:16.537512352 +0100
***************
*** 181,186 ****
--- 181,187 ----
  static void exec_init_tuple_store(PLpgSQL_execstate *estate);
  static bool compatible_tupdesc(TupleDesc td1, TupleDesc td2);
  static void exec_set_found(PLpgSQL_execstate *estate, bool state);
+ static char *unpack_sql_state(int ssval);
  
  
  /* ----------
***************
*** 809,814 ****
--- 810,829 ----
        int                     i;
        int                     n;
  
+       /* setup SQLSTATE and SQLERRM */
+       PLpgSQL_var *var;
+  
+       var = (PLpgSQL_var *) (estate->datums[block->sqlstate_varno]);
+       var->isnull = false;
+       var->freeval = true;
+       var->value = DirectFunctionCall1(textin, CStringGetDatum("00000"));
+  
+       var = (PLpgSQL_var *) (estate->datums[block->sqlerrm_varno]);
+       var->isnull = false;
+       var->freeval = true;
+       var->value = DirectFunctionCall1(textin, CStringGetDatum("Sucessful 
completion"));
+ 
+ 
        /*
         * First initialize all variables declared in this block
         */
***************
*** 918,923 ****
--- 933,949 ----
                        MemoryContextSwitchTo(oldcontext);
                        CurrentResourceOwner = oldowner;
  
+ 
+                       /* set SQLSTATE and SQLERRM variables */
+                       
+                       var = (PLpgSQL_var *) 
(estate->datums[block->sqlstate_varno]);
+                       pfree((void *) (var->value));
+                       var->value = DirectFunctionCall1(textin, 
CStringGetDatum(unpack_sql_state(edata->sqlerrcode)));
+  
+                       var = (PLpgSQL_var *) 
(estate->datums[block->sqlerrm_varno]);
+                       pfree((void *) (var->value));
+                       var->value = DirectFunctionCall1(textin, 
CStringGetDatum(edata->message));
+ 
                        /*
                         * If AtEOSubXact_SPI() popped any SPI context of the 
subxact,
                         * it will have left us in a disconnected state.  We 
need this
***************
*** 4319,4321 ****
--- 4345,4368 ----
                FreeExecutorState(simple_eval_estate);
        simple_eval_estate = NULL;
  }
+ 
+ /* 
+  * unpack MAKE_SQLSTATE code 
+  * This code is redundand backend/utils/error/elog.c. I din't 
+  * wont modify different part than plpgsql
+  */
+  
+ static char *
+ unpack_sql_state(int ssval)
+ {
+       static  char            tbuf[12];
+       int                     i;
+ 
+       for (i = 0; i < 5; i++)
+       {
+               tbuf[i] = PGUNSIXBIT(ssval);
+               ssval >>= 6;
+       }
+       tbuf[i] = '\0';
+       return tbuf;
+ }
diff -c -r src.old/plpgsql.h src/plpgsql.h
*** src.old/plpgsql.h   2005-02-22 08:18:24.000000000 +0100
--- src/plpgsql.h       2005-03-08 08:59:46.877876760 +0100
***************
*** 339,344 ****
--- 339,346 ----
        List       *exceptions;         /* List of WHEN clauses */
        int                     n_initvars;
        int                *initvarnos;
+       int             sqlstate_varno;
+         int           sqlerrm_varno;
  } PLpgSQL_stmt_block;
  
  
---------------------------(end of broadcast)---------------------------
TIP 4: Don't 'kill -9' the postmaster

Reply via email to