v1-0019-plpgsql-reentrant-scanner.patch
text/plain
Filename: v1-0019-plpgsql-reentrant-scanner.patch
Type: text/plain
Part: 18
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v1-0019
Subject: plpgsql: reentrant scanner
| File | + | − |
|---|---|---|
| src/pl/plpgsql/src/pl_comp.c | 10 | 8 |
| src/pl/plpgsql/src/pl_gram.y | 218 | 202 |
| src/pl/plpgsql/src/plpgsql.h | 8 | 8 |
| src/pl/plpgsql/src/pl_scanner.c | 20 | 18 |
From 2cde4c4b10907d0e51a9a6fafc0475feb75cc1b2 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Sat, 7 Dec 2024 00:09:08 +0100
Subject: [PATCH v1 19/19] plpgsql: reentrant scanner
---
src/pl/plpgsql/src/pl_comp.c | 18 +-
src/pl/plpgsql/src/pl_gram.y | 420 +++++++++++++++++---------------
src/pl/plpgsql/src/pl_scanner.c | 38 +--
src/pl/plpgsql/src/plpgsql.h | 16 +-
4 files changed, 256 insertions(+), 236 deletions(-)
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 6255a86d75b..917daebef06 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -269,6 +269,7 @@ do_compile(FunctionCallInfo fcinfo,
Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);
bool is_dml_trigger = CALLED_AS_TRIGGER(fcinfo);
bool is_event_trigger = CALLED_AS_EVENT_TRIGGER(fcinfo);
+ yyscan_t scanner;
Datum prosrcdatum;
char *proc_source;
HeapTuple typeTup;
@@ -292,11 +293,11 @@ do_compile(FunctionCallInfo fcinfo,
/*
* Setup the scanner input and error info. We assume that this function
* cannot be invoked recursively, so there's no need to save and restore
- * the static variables used here.
+ * the static variables used here. XXX
*/
prosrcdatum = SysCacheGetAttrNotNull(PROCOID, procTup, Anum_pg_proc_prosrc);
proc_source = TextDatumGetCString(prosrcdatum);
- plpgsql_scanner_init(proc_source);
+ scanner = plpgsql_scanner_init(proc_source);
plpgsql_error_funcname = pstrdup(NameStr(procStruct->proname));
@@ -779,12 +780,12 @@ do_compile(FunctionCallInfo fcinfo,
/*
* Now parse the function's text
*/
- parse_rc = plpgsql_yyparse();
+ parse_rc = plpgsql_yyparse(scanner);
if (parse_rc != 0)
elog(ERROR, "plpgsql parser returned %d", parse_rc);
function->action = plpgsql_parse_result;
- plpgsql_scanner_finish();
+ plpgsql_scanner_finish(scanner);
pfree(proc_source);
/*
@@ -841,6 +842,7 @@ do_compile(FunctionCallInfo fcinfo,
PLpgSQL_function *
plpgsql_compile_inline(char *proc_source)
{
+ yyscan_t scanner;
char *func_name = "inline_code_block";
PLpgSQL_function *function;
ErrorContextCallback plerrcontext;
@@ -851,9 +853,9 @@ plpgsql_compile_inline(char *proc_source)
/*
* Setup the scanner input and error info. We assume that this function
* cannot be invoked recursively, so there's no need to save and restore
- * the static variables used here.
+ * the static variables used here. XXX
*/
- plpgsql_scanner_init(proc_source);
+ scanner = plpgsql_scanner_init(proc_source);
plpgsql_error_funcname = func_name;
@@ -935,12 +937,12 @@ plpgsql_compile_inline(char *proc_source)
/*
* Now parse the function's text
*/
- parse_rc = plpgsql_yyparse();
+ parse_rc = plpgsql_yyparse(scanner);
if (parse_rc != 0)
elog(ERROR, "plpgsql parser returned %d", parse_rc);
function->action = plpgsql_parse_result;
- plpgsql_scanner_finish();
+ plpgsql_scanner_finish(scanner);
/*
* If it returns VOID (always true at the moment), we allow control to
diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y
index 8182ce28aa1..4d09fa89d99 100644
--- a/src/pl/plpgsql/src/pl_gram.y
+++ b/src/pl/plpgsql/src/pl_gram.y
@@ -63,7 +63,7 @@ static bool tok_is_keyword(int token, union YYSTYPE *lval,
int kw_token, const char *kw_str);
static void word_is_not_variable(PLword *word, int location);
static void cword_is_not_variable(PLcword *cword, int location);
-static void current_token_is_not_variable(int tok);
+static void current_token_is_not_variable(int tok, yyscan_t yyscanner);
static PLpgSQL_expr *read_sql_construct(int until,
int until2,
int until3,
@@ -72,31 +72,33 @@ static PLpgSQL_expr *read_sql_construct(int until,
bool isexpression,
bool valid_sql,
int *startloc,
- int *endtoken);
+ int *endtoken,
+ yyscan_t yyscanner);
static PLpgSQL_expr *read_sql_expression(int until,
- const char *expected);
+ const char *expected, yyscan_t yyscanner);
static PLpgSQL_expr *read_sql_expression2(int until, int until2,
const char *expected,
- int *endtoken);
-static PLpgSQL_expr *read_sql_stmt(void);
-static PLpgSQL_type *read_datatype(int tok);
+ int *endtoken, yyscan_t yyscanner);
+static PLpgSQL_expr *read_sql_stmt(yyscan_t yyscanner);
+static PLpgSQL_type *read_datatype(int tok, yyscan_t yyscanner);
static PLpgSQL_stmt *make_execsql_stmt(int firsttoken, int location,
- PLword *word);
-static PLpgSQL_stmt_fetch *read_fetch_direction(void);
+ PLword *word, yyscan_t yyscanner);
+static PLpgSQL_stmt_fetch *read_fetch_direction(yyscan_t yyscanner);
static void complete_direction(PLpgSQL_stmt_fetch *fetch,
- bool *check_FROM);
-static PLpgSQL_stmt *make_return_stmt(int location);
-static PLpgSQL_stmt *make_return_next_stmt(int location);
-static PLpgSQL_stmt *make_return_query_stmt(int location);
+ bool *check_FROM, yyscan_t yyscanner);
+static PLpgSQL_stmt *make_return_stmt(int location, yyscan_t yyscanner);
+static PLpgSQL_stmt *make_return_next_stmt(int location, yyscan_t yyscanner);
+static PLpgSQL_stmt *make_return_query_stmt(int location, yyscan_t yyscanner);
static PLpgSQL_stmt *make_case(int location, PLpgSQL_expr *t_expr,
List *case_when_list, List *else_stmts);
static char *NameOfDatum(PLwdatum *wdatum);
static void check_assignable(PLpgSQL_datum *datum, int location);
static void read_into_target(PLpgSQL_variable **target,
- bool *strict);
+ bool *strict, yyscan_t yyscanner);
static PLpgSQL_row *read_into_scalar_list(char *initial_name,
PLpgSQL_datum *initial_datum,
- int initial_location);
+ int initial_location,
+ yyscan_t yyscanner);
static PLpgSQL_row *make_scalar_list1(char *initial_name,
PLpgSQL_datum *initial_datum,
int lineno, int location);
@@ -108,12 +110,14 @@ static void check_labels(const char *start_label,
const char *end_label,
int end_location);
static PLpgSQL_expr *read_cursor_args(PLpgSQL_var *cursor,
- int until);
-static List *read_raise_options(void);
+ int until, yyscan_t yyscanner);
+static List *read_raise_options(yyscan_t yyscanner);
static void check_raise_parameters(PLpgSQL_stmt_raise *stmt);
%}
+%parse-param {yyscan_t yyscanner}
+%lex-param {yyscan_t yyscanner}
%expect 0
%name-prefix="plpgsql_yy"
%locations
@@ -577,7 +581,7 @@ opt_scrollable :
decl_cursor_query :
{
- $$ = read_sql_stmt();
+ $$ = read_sql_stmt(yyscanner);
}
;
@@ -706,7 +710,7 @@ decl_varname : T_WORD
if (plpgsql_ns_lookup(plpgsql_ns_top(), true,
$1.ident, NULL, NULL,
NULL) != NULL)
- yyerror("duplicate declaration");
+ yyerror(yyscanner, "duplicate declaration");
if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_SHADOWVAR ||
plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_SHADOWVAR)
@@ -734,7 +738,7 @@ decl_varname : T_WORD
if (plpgsql_ns_lookup(plpgsql_ns_top(), true,
$1, NULL, NULL,
NULL) != NULL)
- yyerror("duplicate declaration");
+ yyerror(yyscanner, "duplicate declaration");
if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_SHADOWVAR ||
plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_SHADOWVAR)
@@ -766,7 +770,7 @@ decl_datatype :
* consume it, and then we must tell bison to forget
* it.
*/
- $$ = read_datatype(yychar);
+ $$ = read_datatype(yychar, yyscanner);
yyclearin;
}
;
@@ -799,7 +803,7 @@ decl_defval : ';'
{ $$ = NULL; }
| decl_defkey
{
- $$ = read_sql_expression(';', ";");
+ $$ = read_sql_expression(';', ";", yyscanner);
}
;
@@ -900,7 +904,8 @@ stmt_perform : K_PERFORM
new->expr = read_sql_construct(';', 0, 0, ";",
RAW_PARSE_DEFAULT,
false, false,
- &startloc, NULL);
+ &startloc, NULL,
+ yyscanner);
/* overwrite "perform" ... */
memcpy(new->expr->query, " SELECT", 7);
/* left-justify to get rid of the leading space */
@@ -923,7 +928,7 @@ stmt_call : K_CALL
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
plpgsql_push_back_token(K_CALL);
- new->expr = read_sql_stmt();
+ new->expr = read_sql_stmt(yyscanner);
new->is_call = true;
/* Remember we may need a procedure resource owner */
@@ -942,7 +947,7 @@ stmt_call : K_CALL
new->lineno = plpgsql_location_to_lineno(@1);
new->stmtid = ++plpgsql_curr_compile->nstatements;
plpgsql_push_back_token(K_DO);
- new->expr = read_sql_stmt();
+ new->expr = read_sql_stmt(yyscanner);
new->is_call = false;
/* Remember we may need a procedure resource owner */
@@ -986,7 +991,8 @@ stmt_assign : T_DATUM
new->expr = read_sql_construct(';', 0, 0, ";",
pmode,
false, true,
- NULL, NULL);
+ NULL, NULL,
+ yyscanner);
$$ = (PLpgSQL_stmt *) new;
}
@@ -1093,7 +1099,7 @@ getdiag_list_item : getdiag_target assign_operator getdiag_item
getdiag_item :
{
- int tok = yylex();
+ int tok = yylex(yyscanner);
if (tok_is_keyword(tok, &yylval,
K_ROW_COUNT, "row_count"))
@@ -1135,7 +1141,7 @@ getdiag_item :
K_RETURNED_SQLSTATE, "returned_sqlstate"))
$$ = PLPGSQL_GETDIAG_RETURNED_SQLSTATE;
else
- yyerror("unrecognized GET DIAGNOSTICS item");
+ yyerror(yyscanner, "unrecognized GET DIAGNOSTICS item");
}
;
@@ -1148,7 +1154,7 @@ getdiag_target : T_DATUM
*/
if ($1.datum->dtype == PLPGSQL_DTYPE_ROW ||
$1.datum->dtype == PLPGSQL_DTYPE_REC ||
- plpgsql_peek() == '[')
+ plpgsql_peek(yyscanner) == '[')
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("\"%s\" is not a scalar variable",
@@ -1222,12 +1228,12 @@ stmt_case : K_CASE opt_expr_until_when case_when_list opt_case_else K_END K_CAS
opt_expr_until_when :
{
PLpgSQL_expr *expr = NULL;
- int tok = yylex();
+ int tok = yylex(yyscanner);
if (tok != K_WHEN)
{
plpgsql_push_back_token(tok);
- expr = read_sql_expression(K_WHEN, "WHEN");
+ expr = read_sql_expression(K_WHEN, "WHEN", yyscanner);
}
plpgsql_push_back_token(K_WHEN);
$$ = expr;
@@ -1347,7 +1353,7 @@ stmt_for : opt_loop_label K_FOR for_control loop_body
for_control : for_variable K_IN
{
- int tok = yylex();
+ int tok = yylex(yyscanner);
int tokloc = yylloc;
if (tok == K_EXECUTE)
@@ -1359,7 +1365,7 @@ for_control : for_variable K_IN
expr = read_sql_expression2(K_LOOP, K_USING,
"LOOP or USING",
- &term);
+ &term, yyscanner);
new = palloc0(sizeof(PLpgSQL_stmt_dynfors));
new->cmd_type = PLPGSQL_STMT_DYNFORS;
@@ -1392,7 +1398,7 @@ for_control : for_variable K_IN
{
expr = read_sql_expression2(',', K_LOOP,
", or LOOP",
- &term);
+ &term, yyscanner);
new->params = lappend(new->params, expr);
} while (term == ',');
}
@@ -1427,8 +1433,7 @@ for_control : for_variable K_IN
parser_errposition(tokloc)));
/* collect cursor's parameters if any */
- new->argquery = read_cursor_args(cursor,
- K_LOOP);
+ new->argquery = read_cursor_args(cursor, K_LOOP, yyscanner);
/* create loop's private RECORD variable */
new->var = (PLpgSQL_variable *)
@@ -1479,7 +1484,8 @@ for_control : for_variable K_IN
true,
false,
&expr1loc,
- &tok);
+ &tok,
+ yyscanner);
if (tok == DOT_DOT)
{
@@ -1500,12 +1506,12 @@ for_control : for_variable K_IN
/* Read and check the second one */
expr2 = read_sql_expression2(K_LOOP, K_BY,
"LOOP",
- &tok);
+ &tok, yyscanner);
/* Get the BY clause if any */
if (tok == K_BY)
expr_by = read_sql_expression(K_LOOP,
- "LOOP");
+ "LOOP", yyscanner);
else
expr_by = NULL;
@@ -1620,13 +1626,14 @@ for_variable : T_DATUM
$$.scalar = $1.datum;
$$.row = NULL;
/* check for comma-separated list */
- tok = yylex();
+ tok = yylex(yyscanner);
plpgsql_push_back_token(tok);
if (tok == ',')
$$.row = (PLpgSQL_datum *)
read_into_scalar_list($$.name,
$$.scalar,
- @1);
+ @1,
+ yyscanner);
}
}
| T_WORD
@@ -1638,7 +1645,7 @@ for_variable : T_DATUM
$$.scalar = NULL;
$$.row = NULL;
/* check for comma-separated list */
- tok = yylex();
+ tok = yylex(yyscanner);
plpgsql_push_back_token(tok);
if (tok == ',')
word_is_not_variable(&($1), @1);
@@ -1765,24 +1772,24 @@ stmt_return : K_RETURN
{
int tok;
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok == 0)
- yyerror("unexpected end of function definition");
+ yyerror(yyscanner, "unexpected end of function definition");
if (tok_is_keyword(tok, &yylval,
K_NEXT, "next"))
{
- $$ = make_return_next_stmt(@1);
+ $$ = make_return_next_stmt(@1, yyscanner);
}
else if (tok_is_keyword(tok, &yylval,
K_QUERY, "query"))
{
- $$ = make_return_query_stmt(@1);
+ $$ = make_return_query_stmt(@1, yyscanner);
}
else
{
plpgsql_push_back_token(tok);
- $$ = make_return_stmt(@1);
+ $$ = make_return_stmt(@1, yyscanner);
}
}
;
@@ -1803,9 +1810,9 @@ stmt_raise : K_RAISE
new->params = NIL;
new->options = NIL;
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok == 0)
- yyerror("unexpected end of function definition");
+ yyerror(yyscanner, "unexpected end of function definition");
/*
* We could have just RAISE, meaning to re-throw
@@ -1820,40 +1827,40 @@ stmt_raise : K_RAISE
K_EXCEPTION, "exception"))
{
new->elog_level = ERROR;
- tok = yylex();
+ tok = yylex(yyscanner);
}
else if (tok_is_keyword(tok, &yylval,
K_WARNING, "warning"))
{
new->elog_level = WARNING;
- tok = yylex();
+ tok = yylex(yyscanner);
}
else if (tok_is_keyword(tok, &yylval,
K_NOTICE, "notice"))
{
new->elog_level = NOTICE;
- tok = yylex();
+ tok = yylex(yyscanner);
}
else if (tok_is_keyword(tok, &yylval,
K_INFO, "info"))
{
new->elog_level = INFO;
- tok = yylex();
+ tok = yylex(yyscanner);
}
else if (tok_is_keyword(tok, &yylval,
K_LOG, "log"))
{
new->elog_level = LOG;
- tok = yylex();
+ tok = yylex(yyscanner);
}
else if (tok_is_keyword(tok, &yylval,
K_DEBUG, "debug"))
{
new->elog_level = DEBUG1;
- tok = yylex();
+ tok = yylex(yyscanner);
}
if (tok == 0)
- yyerror("unexpected end of function definition");
+ yyerror(yyscanner, "unexpected end of function definition");
/*
* Next we can have a condition name, or
@@ -1871,9 +1878,9 @@ stmt_raise : K_RAISE
* begins the list of parameter expressions,
* or USING to begin the options list.
*/
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok != ',' && tok != ';' && tok != K_USING)
- yyerror("syntax error");
+ yyerror(yyscanner, "syntax error");
while (tok == ',')
{
@@ -1883,7 +1890,8 @@ stmt_raise : K_RAISE
", or ; or USING",
RAW_PARSE_PLPGSQL_EXPR,
true, true,
- NULL, &tok);
+ NULL, &tok,
+ yyscanner);
new->params = lappend(new->params, expr);
}
}
@@ -1896,14 +1904,14 @@ stmt_raise : K_RAISE
/* next token should be a string literal */
char *sqlstatestr;
- if (yylex() != SCONST)
- yyerror("syntax error");
+ if (yylex(yyscanner) != SCONST)
+ yyerror(yyscanner, "syntax error");
sqlstatestr = yylval.str;
if (strlen(sqlstatestr) != 5)
- yyerror("invalid SQLSTATE code");
+ yyerror(yyscanner, "invalid SQLSTATE code");
if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5)
- yyerror("invalid SQLSTATE code");
+ yyerror(yyscanner, "invalid SQLSTATE code");
new->condname = sqlstatestr;
}
else
@@ -1913,17 +1921,17 @@ stmt_raise : K_RAISE
else if (plpgsql_token_is_unreserved_keyword(tok))
new->condname = pstrdup(yylval.keyword);
else
- yyerror("syntax error");
+ yyerror(yyscanner, "syntax error");
plpgsql_recognize_err_condition(new->condname,
false);
}
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok != ';' && tok != K_USING)
- yyerror("syntax error");
+ yyerror(yyscanner, "syntax error");
}
if (tok == K_USING)
- new->options = read_raise_options();
+ new->options = read_raise_options(yyscanner);
}
check_raise_parameters(new);
@@ -1945,10 +1953,10 @@ stmt_assert : K_ASSERT
new->cond = read_sql_expression2(',', ';',
", or ;",
- &tok);
+ &tok, yyscanner);
if (tok == ',')
- new->message = read_sql_expression(';', ";");
+ new->message = read_sql_expression(';', ";", yyscanner);
else
new->message = NULL;
@@ -1976,37 +1984,37 @@ loop_body : proc_sect K_END K_LOOP opt_label ';'
*/
stmt_execsql : K_IMPORT
{
- $$ = make_execsql_stmt(K_IMPORT, @1, NULL);
+ $$ = make_execsql_stmt(K_IMPORT, @1, NULL, yyscanner);
}
| K_INSERT
{
- $$ = make_execsql_stmt(K_INSERT, @1, NULL);
+ $$ = make_execsql_stmt(K_INSERT, @1, NULL, yyscanner);
}
| K_MERGE
{
- $$ = make_execsql_stmt(K_MERGE, @1, NULL);
+ $$ = make_execsql_stmt(K_MERGE, @1, NULL, yyscanner);
}
| T_WORD
{
int tok;
- tok = yylex();
+ tok = yylex(yyscanner);
plpgsql_push_back_token(tok);
if (tok == '=' || tok == COLON_EQUALS ||
tok == '[' || tok == '.')
word_is_not_variable(&($1), @1);
- $$ = make_execsql_stmt(T_WORD, @1, &($1));
+ $$ = make_execsql_stmt(T_WORD, @1, &($1), yyscanner);
}
| T_CWORD
{
int tok;
- tok = yylex();
+ tok = yylex(yyscanner);
plpgsql_push_back_token(tok);
if (tok == '=' || tok == COLON_EQUALS ||
tok == '[' || tok == '.')
cword_is_not_variable(&($1), @1);
- $$ = make_execsql_stmt(T_CWORD, @1, NULL);
+ $$ = make_execsql_stmt(T_CWORD, @1, NULL, yyscanner);
}
;
@@ -2020,7 +2028,8 @@ stmt_dynexecute : K_EXECUTE
"INTO or USING or ;",
RAW_PARSE_PLPGSQL_EXPR,
true, true,
- NULL, &endtoken);
+ NULL, &endtoken,
+ yyscanner);
new = palloc(sizeof(PLpgSQL_stmt_dynexecute));
new->cmd_type = PLPGSQL_STMT_DYNEXECUTE;
@@ -2044,29 +2053,30 @@ stmt_dynexecute : K_EXECUTE
if (endtoken == K_INTO)
{
if (new->into) /* multiple INTO */
- yyerror("syntax error");
+ yyerror(yyscanner, "syntax error");
new->into = true;
- read_into_target(&new->target, &new->strict);
- endtoken = yylex();
+ read_into_target(&new->target, &new->strict, yyscanner);
+ endtoken = yylex(yyscanner);
}
else if (endtoken == K_USING)
{
if (new->params) /* multiple USING */
- yyerror("syntax error");
+ yyerror(yyscanner, "syntax error");
do
{
expr = read_sql_construct(',', ';', K_INTO,
", or ; or INTO",
RAW_PARSE_PLPGSQL_EXPR,
true, true,
- NULL, &endtoken);
+ NULL, &endtoken,
+ yyscanner);
new->params = lappend(new->params, expr);
} while (endtoken == ',');
}
else if (endtoken == ';')
break;
else
- yyerror("syntax error");
+ yyerror(yyscanner, "syntax error");
}
$$ = (PLpgSQL_stmt *) new;
@@ -2089,29 +2099,29 @@ stmt_open : K_OPEN cursor_variable
if ($2->cursor_explicit_expr == NULL)
{
/* be nice if we could use opt_scrollable here */
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok_is_keyword(tok, &yylval,
K_NO, "no"))
{
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok_is_keyword(tok, &yylval,
K_SCROLL, "scroll"))
{
new->cursor_options |= CURSOR_OPT_NO_SCROLL;
- tok = yylex();
+ tok = yylex(yyscanner);
}
}
else if (tok_is_keyword(tok, &yylval,
K_SCROLL, "scroll"))
{
new->cursor_options |= CURSOR_OPT_SCROLL;
- tok = yylex();
+ tok = yylex(yyscanner);
}
if (tok != K_FOR)
- yyerror("syntax error, expected \"FOR\"");
+ yyerror(yyscanner, "syntax error, expected \"FOR\"");
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok == K_EXECUTE)
{
int endtoken;
@@ -2119,7 +2129,7 @@ stmt_open : K_OPEN cursor_variable
new->dynquery =
read_sql_expression2(K_USING, ';',
"USING or ;",
- &endtoken);
+ &endtoken, yyscanner);
/* If we found "USING", collect argument(s) */
if (endtoken == K_USING)
@@ -2130,7 +2140,7 @@ stmt_open : K_OPEN cursor_variable
{
expr = read_sql_expression2(',', ';',
", or ;",
- &endtoken);
+ &endtoken, yyscanner);
new->params = lappend(new->params,
expr);
} while (endtoken == ',');
@@ -2139,13 +2149,13 @@ stmt_open : K_OPEN cursor_variable
else
{
plpgsql_push_back_token(tok);
- new->query = read_sql_stmt();
+ new->query = read_sql_stmt(yyscanner);
}
}
else
{
/* predefined cursor query, so read args */
- new->argquery = read_cursor_args($2, ';');
+ new->argquery = read_cursor_args($2, ';', yyscanner);
}
$$ = (PLpgSQL_stmt *) new;
@@ -2158,10 +2168,10 @@ stmt_fetch : K_FETCH opt_fetch_direction cursor_variable K_INTO
PLpgSQL_variable *target;
/* We have already parsed everything through the INTO keyword */
- read_into_target(&target, NULL);
+ read_into_target(&target, NULL, yyscanner);
- if (yylex() != ';')
- yyerror("syntax error");
+ if (yylex(yyscanner) != ';')
+ yyerror(yyscanner, "syntax error");
/*
* We don't allow multiple rows in PL/pgSQL's FETCH
@@ -2196,7 +2206,7 @@ stmt_move : K_MOVE opt_fetch_direction cursor_variable ';'
opt_fetch_direction :
{
- $$ = read_fetch_direction();
+ $$ = read_fetch_direction(yyscanner);
}
;
@@ -2264,7 +2274,7 @@ cursor_variable : T_DATUM
* just throw an error if next token is '['.
*/
if ($1.datum->dtype != PLPGSQL_DTYPE_VAR ||
- plpgsql_peek() == '[')
+ plpgsql_peek(yyscanner) == '[')
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cursor variable must be a simple variable"),
@@ -2384,14 +2394,14 @@ proc_condition : any_identifier
char *sqlstatestr;
/* next token should be a string literal */
- if (yylex() != SCONST)
- yyerror("syntax error");
+ if (yylex(yyscanner) != SCONST)
+ yyerror(yyscanner, "syntax error");
sqlstatestr = yylval.str;
if (strlen(sqlstatestr) != 5)
- yyerror("invalid SQLSTATE code");
+ yyerror(yyscanner, "invalid SQLSTATE code");
if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5)
- yyerror("invalid SQLSTATE code");
+ yyerror(yyscanner, "invalid SQLSTATE code");
new = palloc(sizeof(PLpgSQL_condition));
new->sqlerrstate =
@@ -2409,15 +2419,15 @@ proc_condition : any_identifier
;
expr_until_semi :
- { $$ = read_sql_expression(';', ";"); }
+ { $$ = read_sql_expression(';', ";", yyscanner); }
;
expr_until_then :
- { $$ = read_sql_expression(K_THEN, "THEN"); }
+ { $$ = read_sql_expression(K_THEN, "THEN", yyscanner); }
;
expr_until_loop :
- { $$ = read_sql_expression(K_LOOP, "LOOP"); }
+ { $$ = read_sql_expression(K_LOOP, "LOOP", yyscanner); }
;
opt_block_label :
@@ -2475,7 +2485,7 @@ any_identifier : T_WORD
| T_DATUM
{
if ($1.ident == NULL) /* composite name not OK */
- yyerror("syntax error");
+ yyerror(yyscanner, "syntax error");
$$ = $1.ident;
}
;
@@ -2627,42 +2637,45 @@ cword_is_not_variable(PLcword *cword, int location)
* look at yylval and yylloc.
*/
static void
-current_token_is_not_variable(int tok)
+current_token_is_not_variable(int tok, yyscan_t yyscanner)
{
if (tok == T_WORD)
word_is_not_variable(&(yylval.word), yylloc);
else if (tok == T_CWORD)
cword_is_not_variable(&(yylval.cword), yylloc);
else
- yyerror("syntax error");
+ yyerror(yyscanner, "syntax error");
}
/* Convenience routine to read an expression with one possible terminator */
static PLpgSQL_expr *
-read_sql_expression(int until, const char *expected)
+read_sql_expression(int until, const char *expected, yyscan_t yyscanner)
{
return read_sql_construct(until, 0, 0, expected,
RAW_PARSE_PLPGSQL_EXPR,
- true, true, NULL, NULL);
+ true, true, NULL, NULL,
+ yyscanner);
}
/* Convenience routine to read an expression with two possible terminators */
static PLpgSQL_expr *
read_sql_expression2(int until, int until2, const char *expected,
- int *endtoken)
+ int *endtoken, yyscan_t yyscanner)
{
return read_sql_construct(until, until2, 0, expected,
RAW_PARSE_PLPGSQL_EXPR,
- true, true, NULL, endtoken);
+ true, true, NULL, endtoken,
+ yyscanner);
}
/* Convenience routine to read a SQL statement that must end with ';' */
static PLpgSQL_expr *
-read_sql_stmt(void)
+read_sql_stmt(yyscan_t yyscanner)
{
return read_sql_construct(';', 0, 0, ";",
RAW_PARSE_DEFAULT,
- false, true, NULL, NULL);
+ false, true, NULL, NULL,
+ yyscanner);
}
/*
@@ -2688,7 +2701,8 @@ read_sql_construct(int until,
bool isexpression,
bool valid_sql,
int *startloc,
- int *endtoken)
+ int *endtoken,
+ yyscan_t yyscanner)
{
int tok;
StringInfoData ds;
@@ -2706,7 +2720,7 @@ read_sql_construct(int until,
for (;;)
{
- tok = yylex();
+ tok = yylex(yyscanner);
if (startlocation < 0) /* remember loc of first token */
startlocation = yylloc;
if (tok == until && parenlevel == 0)
@@ -2721,7 +2735,7 @@ read_sql_construct(int until,
{
parenlevel--;
if (parenlevel < 0)
- yyerror("mismatched parentheses");
+ yyerror(yyscanner, "mismatched parentheses");
}
/*
* End of function definition is an error, and we don't expect to
@@ -2731,7 +2745,7 @@ read_sql_construct(int until,
if (tok == 0 || tok == ';')
{
if (parenlevel != 0)
- yyerror("mismatched parentheses");
+ yyerror(yyscanner, "mismatched parentheses");
if (isexpression)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
@@ -2760,9 +2774,9 @@ read_sql_construct(int until,
if (startlocation >= endlocation)
{
if (isexpression)
- yyerror("missing expression");
+ yyerror(yyscanner, "missing expression");
else
- yyerror("missing SQL statement");
+ yyerror(yyscanner, "missing SQL statement");
}
/*
@@ -2794,7 +2808,7 @@ read_sql_construct(int until,
* Returns a PLpgSQL_type struct.
*/
static PLpgSQL_type *
-read_datatype(int tok)
+read_datatype(int tok, yyscan_t yyscanner)
{
StringInfoData ds;
char *type_name;
@@ -2807,7 +2821,7 @@ read_datatype(int tok)
/* Often there will be a lookahead token, but if not, get one */
if (tok == YYEMPTY)
- tok = yylex();
+ tok = yylex(yyscanner);
/* The current token is the start of what we'll pass to parse_datatype */
startlocation = yylloc;
@@ -2820,10 +2834,10 @@ read_datatype(int tok)
{
char *dtname = yylval.word.ident;
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok == '%')
{
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok_is_keyword(tok, &yylval,
K_TYPE, "type"))
result = plpgsql_parse_wordtype(dtname);
@@ -2836,10 +2850,10 @@ read_datatype(int tok)
{
char *dtname = pstrdup(yylval.keyword);
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok == '%')
{
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok_is_keyword(tok, &yylval,
K_TYPE, "type"))
result = plpgsql_parse_wordtype(dtname);
@@ -2852,10 +2866,10 @@ read_datatype(int tok)
{
List *dtnames = yylval.cword.idents;
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok == '%')
{
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok_is_keyword(tok, &yylval,
K_TYPE, "type"))
result = plpgsql_parse_cwordtype(dtnames);
@@ -2877,22 +2891,22 @@ read_datatype(int tok)
{
bool is_array = false;
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok_is_keyword(tok, &yylval,
K_ARRAY, "array"))
{
is_array = true;
- tok = yylex();
+ tok = yylex(yyscanner);
}
while (tok == '[')
{
is_array = true;
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok == ICONST)
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok != ']')
- yyerror("syntax error, expected \"]\"");
- tok = yylex();
+ yyerror(yyscanner, "syntax error, expected \"]\"");
+ tok = yylex(yyscanner);
}
plpgsql_push_back_token(tok);
@@ -2913,9 +2927,9 @@ read_datatype(int tok)
if (tok == 0)
{
if (parenlevel != 0)
- yyerror("mismatched parentheses");
+ yyerror(yyscanner, "mismatched parentheses");
else
- yyerror("incomplete data type declaration");
+ yyerror(yyscanner, "incomplete data type declaration");
}
/* Possible followers for datatype in a declaration */
if (tok == K_COLLATE || tok == K_NOT ||
@@ -2929,7 +2943,7 @@ read_datatype(int tok)
else if (tok == ')')
parenlevel--;
- tok = yylex();
+ tok = yylex(yyscanner);
}
/* set up ds to contain complete typename text */
@@ -2938,7 +2952,7 @@ read_datatype(int tok)
type_name = ds.data;
if (type_name[0] == '\0')
- yyerror("missing data type declaration");
+ yyerror(yyscanner, "missing data type declaration");
result = parse_datatype(type_name, startlocation);
@@ -2955,7 +2969,7 @@ read_datatype(int tok)
* If firsttoken == T_WORD, pass its yylval value as "word", else pass NULL.
*/
static PLpgSQL_stmt *
-make_execsql_stmt(int firsttoken, int location, PLword *word)
+make_execsql_stmt(int firsttoken, int location, PLword *word, yyscan_t yyscanner)
{
StringInfoData ds;
IdentifierLookup save_IdentifierLookup;
@@ -3024,7 +3038,7 @@ make_execsql_stmt(int firsttoken, int location, PLword *word)
for (;;)
{
prev_tok = tok;
- tok = yylex();
+ tok = yylex(yyscanner);
if (have_into && into_end_loc < 0)
into_end_loc = yylloc; /* token after the INTO part */
/* Detect CREATE [OR REPLACE] {FUNCTION|PROCEDURE} */
@@ -3063,7 +3077,7 @@ make_execsql_stmt(int firsttoken, int location, PLword *word)
if (tok == ';' && paren_depth == 0 && begin_depth == 0)
break;
if (tok == 0)
- yyerror("unexpected end of function definition");
+ yyerror(yyscanner, "unexpected end of function definition");
if (tok == K_INTO)
{
if (prev_tok == K_INSERT)
@@ -3073,11 +3087,11 @@ make_execsql_stmt(int firsttoken, int location, PLword *word)
if (firsttoken == K_IMPORT)
continue; /* IMPORT ... INTO is not an INTO-target */
if (have_into)
- yyerror("INTO specified more than once");
+ yyerror(yyscanner, "INTO specified more than once");
have_into = true;
into_start_loc = yylloc;
plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
- read_into_target(&target, &have_strict);
+ read_into_target(&target, &have_strict, yyscanner);
plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
}
}
@@ -3130,7 +3144,7 @@ make_execsql_stmt(int firsttoken, int location, PLword *word)
* Read FETCH or MOVE direction clause (everything through FROM/IN).
*/
static PLpgSQL_stmt_fetch *
-read_fetch_direction(void)
+read_fetch_direction(yyscan_t yyscanner)
{
PLpgSQL_stmt_fetch *fetch;
int tok;
@@ -3149,9 +3163,9 @@ read_fetch_direction(void)
fetch->expr = NULL;
fetch->returns_multiple_rows = false;
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok == 0)
- yyerror("unexpected end of function definition");
+ yyerror(yyscanner, "unexpected end of function definition");
if (tok_is_keyword(tok, &yylval,
K_NEXT, "next"))
@@ -3180,7 +3194,7 @@ read_fetch_direction(void)
fetch->direction = FETCH_ABSOLUTE;
fetch->expr = read_sql_expression2(K_FROM, K_IN,
"FROM or IN",
- NULL);
+ NULL, yyscanner);
check_FROM = false;
}
else if (tok_is_keyword(tok, &yylval,
@@ -3189,7 +3203,7 @@ read_fetch_direction(void)
fetch->direction = FETCH_RELATIVE;
fetch->expr = read_sql_expression2(K_FROM, K_IN,
"FROM or IN",
- NULL);
+ NULL, yyscanner);
check_FROM = false;
}
else if (tok_is_keyword(tok, &yylval,
@@ -3201,13 +3215,13 @@ read_fetch_direction(void)
else if (tok_is_keyword(tok, &yylval,
K_FORWARD, "forward"))
{
- complete_direction(fetch, &check_FROM);
+ complete_direction(fetch, &check_FROM, yyscanner);
}
else if (tok_is_keyword(tok, &yylval,
K_BACKWARD, "backward"))
{
fetch->direction = FETCH_BACKWARD;
- complete_direction(fetch, &check_FROM);
+ complete_direction(fetch, &check_FROM, yyscanner);
}
else if (tok == K_FROM || tok == K_IN)
{
@@ -3233,7 +3247,7 @@ read_fetch_direction(void)
plpgsql_push_back_token(tok);
fetch->expr = read_sql_expression2(K_FROM, K_IN,
"FROM or IN",
- NULL);
+ NULL, yyscanner);
fetch->returns_multiple_rows = true;
check_FROM = false;
}
@@ -3241,9 +3255,9 @@ read_fetch_direction(void)
/* check FROM or IN keyword after direction's specification */
if (check_FROM)
{
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok != K_FROM && tok != K_IN)
- yyerror("expected FROM or IN");
+ yyerror(yyscanner, "expected FROM or IN");
}
return fetch;
@@ -3256,13 +3270,13 @@ read_fetch_direction(void)
* BACKWARD expr, BACKWARD ALL, BACKWARD
*/
static void
-complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM)
+complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM, yyscan_t yyscanner)
{
int tok;
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok == 0)
- yyerror("unexpected end of function definition");
+ yyerror(yyscanner, "unexpected end of function definition");
if (tok == K_FROM || tok == K_IN)
{
@@ -3281,14 +3295,14 @@ complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM)
plpgsql_push_back_token(tok);
fetch->expr = read_sql_expression2(K_FROM, K_IN,
"FROM or IN",
- NULL);
+ NULL, yyscanner);
fetch->returns_multiple_rows = true;
*check_FROM = false;
}
static PLpgSQL_stmt *
-make_return_stmt(int location)
+make_return_stmt(int location, yyscan_t yyscanner)
{
PLpgSQL_stmt_return *new;
@@ -3301,7 +3315,7 @@ make_return_stmt(int location)
if (plpgsql_curr_compile->fn_retset)
{
- if (yylex() != ';')
+ if (yylex(yyscanner) != ';')
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("RETURN cannot have a parameter in function returning set"),
@@ -3310,7 +3324,7 @@ make_return_stmt(int location)
}
else if (plpgsql_curr_compile->fn_rettype == VOIDOID)
{
- if (yylex() != ';')
+ if (yylex(yyscanner) != ';')
{
if (plpgsql_curr_compile->fn_prokind == PROKIND_PROCEDURE)
ereport(ERROR,
@@ -3326,7 +3340,7 @@ make_return_stmt(int location)
}
else if (plpgsql_curr_compile->out_param_varno >= 0)
{
- if (yylex() != ';')
+ if (yylex(yyscanner) != ';')
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("RETURN cannot have a parameter in function with OUT parameters"),
@@ -3339,9 +3353,9 @@ make_return_stmt(int location)
* We want to special-case simple variable references for efficiency.
* So peek ahead to see if that's what we have.
*/
- int tok = yylex();
+ int tok = yylex(yyscanner);
- if (tok == T_DATUM && plpgsql_peek() == ';' &&
+ if (tok == T_DATUM && plpgsql_peek(yyscanner) == ';' &&
(yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_VAR ||
yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_PROMISE ||
yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
@@ -3349,7 +3363,7 @@ make_return_stmt(int location)
{
new->retvarno = yylval.wdatum.datum->dno;
/* eat the semicolon token that we only peeked at above */
- tok = yylex();
+ tok = yylex(yyscanner);
Assert(tok == ';');
}
else
@@ -3361,7 +3375,7 @@ make_return_stmt(int location)
* anything else is a compile-time error.
*/
plpgsql_push_back_token(tok);
- new->expr = read_sql_expression(';', ";");
+ new->expr = read_sql_expression(';', ";", yyscanner);
}
}
@@ -3370,7 +3384,7 @@ make_return_stmt(int location)
static PLpgSQL_stmt *
-make_return_next_stmt(int location)
+make_return_next_stmt(int location, yyscan_t yyscanner)
{
PLpgSQL_stmt_return_next *new;
@@ -3389,7 +3403,7 @@ make_return_next_stmt(int location)
if (plpgsql_curr_compile->out_param_varno >= 0)
{
- if (yylex() != ';')
+ if (yylex(yyscanner) != ';')
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("RETURN NEXT cannot have a parameter in function with OUT parameters"),
@@ -3402,9 +3416,9 @@ make_return_next_stmt(int location)
* We want to special-case simple variable references for efficiency.
* So peek ahead to see if that's what we have.
*/
- int tok = yylex();
+ int tok = yylex(yyscanner);
- if (tok == T_DATUM && plpgsql_peek() == ';' &&
+ if (tok == T_DATUM && plpgsql_peek(yyscanner) == ';' &&
(yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_VAR ||
yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_PROMISE ||
yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
@@ -3412,7 +3426,7 @@ make_return_next_stmt(int location)
{
new->retvarno = yylval.wdatum.datum->dno;
/* eat the semicolon token that we only peeked at above */
- tok = yylex();
+ tok = yylex(yyscanner);
Assert(tok == ';');
}
else
@@ -3424,7 +3438,7 @@ make_return_next_stmt(int location)
* anything else is a compile-time error.
*/
plpgsql_push_back_token(tok);
- new->expr = read_sql_expression(';', ";");
+ new->expr = read_sql_expression(';', ";", yyscanner);
}
}
@@ -3433,7 +3447,7 @@ make_return_next_stmt(int location)
static PLpgSQL_stmt *
-make_return_query_stmt(int location)
+make_return_query_stmt(int location, yyscan_t yyscanner)
{
PLpgSQL_stmt_return_query *new;
int tok;
@@ -3450,11 +3464,11 @@ make_return_query_stmt(int location)
new->stmtid = ++plpgsql_curr_compile->nstatements;
/* check for RETURN QUERY EXECUTE */
- if ((tok = yylex()) != K_EXECUTE)
+ if ((tok = yylex(yyscanner)) != K_EXECUTE)
{
/* ordinary static query */
plpgsql_push_back_token(tok);
- new->query = read_sql_stmt();
+ new->query = read_sql_stmt(yyscanner);
}
else
{
@@ -3462,14 +3476,14 @@ make_return_query_stmt(int location)
int term;
new->dynquery = read_sql_expression2(';', K_USING, "; or USING",
- &term);
+ &term, yyscanner);
if (term == K_USING)
{
do
{
PLpgSQL_expr *expr;
- expr = read_sql_expression2(',', ';', ", or ;", &term);
+ expr = read_sql_expression2(',', ';', ", or ;", &term, yyscanner);
new->params = lappend(new->params, expr);
} while (term == ',');
}
@@ -3523,7 +3537,7 @@ check_assignable(PLpgSQL_datum *datum, int location)
* INTO keyword.
*/
static void
-read_into_target(PLpgSQL_variable **target, bool *strict)
+read_into_target(PLpgSQL_variable **target, bool *strict, yyscan_t yyscanner)
{
int tok;
@@ -3532,11 +3546,11 @@ read_into_target(PLpgSQL_variable **target, bool *strict)
if (strict)
*strict = false;
- tok = yylex();
+ tok = yylex(yyscanner);
if (strict && tok == K_STRICT)
{
*strict = true;
- tok = yylex();
+ tok = yylex(yyscanner);
}
/*
@@ -3555,7 +3569,7 @@ read_into_target(PLpgSQL_variable **target, bool *strict)
check_assignable(yylval.wdatum.datum, yylloc);
*target = (PLpgSQL_variable *) yylval.wdatum.datum;
- if ((tok = yylex()) == ',')
+ if ((tok = yylex(yyscanner)) == ',')
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("record variable cannot be part of multiple-item INTO list"),
@@ -3566,13 +3580,13 @@ read_into_target(PLpgSQL_variable **target, bool *strict)
{
*target = (PLpgSQL_variable *)
read_into_scalar_list(NameOfDatum(&(yylval.wdatum)),
- yylval.wdatum.datum, yylloc);
+ yylval.wdatum.datum, yylloc, yyscanner);
}
break;
default:
/* just to give a better message than "syntax error" */
- current_token_is_not_variable(tok);
+ current_token_is_not_variable(tok, yyscanner);
}
}
@@ -3585,7 +3599,8 @@ read_into_target(PLpgSQL_variable **target, bool *strict)
static PLpgSQL_row *
read_into_scalar_list(char *initial_name,
PLpgSQL_datum *initial_datum,
- int initial_location)
+ int initial_location,
+ yyscan_t yyscanner)
{
int nfields;
char *fieldnames[1024];
@@ -3598,7 +3613,7 @@ read_into_scalar_list(char *initial_name,
varnos[0] = initial_datum->dno;
nfields = 1;
- while ((tok = yylex()) == ',')
+ while ((tok = yylex(yyscanner)) == ',')
{
/* Check for array overflow */
if (nfields >= 1024)
@@ -3607,7 +3622,7 @@ read_into_scalar_list(char *initial_name,
errmsg("too many INTO variables specified"),
parser_errposition(yylloc)));
- tok = yylex();
+ tok = yylex(yyscanner);
switch (tok)
{
case T_DATUM:
@@ -3625,7 +3640,7 @@ read_into_scalar_list(char *initial_name,
default:
/* just to give a better message than "syntax error" */
- current_token_is_not_variable(tok);
+ current_token_is_not_variable(tok, yyscanner);
}
}
@@ -3836,7 +3851,7 @@ check_labels(const char *start_label, const char *end_label, int end_location)
* parens).
*/
static PLpgSQL_expr *
-read_cursor_args(PLpgSQL_var *cursor, int until)
+read_cursor_args(PLpgSQL_var *cursor, int until, yyscan_t yyscanner)
{
PLpgSQL_expr *expr;
PLpgSQL_row *row;
@@ -3846,7 +3861,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until)
StringInfoData ds;
bool any_named = false;
- tok = yylex();
+ tok = yylex(yyscanner);
if (cursor->cursor_explicit_argrow < 0)
{
/* No arguments expected */
@@ -3858,7 +3873,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until)
parser_errposition(yylloc)));
if (tok != until)
- yyerror("syntax error");
+ yyerror(yyscanner, "syntax error");
return NULL;
}
@@ -3887,7 +3902,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until)
int arglocation;
/* Check if it's a named parameter: "param := value" */
- plpgsql_peek2(&tok1, &tok2, &arglocation, NULL);
+ plpgsql_peek2(&tok1, &tok2, &arglocation, NULL, yyscanner);
if (tok1 == IDENT && tok2 == COLON_EQUALS)
{
char *argname;
@@ -3896,7 +3911,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until)
/* Read the argument name, ignoring any matching variable */
save_IdentifierLookup = plpgsql_IdentifierLookup;
plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_DECLARE;
- yylex();
+ yylex(yyscanner);
argname = yylval.str;
plpgsql_IdentifierLookup = save_IdentifierLookup;
@@ -3917,9 +3932,9 @@ read_cursor_args(PLpgSQL_var *cursor, int until)
* Eat the ":=". We already peeked, so the error should never
* happen.
*/
- tok2 = yylex();
+ tok2 = yylex(yyscanner);
if (tok2 != COLON_EQUALS)
- yyerror("syntax error");
+ yyerror(yyscanner, "syntax error");
any_named = true;
}
@@ -3943,7 +3958,8 @@ read_cursor_args(PLpgSQL_var *cursor, int until)
",\" or \")",
RAW_PARSE_PLPGSQL_EXPR,
true, true,
- NULL, &endtoken);
+ NULL, &endtoken,
+ yyscanner);
argv[argpos] = item->query;
@@ -3990,9 +4006,9 @@ read_cursor_args(PLpgSQL_var *cursor, int until)
pfree(ds.data);
/* Next we'd better find the until token */
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok != until)
- yyerror("syntax error");
+ yyerror(yyscanner, "syntax error");
return expr;
}
@@ -4001,7 +4017,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until)
* Parse RAISE ... USING options
*/
static List *
-read_raise_options(void)
+read_raise_options(yyscan_t yyscanner)
{
List *result = NIL;
@@ -4010,8 +4026,8 @@ read_raise_options(void)
PLpgSQL_raise_option *opt;
int tok;
- if ((tok = yylex()) == 0)
- yyerror("unexpected end of function definition");
+ if ((tok = yylex(yyscanner)) == 0)
+ yyerror(yyscanner, "unexpected end of function definition");
opt = (PLpgSQL_raise_option *) palloc(sizeof(PLpgSQL_raise_option));
@@ -4043,13 +4059,13 @@ read_raise_options(void)
K_SCHEMA, "schema"))
opt->opt_type = PLPGSQL_RAISEOPTION_SCHEMA;
else
- yyerror("unrecognized RAISE statement option");
+ yyerror(yyscanner, "unrecognized RAISE statement option");
- tok = yylex();
+ tok = yylex(yyscanner);
if (tok != '=' && tok != COLON_EQUALS)
- yyerror("syntax error, expected \"=\"");
+ yyerror(yyscanner, "syntax error, expected \"=\"");
- opt->expr = read_sql_expression2(',', ';', ", or ;", &tok);
+ opt->expr = read_sql_expression2(',', ';', ", or ;", &tok, yyscanner);
result = lappend(result, opt);
diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c
index 9407da51efa..e24b107909b 100644
--- a/src/pl/plpgsql/src/pl_scanner.c
+++ b/src/pl/plpgsql/src/pl_scanner.c
@@ -103,7 +103,6 @@ typedef struct
*/
/* The stuff the core lexer needs */
-static core_yyscan_t yyscanner = NULL;
static core_yy_extra_type core_yy;
/* The original input string */
@@ -128,7 +127,7 @@ static const char *cur_line_end;
static int cur_line_num;
/* Internal functions */
-static int internal_yylex(TokenAuxData *auxdata);
+static int internal_yylex(TokenAuxData *auxdata, yyscan_t yyscanner);
static void push_back_token(int token, TokenAuxData *auxdata);
static void location_lineno_init(void);
@@ -143,37 +142,37 @@ static void location_lineno_init(void);
* matches one of those.
*/
int
-plpgsql_yylex(void)
+plpgsql_yylex(yyscan_t yyscanner)
{
int tok1;
TokenAuxData aux1;
int kwnum;
- tok1 = internal_yylex(&aux1);
+ tok1 = internal_yylex(&aux1, yyscanner);
if (tok1 == IDENT || tok1 == PARAM)
{
int tok2;
TokenAuxData aux2;
- tok2 = internal_yylex(&aux2);
+ tok2 = internal_yylex(&aux2, yyscanner);
if (tok2 == '.')
{
int tok3;
TokenAuxData aux3;
- tok3 = internal_yylex(&aux3);
+ tok3 = internal_yylex(&aux3, yyscanner);
if (tok3 == IDENT)
{
int tok4;
TokenAuxData aux4;
- tok4 = internal_yylex(&aux4);
+ tok4 = internal_yylex(&aux4, yyscanner);
if (tok4 == '.')
{
int tok5;
TokenAuxData aux5;
- tok5 = internal_yylex(&aux5);
+ tok5 = internal_yylex(&aux5, yyscanner);
if (tok5 == IDENT)
{
if (plpgsql_parse_tripword(aux1.lval.str,
@@ -322,7 +321,7 @@ plpgsql_token_length(void)
* interfacing from the core_YYSTYPE to YYSTYPE union.
*/
static int
-internal_yylex(TokenAuxData *auxdata)
+internal_yylex(TokenAuxData *auxdata, yyscan_t yyscanner)
{
int token;
const char *yytext;
@@ -434,12 +433,12 @@ plpgsql_append_source_text(StringInfo buf,
* be returned as IDENT. Reserved keywords are resolved as usual.
*/
int
-plpgsql_peek(void)
+plpgsql_peek(yyscan_t yyscanner)
{
int tok1;
TokenAuxData aux1;
- tok1 = internal_yylex(&aux1);
+ tok1 = internal_yylex(&aux1, yyscanner);
push_back_token(tok1, &aux1);
return tok1;
}
@@ -453,15 +452,15 @@ plpgsql_peek(void)
* be returned as IDENT. Reserved keywords are resolved as usual.
*/
void
-plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc)
+plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc, yyscan_t yyscanner)
{
int tok1,
tok2;
TokenAuxData aux1,
aux2;
- tok1 = internal_yylex(&aux1);
- tok2 = internal_yylex(&aux2);
+ tok1 = internal_yylex(&aux1, yyscanner);
+ tok2 = internal_yylex(&aux2, yyscanner);
*tok1_p = tok1;
if (tok1_loc)
@@ -513,7 +512,7 @@ plpgsql_scanner_errposition(int location)
* be misleading!
*/
void
-plpgsql_yyerror(const char *message)
+plpgsql_yyerror(yyscan_t yyscanner, const char *message)
{
char *yytext = core_yy.scanbuf + plpgsql_yylloc;
@@ -599,9 +598,11 @@ plpgsql_latest_lineno(void)
* Although it is not fed directly to flex, we need the original string
* to cite in error messages.
*/
-void
+yyscan_t
plpgsql_scanner_init(const char *str)
{
+ yyscan_t yyscanner;
+
/* Start up the core scanner */
yyscanner = scanner_init(str, &core_yy,
&ReservedPLKeywords, ReservedPLKeywordTokens);
@@ -621,17 +622,18 @@ plpgsql_scanner_init(const char *str)
num_pushbacks = 0;
location_lineno_init();
+
+ return yyscanner;
}
/*
* Called after parsing is done to clean up after plpgsql_scanner_init()
*/
void
-plpgsql_scanner_finish(void)
+plpgsql_scanner_finish(yyscan_t yyscanner)
{
/* release storage */
scanner_finish(yyscanner);
/* avoid leaving any dangling pointers */
- yyscanner = NULL;
scanorig = NULL;
}
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 50c3b28472b..dab4e16c72e 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -1315,26 +1315,26 @@ extern void plpgsql_dumptree(PLpgSQL_function *func);
/*
* Scanner functions in pl_scanner.c
*/
-extern int plpgsql_base_yylex(void);
-extern int plpgsql_yylex(void);
+typedef void *yyscan_t;
+extern int plpgsql_yylex(yyscan_t yyscanner);
extern int plpgsql_token_length(void);
extern void plpgsql_push_back_token(int token);
extern bool plpgsql_token_is_unreserved_keyword(int token);
extern void plpgsql_append_source_text(StringInfo buf,
int startlocation, int endlocation);
-extern int plpgsql_peek(void);
+extern int plpgsql_peek(yyscan_t yyscanner);
extern void plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc,
- int *tok2_loc);
+ int *tok2_loc, yyscan_t yyscanner);
extern int plpgsql_scanner_errposition(int location);
-extern void plpgsql_yyerror(const char *message) pg_attribute_noreturn();
+extern void plpgsql_yyerror(yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
extern int plpgsql_location_to_lineno(int location);
extern int plpgsql_latest_lineno(void);
-extern void plpgsql_scanner_init(const char *str);
-extern void plpgsql_scanner_finish(void);
+extern yyscan_t plpgsql_scanner_init(const char *str);
+extern void plpgsql_scanner_finish(yyscan_t yyscanner);
/*
* Externs in gram.y
*/
-extern int plpgsql_yyparse(void);
+extern int plpgsql_yyparse(yyscan_t yyscanner);
#endif /* PLPGSQL_H */
--
2.47.1