Change plpgsql's GET DIAGNOSTICS statement to use SQL99-compatible
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 19 Feb 2001 19:49:53 +0000 (19:49 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 19 Feb 2001 19:49:53 +0000 (19:49 +0000)
syntax.  Fix the RESULT_OID case, which never worked.  Add documentation.

doc/src/sgml/plsql.sgml
src/backend/executor/spi.c
src/include/executor/spi.h
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 85e94990aa0a40580a13088e797032f5d3bbde4a..c887aea0c5dafa02392e37307cdeec06c0a5b5b2 100644 (file)
@@ -102,7 +102,7 @@ $Header$
 
     <para>
      The PL/pgSQL language is case insensitive. All keywords and
-     identifiers can be used in mixed upper- and lowercase.
+     identifiers can be used in mixed upper- and lower-case.
     </para>
     <para>
      PL/pgSQL is a block oriented language. A block is defined as
@@ -181,7 +181,7 @@ END;
        must also have a default value specified.
        </para>
        <para>
-       The default value is evaluated every time the function is called. So
+       The default value is evaluated every time the block is entered. So
        assigning '<replaceable>now</replaceable>' to a variable of type
        <type>timestamp</type> causes the variable to have the
        time of the actual function call, not when the function was
@@ -203,7 +203,7 @@ END;
        corresponding identifier $n will be a rowtype, but it
        must be aliased using the ALIAS command described below. Only the user
        attributes of a table row are accessible in the row, no Oid or other
-       system attributes (hence the row could be from a view and view rows
+       system attributes (because the row could be from a view and view rows
        don't have useful system attributes).
        </para>
        <para>
@@ -311,7 +311,7 @@ RENAME <replaceable>oldname</replaceable> TO <replaceable>newname</replaceable>;
      Using the <replaceable>table.field</replaceable>%TYPE
      causes PL/pgSQL to look up the attributes definitions at the
      first call to the function during the lifetime of a backend.
-     Have a table with a char(20) attribute and some PL/pgSQL functions
+     Suppose we have a table with a char(20) attribute and some PL/pgSQL functions
      that deal with its content in local variables. Now someone
      decides that char(20) isn't enough, dumps the table, drops it,
      recreates it now with the attribute in question defined as
@@ -553,6 +553,26 @@ EXECUTE ''UPDATE tbl SET ''
       </listitem>
      </varlistentry>
 
+     <varlistentry>
+      <term>Obtaining other results status</term>
+      <listitem>
+       <para>
+       <programlisting>
+GET DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item</replaceable> [ , ... ]
+       </programlisting>
+       This command allows retrieval of system status indicators.  Each
+       <replaceable>item</replaceable> is a keyword identifying a state
+       value to be assigned to the specified variable (which should be of
+       the right datatype to receive it).  The currently available status
+       items are <keyword>ROW_COUNT</>, the number of rows processed by
+       the last SQL query sent down to the SQL engine; and
+       <keyword>RESULT_OID</>, the Oid of the last row inserted by the
+       most recent SQL query.  Note that <keyword>RESULT_OID</> is only
+       useful after an INSERT query.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry>
       <term>Returning from the function</term>
       <listitem>
index 1e4533c1fb4c9d3af56ab32cf3d13dc7d98ceae6..5a1548b7c6e5d8ef15a376f40911db69d63ed34a 100644 (file)
 #include "executor/spi_priv.h"
 #include "access/printtup.h"
 
+uint32 SPI_processed = 0;
+Oid SPI_lastoid = InvalidOid;
+SPITupleTable *SPI_tuptable = NULL;
+int SPI_result;
+
 static _SPI_connection *_SPI_stack = NULL;
 static _SPI_connection *_SPI_current = NULL;
 static int     _SPI_connected = -1;
 static int     _SPI_curid = -1;
 
-DLLIMPORT uint32 SPI_processed = 0;
-DLLIMPORT SPITupleTable *SPI_tuptable = NULL;
-DLLIMPORT int SPI_result;
-
 static int     _SPI_execute(char *src, int tcount, _SPI_plan *plan);
 static int     _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount);
 
@@ -155,6 +156,7 @@ AtEOXact_SPI(void)
        _SPI_current = _SPI_stack = NULL;
        _SPI_connected = _SPI_curid = -1;
        SPI_processed = 0;
+       SPI_lastoid = InvalidOid;
        SPI_tuptable = NULL;
 }
 
@@ -623,6 +625,7 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
        CommandCounterIncrement();
 
        SPI_processed = 0;
+       SPI_lastoid = InvalidOid;
        SPI_tuptable = NULL;
        _SPI_current->tuptable = NULL;
        _SPI_current->qtlist = NULL;
@@ -723,6 +726,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount)
        CommandCounterIncrement();
 
        SPI_processed = 0;
+       SPI_lastoid = InvalidOid;
        SPI_tuptable = NULL;
        _SPI_current->tuptable = NULL;
        _SPI_current->qtlist = NULL;
@@ -786,6 +790,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
        bool            isRetrieveIntoRelation = false;
        char       *intoName = NULL;
        int                     res;
+       Oid                     save_lastoid;
 
        switch (operation)
        {
@@ -840,6 +845,8 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
        ExecutorRun(queryDesc, state, EXEC_FOR, (long) tcount);
 
        _SPI_current->processed = state->es_processed;
+       save_lastoid = state->es_lastoid;
+
        if (operation == CMD_SELECT && queryDesc->dest == SPI)
        {
                if (_SPI_checktuples())
@@ -859,6 +866,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
        if (dest == SPI)
        {
                SPI_processed = _SPI_current->processed;
+               SPI_lastoid = save_lastoid;
                SPI_tuptable = _SPI_current->tuptable;
        }
        queryDesc->dest = dest;
index 4834ab4dd871a57d98fcca36da24736f7b8521fe..b95eaae4e9e19e535111175fd71638dcd5e0b3ed 100644 (file)
@@ -71,6 +71,7 @@ typedef struct
 #define SPI_OK_CURSOR                  10
 
 extern DLLIMPORT uint32 SPI_processed;
+extern DLLIMPORT Oid SPI_lastoid;
 extern DLLIMPORT SPITupleTable *SPI_tuptable;
 extern DLLIMPORT int SPI_result;
 
index 61292e6f2802b1a41115cb95a52f248cc3ad29c7..a6193cee359befdc9f41e67ca5f513522d1f6046 100644 (file)
@@ -63,7 +63,13 @@ static       PLpgSQL_expr    *make_tupret_expr(PLpgSQL_row *row);
                {
                        int  nalloc;
                        int  nused;
-                       int  *dtnums;
+                       int      *nums;
+               }                                               intlist;
+               struct
+               {
+                       int  nalloc;
+                       int  nused;
+                       PLpgSQL_diag_item *dtitems;
                }                                               dtlist;
                struct
                {
@@ -119,11 +125,11 @@ static    PLpgSQL_expr    *make_tupret_expr(PLpgSQL_row *row);
 %type <stmt>   stmt_fors, stmt_select, stmt_perform
 %type <stmt>   stmt_dynexecute, stmt_dynfors, stmt_getdiag
 
-%type <dtlist> raise_params
+%type <intlist>        raise_params
 %type <ival>   raise_level, raise_param
 %type <str>            raise_msg
 
-%type <dtlist> getdiag_items, getdiag_targets
+%type <dtlist> getdiag_list
 %type <ival>   getdiag_item, getdiag_target
 
 %type <ival>   lno
@@ -156,11 +162,11 @@ static    PLpgSQL_expr    *make_tupret_expr(PLpgSQL_row *row);
 %token K_NOTICE
 %token K_NULL
 %token K_PERFORM
-%token K_PROCESSED
+%token K_ROW_COUNT
 %token K_RAISE
 %token K_RECORD
 %token K_RENAME
-%token K_RESULT
+%token K_RESULT_OID
 %token K_RETURN
 %token K_REVERSE
 %token K_SELECT
@@ -607,7 +613,7 @@ 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 ';'
+stmt_getdiag   : K_GET K_DIAGNOSTICS lno getdiag_list ';'
                                        {
                                                PLpgSQL_stmt_getdiag     *new;
 
@@ -616,80 +622,50 @@ stmt_getdiag      : K_GET K_DIAGNOSTICS lno K_SELECT getdiag_items K_INTO getdiag_tar
 
                                                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");
-                                               };
+                                               new->ndtitems = $4.nused;
+                                               new->dtitems  = malloc(sizeof(PLpgSQL_diag_item) * $4.nused);
+                                               memcpy(new->dtitems, $4.dtitems, sizeof(PLpgSQL_diag_item) * $4.nused);
 
                                                $$ = (PLpgSQL_stmt *)new;
                                        }
                                ;
 
-getdiag_items : getdiag_items ',' getdiag_item
+getdiag_list : getdiag_list ',' getdiag_target K_ASSIGN getdiag_item
                                        {
                                                if ($1.nused == $1.nalloc)
                                                {
                                                        $1.nalloc *= 2;
-                                                       $1.dtnums = repalloc($1.dtnums, sizeof(int) * $1.nalloc);
+                                                       $1.dtitems = repalloc($1.dtitems, sizeof(PLpgSQL_diag_item) * $1.nalloc);
                                                }
-                                               $1.dtnums[$1.nused++] = $3;
+                                               $1.dtitems[$1.nused].target = $3;
+                                               $1.dtitems[$1.nused].item   = $5;
+                                               $1.nused++;
 
                                                $$.nalloc = $1.nalloc;
                                                $$.nused  = $1.nused;
-                                               $$.dtnums = $1.dtnums;
+                                               $$.dtitems = $1.dtitems;
                                        }
-                               | getdiag_item
+                               | getdiag_target K_ASSIGN 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;
+                                               $$.dtitems = palloc(sizeof(PLpgSQL_diag_item) * $$.nalloc);
+                                               $$.dtitems[0].target = $1;
+                                               $$.dtitems[0].item   = $3;
                                        }
                                ;
 
-getdiag_targets : getdiag_targets ',' getdiag_target
+getdiag_item : K_ROW_COUNT
                                        {
-                                               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;
+                                               $$ = PLPGSQL_GETDIAG_ROW_COUNT;
                                        }
-                               | getdiag_target
+                               | K_RESULT_OID
                                        {
-                                               $$.nalloc = 1;
-                                               $$.nused  = 1;
-                                               $$.dtnums = palloc(sizeof(int) * $$.nalloc);
-                                               $$.dtnums[0] = $1;
+                                               $$ = PLPGSQL_GETDIAG_RESULT_OID;
                                        }
                                ;
 
-
-getdiag_target    : T_VARIABLE
+getdiag_target : T_VARIABLE
                                        {
                                                if (yylval.var->isconst)
                                                {
@@ -1070,7 +1046,7 @@ stmt_raise                : K_RAISE lno raise_level raise_msg raise_params ';'
                                                new->message    = $4;
                                                new->nparams    = $5.nused;
                                                new->params             = malloc(sizeof(int) * $5.nused);
-                                               memcpy(new->params, $5.dtnums, sizeof(int) * $5.nused);
+                                               memcpy(new->params, $5.nums, sizeof(int) * $5.nused);
 
                                                $$ = (PLpgSQL_stmt *)new;
                                        }
@@ -1116,20 +1092,20 @@ raise_params    : raise_params raise_param
                                                if ($1.nused == $1.nalloc)
                                                {
                                                        $1.nalloc *= 2;
-                                                       $1.dtnums = repalloc($1.dtnums, sizeof(int) * $1.nalloc);
+                                                       $1.nums = repalloc($1.nums, sizeof(int) * $1.nalloc);
                                                }
-                                               $1.dtnums[$1.nused++] = $2;
+                                               $1.nums[$1.nused++] = $2;
 
                                                $$.nalloc = $1.nalloc;
                                                $$.nused  = $1.nused;
-                                               $$.dtnums = $1.dtnums;
+                                               $$.nums   = $1.nums;
                                        }
                                | raise_param
                                        {
                                                $$.nalloc = 1;
                                                $$.nused  = 1;
-                                               $$.dtnums = palloc(sizeof(int) * $$.nalloc);
-                                               $$.dtnums[0] = $1;
+                                               $$.nums   = palloc(sizeof(int) * $$.nalloc);
+                                               $$.nums[0] = $1;
                                        }
                                ;
 
index 767dd68347d07430d76081a4f657e6a998f73f86..897f6a23ebcaa6e1af00ba98e21db9461eb4d3d8 100644 (file)
@@ -82,7 +82,7 @@ static int exec_stmt(PLpgSQL_execstate * estate,
 static int exec_stmt_assign(PLpgSQL_execstate * estate,
                                 PLpgSQL_stmt_assign * stmt);
 static int exec_stmt_getdiag(PLpgSQL_execstate * estate,
-                                 PLpgSQL_stmt_getdiag * stmt);
+                                                        PLpgSQL_stmt_getdiag * stmt);
 static int exec_stmt_if(PLpgSQL_execstate * estate,
                         PLpgSQL_stmt_if * stmt);
 static int exec_stmt_loop(PLpgSQL_execstate * estate,
@@ -507,9 +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_GETDIAG:
+                                               stmttype = "get diagnostics";
+                                               break;
                                        case PLPGSQL_STMT_IF:
                                                stmttype = "if";
                                                break;
@@ -1071,35 +1071,40 @@ exec_stmt_getdiag(PLpgSQL_execstate * estate, PLpgSQL_stmt_getdiag * stmt)
        PLpgSQL_datum   *var;
        bool            isnull = false;
 
-       for ( i=0 ; i < stmt->nitems ; i++) 
+       for ( i=0 ; i < stmt->ndtitems ; i++) 
        {
-               if ((stmt->targets[i] <= 0))
-                       break;
+               PLpgSQL_diag_item *dtitem = & stmt->dtitems[i];
+
+               if (dtitem->target <= 0)
+                       continue;
        
-               var = (estate->datums[stmt->targets[i]]);
+               var = (estate->datums[dtitem->target]);
 
                if (var == NULL)
-                       break;
+                       continue;
 
-               switch (stmt->items[i])
+               switch (dtitem->item)
                {
-                       case PLPGSQL_GETDIAG_PROCESSED: 
+                       case PLPGSQL_GETDIAG_ROW_COUNT:
 
-                               exec_assign_value(estate, var, (Datum)SPI_processed, INT4OID, &isnull);
-                               break;
+                               exec_assign_value(estate, var, UInt32GetDatum(SPI_processed),
+                                                                 INT4OID, &isnull);
+                               break;
 
-                       case PLPGSQL_GETDIAG_RESULT:
+                       case PLPGSQL_GETDIAG_RESULT_OID:
 
-                               exec_assign_value(estate, var, (Datum)SPI_result, INT4OID, &isnull);
-                                break;
+                               exec_assign_value(estate, var, ObjectIdGetDatum(SPI_lastoid),
+                                                                 OIDOID, &isnull);
+                               break;
 
                        default:
                        
-                               elog(ERROR, "unknown attribute request %d in get_diagnostic", stmt->items[i]);
-               };
-       };
+                               elog(ERROR, "unknown attribute request %d in get_diagnostic",
+                                        dtitem->item);
+               }
+       }
        
-        return PLPGSQL_RC_OK;
+       return PLPGSQL_RC_OK;
 }
 
 /* ----------
index f92599f6c6bb831a4a6ee475cad08dde9733621e..9e27a7fc3103e2f459c71ef8f450db89fe2f7bb3 100644 (file)
@@ -708,20 +708,24 @@ dump_getdiag(PLpgSQL_stmt_getdiag * stmt)
        int                     i;
 
        dump_ind();
-       printf("GET DIAGNOSTICS SELECT ");
-       for (i = 0; i < stmt->nitems; i++)
+       printf("GET DIAGNOSTICS ");
+       for (i = 0; i < stmt->ndtitems; i++)
        {
+               PLpgSQL_diag_item *dtitem = & stmt->dtitems[i];
+
                if (i != 0)
                        printf(", ");
 
-           switch (stmt->items[i])
+               printf("{var %d} = ", dtitem->target);
+
+           switch (dtitem->item)
                {
-                   case PLPGSQL_GETDIAG_PROCESSED:
-                               printf("PROCESSED");
+                   case PLPGSQL_GETDIAG_ROW_COUNT:
+                               printf("ROW_COUNT");
                                break;
 
-                       case PLPGSQL_GETDIAG_RESULT:
-                               printf("RESULT");
+                       case PLPGSQL_GETDIAG_RESULT_OID:
+                               printf("RESULT_OID");
                                break;
 
                        default:
@@ -729,15 +733,6 @@ dump_getdiag(PLpgSQL_stmt_getdiag * stmt)
                                break;
                }
        }
-       printf(" INTO ");
-       for (i = 0; i < stmt->ntargets; i++)
-       {
-               if (i != 0)
-                       printf(", ");
-
-               printf("{var %d}", stmt->targets[i]);
-       }
-
        printf("\n");
 }
 
index b956cd4876b4b05326c2f1d200c1a1f4c104ab1c..6fcdfcf780582a77b370ab994e8f83b946d2d03f 100644 (file)
@@ -115,8 +115,8 @@ enum
  */
 enum
 {
-        PLPGSQL_GETDIAG_PROCESSED,
-        PLPGSQL_GETDIAG_RESULT
+        PLPGSQL_GETDIAG_ROW_COUNT,
+        PLPGSQL_GETDIAG_RESULT_OID
 };
 
 
@@ -277,14 +277,19 @@ typedef struct
        PLpgSQL_expr *expr;
 }                      PLpgSQL_stmt_assign;
 
+
+typedef struct
+{                                                              /* Get Diagnostics item         */
+       int                     item;                   /* id for diagnostic value desired */
+       int                     target;                 /* where to assign it */
+}                      PLpgSQL_diag_item;
+
 typedef struct
-{                                                              /* Get Disgnostics statement            */
+{                                                              /* Get Diagnostics statement            */
        int                     cmd_type;
        int                     lineno;
-       int                     nitems;
-       int                     *items;
-       int                     ntargets;
-       int                     *targets;
+       int                     ndtitems;
+       PLpgSQL_diag_item *dtitems;
 }                      PLpgSQL_stmt_getdiag;
 
 
index ee7c5580b6ef70f2c690eec102ff09c67d0008e9..51e1fbcede53be50ed96fda01a34fb5d3e10da3a 100644 (file)
@@ -114,13 +114,13 @@ 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;                      }
+result_oid             { return K_RESULT_OID;          }
 return                 { return K_RETURN;                      }
 reverse                        { return K_REVERSE;                     }
+row_count              { return K_ROW_COUNT;           }
 select                 { return K_SELECT;                      }
 then                   { return K_THEN;                        }
 to                             { return K_TO;                          }