Commit 20aea2ec authored by Tom Lane's avatar Tom Lane

Alter plpgsql's lexer so that yylineno and yymore are not used. This

avoids 'input buffer overflow' failure on long literals, improves
performance, gives the right answer for line position in functions
containing multiline literals, suppresses annoying compiler warnings,
and generally is so much better I wonder why we didn't do it before.
parent ea7896bf
...@@ -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.42 2003/04/27 22:21:22 tgl Exp $ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.43 2003/05/05 16:46:27 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -334,7 +334,7 @@ decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval ...@@ -334,7 +334,7 @@ decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval
/* Composite type --- treat as rowtype */ /* Composite type --- treat as rowtype */
PLpgSQL_row *row; PLpgSQL_row *row;
row = build_rowtype($3->typrelid); row = plpgsql_build_rowtype($3->typrelid);
row->dtype = PLPGSQL_DTYPE_ROW; row->dtype = PLPGSQL_DTYPE_ROW;
row->refname = $1.name; row->refname = $1.name;
row->lineno = $1.lineno; row->lineno = $1.lineno;
...@@ -486,7 +486,7 @@ decl_cursor_arglist : decl_cursor_arg ...@@ -486,7 +486,7 @@ decl_cursor_arglist : decl_cursor_arg
new->dtype = PLPGSQL_DTYPE_ROW; new->dtype = PLPGSQL_DTYPE_ROW;
new->refname = strdup("*internal*"); new->refname = strdup("*internal*");
new->lineno = yylineno; new->lineno = plpgsql_scanner_lineno();
new->rowtypeclass = InvalidOid; new->rowtypeclass = InvalidOid;
/* /*
* We make temporary fieldnames/varnos arrays that * We make temporary fieldnames/varnos arrays that
...@@ -553,7 +553,7 @@ decl_aliasitem : T_WORD ...@@ -553,7 +553,7 @@ decl_aliasitem : T_WORD
nsi = plpgsql_ns_lookup(name, NULL); nsi = plpgsql_ns_lookup(name, NULL);
if (nsi == NULL) if (nsi == NULL)
{ {
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "function has no parameter %s", name); elog(ERROR, "function has no parameter %s", name);
} }
...@@ -578,7 +578,7 @@ decl_varname : T_WORD ...@@ -578,7 +578,7 @@ decl_varname : T_WORD
plpgsql_convert_ident(yytext, &name, 1); plpgsql_convert_ident(yytext, &name, 1);
/* name should be malloc'd for use as varname */ /* name should be malloc'd for use as varname */
$$.name = strdup(name); $$.name = strdup(name);
$$.lineno = yylineno; $$.lineno = plpgsql_scanner_lineno();
pfree(name); pfree(name);
} }
; ;
...@@ -625,7 +625,7 @@ decl_defval : ';' ...@@ -625,7 +625,7 @@ decl_defval : ';'
PLpgSQL_dstring ds; PLpgSQL_dstring ds;
PLpgSQL_expr *expr; PLpgSQL_expr *expr;
lno = yylineno; lno = plpgsql_scanner_lineno();
expr = malloc(sizeof(PLpgSQL_expr)); expr = malloc(sizeof(PLpgSQL_expr));
plpgsql_dstring_init(&ds); plpgsql_dstring_init(&ds);
plpgsql_dstring_append(&ds, "SELECT "); plpgsql_dstring_append(&ds, "SELECT ");
...@@ -1034,7 +1034,7 @@ fori_varname : T_VARIABLE ...@@ -1034,7 +1034,7 @@ fori_varname : T_VARIABLE
plpgsql_convert_ident(yytext, &name, 1); plpgsql_convert_ident(yytext, &name, 1);
/* name should be malloc'd for use as varname */ /* name should be malloc'd for use as varname */
$$.name = strdup(name); $$.name = strdup(name);
$$.lineno = yylineno; $$.lineno = plpgsql_scanner_lineno();
pfree(name); pfree(name);
} }
| T_WORD | T_WORD
...@@ -1044,7 +1044,7 @@ fori_varname : T_VARIABLE ...@@ -1044,7 +1044,7 @@ fori_varname : T_VARIABLE
plpgsql_convert_ident(yytext, &name, 1); plpgsql_convert_ident(yytext, &name, 1);
/* name should be malloc'd for use as varname */ /* name should be malloc'd for use as varname */
$$.name = strdup(name); $$.name = strdup(name);
$$.lineno = yylineno; $$.lineno = plpgsql_scanner_lineno();
pfree(name); pfree(name);
} }
; ;
...@@ -1405,7 +1405,7 @@ stmt_open : K_OPEN lno cursor_varptr ...@@ -1405,7 +1405,7 @@ stmt_open : K_OPEN lno cursor_varptr
if (tok != '(') if (tok != '(')
{ {
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "cursor %s has arguments", elog(ERROR, "cursor %s has arguments",
$3->refname); $3->refname);
} }
...@@ -1427,7 +1427,7 @@ stmt_open : K_OPEN lno cursor_varptr ...@@ -1427,7 +1427,7 @@ stmt_open : K_OPEN lno cursor_varptr
if (strncmp(cp, "SELECT", 6) != 0) if (strncmp(cp, "SELECT", 6) != 0)
{ {
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "expected 'SELECT (', got '%s' (internal error)", elog(ERROR, "expected 'SELECT (', got '%s' (internal error)",
new->argquery->query); new->argquery->query);
} }
...@@ -1436,7 +1436,7 @@ stmt_open : K_OPEN lno cursor_varptr ...@@ -1436,7 +1436,7 @@ stmt_open : K_OPEN lno cursor_varptr
cp++; cp++;
if (*cp != '(') if (*cp != '(')
{ {
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "expected 'SELECT (', got '%s' (internal error)", elog(ERROR, "expected 'SELECT (', got '%s' (internal error)",
new->argquery->query); new->argquery->query);
} }
...@@ -1454,13 +1454,13 @@ stmt_open : K_OPEN lno cursor_varptr ...@@ -1454,13 +1454,13 @@ stmt_open : K_OPEN lno cursor_varptr
if (tok == '(') if (tok == '(')
{ {
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "cursor %s has no arguments", $3->refname); elog(ERROR, "cursor %s has no arguments", $3->refname);
} }
if (tok != ';') if (tok != ';')
{ {
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "syntax error at \"%s\"", yytext); elog(ERROR, "syntax error at \"%s\"", yytext);
} }
} }
...@@ -1502,7 +1502,7 @@ cursor_varptr : T_VARIABLE ...@@ -1502,7 +1502,7 @@ cursor_varptr : T_VARIABLE
if (((PLpgSQL_var *) yylval.variable)->datatype->typoid != REFCURSOROID) if (((PLpgSQL_var *) yylval.variable)->datatype->typoid != REFCURSOROID)
{ {
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "%s must be of type cursor or refcursor", elog(ERROR, "%s must be of type cursor or refcursor",
((PLpgSQL_var *) yylval.variable)->refname); ((PLpgSQL_var *) yylval.variable)->refname);
} }
...@@ -1517,7 +1517,7 @@ cursor_variable : T_VARIABLE ...@@ -1517,7 +1517,7 @@ cursor_variable : T_VARIABLE
if (((PLpgSQL_var *) yylval.variable)->datatype->typoid != REFCURSOROID) if (((PLpgSQL_var *) yylval.variable)->datatype->typoid != REFCURSOROID)
{ {
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "%s must be of type refcursor", elog(ERROR, "%s must be of type refcursor",
((PLpgSQL_var *) yylval.variable)->refname); ((PLpgSQL_var *) yylval.variable)->refname);
} }
...@@ -1583,8 +1583,7 @@ opt_lblname : T_WORD ...@@ -1583,8 +1583,7 @@ opt_lblname : T_WORD
lno : lno :
{ {
plpgsql_error_lineno = yylineno; $$ = plpgsql_error_lineno = plpgsql_scanner_lineno();
$$ = yylineno;
} }
; ;
...@@ -1618,7 +1617,7 @@ read_sql_construct(int until, ...@@ -1618,7 +1617,7 @@ read_sql_construct(int until,
char buf[32]; char buf[32];
PLpgSQL_expr *expr; PLpgSQL_expr *expr;
lno = yylineno; lno = plpgsql_scanner_lineno();
plpgsql_dstring_init(&ds); plpgsql_dstring_init(&ds);
plpgsql_dstring_append(&ds, (char *) sqlstart); plpgsql_dstring_append(&ds, (char *) sqlstart);
...@@ -1690,7 +1689,7 @@ read_datatype(int tok) ...@@ -1690,7 +1689,7 @@ read_datatype(int tok)
bool needspace = false; bool needspace = false;
int parenlevel = 0; int parenlevel = 0;
lno = yylineno; lno = plpgsql_scanner_lineno();
/* Often there will be a lookahead token, but if not, get one */ /* Often there will be a lookahead token, but if not, get one */
if (tok == YYEMPTY) if (tok == YYEMPTY)
...@@ -1769,14 +1768,14 @@ make_select_stmt(void) ...@@ -1769,14 +1768,14 @@ make_select_stmt(void)
break; break;
if (tok == 0) if (tok == 0)
{ {
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "unexpected end of file"); elog(ERROR, "unexpected end of file");
} }
if (tok == K_INTO) if (tok == K_INTO)
{ {
if (have_into) if (have_into)
{ {
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "INTO specified more than once"); elog(ERROR, "INTO specified more than once");
} }
tok = yylex(); tok = yylex();
...@@ -1814,7 +1813,7 @@ make_select_stmt(void) ...@@ -1814,7 +1813,7 @@ make_select_stmt(void)
break; break;
default: default:
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "plpgsql: %s is not a variable", elog(ERROR, "plpgsql: %s is not a variable",
yytext); yytext);
} }
...@@ -1824,7 +1823,7 @@ make_select_stmt(void) ...@@ -1824,7 +1823,7 @@ make_select_stmt(void)
row = malloc(sizeof(PLpgSQL_row)); row = malloc(sizeof(PLpgSQL_row));
row->dtype = PLPGSQL_DTYPE_ROW; row->dtype = PLPGSQL_DTYPE_ROW;
row->refname = strdup("*internal*"); row->refname = strdup("*internal*");
row->lineno = yylineno; row->lineno = plpgsql_scanner_lineno();
row->rowtypeclass = InvalidOid; row->rowtypeclass = InvalidOid;
row->nfields = nfields; row->nfields = nfields;
row->fieldnames = malloc(sizeof(char *) * nfields); row->fieldnames = malloc(sizeof(char *) * nfields);
...@@ -1945,7 +1944,7 @@ make_fetch_stmt(void) ...@@ -1945,7 +1944,7 @@ make_fetch_stmt(void)
break; break;
default: default:
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "plpgsql: %s is not a variable", elog(ERROR, "plpgsql: %s is not a variable",
yytext); yytext);
} }
...@@ -1955,7 +1954,7 @@ make_fetch_stmt(void) ...@@ -1955,7 +1954,7 @@ make_fetch_stmt(void)
row = malloc(sizeof(PLpgSQL_row)); row = malloc(sizeof(PLpgSQL_row));
row->dtype = PLPGSQL_DTYPE_ROW; row->dtype = PLPGSQL_DTYPE_ROW;
row->refname = strdup("*internal*"); row->refname = strdup("*internal*");
row->lineno = yylineno; row->lineno = plpgsql_scanner_lineno();
row->rowtypeclass = InvalidOid; row->rowtypeclass = InvalidOid;
row->nfields = nfields; row->nfields = nfields;
row->fieldnames = malloc(sizeof(char *) * nfields); row->fieldnames = malloc(sizeof(char *) * nfields);
...@@ -2028,7 +2027,7 @@ check_assignable(PLpgSQL_datum *datum) ...@@ -2028,7 +2027,7 @@ check_assignable(PLpgSQL_datum *datum)
case PLPGSQL_DTYPE_VAR: case PLPGSQL_DTYPE_VAR:
if (((PLpgSQL_var *) datum)->isconst) if (((PLpgSQL_var *) datum)->isconst)
{ {
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "%s is declared CONSTANT", elog(ERROR, "%s is declared CONSTANT",
((PLpgSQL_var *) datum)->refname); ((PLpgSQL_var *) datum)->refname);
} }
......
...@@ -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.57 2003/04/27 22:21:22 tgl Exp $ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.58 2003/05/05 16:46:27 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -141,7 +141,8 @@ plpgsql_compile(Oid fn_oid, int functype) ...@@ -141,7 +141,8 @@ plpgsql_compile(Oid fn_oid, int functype)
procStruct = (Form_pg_proc) GETSTRUCT(procTup); procStruct = (Form_pg_proc) GETSTRUCT(procTup);
proc_source = DatumGetCString(DirectFunctionCall1(textout, proc_source = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(&procStruct->prosrc))); PointerGetDatum(&procStruct->prosrc)));
plpgsql_setinput(proc_source, functype); plpgsql_scanner_init(proc_source, functype);
pfree(proc_source);
plpgsql_error_funcname = pstrdup(NameStr(procStruct->proname)); plpgsql_error_funcname = pstrdup(NameStr(procStruct->proname));
plpgsql_error_lineno = 0; plpgsql_error_lineno = 0;
...@@ -258,7 +259,7 @@ plpgsql_compile(Oid fn_oid, int functype) ...@@ -258,7 +259,7 @@ plpgsql_compile(Oid fn_oid, int functype)
* For tuple type parameters, we set up a record of * For tuple type parameters, we set up a record of
* that type * that type
*/ */
row = build_rowtype(typeStruct->typrelid); row = plpgsql_build_rowtype(typeStruct->typrelid);
row->refname = strdup(buf); row->refname = strdup(buf);
...@@ -496,6 +497,8 @@ plpgsql_compile(Oid fn_oid, int functype) ...@@ -496,6 +497,8 @@ plpgsql_compile(Oid fn_oid, int functype)
if (parse_rc != 0) if (parse_rc != 0)
elog(ERROR, "plpgsql: parser returned %d ???", parse_rc); elog(ERROR, "plpgsql: parser returned %d ???", parse_rc);
plpgsql_scanner_finish();
/* /*
* If that was successful, complete the functions info. * If that was successful, complete the functions info.
*/ */
...@@ -1200,7 +1203,7 @@ plpgsql_parse_wordrowtype(char *word) ...@@ -1200,7 +1203,7 @@ plpgsql_parse_wordrowtype(char *word)
/* /*
* Build and return the complete row definition * Build and return the complete row definition
*/ */
plpgsql_yylval.row = build_rowtype(classOid); plpgsql_yylval.row = plpgsql_build_rowtype(classOid);
pfree(cp[0]); pfree(cp[0]);
pfree(cp[1]); pfree(cp[1]);
...@@ -1241,7 +1244,7 @@ plpgsql_parse_dblwordrowtype(char *word) ...@@ -1241,7 +1244,7 @@ plpgsql_parse_dblwordrowtype(char *word)
/* /*
* Build and return the complete row definition * Build and return the complete row definition
*/ */
plpgsql_yylval.row = build_rowtype(classOid); plpgsql_yylval.row = plpgsql_build_rowtype(classOid);
pfree(cp); pfree(cp);
...@@ -1252,7 +1255,7 @@ plpgsql_parse_dblwordrowtype(char *word) ...@@ -1252,7 +1255,7 @@ plpgsql_parse_dblwordrowtype(char *word)
* Build a rowtype data structure given the pg_class OID. * Build a rowtype data structure given the pg_class OID.
*/ */
PLpgSQL_row * PLpgSQL_row *
build_rowtype(Oid classOid) plpgsql_build_rowtype(Oid classOid)
{ {
PLpgSQL_row *row; PLpgSQL_row *row;
HeapTuple classtup; HeapTuple classtup;
...@@ -1494,6 +1497,6 @@ plpgsql_add_initdatums(int **varnos) ...@@ -1494,6 +1497,6 @@ plpgsql_add_initdatums(int **varnos)
void void
plpgsql_yyerror(const char *s) plpgsql_yyerror(const char *s)
{ {
plpgsql_error_lineno = plpgsql_yylineno; plpgsql_error_lineno = plpgsql_scanner_lineno();
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/plpgsql.h,v 1.35 2003/04/27 22:21:22 tgl Exp $ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.36 2003/05/05 16:46:28 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -573,13 +573,10 @@ extern PLpgSQL_datum **plpgsql_Datums; ...@@ -573,13 +573,10 @@ extern PLpgSQL_datum **plpgsql_Datums;
extern int plpgsql_error_lineno; extern int plpgsql_error_lineno;
extern char *plpgsql_error_funcname; extern char *plpgsql_error_funcname;
/* linkage to the real yytext and yylineno variables */ /* linkage to the real yytext variable */
extern char *plpgsql_base_yytext; extern char *plpgsql_base_yytext;
#define plpgsql_yytext plpgsql_base_yytext #define plpgsql_yytext plpgsql_base_yytext
extern int plpgsql_base_yylineno;
#define plpgsql_yylineno plpgsql_base_yylineno
extern PLpgSQL_function *plpgsql_curr_compile; extern PLpgSQL_function *plpgsql_curr_compile;
...@@ -601,7 +598,7 @@ extern int plpgsql_parse_tripwordtype(char *word); ...@@ -601,7 +598,7 @@ extern int plpgsql_parse_tripwordtype(char *word);
extern int plpgsql_parse_wordrowtype(char *word); extern int plpgsql_parse_wordrowtype(char *word);
extern int plpgsql_parse_dblwordrowtype(char *word); extern int plpgsql_parse_dblwordrowtype(char *word);
extern PLpgSQL_type *plpgsql_parse_datatype(char *string); extern PLpgSQL_type *plpgsql_parse_datatype(char *string);
extern PLpgSQL_row *build_rowtype(Oid classOid); extern PLpgSQL_row *plpgsql_build_rowtype(Oid classOid);
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_yyerror(const char *s); extern void plpgsql_yyerror(const char *s);
...@@ -660,6 +657,8 @@ extern int plpgsql_yyparse(void); ...@@ -660,6 +657,8 @@ extern int plpgsql_yyparse(void);
extern int plpgsql_base_yylex(void); extern int plpgsql_base_yylex(void);
extern int plpgsql_yylex(void); extern int plpgsql_yylex(void);
extern void plpgsql_push_back_token(int token); extern void plpgsql_push_back_token(int token);
extern void plpgsql_setinput(char *s, int functype); extern int plpgsql_scanner_lineno(void);
extern void plpgsql_scanner_init(const char *str, int functype);
extern void plpgsql_scanner_finish(void);
#endif /* PLPGSQL_H */ #endif /* PLPGSQL_H */
...@@ -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.24 2002/11/07 06:06:17 tgl Exp $ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/Attic/scan.l,v 1.25 2003/05/05 16:46:28 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -39,20 +39,26 @@ ...@@ -39,20 +39,26 @@
#include "plpgsql.h" #include "plpgsql.h"
static char *plpgsql_source; /* No reason to constrain amount of data slurped */
static int plpgsql_bytes_left; #define YY_READ_BUF_SIZE 16777216
/* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
#define fprintf(file, fmt, msg) ereport(FATAL, (errmsg_internal("%s", msg)))
/* Handles to the buffer that the lexer uses internally */
static YY_BUFFER_STATE scanbufhandle;
static char *scanbuf;
static int scanner_functype; static int scanner_functype;
static int scanner_typereported; static int scanner_typereported;
static int pushback_token; static int pushback_token;
static bool have_pushback_token; static bool have_pushback_token;
static int lookahead_token; static int lookahead_token;
static bool have_lookahead_token; static bool have_lookahead_token;
static const char *cur_line_start;
static int cur_line_num;
int plpgsql_SpaceScanned = 0; int plpgsql_SpaceScanned = 0;
static void plpgsql_input(char *buf, int *result, int max);
#define YY_INPUT(buf,res,max) plpgsql_input(buf, &res, max)
%} %}
%option 8bit %option 8bit
...@@ -60,7 +66,6 @@ static void plpgsql_input(char *buf, int *result, int max); ...@@ -60,7 +66,6 @@ static void plpgsql_input(char *buf, int *result, int max);
%option nounput %option nounput
%option noyywrap %option noyywrap
%option yylineno
%option case-insensitive %option case-insensitive
...@@ -78,11 +83,12 @@ space [ \t\n\r\f] ...@@ -78,11 +83,12 @@ space [ \t\n\r\f]
%% %%
/* ---------- /* ----------
* Local variable in scanner to remember where * Local variables in scanner to remember where
* a string or comment started * a string or comment started
* ---------- * ----------
*/ */
int start_lineno = 0; int start_lineno = 0;
char *start_charpos = NULL;
/* ---------- /* ----------
* Reset the state when entering the scanner * Reset the state when entering the scanner
...@@ -185,7 +191,7 @@ dump { return O_DUMP; } ...@@ -185,7 +191,7 @@ dump { return O_DUMP; }
{digit}+ { return T_NUMBER; } {digit}+ { return T_NUMBER; }
\". { \". {
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = plpgsql_scanner_lineno();
elog(ERROR, "unterminated quoted identifier"); elog(ERROR, "unterminated quoted identifier");
} }
...@@ -201,7 +207,7 @@ dump { return O_DUMP; } ...@@ -201,7 +207,7 @@ dump { return O_DUMP; }
*/ */
--[^\r\n]* ; --[^\r\n]* ;
\/\* { start_lineno = yylineno; \/\* { start_lineno = plpgsql_scanner_lineno();
BEGIN IN_COMMENT; BEGIN IN_COMMENT;
} }
<IN_COMMENT>\*\/ { BEGIN INITIAL; plpgsql_SpaceScanned = 1; } <IN_COMMENT>\*\/ { BEGIN INITIAL; plpgsql_SpaceScanned = 1; }
...@@ -214,22 +220,30 @@ dump { return O_DUMP; } ...@@ -214,22 +220,30 @@ dump { return O_DUMP; }
/* ---------- /* ----------
* Collect anything inside of ''s and return one STRING * Collect anything inside of ''s and return one STRING
*
* Hacking yytext/yyleng here lets us avoid using yymore(), which is
* a win for performance. It's safe because we know the underlying
* input buffer is not changing.
* ---------- * ----------
*/ */
' { start_lineno = yylineno; ' {
start_lineno = plpgsql_scanner_lineno();
start_charpos = yytext;
BEGIN IN_STRING; BEGIN IN_STRING;
yymore();
} }
<IN_STRING>\\. | <IN_STRING>\\. { }
<IN_STRING>'' { yymore(); } <IN_STRING>'' { }
<IN_STRING>' { BEGIN INITIAL; <IN_STRING>' {
yyleng -= (yytext - start_charpos);
yytext = start_charpos;
BEGIN INITIAL;
return T_STRING; return T_STRING;
} }
<IN_STRING><<EOF>> { <IN_STRING><<EOF>> {
plpgsql_error_lineno = start_lineno; plpgsql_error_lineno = start_lineno;
elog(ERROR, "unterminated string"); elog(ERROR, "unterminated string");
} }
<IN_STRING>[^'\\]* { yymore(); } <IN_STRING>[^'\\]* { }
/* ---------- /* ----------
* Any unmatched character is returned as is * Any unmatched character is returned as is
...@@ -240,26 +254,6 @@ dump { return O_DUMP; } ...@@ -240,26 +254,6 @@ dump { return O_DUMP; }
%% %%
static void
plpgsql_input(char *buf, int *result, int max)
{
int n = max;
if (n > plpgsql_bytes_left)
n = plpgsql_bytes_left;
if (n == 0)
{
*result = YY_NULL;
return;
}
*result = n;
memcpy(buf, plpgsql_source, n);
plpgsql_source += n;
plpgsql_bytes_left -= n;
}
/* /*
* This is the yylex routine called from outside. It exists to provide * This is the yylex routine called from outside. It exists to provide
* a pushback facility, as well as to allow us to parse syntax that * a pushback facility, as well as to allow us to parse syntax that
...@@ -319,17 +313,35 @@ plpgsql_push_back_token(int token) ...@@ -319,17 +313,35 @@ plpgsql_push_back_token(int token)
have_pushback_token = true; have_pushback_token = true;
} }
/*
* Get the line number at which the current token ends. This substitutes
* for flex's very poorly implemented yylineno facility.
*
* We assume that flex has written a '\0' over the character following the
* current token in scanbuf. So, we just have to count the '\n' characters
* before that. We optimize this a little by keeping track of the last
* '\n' seen so far.
*/
int
plpgsql_scanner_lineno(void)
{
const char *c;
while ((c = strchr(cur_line_start, '\n')) != NULL)
{
cur_line_start = c + 1;
cur_line_num++;
}
return cur_line_num;
}
/* /*
* Initialize the scanner for new input. * Called before any actual parsing is done
*/ */
void void
plpgsql_setinput(char *source, int functype) plpgsql_scanner_init(const char *str, int functype)
{ {
yyrestart(NULL); Size slen;
yylineno = 1;
plpgsql_source = source;
/*---------- /*----------
* Hack: skip any initial newline, so that in the common coding layout * Hack: skip any initial newline, so that in the common coding layout
...@@ -339,16 +351,47 @@ plpgsql_setinput(char *source, int functype) ...@@ -339,16 +351,47 @@ plpgsql_setinput(char *source, int functype)
* we will think "line 1" is what the programmer thinks of as line 1. * we will think "line 1" is what the programmer thinks of as line 1.
*---------- *----------
*/ */
if (*plpgsql_source == '\r') if (*str == '\r')
plpgsql_source++; str++;
if (*plpgsql_source == '\n') if (*str == '\n')
plpgsql_source++; str++;
slen = strlen(str);
plpgsql_bytes_left = strlen(plpgsql_source); /*
* Might be left over after ereport()
*/
if (YY_CURRENT_BUFFER)
yy_delete_buffer(YY_CURRENT_BUFFER);
/*
* Make a scan buffer with special termination needed by flex.
*/
scanbuf = palloc(slen + 2);
memcpy(scanbuf, str, slen);
scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
scanbufhandle = yy_scan_buffer(scanbuf, slen + 2);
/* Other setup */
scanner_functype = functype; scanner_functype = functype;
scanner_typereported = 0; scanner_typereported = 0;
have_pushback_token = false; have_pushback_token = false;
have_lookahead_token = false; have_lookahead_token = false;
cur_line_start = scanbuf;
cur_line_num = 1;
BEGIN(INITIAL);
}
/*
* Called after parsing is done to clean up after plpgsql_scanner_init()
*/
void
plpgsql_scanner_finish(void)
{
yy_delete_buffer(scanbufhandle);
pfree(scanbuf);
} }
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