Fix some problems in new plpgsql cursor operations, found while trying

to reverse-engineer documentation for them.
This commit is contained in:
Tom Lane 2001-11-15 23:31:09 +00:00
parent d4337f6a7c
commit 4be20187ab
4 changed files with 98 additions and 155 deletions

View 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 */

View 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)

View 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";
}
/**********************************************************************

View 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