GET DIAGNOSTICS statement to PL/pgSQL to access SPI_processed
authorJan Wieck <[email protected]>
Tue, 5 Sep 2000 09:02:18 +0000 (09:02 +0000)
committerJan Wieck <[email protected]>
Tue, 5 Sep 2000 09:02:18 +0000 (09:02 +0000)
and SPI_return values. Patch from Philip Warner.

Jan

src/pl/plpgsql/src/gram.y
src/pl/plpgsql/src/pl_exec.c
src/pl/plpgsql/src/pl_funcs.c
src/pl/plpgsql/src/plpgsql.h
src/pl/plpgsql/src/scan.l

index 99f7a1b0f6e820f615264bdbd039c15152498e05..8251d71908ef8791a2e0bc20ca242a87ef42678a 100644 (file)
@@ -4,7 +4,7 @@
  *                       procedural language
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.11 2000/08/31 13:26:15 wieck Exp $
+ *    $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.12 2000/09/05 09:02:18 wieck Exp $
  *
  *    This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -113,12 +113,15 @@ static    PLpgSQL_expr    *make_tupret_expr(PLpgSQL_row *row);
 %type <stmt>   stmt_assign, stmt_if, stmt_loop, stmt_while, stmt_exit
 %type <stmt>   stmt_return, stmt_raise, stmt_execsql, stmt_fori
 %type <stmt>   stmt_fors, stmt_select, stmt_perform
-%type <stmt>   stmt_dynexecute, stmt_dynfors
+%type <stmt>   stmt_dynexecute, stmt_dynfors, stmt_getdiag
 
 %type <dtlist> raise_params
 %type <ival>   raise_level, raise_param
 %type <str>    raise_msg
 
+%type <dtlist> getdiag_items, getdiag_targets
+%type <ival>   getdiag_item, getdiag_target
+
 %type <ival>   lno
 
        /*
@@ -131,6 +134,7 @@ static      PLpgSQL_expr    *make_tupret_expr(PLpgSQL_row *row);
 %token K_DEBUG
 %token K_DECLARE
 %token K_DEFAULT
+%token K_DIAGNOSTICS
 %token K_DOTDOT
 %token K_ELSE
 %token K_END
@@ -139,6 +143,7 @@ static      PLpgSQL_expr    *make_tupret_expr(PLpgSQL_row *row);
 %token K_EXIT
 %token K_FOR
 %token K_FROM
+%token K_GET
 %token K_IF
 %token K_IN
 %token K_INTO
@@ -147,9 +152,11 @@ static     PLpgSQL_expr    *make_tupret_expr(PLpgSQL_row *row);
 %token K_NOTICE
 %token K_NULL
 %token K_PERFORM
+%token  K_PROCESSED
 %token K_RAISE
 %token K_RECORD
 %token K_RENAME
+%token K_RESULT
 %token K_RETURN
 %token K_REVERSE
 %token K_SELECT
@@ -371,7 +378,7 @@ decl_rowtype        : T_ROW
 
 decl_varname   : T_WORD
                    {
-                       $$.name = strdup(yytext);
+                       $$.name = plpgsql_tolower(strdup(yytext));
                        $$.lineno  = yylineno;
                    }
                ;
@@ -576,6 +583,8 @@ proc_stmt   : pl_block
                        { $$ = $1; }
                | stmt_perform
                        { $$ = $1; }
+               | stmt_getdiag
+                       { $$ = $1; }
                ;
 
 stmt_perform   : K_PERFORM lno expr_until_semi
@@ -610,6 +619,100 @@ stmt_assign       : assign_var lno K_ASSIGN expr_until_semi
                    }
                ;
 
+stmt_getdiag   : K_GET K_DIAGNOSTICS lno K_SELECT getdiag_items K_INTO getdiag_targets ';'
+                    {
+                        PLpgSQL_stmt_getdiag     *new;
+
+                        new = malloc(sizeof(PLpgSQL_stmt_getdiag));
+                        memset(new, 0, sizeof(PLpgSQL_stmt_getdiag));
+
+                        new->cmd_type = PLPGSQL_STMT_GETDIAG;
+                        new->lineno   = $3;
+                        new->nitems   = $5.nused;
+                        new->items    = malloc(sizeof(int) * $5.nused);
+                        new->ntargets = $7.nused;
+                        new->targets  = malloc(sizeof(int) * $7.nused);
+                       memcpy(new->items, $5.dtnums, sizeof(int) * $5.nused);
+                       memcpy(new->targets, $7.dtnums, sizeof(int) * $7.nused);
+
+                        if (new->nitems != new->ntargets) {
+                           plpgsql_error_lineno = new->lineno;
+                            plpgsql_comperrinfo();
+                            elog(ERROR, "number of diagnostic items does not match target list");
+                        };
+
+                        $$ = (PLpgSQL_stmt *)new;
+                    }
+                ;
+
+getdiag_items : getdiag_items ',' getdiag_item
+                    {
+                        if ($1.nused == $1.nalloc) {
+                            $1.nalloc *= 2;
+                            $1.dtnums = repalloc($1.dtnums, sizeof(int) * $1.nalloc);
+                        }
+                        $1.dtnums[$1.nused++] = $3;
+
+                        $$.nalloc = $1.nalloc;
+                        $$.nused  = $1.nused;
+                        $$.dtnums = $1.dtnums;
+                    }
+               | getdiag_item
+                    {
+                        $$.nalloc = 1;
+                        $$.nused  = 1;
+                        $$.dtnums = palloc(sizeof(int) * $$.nalloc);
+                        $$.dtnums[0] = $1;
+                    }
+                ;
+
+getdiag_item : K_PROCESSED
+                    {
+                        $$ = PLPGSQL_GETDIAG_PROCESSED;
+                    }
+               | K_RESULT
+                    {
+                        $$ = PLPGSQL_GETDIAG_RESULT;
+                    }
+               ;
+
+getdiag_targets : getdiag_targets ',' getdiag_target
+                    {
+                        if ($1.nused == $1.nalloc) {
+                            $1.nalloc *= 2;
+                            $1.dtnums = repalloc($1.dtnums, sizeof(int) * $1.nalloc);
+                        }
+                        $1.dtnums[$1.nused++] = $3;
+
+                        $$.nalloc = $1.nalloc;
+                        $$.nused  = $1.nused;
+                        $$.dtnums = $1.dtnums;
+                    }
+               | getdiag_target
+                    {
+                        $$.nalloc = 1;
+                        $$.nused  = 1;
+                        $$.dtnums = palloc(sizeof(int) * $$.nalloc);
+                        $$.dtnums[0] = $1;
+                    }
+                ;
+
+
+getdiag_target     : T_VARIABLE
+                    {
+                        if (yylval.var->isconst) {
+                            plpgsql_comperrinfo();
+                            elog(ERROR, "%s is declared CONSTANT; can not receive diagnostics", yylval.var->refname);
+                        }
+                        $$ = yylval.var->varno;
+                    }
+                | T_RECFIELD
+                    {
+                        $$ = yylval.recfield->rfno;
+                    }
+                ;
+
 assign_var     : T_VARIABLE
                    {
                        if (yylval.var->isconst) {
index 7740c2790ee71d542fecaf49601c5fb618af488c..ac4208c7195a0b963199c4106f06ed9380959789 100644 (file)
@@ -3,7 +3,7 @@
  *                       procedural language
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.29 2000/08/31 13:26:16 wieck Exp $
+ *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.30 2000/09/05 09:02:18 wieck Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -80,6 +80,8 @@ static int exec_stmt(PLpgSQL_execstate * estate,
                  PLpgSQL_stmt * stmt);
 static int exec_stmt_assign(PLpgSQL_execstate * estate,
                                 PLpgSQL_stmt_assign * stmt);
+static int exec_stmt_getdiag(PLpgSQL_execstate * estate,
+                                 PLpgSQL_stmt_getdiag * stmt);
 static int exec_stmt_if(PLpgSQL_execstate * estate,
                         PLpgSQL_stmt_if * stmt);
 static int exec_stmt_loop(PLpgSQL_execstate * estate,
@@ -193,6 +195,9 @@ plpgsql_exec_function(PLpgSQL_function * func, FunctionCallInfo fcinfo)
                                        case PLPGSQL_STMT_ASSIGN:
                                                stmttype = "assignment";
                                                break;
+                                       case PLPGSQL_STMT_GETDIAG:
+                                               stmttype = "get diagnostics";
+                                               break;
                                        case PLPGSQL_STMT_IF:
                                                stmttype = "if";
                                                break;
@@ -502,6 +507,9 @@ plpgsql_exec_trigger(PLpgSQL_function * func,
                                        case PLPGSQL_STMT_ASSIGN:
                                                stmttype = "assignment";
                                                break;
+                                        case PLPGSQL_STMT_GETDIAG:
+                                                stmttype = "get diagnostics";
+                                                break;
                                        case PLPGSQL_STMT_IF:
                                                stmttype = "if";
                                                break;
@@ -971,6 +979,10 @@ exec_stmt(PLpgSQL_execstate * estate, PLpgSQL_stmt * stmt)
                        rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
                        break;
 
+               case PLPGSQL_STMT_GETDIAG:
+                       rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt);
+                       break;
+
                case PLPGSQL_STMT_IF:
                        rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt);
                        break;
@@ -1047,6 +1059,49 @@ exec_stmt_assign(PLpgSQL_execstate * estate, PLpgSQL_stmt_assign * stmt)
        return PLPGSQL_RC_OK;
 }
 
+/* ----------
+ * exec_stmt_getdiag                    Put internal PG information into
+ *                                      specified variables.
+ * ----------
+ */
+static int
+exec_stmt_getdiag(PLpgSQL_execstate * estate, PLpgSQL_stmt_getdiag * stmt)
+{
+       int             i;
+       PLpgSQL_datum   *var;
+       HeapTuple       typeTup;
+        bool            isnull = false;
+
+       for ( i=0 ; i < stmt->nitems ; i++) 
+       {
+               if ((stmt->targets[i] <= 0))
+                       break;
+       
+               var = (estate->datums[stmt->targets[i]]);
+
+               if (var == NULL)
+                       break;
+
+               switch (stmt->items[i])
+               {
+                       case PLPGSQL_GETDIAG_PROCESSED: 
+
+                               exec_assign_value(estate, var, (Datum)SPI_processed, INT4OID, &isnull);
+                               break;
+
+                       case PLPGSQL_GETDIAG_RESULT:
+
+                               exec_assign_value(estate, var, (Datum)SPI_result, INT4OID, &isnull);
+                                break;
+
+                       default:
+                       
+                               elog(ERROR, "unknown attribute request %d in get_diagnostic", stmt->items[i]);
+               };
+       };
+       
+        return PLPGSQL_RC_OK;
+}
 
 /* ----------
  * exec_stmt_if                                Evaluate a bool expression and
index dc1a2f423d6f9831dd2fecb614aac8617a41a144..d7059bf3e29ff8683606c0b2bddcdc7d87379a2c 100644 (file)
@@ -3,7 +3,7 @@
  *                       procedural language
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.7 2000/08/31 13:26:16 wieck Exp $
+ *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.8 2000/09/05 09:02:18 wieck Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -390,6 +390,7 @@ static void dump_raise(PLpgSQL_stmt_raise * stmt);
 static void dump_execsql(PLpgSQL_stmt_execsql * stmt);
 static void dump_dynexecute(PLpgSQL_stmt_dynexecute * stmt);
 static void dump_dynfors(PLpgSQL_stmt_dynfors * stmt);
+static void dump_getdiag(PLpgSQL_stmt_getdiag * stmt);
 static void dump_expr(PLpgSQL_expr * expr);
 
 
@@ -450,6 +451,9 @@ dump_stmt(PLpgSQL_stmt * stmt)
                case PLPGSQL_STMT_DYNFORS:
                        dump_dynfors((PLpgSQL_stmt_dynfors *) stmt);
                        break;
+               case PLPGSQL_STMT_GETDIAG:
+                       dump_getdiag((PLpgSQL_stmt_getdiag *) stmt);
+                       break;
                default:
                        elog(ERROR, "plpgsql_dump: unknown cmd_type %d\n", stmt->cmd_type);
                        break;
@@ -637,7 +641,7 @@ dump_return(PLpgSQL_stmt_return * stmt)
 {
        dump_ind();
        printf("RETURN ");
-       if (stmt->retrecno >= 0)
+       if (stmt->retrecno > 0)
                printf("record %d", stmt->retrecno);
        else
        {
@@ -698,6 +702,45 @@ dump_dynfors(PLpgSQL_stmt_dynfors * stmt)
        printf("    ENDFORS\n");
 }
 
+static void
+dump_getdiag(PLpgSQL_stmt_getdiag * stmt)
+{
+       int                     i;
+
+       dump_ind();
+       printf("GET DIAGNOSTICS SELECT ");
+       for (i = 0; i < stmt->nitems; i++)
+       {
+               if (i != 0)
+                       printf(", ");
+
+           switch (stmt->items[i])
+               {
+                   case PLPGSQL_GETDIAG_PROCESSED:
+                               printf("PROCESSED");
+                               break;
+
+                       case PLPGSQL_GETDIAG_RESULT:
+                               printf("RESULT");
+                               break;
+
+                       default:
+                           printf("???");
+                               break;
+               }
+       }
+       printf(" INTO ");
+       for (i = 0; i < stmt->ntargets; i++)
+       {
+               if (i != 0)
+                       printf(", ");
+
+               printf("{var %d}", stmt->targets[i]);
+       }
+
+       printf("\n");
+}
+
 static void
 dump_expr(PLpgSQL_expr * expr)
 {
index e48a56ce89303736cafe5f73f3d272532d5a4e90..e03fed063c017d7da294baf119f1074269af8376 100644 (file)
@@ -3,7 +3,7 @@
  *                       procedural language
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.10 2000/08/31 13:26:16 wieck Exp $
+ *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.11 2000/09/05 09:02:18 wieck Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -93,7 +93,8 @@ enum
        PLPGSQL_STMT_RAISE,
        PLPGSQL_STMT_EXECSQL,
        PLPGSQL_STMT_DYNEXECUTE,
-       PLPGSQL_STMT_DYNFORS
+       PLPGSQL_STMT_DYNFORS,
+       PLPGSQL_STMT_GETDIAG
 };
 
 
@@ -108,6 +109,17 @@ enum
        PLPGSQL_RC_RETURN
 };
 
+/* ----------
+ * GET DIAGNOSTICS system attrs
+ * ----------
+ */
+enum
+{
+        PLPGSQL_GETDIAG_PROCESSED,
+        PLPGSQL_GETDIAG_RESULT
+};
+
+
 /**********************************************************************
  * Node and structure definitions
  **********************************************************************/
@@ -265,6 +277,16 @@ typedef struct
        PLpgSQL_expr *expr;
 }                      PLpgSQL_stmt_assign;
 
+typedef struct
+{                                                              /* Get Disgnostics statement            */
+       int                     cmd_type;
+       int                     lineno;
+       int                     nitems;
+       int                     *items;
+       int                     ntargets;
+       int                     *targets;
+}                      PLpgSQL_stmt_getdiag;
+
 
 typedef struct
 {                                                              /* IF statement                         */
index 73b605032f126f82da082154657375a2a69eba3b..4cb7ed86157b69ac6317d83ec2b57624a7df1071 100644 (file)
@@ -4,7 +4,7 @@
  *                       procedural language
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.6 2000/08/31 13:26:16 wieck Exp $
+ *    $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.7 2000/09/05 09:02:18 wieck Exp $
  *
  *    This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -97,6 +97,7 @@ constant              { return K_CONSTANT;            }
 debug                  { return K_DEBUG;                       }
 declare                        { return K_DECLARE;                     }
 default                        { return K_DEFAULT;                     }
+diagnostics            { return K_DIAGNOSTICS;         }
 else                   { return K_ELSE;                        }
 end                            { return K_END;                         }
 exception              { return K_EXCEPTION;           }
@@ -104,6 +105,7 @@ execute                     { return K_EXECUTE;                     }
 exit                   { return K_EXIT;                        }
 for                            { return K_FOR;                         }
 from                   { return K_FROM;                        }
+get                            { return K_GET;                         }
 if                             { return K_IF;                          }
 in                             { return K_IN;                          }
 into                   { return K_INTO;                        }
@@ -112,9 +114,11 @@ not                                { return K_NOT;                         }
 notice                 { return K_NOTICE;                      }
 null                   { return K_NULL;                        }
 perform                        { return K_PERFORM;                     }
+processed              { return K_PROCESSED;                   }
 raise                  { return K_RAISE;                       }
 record                 { return K_RECORD;                      }
 rename                 { return K_RENAME;                      }
+result                 { return K_RESULT;                      }
 return                 { return K_RETURN;                      }
 reverse                        { return K_REVERSE;                     }
 select                 { return K_SELECT;                      }