]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Change plpgsql compiler so that all elogs are trapped and a suitable
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 9 Oct 2001 15:59:56 +0000 (15:59 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 9 Oct 2001 15:59:56 +0000 (15:59 +0000)
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.

src/pl/plpgsql/src/gram.y
src/pl/plpgsql/src/pl_comp.c
src/pl/plpgsql/src/pl_funcs.c
src/pl/plpgsql/src/pl_handler.c
src/pl/plpgsql/src/plpgsql.h
src/pl/plpgsql/src/scan.l

index a2d37c3f99641db68cc0025e64a270d8f96b9614..a7da1710c1a3171fdf3d9228f7abefa2057c8871 100644 (file)
@@ -4,7 +4,7 @@
  *                                               procedural language
  *
  * 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.
  *
@@ -507,10 +507,16 @@ decl_aliasitem    : T_WORD
                                                plpgsql_ns_setlocal(false);
                                                name = plpgsql_tolower(yytext);
                                                if (name[0] != '$')
+                                               {
+                                                       plpgsql_error_lineno = yylineno;
                                                        elog(ERROR, "can only alias positional parameters");
+                                               }
                                                nsi = plpgsql_ns_lookup(name, NULL);
                                                if (nsi == NULL)
+                                               {
+                                                       plpgsql_error_lineno = yylineno;
                                                        elog(ERROR, "function has no parameter %s", name);
+                                               }
 
                                                plpgsql_ns_setlocal(true);
 
@@ -585,14 +591,12 @@ decl_defval               : ';'
                                                {
                                                        case 0:
                                                                plpgsql_error_lineno = lno;
-                                                               plpgsql_comperrinfo();
                                                                elog(ERROR, "unexpected end of file");
                                                        case K_NULL:
                                                                if (yylex() != ';')
                                                                {
                                                                        plpgsql_error_lineno = lno;
-                                                                       plpgsql_comperrinfo();
-                                                                       elog(ERROR, "expectec ; after NULL");
+                                                                       elog(ERROR, "expected ; after NULL");
                                                                }
                                                                free(expr);
                                                                plpgsql_dstring_free(&ds);
@@ -607,7 +611,6 @@ decl_defval         : ';'
                                                                        if (tok == 0)
                                                                        {
                                                                                plpgsql_error_lineno = lno;
-                                                                               plpgsql_comperrinfo();
                                                                                elog(ERROR, "unterminated default value");
                                                                        }
                                                                        if (plpgsql_SpaceScanned)
@@ -793,7 +796,7 @@ getdiag_target      : T_VARIABLE
                                        {
                                                if (yylval.var->isconst)
                                                {
-                                                       plpgsql_comperrinfo();
+                                                       plpgsql_error_lineno = yylineno;
                                                        elog(ERROR, "%s is declared CONSTANT; can not receive diagnostics", yylval.var->refname);
                                                }
                                                $$ = yylval.var->varno;
@@ -809,7 +812,7 @@ assign_var          : T_VARIABLE
                                        {
                                                if (yylval.var->isconst)
                                                {
-                                                       plpgsql_comperrinfo();
+                                                       plpgsql_error_lineno = yylineno;
                                                        elog(ERROR, "%s is declared CONSTANT", yylval.var->refname);
                                                }
                                                $$ = yylval.var->varno;
@@ -1045,7 +1048,6 @@ fori_lower                :
                                                                        if (tok == 0)
                                                                        {
                                                                                plpgsql_error_lineno = lno;
-                                                                               plpgsql_comperrinfo();
                                                                                elog(ERROR, "missing .. to terminate lower bound of for loop");
                                                                        }
                                                                        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_
                                                                new->row = (PLpgSQL_row *)$4;
                                                                break;
                                                        default:
-                                                               plpgsql_comperrinfo();
                                                                elog(ERROR, "unknown dtype %d in stmt_fors", $4->dtype);
                                                }
                                                new->query = $7;
@@ -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;
                                                                break;
                                                        default:
-                                                               plpgsql_comperrinfo();
                                                                elog(ERROR, "unknown dtype %d in stmt_dynfors", $4->dtype);
                                                }
                                                new->query = $7;
@@ -1339,7 +1339,7 @@ stmt_open         : K_OPEN lno cursor_varptr
 
                                                        if (tok != K_FOR)
                                                        {
-                                                               plpgsql_comperrinfo();
+                                                               plpgsql_error_lineno = $2;
                                                                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
                                                                        break;
 
                                                                default:
-                                                                       plpgsql_comperrinfo();
+                                                                       plpgsql_error_lineno = $2;
                                                                        elog(ERROR, "syntax error at \"%s\"", yytext);
                                                        }
 
@@ -1370,7 +1370,7 @@ stmt_open         : K_OPEN lno cursor_varptr
 
                                                                if (tok != '(')
                                                                {
-                                                                       plpgsql_comperrinfo();
+                                                                       plpgsql_error_lineno = yylineno;
                                                                        elog(ERROR, "cursor %s has arguments", $3->refname);
                                                                }
 
@@ -1384,7 +1384,7 @@ stmt_open         : K_OPEN lno cursor_varptr
                                                                --cp;
                                                                if (*cp != ')')
                                                                {
-                                                                       plpgsql_comperrinfo();
+                                                                       plpgsql_error_lineno = yylineno;
                                                                        elog(ERROR, "missing )");
                                                                }
                                                                *cp = '\0';
@@ -1395,13 +1395,13 @@ stmt_open               : K_OPEN lno cursor_varptr
 
                                                                if (tok == '(')
                                                                {
-                                                                       plpgsql_comperrinfo();
+                                                                       plpgsql_error_lineno = yylineno;
                                                                        elog(ERROR, "cursor %s has no arguments", $3->refname);
                                                                }
                                                                
                                                                if (tok != ';')
                                                                {
-                                                                       plpgsql_comperrinfo();
+                                                                       plpgsql_error_lineno = yylineno;
                                                                        elog(ERROR, "syntax error at \"%s\"", yytext);
                                                                }
                                                        }
@@ -1440,7 +1440,7 @@ cursor_varptr     : T_VARIABLE
                                        {
                                                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);
                                                }
                                                $$ = yylval.var;
@@ -1451,7 +1451,7 @@ cursor_variable   : T_VARIABLE
                                        {
                                                if (yylval.var->datatype->typoid != REFCURSOROID)
                                                {
-                                                       plpgsql_comperrinfo();
+                                                       plpgsql_error_lineno = yylineno;
                                                        elog(ERROR, "%s must be of type refcursor", yylval.var->refname);
                                                }
                                                $$ = yylval.var->varno;
@@ -1545,7 +1545,6 @@ read_sqlstmt (int until, char *s, char *sqlstart)
                {
                        case 0:
                                plpgsql_error_lineno = lno;
-                               plpgsql_comperrinfo();
                                elog(ERROR, "missing %s at end of SQL statement", s);
                                break;
 
@@ -1613,7 +1612,6 @@ read_datatype(int tok)
                if (tok == 0)
                {
                        plpgsql_error_lineno = lno;
-                       plpgsql_comperrinfo();
                        elog(ERROR, "incomplete datatype declaration");
                }
                /* Possible followers for datatype in a declaration */
@@ -1636,6 +1634,8 @@ read_datatype(int 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));
 
        plpgsql_dstring_free(&ds);
@@ -1711,7 +1711,6 @@ make_select_stmt()
                                if (tok == 0)
                                {
                                        plpgsql_error_lineno = yylineno;
-                                       plpgsql_comperrinfo();
                                        elog(ERROR, "unexpected end of file");
                                }
                                plpgsql_dstring_append(&ds, yytext);
@@ -1772,6 +1771,7 @@ make_select_stmt()
                                                        break;
 
                                                default:
+                                                       plpgsql_error_lineno = yylineno;
                                                        elog(ERROR, "plpgsql: %s is not a variable or record field", yytext);
                                        }
                                }
@@ -1850,7 +1850,6 @@ make_select_stmt()
                                                        if (tok == 0)
                                                        {
                                                                plpgsql_error_lineno = yylineno;
-                                                               plpgsql_comperrinfo();
                                                                elog(ERROR, "unexpected end of file");
                                                        }
                                                        plpgsql_dstring_append(&ds, yytext);
@@ -1899,7 +1898,6 @@ make_select_stmt()
                                if (tok == 0)
                                {
                                        plpgsql_error_lineno = yylineno;
-                                       plpgsql_comperrinfo();
                                        elog(ERROR, "unexpected end of file");
                                }
                                plpgsql_dstring_append(&ds, yytext);
@@ -1989,6 +1987,7 @@ make_fetch_stmt()
                                                        break;
 
                                                default:
+                                                       plpgsql_error_lineno = yylineno;
                                                        elog(ERROR, "plpgsql: %s is not a variable or record field", yytext);
                                        }
                                }
@@ -2013,16 +2012,18 @@ make_fetch_stmt()
                        break;
 
                default:
-                       {
-                               elog(ERROR, "syntax error at '%s'", yytext);
-                       }
+                       plpgsql_error_lineno = yylineno;
+                       elog(ERROR, "syntax error at '%s'", yytext);
        }
 
        if (!have_nexttok)
                tok = yylex();
 
        if (tok != ';')
+       {
+               plpgsql_error_lineno = yylineno;
                elog(ERROR, "syntax error at '%s'", yytext);
+       }
 
        fetch = malloc(sizeof(PLpgSQL_stmt_select));
        memset(fetch, 0, sizeof(PLpgSQL_stmt_fetch));
index c06a2c878119912275899258539b48530ec4f942..39630876ef3116d88da3a650b526e88d9fc32eee 100644 (file)
@@ -3,7 +3,7 @@
  *                       procedural language
  *
  * 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.
  *
@@ -40,6 +40,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <ctype.h>
+#include <setjmp.h>
 
 #include "pl.tab.h"
 
@@ -55,6 +56,7 @@
 #include "fmgr.h"
 #include "parser/gramparse.h"
 #include "parser/parse_type.h"
+#include "tcop/tcopprot.h"
 #include "utils/builtins.h"
 #include "utils/syscache.h"
 
@@ -119,18 +121,7 @@ plpgsql_compile(Oid fn_oid, int functype)
        PLpgSQL_rec *rec;
        int                     i;
        int                     arg_varnos[FUNC_MAX_ARGS];
-
-       /*
-        * 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;
+       sigjmp_buf      save_restart;
 
        /*
         * Lookup the pg_proc tuple by Oid
@@ -151,6 +142,41 @@ plpgsql_compile(Oid fn_oid, int functype)
        plpgsql_error_funcname = pstrdup(NameStr(procStruct->proname));
        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
         */
@@ -158,9 +184,11 @@ plpgsql_compile(Oid fn_oid, int functype)
        memset(function, 0, sizeof(PLpgSQL_function));
        plpgsql_curr_compile = function;
 
-       function->fn_functype = functype;
-       function->fn_oid = fn_oid;
        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)
        {
@@ -180,7 +208,6 @@ plpgsql_compile(Oid fn_oid, int functype)
                                                                         0, 0, 0);
                        if (!HeapTupleIsValid(typeTup))
                        {
-                               plpgsql_comperrinfo();
                                if (!OidIsValid(procStruct->prorettype))
                                        elog(ERROR, "plpgsql functions cannot return type \"opaque\""
                                                 "\n\texcept when used as triggers");
@@ -215,7 +242,6 @@ plpgsql_compile(Oid fn_oid, int functype)
                                                                                 0, 0, 0);
                                if (!HeapTupleIsValid(typeTup))
                                {
-                                       plpgsql_comperrinfo();
                                        if (!OidIsValid(procStruct->proargtypes[i]))
                                                elog(ERROR, "plpgsql functions cannot take type \"opaque\"");
                                        else
@@ -233,11 +259,8 @@ plpgsql_compile(Oid fn_oid, int functype)
                                         */
                                        sprintf(buf, "%s%%rowtype", NameStr(typeStruct->typname));
                                        if (plpgsql_parse_wordrowtype(buf) != T_ROW)
-                                       {
-                                               plpgsql_comperrinfo();
                                                elog(ERROR, "cannot get tuple struct of argument %d",
                                                         i + 1);
-                                       }
 
                                        row = plpgsql_yylval.row;
                                        sprintf(buf, "$%d", i + 1);
@@ -485,10 +508,7 @@ plpgsql_compile(Oid fn_oid, int functype)
         */
        parse_rc = plpgsql_yyparse();
        if (parse_rc != 0)
-       {
-               plpgsql_comperrinfo();
                elog(ERROR, "plpgsql: parser returned %d ???", parse_rc);
-       }
 
        /*
         * If that was successful, complete the functions info.
@@ -504,6 +524,13 @@ plpgsql_compile(Oid fn_oid, int functype)
 
        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
         */
@@ -703,7 +730,6 @@ plpgsql_parse_dblword(char *string)
                                                return T_VARIABLE;
                                        }
                                }
-                               plpgsql_comperrinfo();
                                elog(ERROR, "row %s doesn't have a field %s",
                                         word1, word2);
                        }
@@ -807,7 +833,6 @@ plpgsql_parse_tripword(char *string)
                                                return T_VARIABLE;
                                        }
                                }
-                               plpgsql_comperrinfo();
                                elog(ERROR, "row %s.%s doesn't have a field %s",
                                         word1, word2, word3);
                        }
@@ -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);
-       if (classStruct->relkind != 'r' && classStruct->relkind != 's')
+       if (classStruct->relkind != RELKIND_RELATION &&
+               classStruct->relkind != RELKIND_SEQUENCE &&
+               classStruct->relkind != RELKIND_VIEW)
        {
                ReleaseSysCache(classtup);
                pfree(word1);
@@ -1018,11 +1045,8 @@ plpgsql_parse_dblwordtype(char *string)
                                                         ObjectIdGetDatum(attrStruct->atttypid),
                                                         0, 0, 0);
        if (!HeapTupleIsValid(typetup))
-       {
-               plpgsql_comperrinfo();
                elog(ERROR, "cache lookup for type %u of %s.%s failed",
                         attrStruct->atttypid, word1, word2);
-       }
        typeStruct = (Form_pg_type) GETSTRUCT(typetup);
 
        /*
@@ -1079,19 +1103,13 @@ plpgsql_parse_wordrowtype(char *string)
                                                          PointerGetDatum(word1),
                                                          0, 0, 0);
        if (!HeapTupleIsValid(classtup))
-       {
-               plpgsql_comperrinfo();
                elog(ERROR, "%s: no such class", word1);
-       }
        classStruct = (Form_pg_class) GETSTRUCT(classtup);
        /* accept relation, sequence, or view pg_class entries */
-       if (classStruct->relkind != 'r' &&
-               classStruct->relkind != 's' &&
-               classStruct->relkind != 'v')
-       {
-               plpgsql_comperrinfo();
+       if (classStruct->relkind != RELKIND_RELATION &&
+               classStruct->relkind != RELKIND_SEQUENCE &&
+               classStruct->relkind != RELKIND_VIEW)
                elog(ERROR, "%s isn't a table", word1);
-       }
 
        /*
         * Fetch the table's pg_type tuple too
@@ -1100,10 +1118,7 @@ plpgsql_parse_wordrowtype(char *string)
                                                         PointerGetDatum(word1),
                                                         0, 0, 0);
        if (!HeapTupleIsValid(typetup))
-       {
-               plpgsql_comperrinfo();
                elog(ERROR, "cache lookup for %s in pg_type failed", word1);
-       }
 
        /*
         * Create a row datum entry and all the required variables that it
@@ -1131,11 +1146,8 @@ plpgsql_parse_wordrowtype(char *string)
                                                                 Int16GetDatum(i + 1),
                                                                 0, 0);
                if (!HeapTupleIsValid(attrtup))
-               {
-                       plpgsql_comperrinfo();
                        elog(ERROR, "cache lookup for attribute %d of class %s failed",
                                 i + 1, word1);
-               }
                attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);
 
                cp = pstrdup(NameStr(attrStruct->attname));
@@ -1144,11 +1156,8 @@ plpgsql_parse_wordrowtype(char *string)
                                                                 ObjectIdGetDatum(attrStruct->atttypid),
                                                                 0, 0, 0);
                if (!HeapTupleIsValid(typetup))
-               {
-                       plpgsql_comperrinfo();
                        elog(ERROR, "cache lookup for type %u of %s.%s failed",
                                 attrStruct->atttypid, word1, cp);
-               }
                typeStruct = (Form_pg_type) GETSTRUCT(typetup);
 
                /*
@@ -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
  * ---------
@@ -1338,6 +1334,5 @@ void
 plpgsql_yyerror(const char *s)
 {
        plpgsql_error_lineno = plpgsql_yylineno;
-       plpgsql_comperrinfo();
        elog(ERROR, "%s at or near \"%s\"", s, plpgsql_yytext);
 }
index cce131b0c2ddec24e2216a4723261d8b78dbb858..61ab93a6cd4672d99d80d906d748be29afbaac0e 100644 (file)
@@ -3,7 +3,7 @@
  *                       procedural language
  *
  * 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.
  *
@@ -324,6 +324,7 @@ plpgsql_ns_rename(char *oldname, char *newname)
 char *
 plpgsql_tolower(char *s)
 {
+       char       *sstart = s;
        char       *ret;
        char       *cp;
 
@@ -342,10 +343,7 @@ plpgsql_tolower(char *s)
                                *cp++ = *s++;
                        }
                        if (*s != '"')
-                       {
-                               plpgsql_comperrinfo();
-                               elog(ERROR, "unterminated \"");
-                       }
+                               elog(ERROR, "unterminated \" in name %s", sstart);
                        s++;
                }
                else
index 8801ce55e375df13161e248ed71d342a1d69d65a..bacd287fdda04c5b3a248e408190e3e4ebc87813 100644 (file)
@@ -3,7 +3,7 @@
  *                       procedural language
  *
  * 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.
  *
@@ -58,6 +58,9 @@
 static PLpgSQL_function *compiled_functions = NULL;
 
 
+static bool func_up_to_date(PLpgSQL_function *func);
+
+
 /* ----------
  * plpgsql_call_handler
  *
@@ -72,6 +75,7 @@ Datum
 plpgsql_call_handler(PG_FUNCTION_ARGS)
 {
        bool            isTrigger = CALLED_AS_TRIGGER(fcinfo);
+       Oid                     funcOid = fcinfo->flinfo->fn_oid;
        PLpgSQL_function *func;
        Datum           retval;
 
@@ -86,17 +90,24 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
         * (ie, current FmgrInfo has been used before)
         */
        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)
                {
-                       if (funcOid == func->fn_oid)
+                       if (funcOid == func->fn_oid && func_up_to_date(func))
                                break;
                }
 
@@ -135,3 +146,30 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
 
        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;
+}
index fc2032dbd6d96ffdba3371066ea93d784f270274..147659e7cca6e97bc65e8f2c94848f0a895b1320 100644 (file)
@@ -3,7 +3,7 @@
  *                       procedural language
  *
  * 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.
  *
@@ -455,9 +455,12 @@ typedef struct
 
 typedef struct PLpgSQL_function
 {                                                              /* Complete compiled function     */
-       Oid                     fn_oid;
        char       *fn_name;
+       Oid                     fn_oid;
+       TransactionId fn_xmin;
+       CommandId       fn_cmin;
        int                     fn_functype;
+
        Oid                     fn_rettype;
        int                     fn_rettyplen;
        bool            fn_retbyval;
@@ -482,7 +485,8 @@ typedef struct PLpgSQL_function
        int                     ndatums;
        PLpgSQL_datum **datums;
        PLpgSQL_stmt_block *action;
-       struct PLpgSQL_function *next;
+
+       struct PLpgSQL_function *next; /* for chaining list of functions */
 }                      PLpgSQL_function;
 
 
@@ -549,7 +553,6 @@ extern int  plpgsql_parse_wordrowtype(char *string);
 extern PLpgSQL_type *plpgsql_parse_datatype(char *string);
 extern void plpgsql_adddatum(PLpgSQL_datum * new);
 extern int     plpgsql_add_initdatums(int **varnos);
-extern void plpgsql_comperrinfo(void);
 extern void plpgsql_yyerror(const char *s);
 
 /* ----------
index dfb16f817712fcef867ef6b5a40a9ad99fee2ff9..49191fa106f61f2c42941aec58b597ef20256855 100644 (file)
@@ -4,7 +4,7 @@
  *                       procedural language
  *
  * 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.
  *
@@ -180,9 +180,9 @@ dump                        { return O_DUMP;                        }
 <IN_COMMENT>\*\/       { BEGIN INITIAL;                        }
 <IN_COMMENT>\n         ;
 <IN_COMMENT>.          ;
-<IN_COMMENT><<EOF>>    { plpgsql_comperrinfo();
-                         elog(ERROR, "unterminated comment starting on line %d",
-                               start_lineno);
+<IN_COMMENT><<EOF>>    {
+                               plpgsql_error_lineno = start_lineno;
+                               elog(ERROR, "unterminated comment");
                        }
 
     /* ----------
@@ -198,9 +198,9 @@ dump                        { return O_DUMP;                        }
 <IN_STRING>'           { BEGIN INITIAL;
                          return T_STRING;
                        }
-<IN_STRING><<EOF>>     { plpgsql_comperrinfo();
-                         elog(ERROR, "unterminated string starting on line %d", 
-                               start_lineno);
+<IN_STRING><<EOF>>     {
+                               plpgsql_error_lineno = start_lineno;
+                               elog(ERROR, "unterminated string");
                        }
 <IN_STRING>[^'\\]*     { yymore();                             }