aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2001-11-15 23:31:09 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2001-11-15 23:31:09 +0000
commit4be20187ab0c8dd95a1dd62b67a17ffaf1f33279 (patch)
tree021eaeba2581a0f48575ada51d2d5a9d75649d6c /src
parentd4337f6a7c6ee7751c1427f0cb4acf90e1485955 (diff)
downloadpostgresql-4be20187ab0c8dd95a1dd62b67a17ffaf1f33279.tar.gz
postgresql-4be20187ab0c8dd95a1dd62b67a17ffaf1f33279.zip
Fix some problems in new plpgsql cursor operations, found while trying
to reverse-engineer documentation for them.
Diffstat (limited to 'src')
-rw-r--r--src/pl/plpgsql/src/gram.y46
-rw-r--r--src/pl/plpgsql/src/pl_exec.c153
-rw-r--r--src/pl/plpgsql/src/pl_funcs.c49
-rw-r--r--src/pl/plpgsql/src/plpgsql.h5
4 files changed, 98 insertions, 155 deletions
diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y
index a7da1710c1a..abb2ac8e7f3 100644
--- a/src/pl/plpgsql/src/gram.y
+++ b/src/pl/plpgsql/src/gram.y
@@ -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 */
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 5f2d58f4dd9..d61fac52897 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -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)
diff --git a/src/pl/plpgsql/src/pl_funcs.c b/src/pl/plpgsql/src/pl_funcs.c
index 61ab93a6cd4..6a503505c4c 100644
--- a/src/pl/plpgsql/src/pl_funcs.c
+++ b/src/pl/plpgsql/src/pl_funcs.c
@@ -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";
+}
/**********************************************************************
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 8065764ed57..7856a0dbb5f 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -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