OSDN Git Service

Fix some problems in new plpgsql cursor operations, found while trying
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 15 Nov 2001 23:31:09 +0000 (23:31 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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 a7da171..abb2ac8 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 5f2d58f..d61fac5 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 61ab93a..6a50350 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 8065764..7856a0d 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