Commit 2f1c24cb authored by Tom Lane's avatar Tom Lane

Change plpgsql compiler so that all elogs are trapped and a suitable

NOTICE added about error location (same method already used by plpgsql
executor).  Add checking of pg_proc row xmin/cmin to ensure that
plpgsql functions will be recompiled after they've been modified by
CREATE OR REPLACE FUNCTION.
parent c7816006
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.26 2001/10/09 04:15:38 tgl Exp $ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.27 2001/10/09 15:59:56 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -507,10 +507,16 @@ decl_aliasitem : T_WORD ...@@ -507,10 +507,16 @@ decl_aliasitem : T_WORD
plpgsql_ns_setlocal(false); plpgsql_ns_setlocal(false);
name = plpgsql_tolower(yytext); name = plpgsql_tolower(yytext);
if (name[0] != '$') if (name[0] != '$')
{
plpgsql_error_lineno = yylineno;
elog(ERROR, "can only alias positional parameters"); elog(ERROR, "can only alias positional parameters");
}
nsi = plpgsql_ns_lookup(name, NULL); nsi = plpgsql_ns_lookup(name, NULL);
if (nsi == NULL) if (nsi == NULL)
{
plpgsql_error_lineno = yylineno;
elog(ERROR, "function has no parameter %s", name); elog(ERROR, "function has no parameter %s", name);
}
plpgsql_ns_setlocal(true); plpgsql_ns_setlocal(true);
...@@ -585,14 +591,12 @@ decl_defval : ';' ...@@ -585,14 +591,12 @@ decl_defval : ';'
{ {
case 0: case 0:
plpgsql_error_lineno = lno; plpgsql_error_lineno = lno;
plpgsql_comperrinfo();
elog(ERROR, "unexpected end of file"); elog(ERROR, "unexpected end of file");
case K_NULL: case K_NULL:
if (yylex() != ';') if (yylex() != ';')
{ {
plpgsql_error_lineno = lno; plpgsql_error_lineno = lno;
plpgsql_comperrinfo(); elog(ERROR, "expected ; after NULL");
elog(ERROR, "expectec ; after NULL");
} }
free(expr); free(expr);
plpgsql_dstring_free(&ds); plpgsql_dstring_free(&ds);
...@@ -607,7 +611,6 @@ decl_defval : ';' ...@@ -607,7 +611,6 @@ decl_defval : ';'
if (tok == 0) if (tok == 0)
{ {
plpgsql_error_lineno = lno; plpgsql_error_lineno = lno;
plpgsql_comperrinfo();
elog(ERROR, "unterminated default value"); elog(ERROR, "unterminated default value");
} }
if (plpgsql_SpaceScanned) if (plpgsql_SpaceScanned)
...@@ -793,7 +796,7 @@ getdiag_target : T_VARIABLE ...@@ -793,7 +796,7 @@ getdiag_target : T_VARIABLE
{ {
if (yylval.var->isconst) if (yylval.var->isconst)
{ {
plpgsql_comperrinfo(); plpgsql_error_lineno = yylineno;
elog(ERROR, "%s is declared CONSTANT; can not receive diagnostics", yylval.var->refname); elog(ERROR, "%s is declared CONSTANT; can not receive diagnostics", yylval.var->refname);
} }
$$ = yylval.var->varno; $$ = yylval.var->varno;
...@@ -809,7 +812,7 @@ assign_var : T_VARIABLE ...@@ -809,7 +812,7 @@ assign_var : T_VARIABLE
{ {
if (yylval.var->isconst) if (yylval.var->isconst)
{ {
plpgsql_comperrinfo(); plpgsql_error_lineno = yylineno;
elog(ERROR, "%s is declared CONSTANT", yylval.var->refname); elog(ERROR, "%s is declared CONSTANT", yylval.var->refname);
} }
$$ = yylval.var->varno; $$ = yylval.var->varno;
...@@ -1045,7 +1048,6 @@ fori_lower : ...@@ -1045,7 +1048,6 @@ fori_lower :
if (tok == 0) if (tok == 0)
{ {
plpgsql_error_lineno = lno; plpgsql_error_lineno = lno;
plpgsql_comperrinfo();
elog(ERROR, "missing .. to terminate lower bound of for loop"); elog(ERROR, "missing .. to terminate lower bound of for loop");
} }
plpgsql_dstring_append(&ds, yytext); plpgsql_dstring_append(&ds, yytext);
...@@ -1083,7 +1085,6 @@ stmt_fors : opt_label K_FOR lno fors_target K_IN K_SELECT expr_until_loop loop_ ...@@ -1083,7 +1085,6 @@ stmt_fors : opt_label K_FOR lno fors_target K_IN K_SELECT expr_until_loop loop_
new->row = (PLpgSQL_row *)$4; new->row = (PLpgSQL_row *)$4;
break; break;
default: default:
plpgsql_comperrinfo();
elog(ERROR, "unknown dtype %d in stmt_fors", $4->dtype); elog(ERROR, "unknown dtype %d in stmt_fors", $4->dtype);
} }
new->query = $7; new->query = $7;
...@@ -1113,7 +1114,6 @@ stmt_dynfors : opt_label K_FOR lno fors_target K_IN K_EXECUTE expr_until_loop lo ...@@ -1113,7 +1114,6 @@ stmt_dynfors : opt_label K_FOR lno fors_target K_IN K_EXECUTE expr_until_loop lo
new->row = (PLpgSQL_row *)$4; new->row = (PLpgSQL_row *)$4;
break; break;
default: default:
plpgsql_comperrinfo();
elog(ERROR, "unknown dtype %d in stmt_dynfors", $4->dtype); elog(ERROR, "unknown dtype %d in stmt_dynfors", $4->dtype);
} }
new->query = $7; new->query = $7;
...@@ -1339,7 +1339,7 @@ stmt_open : K_OPEN lno cursor_varptr ...@@ -1339,7 +1339,7 @@ stmt_open : K_OPEN lno cursor_varptr
if (tok != K_FOR) if (tok != K_FOR)
{ {
plpgsql_comperrinfo(); plpgsql_error_lineno = $2;
elog(ERROR, "syntax error at \"%s\" - expected FOR to open a reference cursor", yytext); elog(ERROR, "syntax error at \"%s\" - expected FOR to open a reference cursor", yytext);
} }
...@@ -1355,7 +1355,7 @@ stmt_open : K_OPEN lno cursor_varptr ...@@ -1355,7 +1355,7 @@ stmt_open : K_OPEN lno cursor_varptr
break; break;
default: default:
plpgsql_comperrinfo(); plpgsql_error_lineno = $2;
elog(ERROR, "syntax error at \"%s\"", yytext); elog(ERROR, "syntax error at \"%s\"", yytext);
} }
...@@ -1370,7 +1370,7 @@ stmt_open : K_OPEN lno cursor_varptr ...@@ -1370,7 +1370,7 @@ stmt_open : K_OPEN lno cursor_varptr
if (tok != '(') if (tok != '(')
{ {
plpgsql_comperrinfo(); plpgsql_error_lineno = yylineno;
elog(ERROR, "cursor %s has arguments", $3->refname); elog(ERROR, "cursor %s has arguments", $3->refname);
} }
...@@ -1384,7 +1384,7 @@ stmt_open : K_OPEN lno cursor_varptr ...@@ -1384,7 +1384,7 @@ stmt_open : K_OPEN lno cursor_varptr
--cp; --cp;
if (*cp != ')') if (*cp != ')')
{ {
plpgsql_comperrinfo(); plpgsql_error_lineno = yylineno;
elog(ERROR, "missing )"); elog(ERROR, "missing )");
} }
*cp = '\0'; *cp = '\0';
...@@ -1395,13 +1395,13 @@ stmt_open : K_OPEN lno cursor_varptr ...@@ -1395,13 +1395,13 @@ stmt_open : K_OPEN lno cursor_varptr
if (tok == '(') if (tok == '(')
{ {
plpgsql_comperrinfo(); plpgsql_error_lineno = yylineno;
elog(ERROR, "cursor %s has no arguments", $3->refname); elog(ERROR, "cursor %s has no arguments", $3->refname);
} }
if (tok != ';') if (tok != ';')
{ {
plpgsql_comperrinfo(); plpgsql_error_lineno = yylineno;
elog(ERROR, "syntax error at \"%s\"", yytext); elog(ERROR, "syntax error at \"%s\"", yytext);
} }
} }
...@@ -1440,7 +1440,7 @@ cursor_varptr : T_VARIABLE ...@@ -1440,7 +1440,7 @@ cursor_varptr : T_VARIABLE
{ {
if (yylval.var->datatype->typoid != REFCURSOROID) if (yylval.var->datatype->typoid != REFCURSOROID)
{ {
plpgsql_comperrinfo(); plpgsql_error_lineno = yylineno;
elog(ERROR, "%s must be of type cursor or refcursor", yylval.var->refname); elog(ERROR, "%s must be of type cursor or refcursor", yylval.var->refname);
} }
$$ = yylval.var; $$ = yylval.var;
...@@ -1451,7 +1451,7 @@ cursor_variable : T_VARIABLE ...@@ -1451,7 +1451,7 @@ cursor_variable : T_VARIABLE
{ {
if (yylval.var->datatype->typoid != REFCURSOROID) if (yylval.var->datatype->typoid != REFCURSOROID)
{ {
plpgsql_comperrinfo(); plpgsql_error_lineno = yylineno;
elog(ERROR, "%s must be of type refcursor", yylval.var->refname); elog(ERROR, "%s must be of type refcursor", yylval.var->refname);
} }
$$ = yylval.var->varno; $$ = yylval.var->varno;
...@@ -1545,7 +1545,6 @@ read_sqlstmt (int until, char *s, char *sqlstart) ...@@ -1545,7 +1545,6 @@ read_sqlstmt (int until, char *s, char *sqlstart)
{ {
case 0: case 0:
plpgsql_error_lineno = lno; plpgsql_error_lineno = lno;
plpgsql_comperrinfo();
elog(ERROR, "missing %s at end of SQL statement", s); elog(ERROR, "missing %s at end of SQL statement", s);
break; break;
...@@ -1613,7 +1612,6 @@ read_datatype(int tok) ...@@ -1613,7 +1612,6 @@ read_datatype(int tok)
if (tok == 0) if (tok == 0)
{ {
plpgsql_error_lineno = lno; plpgsql_error_lineno = lno;
plpgsql_comperrinfo();
elog(ERROR, "incomplete datatype declaration"); elog(ERROR, "incomplete datatype declaration");
} }
/* Possible followers for datatype in a declaration */ /* Possible followers for datatype in a declaration */
...@@ -1636,6 +1634,8 @@ read_datatype(int tok) ...@@ -1636,6 +1634,8 @@ read_datatype(int tok)
plpgsql_push_back_token(tok); plpgsql_push_back_token(tok);
plpgsql_error_lineno = lno; /* in case of error in parse_datatype */
result = plpgsql_parse_datatype(plpgsql_dstring_get(&ds)); result = plpgsql_parse_datatype(plpgsql_dstring_get(&ds));
plpgsql_dstring_free(&ds); plpgsql_dstring_free(&ds);
...@@ -1711,7 +1711,6 @@ make_select_stmt() ...@@ -1711,7 +1711,6 @@ make_select_stmt()
if (tok == 0) if (tok == 0)
{ {
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = yylineno;
plpgsql_comperrinfo();
elog(ERROR, "unexpected end of file"); elog(ERROR, "unexpected end of file");
} }
plpgsql_dstring_append(&ds, yytext); plpgsql_dstring_append(&ds, yytext);
...@@ -1772,6 +1771,7 @@ make_select_stmt() ...@@ -1772,6 +1771,7 @@ make_select_stmt()
break; break;
default: default:
plpgsql_error_lineno = yylineno;
elog(ERROR, "plpgsql: %s is not a variable or record field", yytext); elog(ERROR, "plpgsql: %s is not a variable or record field", yytext);
} }
} }
...@@ -1850,7 +1850,6 @@ make_select_stmt() ...@@ -1850,7 +1850,6 @@ make_select_stmt()
if (tok == 0) if (tok == 0)
{ {
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = yylineno;
plpgsql_comperrinfo();
elog(ERROR, "unexpected end of file"); elog(ERROR, "unexpected end of file");
} }
plpgsql_dstring_append(&ds, yytext); plpgsql_dstring_append(&ds, yytext);
...@@ -1899,7 +1898,6 @@ make_select_stmt() ...@@ -1899,7 +1898,6 @@ make_select_stmt()
if (tok == 0) if (tok == 0)
{ {
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = yylineno;
plpgsql_comperrinfo();
elog(ERROR, "unexpected end of file"); elog(ERROR, "unexpected end of file");
} }
plpgsql_dstring_append(&ds, yytext); plpgsql_dstring_append(&ds, yytext);
...@@ -1989,6 +1987,7 @@ make_fetch_stmt() ...@@ -1989,6 +1987,7 @@ make_fetch_stmt()
break; break;
default: default:
plpgsql_error_lineno = yylineno;
elog(ERROR, "plpgsql: %s is not a variable or record field", yytext); elog(ERROR, "plpgsql: %s is not a variable or record field", yytext);
} }
} }
...@@ -2013,16 +2012,18 @@ make_fetch_stmt() ...@@ -2013,16 +2012,18 @@ make_fetch_stmt()
break; break;
default: default:
{ plpgsql_error_lineno = yylineno;
elog(ERROR, "syntax error at '%s'", yytext); elog(ERROR, "syntax error at '%s'", yytext);
} }
}
if (!have_nexttok) if (!have_nexttok)
tok = yylex(); tok = yylex();
if (tok != ';') if (tok != ';')
{
plpgsql_error_lineno = yylineno;
elog(ERROR, "syntax error at '%s'", yytext); elog(ERROR, "syntax error at '%s'", yytext);
}
fetch = malloc(sizeof(PLpgSQL_stmt_select)); fetch = malloc(sizeof(PLpgSQL_stmt_select));
memset(fetch, 0, sizeof(PLpgSQL_stmt_fetch)); memset(fetch, 0, sizeof(PLpgSQL_stmt_fetch));
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.35 2001/10/09 04:15:38 tgl Exp $ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.36 2001/10/09 15:59:56 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <ctype.h> #include <ctype.h>
#include <setjmp.h>
#include "pl.tab.h" #include "pl.tab.h"
...@@ -55,6 +56,7 @@ ...@@ -55,6 +56,7 @@
#include "fmgr.h" #include "fmgr.h"
#include "parser/gramparse.h" #include "parser/gramparse.h"
#include "parser/parse_type.h" #include "parser/parse_type.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/syscache.h" #include "utils/syscache.h"
...@@ -119,18 +121,7 @@ plpgsql_compile(Oid fn_oid, int functype) ...@@ -119,18 +121,7 @@ plpgsql_compile(Oid fn_oid, int functype)
PLpgSQL_rec *rec; PLpgSQL_rec *rec;
int i; int i;
int arg_varnos[FUNC_MAX_ARGS]; int arg_varnos[FUNC_MAX_ARGS];
sigjmp_buf save_restart;
/*
* Initialize the compiler
*/
plpgsql_ns_init();
plpgsql_ns_push(NULL);
plpgsql_DumpExecTree = 0;
datums_alloc = 128;
plpgsql_nDatums = 0;
plpgsql_Datums = palloc(sizeof(PLpgSQL_datum *) * datums_alloc);
datums_last = 0;
/* /*
* Lookup the pg_proc tuple by Oid * Lookup the pg_proc tuple by Oid
...@@ -151,6 +142,41 @@ plpgsql_compile(Oid fn_oid, int functype) ...@@ -151,6 +142,41 @@ plpgsql_compile(Oid fn_oid, int functype)
plpgsql_error_funcname = pstrdup(NameStr(procStruct->proname)); plpgsql_error_funcname = pstrdup(NameStr(procStruct->proname));
plpgsql_error_lineno = 0; plpgsql_error_lineno = 0;
/*
* Catch elog() so we can provide notice about where the error is
*/
memcpy(&save_restart, &Warn_restart, sizeof(save_restart));
if (sigsetjmp(Warn_restart, 1) != 0)
{
memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));
/*
* If we are the first of cascaded error catchings, print where
* this happened
*/
if (plpgsql_error_funcname != NULL)
{
elog(NOTICE, "plpgsql: ERROR during compile of %s near line %d",
plpgsql_error_funcname, plpgsql_error_lineno);
plpgsql_error_funcname = NULL;
}
siglongjmp(Warn_restart, 1);
}
/*
* Initialize the compiler
*/
plpgsql_ns_init();
plpgsql_ns_push(NULL);
plpgsql_DumpExecTree = 0;
datums_alloc = 128;
plpgsql_nDatums = 0;
plpgsql_Datums = palloc(sizeof(PLpgSQL_datum *) * datums_alloc);
datums_last = 0;
/* /*
* Create the new function node * Create the new function node
*/ */
...@@ -158,9 +184,11 @@ plpgsql_compile(Oid fn_oid, int functype) ...@@ -158,9 +184,11 @@ plpgsql_compile(Oid fn_oid, int functype)
memset(function, 0, sizeof(PLpgSQL_function)); memset(function, 0, sizeof(PLpgSQL_function));
plpgsql_curr_compile = function; plpgsql_curr_compile = function;
function->fn_functype = functype;
function->fn_oid = fn_oid;
function->fn_name = strdup(NameStr(procStruct->proname)); function->fn_name = strdup(NameStr(procStruct->proname));
function->fn_oid = fn_oid;
function->fn_xmin = procTup->t_data->t_xmin;
function->fn_cmin = procTup->t_data->t_cmin;
function->fn_functype = functype;
switch (functype) switch (functype)
{ {
...@@ -180,7 +208,6 @@ plpgsql_compile(Oid fn_oid, int functype) ...@@ -180,7 +208,6 @@ plpgsql_compile(Oid fn_oid, int functype)
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(typeTup)) if (!HeapTupleIsValid(typeTup))
{ {
plpgsql_comperrinfo();
if (!OidIsValid(procStruct->prorettype)) if (!OidIsValid(procStruct->prorettype))
elog(ERROR, "plpgsql functions cannot return type \"opaque\"" elog(ERROR, "plpgsql functions cannot return type \"opaque\""
"\n\texcept when used as triggers"); "\n\texcept when used as triggers");
...@@ -215,7 +242,6 @@ plpgsql_compile(Oid fn_oid, int functype) ...@@ -215,7 +242,6 @@ plpgsql_compile(Oid fn_oid, int functype)
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(typeTup)) if (!HeapTupleIsValid(typeTup))
{ {
plpgsql_comperrinfo();
if (!OidIsValid(procStruct->proargtypes[i])) if (!OidIsValid(procStruct->proargtypes[i]))
elog(ERROR, "plpgsql functions cannot take type \"opaque\""); elog(ERROR, "plpgsql functions cannot take type \"opaque\"");
else else
...@@ -233,11 +259,8 @@ plpgsql_compile(Oid fn_oid, int functype) ...@@ -233,11 +259,8 @@ plpgsql_compile(Oid fn_oid, int functype)
*/ */
sprintf(buf, "%s%%rowtype", NameStr(typeStruct->typname)); sprintf(buf, "%s%%rowtype", NameStr(typeStruct->typname));
if (plpgsql_parse_wordrowtype(buf) != T_ROW) if (plpgsql_parse_wordrowtype(buf) != T_ROW)
{
plpgsql_comperrinfo();
elog(ERROR, "cannot get tuple struct of argument %d", elog(ERROR, "cannot get tuple struct of argument %d",
i + 1); i + 1);
}
row = plpgsql_yylval.row; row = plpgsql_yylval.row;
sprintf(buf, "$%d", i + 1); sprintf(buf, "$%d", i + 1);
...@@ -485,10 +508,7 @@ plpgsql_compile(Oid fn_oid, int functype) ...@@ -485,10 +508,7 @@ plpgsql_compile(Oid fn_oid, int functype)
*/ */
parse_rc = plpgsql_yyparse(); parse_rc = plpgsql_yyparse();
if (parse_rc != 0) if (parse_rc != 0)
{
plpgsql_comperrinfo();
elog(ERROR, "plpgsql: parser returned %d ???", parse_rc); elog(ERROR, "plpgsql: parser returned %d ???", parse_rc);
}
/* /*
* If that was successful, complete the functions info. * If that was successful, complete the functions info.
...@@ -504,6 +524,13 @@ plpgsql_compile(Oid fn_oid, int functype) ...@@ -504,6 +524,13 @@ plpgsql_compile(Oid fn_oid, int functype)
ReleaseSysCache(procTup); ReleaseSysCache(procTup);
/*
* Restore the previous elog() jump target
*/
plpgsql_error_funcname = NULL;
plpgsql_error_lineno = 0;
memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));
/* /*
* Finally return the compiled function * Finally return the compiled function
*/ */
...@@ -703,7 +730,6 @@ plpgsql_parse_dblword(char *string) ...@@ -703,7 +730,6 @@ plpgsql_parse_dblword(char *string)
return T_VARIABLE; return T_VARIABLE;
} }
} }
plpgsql_comperrinfo();
elog(ERROR, "row %s doesn't have a field %s", elog(ERROR, "row %s doesn't have a field %s",
word1, word2); word1, word2);
} }
...@@ -807,7 +833,6 @@ plpgsql_parse_tripword(char *string) ...@@ -807,7 +833,6 @@ plpgsql_parse_tripword(char *string)
return T_VARIABLE; return T_VARIABLE;
} }
} }
plpgsql_comperrinfo();
elog(ERROR, "row %s.%s doesn't have a field %s", elog(ERROR, "row %s.%s doesn't have a field %s",
word1, word2, word3); word1, word2, word3);
} }
...@@ -989,10 +1014,12 @@ plpgsql_parse_dblwordtype(char *string) ...@@ -989,10 +1014,12 @@ plpgsql_parse_dblwordtype(char *string)
} }
/* /*
* It must be a (shared) relation class * It must be a relation, sequence or view
*/ */
classStruct = (Form_pg_class) GETSTRUCT(classtup); classStruct = (Form_pg_class) GETSTRUCT(classtup);
if (classStruct->relkind != 'r' && classStruct->relkind != 's') if (classStruct->relkind != RELKIND_RELATION &&
classStruct->relkind != RELKIND_SEQUENCE &&
classStruct->relkind != RELKIND_VIEW)
{ {
ReleaseSysCache(classtup); ReleaseSysCache(classtup);
pfree(word1); pfree(word1);
...@@ -1018,11 +1045,8 @@ plpgsql_parse_dblwordtype(char *string) ...@@ -1018,11 +1045,8 @@ plpgsql_parse_dblwordtype(char *string)
ObjectIdGetDatum(attrStruct->atttypid), ObjectIdGetDatum(attrStruct->atttypid),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(typetup)) if (!HeapTupleIsValid(typetup))
{
plpgsql_comperrinfo();
elog(ERROR, "cache lookup for type %u of %s.%s failed", elog(ERROR, "cache lookup for type %u of %s.%s failed",
attrStruct->atttypid, word1, word2); attrStruct->atttypid, word1, word2);
}
typeStruct = (Form_pg_type) GETSTRUCT(typetup); typeStruct = (Form_pg_type) GETSTRUCT(typetup);
/* /*
...@@ -1079,19 +1103,13 @@ plpgsql_parse_wordrowtype(char *string) ...@@ -1079,19 +1103,13 @@ plpgsql_parse_wordrowtype(char *string)
PointerGetDatum(word1), PointerGetDatum(word1),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(classtup)) if (!HeapTupleIsValid(classtup))
{
plpgsql_comperrinfo();
elog(ERROR, "%s: no such class", word1); elog(ERROR, "%s: no such class", word1);
}
classStruct = (Form_pg_class) GETSTRUCT(classtup); classStruct = (Form_pg_class) GETSTRUCT(classtup);
/* accept relation, sequence, or view pg_class entries */ /* accept relation, sequence, or view pg_class entries */
if (classStruct->relkind != 'r' && if (classStruct->relkind != RELKIND_RELATION &&
classStruct->relkind != 's' && classStruct->relkind != RELKIND_SEQUENCE &&
classStruct->relkind != 'v') classStruct->relkind != RELKIND_VIEW)
{
plpgsql_comperrinfo();
elog(ERROR, "%s isn't a table", word1); elog(ERROR, "%s isn't a table", word1);
}
/* /*
* Fetch the table's pg_type tuple too * Fetch the table's pg_type tuple too
...@@ -1100,10 +1118,7 @@ plpgsql_parse_wordrowtype(char *string) ...@@ -1100,10 +1118,7 @@ plpgsql_parse_wordrowtype(char *string)
PointerGetDatum(word1), PointerGetDatum(word1),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(typetup)) if (!HeapTupleIsValid(typetup))
{
plpgsql_comperrinfo();
elog(ERROR, "cache lookup for %s in pg_type failed", word1); elog(ERROR, "cache lookup for %s in pg_type failed", word1);
}
/* /*
* Create a row datum entry and all the required variables that it * Create a row datum entry and all the required variables that it
...@@ -1131,11 +1146,8 @@ plpgsql_parse_wordrowtype(char *string) ...@@ -1131,11 +1146,8 @@ plpgsql_parse_wordrowtype(char *string)
Int16GetDatum(i + 1), Int16GetDatum(i + 1),
0, 0); 0, 0);
if (!HeapTupleIsValid(attrtup)) if (!HeapTupleIsValid(attrtup))
{
plpgsql_comperrinfo();
elog(ERROR, "cache lookup for attribute %d of class %s failed", elog(ERROR, "cache lookup for attribute %d of class %s failed",
i + 1, word1); i + 1, word1);
}
attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup); attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);
cp = pstrdup(NameStr(attrStruct->attname)); cp = pstrdup(NameStr(attrStruct->attname));
...@@ -1144,11 +1156,8 @@ plpgsql_parse_wordrowtype(char *string) ...@@ -1144,11 +1156,8 @@ plpgsql_parse_wordrowtype(char *string)
ObjectIdGetDatum(attrStruct->atttypid), ObjectIdGetDatum(attrStruct->atttypid),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(typetup)) if (!HeapTupleIsValid(typetup))
{
plpgsql_comperrinfo();
elog(ERROR, "cache lookup for type %u of %s.%s failed", elog(ERROR, "cache lookup for type %u of %s.%s failed",
attrStruct->atttypid, word1, cp); attrStruct->atttypid, word1, cp);
}
typeStruct = (Form_pg_type) GETSTRUCT(typetup); typeStruct = (Form_pg_type) GETSTRUCT(typetup);
/* /*
...@@ -1316,19 +1325,6 @@ plpgsql_add_initdatums(int **varnos) ...@@ -1316,19 +1325,6 @@ plpgsql_add_initdatums(int **varnos)
} }
/* ----------
* plpgsql_comperrinfo Called before elog(ERROR, ...)
* during compile.
* ----------
*/
void
plpgsql_comperrinfo()
{
elog(NOTICE, "plpgsql: ERROR during compile of %s near line %d",
plpgsql_error_funcname, plpgsql_error_lineno);
}
/* --------- /* ---------
* plpgsql_yyerror Handle parser error * plpgsql_yyerror Handle parser error
* --------- * ---------
...@@ -1338,6 +1334,5 @@ void ...@@ -1338,6 +1334,5 @@ void
plpgsql_yyerror(const char *s) plpgsql_yyerror(const char *s)
{ {
plpgsql_error_lineno = plpgsql_yylineno; plpgsql_error_lineno = plpgsql_yylineno;
plpgsql_comperrinfo();
elog(ERROR, "%s at or near \"%s\"", s, plpgsql_yytext); elog(ERROR, "%s at or near \"%s\"", s, plpgsql_yytext);
} }
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.15 2001/07/12 17:42:08 momjian Exp $ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.16 2001/10/09 15:59:56 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -324,6 +324,7 @@ plpgsql_ns_rename(char *oldname, char *newname) ...@@ -324,6 +324,7 @@ plpgsql_ns_rename(char *oldname, char *newname)
char * char *
plpgsql_tolower(char *s) plpgsql_tolower(char *s)
{ {
char *sstart = s;
char *ret; char *ret;
char *cp; char *cp;
...@@ -342,10 +343,7 @@ plpgsql_tolower(char *s) ...@@ -342,10 +343,7 @@ plpgsql_tolower(char *s)
*cp++ = *s++; *cp++ = *s++;
} }
if (*s != '"') if (*s != '"')
{ elog(ERROR, "unterminated \" in name %s", sstart);
plpgsql_comperrinfo();
elog(ERROR, "unterminated \"");
}
s++; s++;
} }
else else
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.8 2001/03/22 06:16:21 momjian Exp $ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.9 2001/10/09 15:59:56 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -58,6 +58,9 @@ ...@@ -58,6 +58,9 @@
static PLpgSQL_function *compiled_functions = NULL; static PLpgSQL_function *compiled_functions = NULL;
static bool func_up_to_date(PLpgSQL_function *func);
/* ---------- /* ----------
* plpgsql_call_handler * plpgsql_call_handler
* *
...@@ -72,6 +75,7 @@ Datum ...@@ -72,6 +75,7 @@ Datum
plpgsql_call_handler(PG_FUNCTION_ARGS) plpgsql_call_handler(PG_FUNCTION_ARGS)
{ {
bool isTrigger = CALLED_AS_TRIGGER(fcinfo); bool isTrigger = CALLED_AS_TRIGGER(fcinfo);
Oid funcOid = fcinfo->flinfo->fn_oid;
PLpgSQL_function *func; PLpgSQL_function *func;
Datum retval; Datum retval;
...@@ -86,17 +90,24 @@ plpgsql_call_handler(PG_FUNCTION_ARGS) ...@@ -86,17 +90,24 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
* (ie, current FmgrInfo has been used before) * (ie, current FmgrInfo has been used before)
*/ */
func = (PLpgSQL_function *) fcinfo->flinfo->fn_extra; func = (PLpgSQL_function *) fcinfo->flinfo->fn_extra;
if (func == NULL) if (func != NULL)
{ {
Assert(func->fn_oid == funcOid);
/* /*
* Check if we already compiled this function * But is the function still up to date?
*/ */
Oid funcOid = fcinfo->flinfo->fn_oid; if (! func_up_to_date(func))
func = NULL;
}
if (func == NULL)
{
/*
* Check if we already compiled this function for another caller
*/
for (func = compiled_functions; func != NULL; func = func->next) for (func = compiled_functions; func != NULL; func = func->next)
{ {
if (funcOid == func->fn_oid) if (funcOid == func->fn_oid && func_up_to_date(func))
break; break;
} }
...@@ -135,3 +146,30 @@ plpgsql_call_handler(PG_FUNCTION_ARGS) ...@@ -135,3 +146,30 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
return retval; return retval;
} }
/*
* Check to see if a compiled function is still up-to-date. This
* is needed because CREATE OR REPLACE FUNCTION can modify the
* function's pg_proc entry without changing its OID.
*/
static bool
func_up_to_date(PLpgSQL_function *func)
{
HeapTuple procTup;
bool result;
procTup = SearchSysCache(PROCOID,
ObjectIdGetDatum(func->fn_oid),
0, 0, 0);
if (!HeapTupleIsValid(procTup))
elog(ERROR, "plpgsql: cache lookup for proc %u failed",
func->fn_oid);
result = (func->fn_xmin == procTup->t_data->t_xmin &&
func->fn_cmin == procTup->t_data->t_cmin);
ReleaseSysCache(procTup);
return result;
}
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.18 2001/10/09 04:15:38 tgl Exp $ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.19 2001/10/09 15:59:56 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -455,9 +455,12 @@ typedef struct ...@@ -455,9 +455,12 @@ typedef struct
typedef struct PLpgSQL_function typedef struct PLpgSQL_function
{ /* Complete compiled function */ { /* Complete compiled function */
Oid fn_oid;
char *fn_name; char *fn_name;
Oid fn_oid;
TransactionId fn_xmin;
CommandId fn_cmin;
int fn_functype; int fn_functype;
Oid fn_rettype; Oid fn_rettype;
int fn_rettyplen; int fn_rettyplen;
bool fn_retbyval; bool fn_retbyval;
...@@ -482,7 +485,8 @@ typedef struct PLpgSQL_function ...@@ -482,7 +485,8 @@ typedef struct PLpgSQL_function
int ndatums; int ndatums;
PLpgSQL_datum **datums; PLpgSQL_datum **datums;
PLpgSQL_stmt_block *action; PLpgSQL_stmt_block *action;
struct PLpgSQL_function *next;
struct PLpgSQL_function *next; /* for chaining list of functions */
} PLpgSQL_function; } PLpgSQL_function;
...@@ -549,7 +553,6 @@ extern int plpgsql_parse_wordrowtype(char *string); ...@@ -549,7 +553,6 @@ extern int plpgsql_parse_wordrowtype(char *string);
extern PLpgSQL_type *plpgsql_parse_datatype(char *string); extern PLpgSQL_type *plpgsql_parse_datatype(char *string);
extern void plpgsql_adddatum(PLpgSQL_datum * new); extern void plpgsql_adddatum(PLpgSQL_datum * new);
extern int plpgsql_add_initdatums(int **varnos); extern int plpgsql_add_initdatums(int **varnos);
extern void plpgsql_comperrinfo(void);
extern void plpgsql_yyerror(const char *s); extern void plpgsql_yyerror(const char *s);
/* ---------- /* ----------
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.15 2001/10/09 04:15:38 tgl Exp $ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.16 2001/10/09 15:59:56 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -180,9 +180,9 @@ dump { return O_DUMP; } ...@@ -180,9 +180,9 @@ dump { return O_DUMP; }
<IN_COMMENT>\*\/ { BEGIN INITIAL; } <IN_COMMENT>\*\/ { BEGIN INITIAL; }
<IN_COMMENT>\n ; <IN_COMMENT>\n ;
<IN_COMMENT>. ; <IN_COMMENT>. ;
<IN_COMMENT><<EOF>> { plpgsql_comperrinfo(); <IN_COMMENT><<EOF>> {
elog(ERROR, "unterminated comment starting on line %d", plpgsql_error_lineno = start_lineno;
start_lineno); elog(ERROR, "unterminated comment");
} }
/* ---------- /* ----------
...@@ -198,9 +198,9 @@ dump { return O_DUMP; } ...@@ -198,9 +198,9 @@ dump { return O_DUMP; }
<IN_STRING>' { BEGIN INITIAL; <IN_STRING>' { BEGIN INITIAL;
return T_STRING; return T_STRING;
} }
<IN_STRING><<EOF>> { plpgsql_comperrinfo(); <IN_STRING><<EOF>> {
elog(ERROR, "unterminated string starting on line %d", plpgsql_error_lineno = start_lineno;
start_lineno); elog(ERROR, "unterminated string");
} }
<IN_STRING>[^'\\]* { yymore(); } <IN_STRING>[^'\\]* { yymore(); }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment