Fix some problems in new plpgsql cursor operations, found while trying
authorTom Lane
Thu, 15 Nov 2001 23:31:09 +0000 (23:31 +0000)
committerTom Lane
Thu, 15 Nov 2001 23:31:09 +0000 (23:31 +0000)
to reverse-engineer documentation for them.

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

index a7da1710c1a3171fdf3d9228f7abefa2057c8871..abb2ac8e7f39c9143b2afc45e7a21e6ff724c54a 100644 (file)
@@ -4,7 +4,7 @@
  *                       procedural language
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.27 2001/10/09 15:59:56 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.28 2001/11/15 23:31:09 tgl Exp $
  *
  *   This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -351,7 +351,9 @@ decl_statement  : decl_varname decl_const decl_datatype decl_notnull decl_defval
                    {
                        plpgsql_ns_rename($2, $4);
                    }
-               | decl_varname K_CURSOR decl_cursor_args decl_is_from K_SELECT decl_cursor_query
+               | decl_varname K_CURSOR
+                   { plpgsql_ns_push(NULL); }
+                 decl_cursor_args decl_is_from K_SELECT decl_cursor_query
                    {
                        PLpgSQL_var *new;
                        PLpgSQL_expr *curname_def;
@@ -359,6 +361,7 @@ decl_statement  : decl_varname decl_const decl_datatype decl_notnull decl_defval
                        char        *cp1;
                        char        *cp2;
 
+                       /* pop local namespace for cursor args */
                        plpgsql_ns_pop();
 
                        new = malloc(sizeof(PLpgSQL_var));
@@ -381,22 +384,21 @@ decl_statement    : decl_varname decl_const decl_datatype decl_notnull decl_defval
                                *cp2++ = '\\';
                            *cp2++ = *cp1++;
                        }
-                       *cp2++ = '\'';
-                       *cp2 = '\0';
+                       strcpy(cp2, "'::refcursor");
                        curname_def->query = strdup(buf);
                        new->default_val = curname_def;
 
                        new->datatype = plpgsql_parse_datatype("refcursor");
 
-                       new->cursor_explicit_expr = $6;
-                       if ($3 == NULL)
+                       new->cursor_explicit_expr = $7;
+                       if ($4 == NULL)
                            new->cursor_explicit_argrow = -1;
                        else
-                           new->cursor_explicit_argrow = $3->rowno;
+                           new->cursor_explicit_argrow = $4->rowno;
 
                        plpgsql_adddatum((PLpgSQL_datum *)new);
                        plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno,
-                                               $1.name);
+                                          $1.name);
                    }
                ;
 
@@ -416,15 +418,17 @@ decl_cursor_args :
                    {
                        $$ = NULL;
                    }
-               | decl_cursor_openparen decl_cursor_arglist ')'
+               | '(' decl_cursor_arglist ')'
                    {
+                       /* Copy the temp arrays to malloc'd storage */
+                       int nfields = $2->nfields;
                        char **ftmp;
                        int *vtmp;
 
-                       ftmp = malloc($2->nfields * sizeof(char *));
-                       vtmp = malloc($2->nfields * sizeof(int));
-                       memcpy(ftmp, $2->fieldnames, $2->nfields * sizeof(char *));
-                       memcpy(vtmp, $2->varnos, $2->nfields * sizeof(int));
+                       ftmp = malloc(nfields * sizeof(char *));
+                       vtmp = malloc(nfields * sizeof(int));
+                       memcpy(ftmp, $2->fieldnames, nfields * sizeof(char *));
+                       memcpy(vtmp, $2->varnos, nfields * sizeof(int));
 
                        pfree((char *)($2->fieldnames));
                        pfree((char *)($2->varnos));
@@ -449,6 +453,12 @@ decl_cursor_arglist : decl_cursor_arg
                        new->refname = strdup("*internal*");
                        new->lineno = yylineno;
                        new->rowtypeclass = InvalidOid;
+                       /*
+                        * We make temporary fieldnames/varnos arrays that
+                        * are much bigger than necessary.  We will resize
+                        * them to just the needed size in the
+                        * decl_cursor_args production.
+                        */
                        new->fieldnames = palloc(1024 * sizeof(char *));
                        new->varnos = palloc(1024 * sizeof(int));
                        new->nfields = 1;
@@ -464,6 +474,8 @@ decl_cursor_arglist : decl_cursor_arg
 
                        $1->fieldnames[i] = $3->refname;
                        $1->varnos[i] = $3->varno;
+
+                       $$ = $1;
                    }
                ;
 
@@ -484,18 +496,12 @@ decl_cursor_arg : decl_varname decl_datatype
 
                        plpgsql_adddatum((PLpgSQL_datum *)new);
                        plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno,
-                                               $1.name);
+                                          $1.name);
                        
                        $$ = new;
                    }
                ;
 
-decl_cursor_openparen : '('
-                   {
-                       plpgsql_ns_push(NULL);
-                   }
-               ;
-
 decl_is_from   :   K_IS |      /* Oracle */
                    K_FOR;      /* ANSI */
 
index 5f2d58f4dd99f315be5eecc1523f401cc8bea915..d61fac528970498960eed3d516f7d86e0f87c90a 100644 (file)
@@ -3,7 +3,7 @@
  *           procedural language
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.51 2001/11/13 02:05:27 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.52 2001/11/15 23:31:09 tgl Exp $
  *
  *   This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -192,76 +192,12 @@ plpgsql_exec_function(PLpgSQL_function * func, FunctionCallInfo fcinfo)
            elog(NOTICE, "Error occurred while executing PL/pgSQL function %s",
                 error_info_func->fn_name);
            if (error_info_stmt != NULL)
-           {
-               char       *stmttype;
-
-               switch (error_info_stmt->cmd_type)
-               {
-                   case PLPGSQL_STMT_BLOCK:
-                       stmttype = "blocks variable initialization";
-                       break;
-                   case PLPGSQL_STMT_ASSIGN:
-                       stmttype = "assignment";
-                       break;
-                   case PLPGSQL_STMT_GETDIAG:
-                       stmttype = "get diagnostics";
-                       break;
-                   case PLPGSQL_STMT_IF:
-                       stmttype = "if";
-                       break;
-                   case PLPGSQL_STMT_LOOP:
-                       stmttype = "loop";
-                       break;
-                   case PLPGSQL_STMT_WHILE:
-                       stmttype = "while";
-                       break;
-                   case PLPGSQL_STMT_FORI:
-                       stmttype = "for with integer loopvar";
-                       break;
-                   case PLPGSQL_STMT_FORS:
-                       stmttype = "for over select rows";
-                       break;
-                   case PLPGSQL_STMT_SELECT:
-                       stmttype = "select into variables";
-                       break;
-                   case PLPGSQL_STMT_EXIT:
-                       stmttype = "exit";
-                       break;
-                   case PLPGSQL_STMT_RETURN:
-                       stmttype = "return";
-                       break;
-                   case PLPGSQL_STMT_RAISE:
-                       stmttype = "raise";
-                       break;
-                   case PLPGSQL_STMT_EXECSQL:
-                       stmttype = "SQL statement";
-                       break;
-                   case PLPGSQL_STMT_DYNEXECUTE:
-                       stmttype = "execute statement";
-                       break;
-                   case PLPGSQL_STMT_DYNFORS:
-                       stmttype = "for over execute statement";
-                       break;
-                   case PLPGSQL_STMT_FETCH:
-                       stmttype = "fetch";
-                       break;
-                   case PLPGSQL_STMT_CLOSE:
-                       stmttype = "close";
-                       break;
-                   default:
-                       stmttype = "unknown";
-                       break;
-               }
                elog(NOTICE, "line %d at %s", error_info_stmt->lineno,
-                    stmttype);
-           }
+                    plpgsql_stmt_typename(error_info_stmt));
+           else if (error_info_text != NULL)
+               elog(NOTICE, "%s", error_info_text);
            else
-           {
-               if (error_info_text != NULL)
-                   elog(NOTICE, "%s", error_info_text);
-               else
-                   elog(NOTICE, "no more error information available");
-           }
+               elog(NOTICE, "no more error information available");
 
            error_info_func = NULL;
            error_info_stmt = NULL;
@@ -504,70 +440,12 @@ plpgsql_exec_trigger(PLpgSQL_function * func,
            elog(NOTICE, "Error occurred while executing PL/pgSQL function %s",
                 error_info_func->fn_name);
            if (error_info_stmt != NULL)
-           {
-               char       *stmttype;
-
-               switch (error_info_stmt->cmd_type)
-               {
-                   case PLPGSQL_STMT_BLOCK:
-                       stmttype = "blocks variable initialization";
-                       break;
-                   case PLPGSQL_STMT_ASSIGN:
-                       stmttype = "assignment";
-                       break;
-                   case PLPGSQL_STMT_GETDIAG:
-                       stmttype = "get diagnostics";
-                       break;
-                   case PLPGSQL_STMT_IF:
-                       stmttype = "if";
-                       break;
-                   case PLPGSQL_STMT_LOOP:
-                       stmttype = "loop";
-                       break;
-                   case PLPGSQL_STMT_WHILE:
-                       stmttype = "while";
-                       break;
-                   case PLPGSQL_STMT_FORI:
-                       stmttype = "for with integer loopvar";
-                       break;
-                   case PLPGSQL_STMT_FORS:
-                       stmttype = "for over select rows";
-                       break;
-                   case PLPGSQL_STMT_SELECT:
-                       stmttype = "select into variables";
-                       break;
-                   case PLPGSQL_STMT_EXIT:
-                       stmttype = "exit";
-                       break;
-                   case PLPGSQL_STMT_RETURN:
-                       stmttype = "return";
-                       break;
-                   case PLPGSQL_STMT_RAISE:
-                       stmttype = "raise";
-                       break;
-                   case PLPGSQL_STMT_EXECSQL:
-                       stmttype = "SQL statement";
-                       break;
-                   case PLPGSQL_STMT_DYNEXECUTE:
-                       stmttype = "execute statement";
-                       break;
-                   case PLPGSQL_STMT_DYNFORS:
-                       stmttype = "for over execute statement";
-                       break;
-                   default:
-                       stmttype = "unknown";
-                       break;
-               }
                elog(NOTICE, "line %d at %s", error_info_stmt->lineno,
-                    stmttype);
-           }
+                    plpgsql_stmt_typename(error_info_stmt));
+           else if (error_info_text != NULL)
+               elog(NOTICE, "%s", error_info_text);
            else
-           {
-               if (error_info_text != NULL)
-                   elog(NOTICE, "%s", error_info_text);
-               else
-                   elog(NOTICE, "no more error information available");
-           }
+               elog(NOTICE, "no more error information available");
 
            error_info_func = NULL;
            error_info_stmt = NULL;
@@ -2412,7 +2290,7 @@ exec_stmt_open(PLpgSQL_execstate * estate, PLpgSQL_stmt_open * stmt)
        HeapTuple   typetup;
        Form_pg_type typeStruct;
        FmgrInfo    finfo_output;
-       void       *curplan = NULL;
+       void       *curplan;
 
        /* ----------
         * We evaluate the string expression after the
@@ -2471,6 +2349,9 @@ exec_stmt_open(PLpgSQL_execstate * estate, PLpgSQL_stmt_open * stmt)
    {
        /* ----------
         * This is an OPEN cursor
+        *
+        * Note: parser should already have checked that statement supplies
+        * args iff cursor needs them, but we check again to be safe.
         * ----------
         */
        if (stmt->argquery != NULL)
@@ -2483,6 +2364,9 @@ exec_stmt_open(PLpgSQL_execstate * estate, PLpgSQL_stmt_open * stmt)
             */
            PLpgSQL_stmt_select set_args;
 
+           if (curvar->cursor_explicit_argrow < 0)
+               elog(ERROR, "arguments given for cursor without arguments");
+
            memset(&set_args, 0, sizeof(set_args));
            set_args.cmd_type = PLPGSQL_STMT_SELECT;
            set_args.lineno = stmt->lineno;
@@ -2493,6 +2377,11 @@ exec_stmt_open(PLpgSQL_execstate * estate, PLpgSQL_stmt_open * stmt)
            if (exec_stmt_select(estate, &set_args) != PLPGSQL_RC_OK)
                elog(ERROR, "open cursor failed during argument processing");
        }
+       else
+       {
+           if (curvar->cursor_explicit_argrow >= 0)
+               elog(ERROR, "arguments required for cursor");
+       }
 
        query = curvar->cursor_explicit_expr;
        if (query->plan == NULL)
index 61ab93a6cd4672d99d80d906d748be29afbaac0e..6a503505c4c23535558add8011ae64faa427ac2f 100644 (file)
@@ -3,7 +3,7 @@
  *           procedural language
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.16 2001/10/09 15:59:56 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.17 2001/11/15 23:31:09 tgl Exp $
  *
  *   This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -360,7 +360,54 @@ plpgsql_tolower(char *s)
 }
 
 
+/*
+ * Statement type as a string, for use in error messages etc.
+ */
+const char *
+plpgsql_stmt_typename(PLpgSQL_stmt * stmt)
+{
+   switch (stmt->cmd_type)
+   {
+       case PLPGSQL_STMT_BLOCK:
+           return "block variables initialization";
+       case PLPGSQL_STMT_ASSIGN:
+           return "assignment";
+       case PLPGSQL_STMT_IF:
+           return "if";
+       case PLPGSQL_STMT_LOOP:
+           return "loop";
+       case PLPGSQL_STMT_WHILE:
+           return "while";
+       case PLPGSQL_STMT_FORI:
+           return "for with integer loopvar";
+       case PLPGSQL_STMT_FORS:
+           return "for over select rows";
+       case PLPGSQL_STMT_SELECT:
+           return "select into variables";
+       case PLPGSQL_STMT_EXIT:
+           return "exit";
+       case PLPGSQL_STMT_RETURN:
+           return "return";
+       case PLPGSQL_STMT_RAISE:
+           return "raise";
+       case PLPGSQL_STMT_EXECSQL:
+           return "SQL statement";
+       case PLPGSQL_STMT_DYNEXECUTE:
+           return "execute statement";
+       case PLPGSQL_STMT_DYNFORS:
+           return "for over execute statement";
+       case PLPGSQL_STMT_GETDIAG:
+           return "get diagnostics";
+       case PLPGSQL_STMT_OPEN:
+           return "open";
+       case PLPGSQL_STMT_FETCH:
+           return "fetch";
+       case PLPGSQL_STMT_CLOSE:
+           return "close";
+   }
 
+   return "unknown";
+}
 
 
 /**********************************************************************
index 8065764ed5778671acdfa5838dfc50e708209ef1..7856a0dbb5fe0c5e448540856fdab1ee6ea146c4 100644 (file)
@@ -3,7 +3,7 @@
  *           procedural language
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.22 2001/11/05 17:46:39 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.23 2001/11/15 23:31:09 tgl Exp $
  *
  *   This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -598,8 +598,9 @@ extern void plpgsql_ns_rename(char *oldname, char *newname);
  * Other functions in pl_funcs.c
  * ----------
  */
-extern void plpgsql_dumptree(PLpgSQL_function * func);
 extern char *plpgsql_tolower(char *s);
+extern const char *plpgsql_stmt_typename(PLpgSQL_stmt * stmt);
+extern void plpgsql_dumptree(PLpgSQL_function * func);
 
 /* ----------
  * Externs in gram.y and scan.l