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 * procedural language
* *
* IDENTIFICATION * 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. * 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); 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_var *new;
PLpgSQL_expr *curname_def; PLpgSQL_expr *curname_def;
@ -359,6 +361,7 @@ decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval
char *cp1; char *cp1;
char *cp2; char *cp2;
/* pop local namespace for cursor args */
plpgsql_ns_pop(); plpgsql_ns_pop();
new = malloc(sizeof(PLpgSQL_var)); new = malloc(sizeof(PLpgSQL_var));
@ -381,22 +384,21 @@ decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval
*cp2++ = '\\'; *cp2++ = '\\';
*cp2++ = *cp1++; *cp2++ = *cp1++;
} }
*cp2++ = '\''; strcpy(cp2, "'::refcursor");
*cp2 = '\0';
curname_def->query = strdup(buf); curname_def->query = strdup(buf);
new->default_val = curname_def; new->default_val = curname_def;
new->datatype = plpgsql_parse_datatype("refcursor"); new->datatype = plpgsql_parse_datatype("refcursor");
new->cursor_explicit_expr = $6; new->cursor_explicit_expr = $7;
if ($3 == NULL) if ($4 == NULL)
new->cursor_explicit_argrow = -1; new->cursor_explicit_argrow = -1;
else else
new->cursor_explicit_argrow = $3->rowno; new->cursor_explicit_argrow = $4->rowno;
plpgsql_adddatum((PLpgSQL_datum *)new); plpgsql_adddatum((PLpgSQL_datum *)new);
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno, plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno,
$1.name); $1.name);
} }
; ;
@ -416,15 +418,17 @@ decl_cursor_args :
{ {
$$ = NULL; $$ = NULL;
} }
| decl_cursor_openparen decl_cursor_arglist ')' | '(' decl_cursor_arglist ')'
{ {
/* Copy the temp arrays to malloc'd storage */
int nfields = $2->nfields;
char **ftmp; char **ftmp;
int *vtmp; int *vtmp;
ftmp = malloc($2->nfields * sizeof(char *)); ftmp = malloc(nfields * sizeof(char *));
vtmp = malloc($2->nfields * sizeof(int)); vtmp = malloc(nfields * sizeof(int));
memcpy(ftmp, $2->fieldnames, $2->nfields * sizeof(char *)); memcpy(ftmp, $2->fieldnames, nfields * sizeof(char *));
memcpy(vtmp, $2->varnos, $2->nfields * sizeof(int)); memcpy(vtmp, $2->varnos, nfields * sizeof(int));
pfree((char *)($2->fieldnames)); pfree((char *)($2->fieldnames));
pfree((char *)($2->varnos)); pfree((char *)($2->varnos));
@ -449,6 +453,12 @@ decl_cursor_arglist : decl_cursor_arg
new->refname = strdup("*internal*"); new->refname = strdup("*internal*");
new->lineno = yylineno; new->lineno = yylineno;
new->rowtypeclass = InvalidOid; 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->fieldnames = palloc(1024 * sizeof(char *));
new->varnos = palloc(1024 * sizeof(int)); new->varnos = palloc(1024 * sizeof(int));
new->nfields = 1; new->nfields = 1;
@ -464,6 +474,8 @@ decl_cursor_arglist : decl_cursor_arg
$1->fieldnames[i] = $3->refname; $1->fieldnames[i] = $3->refname;
$1->varnos[i] = $3->varno; $1->varnos[i] = $3->varno;
$$ = $1;
} }
; ;
@ -484,18 +496,12 @@ decl_cursor_arg : decl_varname decl_datatype
plpgsql_adddatum((PLpgSQL_datum *)new); plpgsql_adddatum((PLpgSQL_datum *)new);
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno, plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno,
$1.name); $1.name);
$$ = new; $$ = new;
} }
; ;
decl_cursor_openparen : '('
{
plpgsql_ns_push(NULL);
}
;
decl_is_from : K_IS | /* Oracle */ decl_is_from : K_IS | /* Oracle */
K_FOR; /* ANSI */ K_FOR; /* ANSI */

View File

@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * 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. * 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", elog(NOTICE, "Error occurred while executing PL/pgSQL function %s",
error_info_func->fn_name); error_info_func->fn_name);
if (error_info_stmt != NULL) 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, 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 else
{ elog(NOTICE, "no more error information available");
if (error_info_text != NULL)
elog(NOTICE, "%s", error_info_text);
else
elog(NOTICE, "no more error information available");
}
error_info_func = NULL; error_info_func = NULL;
error_info_stmt = 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", elog(NOTICE, "Error occurred while executing PL/pgSQL function %s",
error_info_func->fn_name); error_info_func->fn_name);
if (error_info_stmt != NULL) 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, 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 else
{ elog(NOTICE, "no more error information available");
if (error_info_text != NULL)
elog(NOTICE, "%s", error_info_text);
else
elog(NOTICE, "no more error information available");
}
error_info_func = NULL; error_info_func = NULL;
error_info_stmt = NULL; error_info_stmt = NULL;
@ -2412,7 +2290,7 @@ exec_stmt_open(PLpgSQL_execstate * estate, PLpgSQL_stmt_open * stmt)
HeapTuple typetup; HeapTuple typetup;
Form_pg_type typeStruct; Form_pg_type typeStruct;
FmgrInfo finfo_output; FmgrInfo finfo_output;
void *curplan = NULL; void *curplan;
/* ---------- /* ----------
* We evaluate the string expression after the * 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 * 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) if (stmt->argquery != NULL)
@ -2483,6 +2364,9 @@ exec_stmt_open(PLpgSQL_execstate * estate, PLpgSQL_stmt_open * stmt)
*/ */
PLpgSQL_stmt_select set_args; 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)); memset(&set_args, 0, sizeof(set_args));
set_args.cmd_type = PLPGSQL_STMT_SELECT; set_args.cmd_type = PLPGSQL_STMT_SELECT;
set_args.lineno = stmt->lineno; 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) if (exec_stmt_select(estate, &set_args) != PLPGSQL_RC_OK)
elog(ERROR, "open cursor failed during argument processing"); 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; query = curvar->cursor_explicit_expr;
if (query->plan == NULL) if (query->plan == NULL)

View File

@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * 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. * 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 * procedural language
* *
* IDENTIFICATION * 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. * 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 * Other functions in pl_funcs.c
* ---------- * ----------
*/ */
extern void plpgsql_dumptree(PLpgSQL_function * func);
extern char *plpgsql_tolower(char *s); 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 * Externs in gram.y and scan.l