diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y index a2d37c3f99641db68cc0025e64a270d8f96b9614..a7da1710c1a3171fdf3d9228f7abefa2057c8871 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.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)); diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index c06a2c878119912275899258539b48530ec4f942..39630876ef3116d88da3a650b526e88d9fc32eee 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -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); } diff --git a/src/pl/plpgsql/src/pl_funcs.c b/src/pl/plpgsql/src/pl_funcs.c index cce131b0c2ddec24e2216a4723261d8b78dbb858..61ab93a6cd4672d99d80d906d748be29afbaac0e 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.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 diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c index 8801ce55e375df13161e248ed71d342a1d69d65a..bacd287fdda04c5b3a248e408190e3e4ebc87813 100644 --- a/src/pl/plpgsql/src/pl_handler.c +++ b/src/pl/plpgsql/src/pl_handler.c @@ -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; +} diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index fc2032dbd6d96ffdba3371066ea93d784f270274..147659e7cca6e97bc65e8f2c94848f0a895b1320 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.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); /* ---------- diff --git a/src/pl/plpgsql/src/scan.l b/src/pl/plpgsql/src/scan.l index dfb16f817712fcef867ef6b5a40a9ad99fee2ff9..49191fa106f61f2c42941aec58b597ef20256855 100644 --- a/src/pl/plpgsql/src/scan.l +++ b/src/pl/plpgsql/src/scan.l @@ -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(); }