v3-0004-plpgsql-yyextra.patch
text/plain
Filename: v3-0004-plpgsql-yyextra.patch
Type: text/plain
Part: 3
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 v3-0004
Subject: plpgsql: yyextra
| File | + | − |
|---|---|---|
| src/pl/plpgsql/src/pl_comp.c | 22 | 11 |
| src/pl/plpgsql/src/pl_gram.y | 119 | 115 |
| src/pl/plpgsql/src/plpgsql.h | 7 | 6 |
| src/pl/plpgsql/src/pl_scanner.c | 102 | 87 |
From 4c3e4f0da9a2fa1f646da9362b39974e7e44117e Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 26 Dec 2024 17:01:39 +0100
Subject: [PATCH v3 4/4] plpgsql: yyextra
---
src/pl/plpgsql/src/pl_comp.c | 33 +++--
src/pl/plpgsql/src/pl_gram.y | 234 ++++++++++++++++----------------
src/pl/plpgsql/src/pl_scanner.c | 189 ++++++++++++++------------
src/pl/plpgsql/src/plpgsql.h | 13 +-
4 files changed, 250 insertions(+), 219 deletions(-)
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 57685c4e948..f443423b98c 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -237,6 +237,12 @@ plpgsql_compile(FunctionCallInfo fcinfo, bool forValidator)
return function;
}
+struct compile_error_callback_arg
+{
+ const char *proc_source;
+ yyscan_t yyscanner;
+};
+
/*
* This is the slow part of plpgsql_compile().
*
@@ -277,6 +283,7 @@ do_compile(FunctionCallInfo fcinfo,
PLpgSQL_variable *var;
PLpgSQL_rec *rec;
int i;
+ struct compile_error_callback_arg cbarg;
ErrorContextCallback plerrcontext;
int parse_rc;
Oid rettypeid;
@@ -291,9 +298,7 @@ do_compile(FunctionCallInfo fcinfo,
MemoryContext func_cxt;
/*
- * 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.
+ * Setup the scanner input and error info.
*/
prosrcdatum = SysCacheGetAttrNotNull(PROCOID, procTup, Anum_pg_proc_prosrc);
proc_source = TextDatumGetCString(prosrcdatum);
@@ -304,8 +309,10 @@ do_compile(FunctionCallInfo fcinfo,
/*
* Setup error traceback support for ereport()
*/
+ cbarg.proc_source = forValidator ? proc_source : NULL;
+ cbarg.yyscanner = scanner;
plerrcontext.callback = plpgsql_compile_error_callback;
- plerrcontext.arg = forValidator ? proc_source : NULL;
+ plerrcontext.arg = &cbarg;
plerrcontext.previous = error_context_stack;
error_context_stack = &plerrcontext;
@@ -845,15 +852,14 @@ plpgsql_compile_inline(char *proc_source)
yyscan_t scanner;
char *func_name = "inline_code_block";
PLpgSQL_function *function;
+ struct compile_error_callback_arg cbarg;
ErrorContextCallback plerrcontext;
PLpgSQL_variable *var;
int parse_rc;
MemoryContext func_cxt;
/*
- * 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.
+ * Setup the scanner input and error info.
*/
scanner = plpgsql_scanner_init(proc_source);
@@ -862,8 +868,10 @@ plpgsql_compile_inline(char *proc_source)
/*
* Setup error traceback support for ereport()
*/
+ cbarg.proc_source = proc_source;
+ cbarg.yyscanner = scanner;
plerrcontext.callback = plpgsql_compile_error_callback;
- plerrcontext.arg = proc_source;
+ plerrcontext.arg = &cbarg;
plerrcontext.previous = error_context_stack;
error_context_stack = &plerrcontext;
@@ -980,13 +988,16 @@ plpgsql_compile_inline(char *proc_source)
static void
plpgsql_compile_error_callback(void *arg)
{
- if (arg)
+ struct compile_error_callback_arg *cbarg = (struct compile_error_callback_arg *) arg;
+ yyscan_t yyscanner = cbarg->yyscanner;
+
+ if (cbarg->proc_source)
{
/*
* Try to convert syntax error position to reference text of original
* CREATE FUNCTION or DO command.
*/
- if (function_parse_error_transpose((const char *) arg))
+ if (function_parse_error_transpose(cbarg->proc_source))
return;
/*
@@ -997,7 +1008,7 @@ plpgsql_compile_error_callback(void *arg)
if (plpgsql_error_funcname)
errcontext("compilation of PL/pgSQL function \"%s\" near line %d",
- plpgsql_error_funcname, plpgsql_latest_lineno());
+ plpgsql_error_funcname, plpgsql_latest_lineno(yyscanner));
}
diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y
index cb5c2dca186..5f712198e5c 100644
--- a/src/pl/plpgsql/src/pl_gram.y
+++ b/src/pl/plpgsql/src/pl_gram.y
@@ -49,16 +49,17 @@
typedef struct
{
int location;
+ yyscan_t yyscanner;
} sql_error_callback_arg;
-#define parser_errposition(pos) plpgsql_scanner_errposition(pos)
+#define parser_errposition(pos) plpgsql_scanner_errposition(pos, yyscanner)
union YYSTYPE; /* need forward reference for tok_is_keyword */
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 word_is_not_variable(PLword *word, int location, yyscan_t yyscanner);
+static void cword_is_not_variable(PLcword *cword, int location, yyscan_t yyscanner);
static void current_token_is_not_variable(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner);
static PLpgSQL_expr *read_sql_construct(int until,
int until2,
@@ -87,9 +88,9 @@ static PLpgSQL_stmt *make_return_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *y
static PLpgSQL_stmt *make_return_next_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner);
static PLpgSQL_stmt *make_return_query_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner);
static PLpgSQL_stmt *make_case(int location, PLpgSQL_expr *t_expr,
- List *case_when_list, List *else_stmts);
+ List *case_when_list, List *else_stmts, yyscan_t yyscanner);
static char *NameOfDatum(PLwdatum *wdatum);
-static void check_assignable(PLpgSQL_datum *datum, int location);
+static void check_assignable(PLpgSQL_datum *datum, int location, yyscan_t yyscanner);
static void read_into_target(PLpgSQL_variable **target, bool *strict,
YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner);
static PLpgSQL_row *read_into_scalar_list(char *initial_name,
@@ -99,14 +100,15 @@ static PLpgSQL_row *read_into_scalar_list(char *initial_name,
yyscan_t yyscanner);
static PLpgSQL_row *make_scalar_list1(char *initial_name,
PLpgSQL_datum *initial_datum,
- int lineno, int location);
+ int lineno, int location, yyscan_t yyscanner);
static void check_sql_expr(const char *stmt,
- RawParseMode parseMode, int location);
+ RawParseMode parseMode, int location, yyscan_t yyscanner);
static void plpgsql_sql_error_callback(void *arg);
static PLpgSQL_type *parse_datatype(const char *string, int location);
static void check_labels(const char *start_label,
const char *end_label,
- int end_location);
+ int end_location,
+ yyscan_t yyscanner);
static PLpgSQL_expr *read_cursor_args(PLpgSQL_var *cursor, int until,
YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner);
static List *read_raise_options(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner);
@@ -421,7 +423,7 @@ pl_block : decl_sect K_BEGIN proc_sect exception_sect K_END opt_label
new = palloc0(sizeof(PLpgSQL_stmt_block));
new->cmd_type = PLPGSQL_STMT_BLOCK;
- new->lineno = plpgsql_location_to_lineno(@2);
+ new->lineno = plpgsql_location_to_lineno(@2, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->label = $1.label;
new->n_initvars = $1.n_initvars;
@@ -429,7 +431,7 @@ pl_block : decl_sect K_BEGIN proc_sect exception_sect K_END opt_label
new->body = $3;
new->exceptions = $4;
- check_labels($1.label, $6, @6);
+ check_labels($1.label, $6, @6, yyscanner);
plpgsql_ns_pop();
$$ = (PLpgSQL_stmt *) new;
@@ -597,7 +599,7 @@ decl_cursor_args :
new = palloc0(sizeof(PLpgSQL_row));
new->dtype = PLPGSQL_DTYPE_ROW;
new->refname = "(unnamed row)";
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
new->rowtupdesc = NULL;
new->nfields = list_length($2);
new->fieldnames = palloc(new->nfields * sizeof(char *));
@@ -701,7 +703,7 @@ decl_aliasitem : T_WORD
decl_varname : T_WORD
{
$$.name = $1.ident;
- $$.lineno = plpgsql_location_to_lineno(@1);
+ $$.lineno = plpgsql_location_to_lineno(@1, yyscanner);
/*
* Check to make sure name isn't already declared
* in the current block.
@@ -729,7 +731,7 @@ decl_varname : T_WORD
| unreserved_keyword
{
$$.name = pstrdup($1);
- $$.lineno = plpgsql_location_to_lineno(@1);
+ $$.lineno = plpgsql_location_to_lineno(@1, yyscanner);
/*
* Check to make sure name isn't already declared
* in the current block.
@@ -888,9 +890,9 @@ stmt_perform : K_PERFORM
new = palloc0(sizeof(PLpgSQL_stmt_perform));
new->cmd_type = PLPGSQL_STMT_PERFORM;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
- plpgsql_push_back_token(K_PERFORM, &yylval, &yylloc);
+ plpgsql_push_back_token(K_PERFORM, &yylval, &yylloc, yyscanner);
/*
* Since PERFORM isn't legal SQL, we have to cheat to
@@ -912,7 +914,7 @@ stmt_perform : K_PERFORM
strlen(new->expr->query));
/* offset syntax error position to account for that */
check_sql_expr(new->expr->query, new->expr->parseMode,
- startloc + 1);
+ startloc + 1, yyscanner);
$$ = (PLpgSQL_stmt *) new;
}
@@ -924,9 +926,9 @@ stmt_call : K_CALL
new = palloc0(sizeof(PLpgSQL_stmt_call));
new->cmd_type = PLPGSQL_STMT_CALL;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
- plpgsql_push_back_token(K_CALL, &yylval, &yylloc);
+ plpgsql_push_back_token(K_CALL, &yylval, &yylloc, yyscanner);
new->expr = read_sql_stmt(&yylval, &yylloc, yyscanner);
new->is_call = true;
@@ -943,9 +945,9 @@ stmt_call : K_CALL
new = palloc0(sizeof(PLpgSQL_stmt_call));
new->cmd_type = PLPGSQL_STMT_CALL;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
- plpgsql_push_back_token(K_DO, &yylval, &yylloc);
+ plpgsql_push_back_token(K_DO, &yylval, &yylloc, yyscanner);
new->expr = read_sql_stmt(&yylval, &yylloc, yyscanner);
new->is_call = false;
@@ -979,14 +981,14 @@ stmt_assign : T_DATUM
pmode = 0; /* keep compiler quiet */
}
- check_assignable($1.datum, @1);
+ check_assignable($1.datum, @1, yyscanner);
new = palloc0(sizeof(PLpgSQL_stmt_assign));
new->cmd_type = PLPGSQL_STMT_ASSIGN;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->varno = $1.datum->dno;
/* Push back the head name to include it in the stmt */
- plpgsql_push_back_token(T_DATUM, &yylval, &yylloc);
+ plpgsql_push_back_token(T_DATUM, &yylval, &yylloc, yyscanner);
new->expr = read_sql_construct(';', 0, 0, ";",
pmode,
false, true,
@@ -1004,7 +1006,7 @@ stmt_getdiag : K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';'
new = palloc0(sizeof(PLpgSQL_stmt_getdiag));
new->cmd_type = PLPGSQL_STMT_GETDIAG;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->is_stacked = $2;
new->diag_items = $4;
@@ -1159,18 +1161,18 @@ getdiag_target : T_DATUM
errmsg("\"%s\" is not a scalar variable",
NameOfDatum(&($1))),
parser_errposition(@1)));
- check_assignable($1.datum, @1);
+ check_assignable($1.datum, @1, yyscanner);
$$ = $1.datum;
}
| T_WORD
{
/* just to give a better message than "syntax error" */
- word_is_not_variable(&($1), @1);
+ word_is_not_variable(&($1), @1, yyscanner);
}
| T_CWORD
{
/* just to give a better message than "syntax error" */
- cword_is_not_variable(&($1), @1);
+ cword_is_not_variable(&($1), @1, yyscanner);
}
;
@@ -1180,7 +1182,7 @@ stmt_if : K_IF expr_until_then proc_sect stmt_elsifs stmt_else K_END K_IF ';'
new = palloc0(sizeof(PLpgSQL_stmt_if));
new->cmd_type = PLPGSQL_STMT_IF;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->cond = $2;
new->then_body = $3;
@@ -1200,7 +1202,7 @@ stmt_elsifs :
PLpgSQL_if_elsif *new;
new = palloc0(sizeof(PLpgSQL_if_elsif));
- new->lineno = plpgsql_location_to_lineno(@2);
+ new->lineno = plpgsql_location_to_lineno(@2, yyscanner);
new->cond = $3;
new->stmts = $4;
@@ -1220,7 +1222,7 @@ stmt_else :
stmt_case : K_CASE opt_expr_until_when case_when_list opt_case_else K_END K_CASE ';'
{
- $$ = make_case(@1, $2, $3, $4);
+ $$ = make_case(@1, $2, $3, $4, yyscanner);
}
;
@@ -1231,10 +1233,10 @@ opt_expr_until_when :
if (tok != K_WHEN)
{
- plpgsql_push_back_token(tok, &yylval, &yylloc);
+ plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner);
expr = read_sql_expression(K_WHEN, "WHEN", &yylval, &yylloc, yyscanner);
}
- plpgsql_push_back_token(K_WHEN, &yylval, &yylloc);
+ plpgsql_push_back_token(K_WHEN, &yylval, &yylloc, yyscanner);
$$ = expr;
}
;
@@ -1253,7 +1255,7 @@ case_when : K_WHEN expr_until_then proc_sect
{
PLpgSQL_case_when *new = palloc(sizeof(PLpgSQL_case_when));
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
new->expr = $2;
new->stmts = $3;
$$ = new;
@@ -1285,12 +1287,12 @@ stmt_loop : opt_loop_label K_LOOP loop_body
new = palloc0(sizeof(PLpgSQL_stmt_loop));
new->cmd_type = PLPGSQL_STMT_LOOP;
- new->lineno = plpgsql_location_to_lineno(@2);
+ new->lineno = plpgsql_location_to_lineno(@2, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->label = $1;
new->body = $3.stmts;
- check_labels($1, $3.end_label, $3.end_label_location);
+ check_labels($1, $3.end_label, $3.end_label_location, yyscanner);
plpgsql_ns_pop();
$$ = (PLpgSQL_stmt *) new;
@@ -1303,13 +1305,13 @@ stmt_while : opt_loop_label K_WHILE expr_until_loop loop_body
new = palloc0(sizeof(PLpgSQL_stmt_while));
new->cmd_type = PLPGSQL_STMT_WHILE;
- new->lineno = plpgsql_location_to_lineno(@2);
+ new->lineno = plpgsql_location_to_lineno(@2, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->label = $1;
new->cond = $3;
new->body = $4.stmts;
- check_labels($1, $4.end_label, $4.end_label_location);
+ check_labels($1, $4.end_label, $4.end_label_location, yyscanner);
plpgsql_ns_pop();
$$ = (PLpgSQL_stmt *) new;
@@ -1324,7 +1326,7 @@ stmt_for : opt_loop_label K_FOR for_control loop_body
PLpgSQL_stmt_fori *new;
new = (PLpgSQL_stmt_fori *) $3;
- new->lineno = plpgsql_location_to_lineno(@2);
+ new->lineno = plpgsql_location_to_lineno(@2, yyscanner);
new->label = $1;
new->body = $4.stmts;
$$ = (PLpgSQL_stmt *) new;
@@ -1338,13 +1340,13 @@ stmt_for : opt_loop_label K_FOR for_control loop_body
$3->cmd_type == PLPGSQL_STMT_DYNFORS);
/* forq is the common supertype of all three */
new = (PLpgSQL_stmt_forq *) $3;
- new->lineno = plpgsql_location_to_lineno(@2);
+ new->lineno = plpgsql_location_to_lineno(@2, yyscanner);
new->label = $1;
new->body = $4.stmts;
$$ = (PLpgSQL_stmt *) new;
}
- check_labels($1, $4.end_label, $4.end_label_location);
+ check_labels($1, $4.end_label, $4.end_label_location, yyscanner);
/* close namespace started in opt_loop_label */
plpgsql_ns_pop();
}
@@ -1372,14 +1374,14 @@ for_control : for_variable K_IN
if ($1.row)
{
new->var = (PLpgSQL_variable *) $1.row;
- check_assignable($1.row, @1);
+ check_assignable($1.row, @1, yyscanner);
}
else if ($1.scalar)
{
/* convert single scalar to list */
new->var = (PLpgSQL_variable *)
make_scalar_list1($1.name, $1.scalar,
- $1.lineno, @1);
+ $1.lineno, @1, yyscanner);
/* make_scalar_list1 did check_assignable */
}
else
@@ -1466,7 +1468,7 @@ for_control : for_variable K_IN
K_REVERSE, "reverse"))
reverse = true;
else
- plpgsql_push_back_token(tok, &yylval, &yylloc);
+ plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner);
/*
* Read tokens until we see either a ".."
@@ -1500,7 +1502,7 @@ for_control : for_variable K_IN
*/
expr1->parseMode = RAW_PARSE_PLPGSQL_EXPR;
check_sql_expr(expr1->query, expr1->parseMode,
- expr1loc);
+ expr1loc, yyscanner);
/* Read and check the second one */
expr2 = read_sql_expression2(K_LOOP, K_BY,
@@ -1557,7 +1559,7 @@ for_control : for_variable K_IN
/* Check syntax as a regular query */
check_sql_expr(expr1->query, expr1->parseMode,
- expr1loc);
+ expr1loc, yyscanner);
new = palloc0(sizeof(PLpgSQL_stmt_fors));
new->cmd_type = PLPGSQL_STMT_FORS;
@@ -1565,14 +1567,14 @@ for_control : for_variable K_IN
if ($1.row)
{
new->var = (PLpgSQL_variable *) $1.row;
- check_assignable($1.row, @1);
+ check_assignable($1.row, @1, yyscanner);
}
else if ($1.scalar)
{
/* convert single scalar to list */
new->var = (PLpgSQL_variable *)
make_scalar_list1($1.name, $1.scalar,
- $1.lineno, @1);
+ $1.lineno, @1, yyscanner);
/* make_scalar_list1 did check_assignable */
}
else
@@ -1611,7 +1613,7 @@ for_control : for_variable K_IN
for_variable : T_DATUM
{
$$.name = NameOfDatum(&($1));
- $$.lineno = plpgsql_location_to_lineno(@1);
+ $$.lineno = plpgsql_location_to_lineno(@1, yyscanner);
if ($1.datum->dtype == PLPGSQL_DTYPE_ROW ||
$1.datum->dtype == PLPGSQL_DTYPE_REC)
{
@@ -1626,7 +1628,7 @@ for_variable : T_DATUM
$$.row = NULL;
/* check for comma-separated list */
tok = yylex(&yylval, &yylloc, yyscanner);
- plpgsql_push_back_token(tok, &yylval, &yylloc);
+ plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner);
if (tok == ',')
$$.row = (PLpgSQL_datum *)
read_into_scalar_list($$.name,
@@ -1641,19 +1643,19 @@ for_variable : T_DATUM
int tok;
$$.name = $1.ident;
- $$.lineno = plpgsql_location_to_lineno(@1);
+ $$.lineno = plpgsql_location_to_lineno(@1, yyscanner);
$$.scalar = NULL;
$$.row = NULL;
/* check for comma-separated list */
tok = yylex(&yylval, &yylloc, yyscanner);
- plpgsql_push_back_token(tok, &yylval, &yylloc);
+ plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner);
if (tok == ',')
- word_is_not_variable(&($1), @1);
+ word_is_not_variable(&($1), @1, yyscanner);
}
| T_CWORD
{
/* just to give a better message than "syntax error" */
- cword_is_not_variable(&($1), @1);
+ cword_is_not_variable(&($1), @1, yyscanner);
}
;
@@ -1663,7 +1665,7 @@ stmt_foreach_a : opt_loop_label K_FOREACH for_variable foreach_slice K_IN K_ARRA
new = palloc0(sizeof(PLpgSQL_stmt_foreach_a));
new->cmd_type = PLPGSQL_STMT_FOREACH_A;
- new->lineno = plpgsql_location_to_lineno(@2);
+ new->lineno = plpgsql_location_to_lineno(@2, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->label = $1;
new->slice = $4;
@@ -1673,12 +1675,12 @@ stmt_foreach_a : opt_loop_label K_FOREACH for_variable foreach_slice K_IN K_ARRA
if ($3.row)
{
new->varno = $3.row->dno;
- check_assignable($3.row, @3);
+ check_assignable($3.row, @3, yyscanner);
}
else if ($3.scalar)
{
new->varno = $3.scalar->dno;
- check_assignable($3.scalar, @3);
+ check_assignable($3.scalar, @3, yyscanner);
}
else
{
@@ -1688,7 +1690,7 @@ stmt_foreach_a : opt_loop_label K_FOREACH for_variable foreach_slice K_IN K_ARRA
parser_errposition(@3)));
}
- check_labels($1, $8.end_label, $8.end_label_location);
+ check_labels($1, $8.end_label, $8.end_label_location, yyscanner);
plpgsql_ns_pop();
$$ = (PLpgSQL_stmt *) new;
@@ -1713,7 +1715,7 @@ stmt_exit : exit_type opt_label opt_exitcond
new->cmd_type = PLPGSQL_STMT_EXIT;
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->is_exit = $1;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
new->label = $2;
new->cond = $3;
@@ -1788,7 +1790,7 @@ stmt_return : K_RETURN
}
else
{
- plpgsql_push_back_token(tok, &yylval, &yylloc);
+ plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner);
$$ = make_return_stmt(@1, &yylval, &yylloc, yyscanner);
}
}
@@ -1802,7 +1804,7 @@ stmt_raise : K_RAISE
new = palloc(sizeof(PLpgSQL_stmt_raise));
new->cmd_type = PLPGSQL_STMT_RAISE;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->elog_level = ERROR; /* default */
new->condname = NULL;
@@ -1948,7 +1950,7 @@ stmt_assert : K_ASSERT
new = palloc(sizeof(PLpgSQL_stmt_assert));
new->cmd_type = PLPGSQL_STMT_ASSERT;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->cond = read_sql_expression2(',', ';',
@@ -1999,10 +2001,10 @@ stmt_execsql : K_IMPORT
int tok;
tok = yylex(&yylval, &yylloc, yyscanner);
- plpgsql_push_back_token(tok, &yylval, &yylloc);
+ plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner);
if (tok == '=' || tok == COLON_EQUALS ||
tok == '[' || tok == '.')
- word_is_not_variable(&($1), @1);
+ word_is_not_variable(&($1), @1, yyscanner);
$$ = make_execsql_stmt(T_WORD, @1, &($1), &yylval, &yylloc, yyscanner);
}
| T_CWORD
@@ -2010,10 +2012,10 @@ stmt_execsql : K_IMPORT
int tok;
tok = yylex(&yylval, &yylloc, yyscanner);
- plpgsql_push_back_token(tok, &yylval, &yylloc);
+ plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner);
if (tok == '=' || tok == COLON_EQUALS ||
tok == '[' || tok == '.')
- cword_is_not_variable(&($1), @1);
+ cword_is_not_variable(&($1), @1, yyscanner);
$$ = make_execsql_stmt(T_CWORD, @1, NULL, &yylval, &yylloc, yyscanner);
}
;
@@ -2033,7 +2035,7 @@ stmt_dynexecute : K_EXECUTE
new = palloc(sizeof(PLpgSQL_stmt_dynexecute));
new->cmd_type = PLPGSQL_STMT_DYNEXECUTE;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->query = expr;
new->into = false;
@@ -2091,7 +2093,7 @@ stmt_open : K_OPEN cursor_variable
new = palloc0(sizeof(PLpgSQL_stmt_open));
new->cmd_type = PLPGSQL_STMT_OPEN;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->curvar = $2->dno;
new->cursor_options = CURSOR_OPT_FAST_PLAN;
@@ -2148,7 +2150,7 @@ stmt_open : K_OPEN cursor_variable
}
else
{
- plpgsql_push_back_token(tok, &yylval, &yylloc);
+ plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner);
new->query = read_sql_stmt(&yylval, &yylloc, yyscanner);
}
}
@@ -2183,7 +2185,7 @@ stmt_fetch : K_FETCH opt_fetch_direction cursor_variable K_INTO
errmsg("FETCH statement cannot return multiple rows"),
parser_errposition(@1)));
- fetch->lineno = plpgsql_location_to_lineno(@1);
+ fetch->lineno = plpgsql_location_to_lineno(@1, yyscanner);
fetch->target = target;
fetch->curvar = $3->dno;
fetch->is_move = false;
@@ -2196,7 +2198,7 @@ stmt_move : K_MOVE opt_fetch_direction cursor_variable ';'
{
PLpgSQL_stmt_fetch *fetch = $2;
- fetch->lineno = plpgsql_location_to_lineno(@1);
+ fetch->lineno = plpgsql_location_to_lineno(@1, yyscanner);
fetch->curvar = $3->dno;
fetch->is_move = true;
@@ -2216,7 +2218,7 @@ stmt_close : K_CLOSE cursor_variable ';'
new = palloc(sizeof(PLpgSQL_stmt_close));
new->cmd_type = PLPGSQL_STMT_CLOSE;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->curvar = $2->dno;
@@ -2237,7 +2239,7 @@ stmt_commit : K_COMMIT opt_transaction_chain ';'
new = palloc(sizeof(PLpgSQL_stmt_commit));
new->cmd_type = PLPGSQL_STMT_COMMIT;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->chain = $2;
@@ -2251,7 +2253,7 @@ stmt_rollback : K_ROLLBACK opt_transaction_chain ';'
new = palloc(sizeof(PLpgSQL_stmt_rollback));
new->cmd_type = PLPGSQL_STMT_ROLLBACK;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->chain = $2;
@@ -2291,12 +2293,12 @@ cursor_variable : T_DATUM
| T_WORD
{
/* just to give a better message than "syntax error" */
- word_is_not_variable(&($1), @1);
+ word_is_not_variable(&($1), @1, yyscanner);
}
| T_CWORD
{
/* just to give a better message than "syntax error" */
- cword_is_not_variable(&($1), @1);
+ cword_is_not_variable(&($1), @1, yyscanner);
}
;
@@ -2311,7 +2313,7 @@ exception_sect :
* scope of the names extends to the end of the
* current block.
*/
- int lineno = plpgsql_location_to_lineno(@1);
+ int lineno = plpgsql_location_to_lineno(@1, yyscanner);
PLpgSQL_exception_block *new = palloc(sizeof(PLpgSQL_exception_block));
PLpgSQL_variable *var;
@@ -2359,7 +2361,7 @@ proc_exception : K_WHEN proc_conditions K_THEN proc_sect
PLpgSQL_exception *new;
new = palloc0(sizeof(PLpgSQL_exception));
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
new->conditions = $2;
new->action = $4;
@@ -2611,7 +2613,7 @@ tok_is_keyword(int token, union YYSTYPE *lval,
* ie, unrecognized variable.
*/
static void
-word_is_not_variable(PLword *word, int location)
+word_is_not_variable(PLword *word, int location, yyscan_t yyscanner)
{
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
@@ -2622,7 +2624,7 @@ word_is_not_variable(PLword *word, int location)
/* Same, for a CWORD */
static void
-cword_is_not_variable(PLcword *cword, int location)
+cword_is_not_variable(PLcword *cword, int location, yyscan_t yyscanner)
{
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
@@ -2640,9 +2642,9 @@ static void
current_token_is_not_variable(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
{
if (tok == T_WORD)
- word_is_not_variable(&(yylvalp->word), *yyllocp);
+ word_is_not_variable(&(yylvalp->word), *yyllocp, yyscanner);
else if (tok == T_CWORD)
- cword_is_not_variable(&(yylvalp->cword), *yyllocp);
+ cword_is_not_variable(&(yylvalp->cword), *yyllocp, yyscanner);
else
yyerror(yyllocp, yyscanner, "syntax error");
}
@@ -2762,7 +2764,7 @@ read_sql_construct(int until,
parser_errposition(*yyllocp)));
}
/* Remember end+1 location of last accepted token */
- endlocation = *yyllocp + plpgsql_token_length();
+ endlocation = *yyllocp + plpgsql_token_length(yyscanner);
}
plpgsql_IdentifierLookup = save_IdentifierLookup;
@@ -2788,7 +2790,7 @@ read_sql_construct(int until,
* whitespace by hand, but that causes problems if there's a "-- comment"
* in front of said whitespace.)
*/
- plpgsql_append_source_text(&ds, startlocation, endlocation);
+ plpgsql_append_source_text(&ds, startlocation, endlocation, yyscanner);
expr = palloc0(sizeof(PLpgSQL_expr));
expr->query = pstrdup(ds.data);
@@ -2800,7 +2802,7 @@ read_sql_construct(int until,
pfree(ds.data);
if (valid_sql)
- check_sql_expr(expr->query, expr->parseMode, startlocation);
+ check_sql_expr(expr->query, expr->parseMode, startlocation, yyscanner);
return expr;
}
@@ -2910,7 +2912,7 @@ read_datatype(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
yyerror(yyllocp, yyscanner, "syntax error, expected \"]\"");
tok = yylex(yylvalp, yyllocp, yyscanner);
}
- plpgsql_push_back_token(tok, yylvalp, yyllocp);
+ plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
if (is_array)
result = plpgsql_build_datatype_arrayof(result);
@@ -2950,7 +2952,7 @@ read_datatype(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
/* set up ds to contain complete typename text */
initStringInfo(&ds);
- plpgsql_append_source_text(&ds, startlocation, *yyllocp);
+ plpgsql_append_source_text(&ds, startlocation, *yyllocp, yyscanner);
type_name = ds.data;
if (type_name[0] == '\0')
@@ -2960,7 +2962,7 @@ read_datatype(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
pfree(ds.data);
- plpgsql_push_back_token(tok, yylvalp, yyllocp);
+ plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
return result;
}
@@ -3107,12 +3109,12 @@ make_execsql_stmt(int firsttoken, int location, PLword *word, YYSTYPE *yylvalp,
* text, so that locations within the redacted SQL statement still
* line up with those in the original source text.
*/
- plpgsql_append_source_text(&ds, location, into_start_loc);
+ plpgsql_append_source_text(&ds, location, into_start_loc, yyscanner);
appendStringInfoSpaces(&ds, into_end_loc - into_start_loc);
- plpgsql_append_source_text(&ds, into_end_loc, *yyllocp);
+ plpgsql_append_source_text(&ds, into_end_loc, *yyllocp, yyscanner);
}
else
- plpgsql_append_source_text(&ds, location, *yyllocp);
+ plpgsql_append_source_text(&ds, location, *yyllocp, yyscanner);
/* trim any trailing whitespace, for neatness */
while (ds.len > 0 && scanner_isspace(ds.data[ds.len - 1]))
@@ -3127,11 +3129,11 @@ make_execsql_stmt(int firsttoken, int location, PLword *word, YYSTYPE *yylvalp,
expr->ns = plpgsql_ns_top();
pfree(ds.data);
- check_sql_expr(expr->query, expr->parseMode, location);
+ check_sql_expr(expr->query, expr->parseMode, location, yyscanner);
execsql = palloc0(sizeof(PLpgSQL_stmt_execsql));
execsql->cmd_type = PLPGSQL_STMT_EXECSQL;
- execsql->lineno = plpgsql_location_to_lineno(location);
+ execsql->lineno = plpgsql_location_to_lineno(location, yyscanner);
execsql->stmtid = ++plpgsql_curr_compile->nstatements;
execsql->sqlstmt = expr;
execsql->into = have_into;
@@ -3233,7 +3235,7 @@ read_fetch_direction(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
else if (tok == T_DATUM)
{
/* Assume there's no direction clause and tok is a cursor name */
- plpgsql_push_back_token(tok, yylvalp, yyllocp);
+ plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
check_FROM = false;
}
else
@@ -3246,7 +3248,7 @@ read_fetch_direction(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
* will trigger. Perhaps this can be improved someday, but it hardly
* seems worth a lot of work.
*/
- plpgsql_push_back_token(tok, yylvalp, yyllocp);
+ plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
fetch->expr = read_sql_expression2(K_FROM, K_IN,
"FROM or IN",
NULL, yylvalp, yyllocp, yyscanner);
@@ -3294,7 +3296,7 @@ complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM, YYSTYPE *yylvalp
return;
}
- plpgsql_push_back_token(tok, yylvalp, yyllocp);
+ plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
fetch->expr = read_sql_expression2(K_FROM, K_IN,
"FROM or IN",
NULL, yylvalp, yyllocp, yyscanner);
@@ -3310,7 +3312,7 @@ make_return_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yysc
new = palloc0(sizeof(PLpgSQL_stmt_return));
new->cmd_type = PLPGSQL_STMT_RETURN;
- new->lineno = plpgsql_location_to_lineno(location);
+ new->lineno = plpgsql_location_to_lineno(location, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->expr = NULL;
new->retvarno = -1;
@@ -3376,7 +3378,7 @@ make_return_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yysc
* Note that a well-formed expression is _required_ here; anything
* else is a compile-time error.
*/
- plpgsql_push_back_token(tok, yylvalp, yyllocp);
+ plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
new->expr = read_sql_expression(';', ";", yylvalp, yyllocp, yyscanner);
}
}
@@ -3398,7 +3400,7 @@ make_return_next_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t
new = palloc0(sizeof(PLpgSQL_stmt_return_next));
new->cmd_type = PLPGSQL_STMT_RETURN_NEXT;
- new->lineno = plpgsql_location_to_lineno(location);
+ new->lineno = plpgsql_location_to_lineno(location, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->expr = NULL;
new->retvarno = -1;
@@ -3439,7 +3441,7 @@ make_return_next_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t
* Note that a well-formed expression is _required_ here; anything
* else is a compile-time error.
*/
- plpgsql_push_back_token(tok, yylvalp, yyllocp);
+ plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
new->expr = read_sql_expression(';', ";", yylvalp, yyllocp, yyscanner);
}
}
@@ -3462,14 +3464,14 @@ make_return_query_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_
new = palloc0(sizeof(PLpgSQL_stmt_return_query));
new->cmd_type = PLPGSQL_STMT_RETURN_QUERY;
- new->lineno = plpgsql_location_to_lineno(location);
+ new->lineno = plpgsql_location_to_lineno(location, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
/* check for RETURN QUERY EXECUTE */
if ((tok = yylex(yylvalp, yyllocp, yyscanner)) != K_EXECUTE)
{
/* ordinary static query */
- plpgsql_push_back_token(tok, yylvalp, yyllocp);
+ plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
new->query = read_sql_stmt(yylvalp, yyllocp, yyscanner);
}
else
@@ -3506,7 +3508,7 @@ NameOfDatum(PLwdatum *wdatum)
}
static void
-check_assignable(PLpgSQL_datum *datum, int location)
+check_assignable(PLpgSQL_datum *datum, int location, yyscan_t yyscanner)
{
switch (datum->dtype)
{
@@ -3526,7 +3528,7 @@ check_assignable(PLpgSQL_datum *datum, int location)
case PLPGSQL_DTYPE_RECFIELD:
/* assignable if parent record is */
check_assignable(plpgsql_Datums[((PLpgSQL_recfield *) datum)->recparentno],
- location);
+ location, yyscanner);
break;
default:
elog(ERROR, "unrecognized dtype: %d", datum->dtype);
@@ -3568,7 +3570,7 @@ read_into_target(PLpgSQL_variable **target, bool *strict, YYSTYPE *yylvalp, YYLT
if (yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_REC)
{
- check_assignable(yylvalp->wdatum.datum, *yyllocp);
+ check_assignable(yylvalp->wdatum.datum, *yyllocp, yyscanner);
*target = (PLpgSQL_variable *) yylvalp->wdatum.datum;
if ((tok = yylex(yylvalp, yyllocp, yyscanner)) == ',')
@@ -3576,7 +3578,7 @@ read_into_target(PLpgSQL_variable **target, bool *strict, YYSTYPE *yylvalp, YYLT
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("record variable cannot be part of multiple-item INTO list"),
parser_errposition(*yyllocp)));
- plpgsql_push_back_token(tok, yylvalp, yyllocp);
+ plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
}
else
{
@@ -3611,7 +3613,7 @@ read_into_scalar_list(char *initial_name,
PLpgSQL_row *row;
int tok;
- check_assignable(initial_datum, initial_location);
+ check_assignable(initial_datum, initial_location, yyscanner);
fieldnames[0] = initial_name;
varnos[0] = initial_datum->dno;
nfields = 1;
@@ -3629,7 +3631,7 @@ read_into_scalar_list(char *initial_name,
switch (tok)
{
case T_DATUM:
- check_assignable(yylvalp->wdatum.datum, *yyllocp);
+ check_assignable(yylvalp->wdatum.datum, *yyllocp, yyscanner);
if (yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_REC)
ereport(ERROR,
@@ -3651,12 +3653,12 @@ read_into_scalar_list(char *initial_name,
* We read an extra, non-comma token from yylex(), so push it back onto
* the input stream
*/
- plpgsql_push_back_token(tok, yylvalp, yyllocp);
+ plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
row = palloc0(sizeof(PLpgSQL_row));
row->dtype = PLPGSQL_DTYPE_ROW;
row->refname = "(unnamed row)";
- row->lineno = plpgsql_location_to_lineno(initial_location);
+ row->lineno = plpgsql_location_to_lineno(initial_location, yyscanner);
row->rowtupdesc = NULL;
row->nfields = nfields;
row->fieldnames = palloc(sizeof(char *) * nfields);
@@ -3682,11 +3684,11 @@ read_into_scalar_list(char *initial_name,
static PLpgSQL_row *
make_scalar_list1(char *initial_name,
PLpgSQL_datum *initial_datum,
- int lineno, int location)
+ int lineno, int location, yyscan_t yyscanner)
{
PLpgSQL_row *row;
- check_assignable(initial_datum, location);
+ check_assignable(initial_datum, location, yyscanner);
row = palloc0(sizeof(PLpgSQL_row));
row->dtype = PLPGSQL_DTYPE_ROW;
@@ -3727,7 +3729,7 @@ make_scalar_list1(char *initial_name,
* If no error cursor is provided, we'll just point at "location".
*/
static void
-check_sql_expr(const char *stmt, RawParseMode parseMode, int location)
+check_sql_expr(const char *stmt, RawParseMode parseMode, int location, yyscan_t yyscanner)
{
sql_error_callback_arg cbarg;
ErrorContextCallback syntax_errcontext;
@@ -3737,6 +3739,7 @@ check_sql_expr(const char *stmt, RawParseMode parseMode, int location)
return;
cbarg.location = location;
+ cbarg.yyscanner = yyscanner;
syntax_errcontext.callback = plpgsql_sql_error_callback;
syntax_errcontext.arg = &cbarg;
@@ -3755,6 +3758,7 @@ static void
plpgsql_sql_error_callback(void *arg)
{
sql_error_callback_arg *cbarg = (sql_error_callback_arg *) arg;
+ yyscan_t yyscanner = cbarg->yyscanner;
int errpos;
/*
@@ -3823,7 +3827,7 @@ parse_datatype(const char *string, int location)
* Check block starting and ending labels match.
*/
static void
-check_labels(const char *start_label, const char *end_label, int end_location)
+check_labels(const char *start_label, const char *end_label, int end_location, yyscan_t yyscanner)
{
if (end_label)
{
@@ -4119,13 +4123,13 @@ check_raise_parameters(PLpgSQL_stmt_raise *stmt)
*/
static PLpgSQL_stmt *
make_case(int location, PLpgSQL_expr *t_expr,
- List *case_when_list, List *else_stmts)
+ List *case_when_list, List *else_stmts, yyscan_t yyscanner)
{
PLpgSQL_stmt_case *new;
new = palloc(sizeof(PLpgSQL_stmt_case));
new->cmd_type = PLPGSQL_STMT_CASE;
- new->lineno = plpgsql_location_to_lineno(location);
+ new->lineno = plpgsql_location_to_lineno(location, yyscanner);
new->stmtid = ++plpgsql_curr_compile->nstatements;
new->t_expr = t_expr;
new->t_varno = 0;
diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c
index abf2d40c07a..e3cff48b322 100644
--- a/src/pl/plpgsql/src/pl_scanner.c
+++ b/src/pl/plpgsql/src/pl_scanner.c
@@ -95,41 +95,56 @@ typedef struct
int leng; /* length in bytes */
} TokenAuxData;
+#define MAX_PUSHBACKS 4
+
/*
- * Scanner working state. At some point we might wish to fold all this
- * into a YY_EXTRA struct. For the moment, there is no need for plpgsql's
- * lexer to be re-entrant, and the notational burden of passing a yyscanner
- * pointer around is great enough to not want to do it without need.
+ * Scanner working state.
*/
+struct plpgsql_yy_extra_type
+{
+ /* The stuff the core lexer needs */
+ core_yy_extra_type core_yy_extra;
-/* The stuff the core lexer needs */
-static core_yy_extra_type core_yy_extra;
-
-/* The original input string */
-static const char *scanorig;
-
-/* Current token's length (corresponds to plpgsql_yylval and plpgsql_yylloc) */
-static int plpgsql_yyleng;
+ /* The original input string */
+ const char *scanorig;
-/* Current token's code (corresponds to plpgsql_yylval and plpgsql_yylloc) */
-static int plpgsql_yytoken;
+ /*
+ * Current token's length (corresponds to plpgsql_yylval and
+ * plpgsql_yylloc)
+ */
+ int plpgsql_yyleng;
-/* Token pushback stack */
-#define MAX_PUSHBACKS 4
+ /* Current token's code (corresponds to plpgsql_yylval and plpgsql_yylloc) */
+ int plpgsql_yytoken;
-static int num_pushbacks;
-static int pushback_token[MAX_PUSHBACKS];
-static TokenAuxData pushback_auxdata[MAX_PUSHBACKS];
+ /* Token pushback stack */
+ int num_pushbacks;
+ int pushback_token[MAX_PUSHBACKS];
+ TokenAuxData pushback_auxdata[MAX_PUSHBACKS];
-/* State for plpgsql_location_to_lineno() */
-static const char *cur_line_start;
-static const char *cur_line_end;
-static int cur_line_num;
+ /* State for plpgsql_location_to_lineno() */
+ const char *cur_line_start;
+ const char *cur_line_end;
+ int cur_line_num;
+};
/* Internal functions */
static int internal_yylex(TokenAuxData *auxdata, yyscan_t yyscanner);
-static void push_back_token(int token, TokenAuxData *auxdata);
-static void location_lineno_init(void);
+static void push_back_token(int token, TokenAuxData *auxdata, yyscan_t yyscanner);
+static void location_lineno_init(yyscan_t yyscanner);
+
+/*
+ * This is normally provided by the generated flex code, but we don't have
+ * that here, so we make a minimal version ourselves.
+ */
+struct yyguts_t
+{
+ struct plpgsql_yy_extra_type *yyextra_r;
+};
+
+/* see scan.l */
+#undef yyextra
+#define yyextra (((struct yyguts_t *) yyscanner)->yyextra_r)
/*
@@ -189,8 +204,8 @@ plpgsql_yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
else
{
/* not A.B.C, so just process A.B */
- push_back_token(tok5, &aux5);
- push_back_token(tok4, &aux4);
+ push_back_token(tok5, &aux5, yyscanner);
+ push_back_token(tok4, &aux4, yyscanner);
if (plpgsql_parse_dblword(aux1.lval.str,
aux3.lval.str,
&aux1.lval.wdatum,
@@ -205,7 +220,7 @@ plpgsql_yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
else
{
/* not A.B.C, so just process A.B */
- push_back_token(tok4, &aux4);
+ push_back_token(tok4, &aux4, yyscanner);
if (plpgsql_parse_dblword(aux1.lval.str,
aux3.lval.str,
&aux1.lval.wdatum,
@@ -220,10 +235,10 @@ plpgsql_yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
else
{
/* not A.B, so just process A */
- push_back_token(tok3, &aux3);
- push_back_token(tok2, &aux2);
+ push_back_token(tok3, &aux3, yyscanner);
+ push_back_token(tok2, &aux2, yyscanner);
if (plpgsql_parse_word(aux1.lval.str,
- core_yy_extra.scanbuf + aux1.lloc,
+ yyextra->core_yy_extra.scanbuf + aux1.lloc,
true,
&aux1.lval.wdatum,
&aux1.lval.word))
@@ -243,7 +258,7 @@ plpgsql_yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
else
{
/* not A.B, so just process A */
- push_back_token(tok2, &aux2);
+ push_back_token(tok2, &aux2, yyscanner);
/*
* See if it matches a variable name, except in the context where
@@ -263,8 +278,8 @@ plpgsql_yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
* non-variable cases.
*/
if (plpgsql_parse_word(aux1.lval.str,
- core_yy_extra.scanbuf + aux1.lloc,
- (!AT_STMT_START(plpgsql_yytoken) ||
+ yyextra->core_yy_extra.scanbuf + aux1.lloc,
+ (!AT_STMT_START(yyextra->plpgsql_yytoken) ||
(tok2 == '=' || tok2 == COLON_EQUALS ||
tok2 == '[')),
&aux1.lval.wdatum,
@@ -298,8 +313,8 @@ plpgsql_yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
*yylvalp = aux1.lval;
*yyllocp = aux1.lloc;
- plpgsql_yyleng = aux1.leng;
- plpgsql_yytoken = tok1;
+ yyextra->plpgsql_yyleng = aux1.leng;
+ yyextra->plpgsql_yytoken = tok1;
return tok1;
}
@@ -309,9 +324,9 @@ plpgsql_yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
* In the case of compound tokens, the length includes all the parts.
*/
int
-plpgsql_token_length(void)
+plpgsql_token_length(yyscan_t yyscanner)
{
- return plpgsql_yyleng;
+ return yyextra->plpgsql_yyleng;
}
/*
@@ -326,11 +341,11 @@ internal_yylex(TokenAuxData *auxdata, yyscan_t yyscanner)
int token;
const char *yytext;
- if (num_pushbacks > 0)
+ if (yyextra->num_pushbacks > 0)
{
- num_pushbacks--;
- token = pushback_token[num_pushbacks];
- *auxdata = pushback_auxdata[num_pushbacks];
+ yyextra->num_pushbacks--;
+ token = yyextra->pushback_token[yyextra->num_pushbacks];
+ *auxdata = yyextra->pushback_auxdata[yyextra->num_pushbacks];
}
else
{
@@ -339,7 +354,7 @@ internal_yylex(TokenAuxData *auxdata, yyscan_t yyscanner)
yyscanner);
/* remember the length of yytext before it gets changed */
- yytext = core_yy_extra.scanbuf + auxdata->lloc;
+ yytext = yyextra->core_yy_extra.scanbuf + auxdata->lloc;
auxdata->leng = strlen(yytext);
/* Check for << >> and #, which the core considers operators */
@@ -367,13 +382,13 @@ internal_yylex(TokenAuxData *auxdata, yyscan_t yyscanner)
* Push back a token to be re-read by next internal_yylex() call.
*/
static void
-push_back_token(int token, TokenAuxData *auxdata)
+push_back_token(int token, TokenAuxData *auxdata, yyscan_t yyscanner)
{
- if (num_pushbacks >= MAX_PUSHBACKS)
+ if (yyextra->num_pushbacks >= MAX_PUSHBACKS)
elog(ERROR, "too many tokens pushed back");
- pushback_token[num_pushbacks] = token;
- pushback_auxdata[num_pushbacks] = *auxdata;
- num_pushbacks++;
+ yyextra->pushback_token[yyextra->num_pushbacks] = token;
+ yyextra->pushback_auxdata[yyextra->num_pushbacks] = *auxdata;
+ yyextra->num_pushbacks++;
}
/*
@@ -383,14 +398,14 @@ push_back_token(int token, TokenAuxData *auxdata)
* is not a good idea to push back a token code other than what you read.
*/
void
-plpgsql_push_back_token(int token, YYSTYPE *yylvalp, YYLTYPE *yyllocp)
+plpgsql_push_back_token(int token, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
{
TokenAuxData auxdata;
auxdata.lval = *yylvalp;
auxdata.lloc = *yyllocp;
- auxdata.leng = plpgsql_yyleng;
- push_back_token(token, &auxdata);
+ auxdata.leng = yyextra->plpgsql_yyleng;
+ push_back_token(token, &auxdata, yyscanner);
}
/*
@@ -418,10 +433,11 @@ plpgsql_token_is_unreserved_keyword(int token)
*/
void
plpgsql_append_source_text(StringInfo buf,
- int startlocation, int endlocation)
+ int startlocation, int endlocation,
+ yyscan_t yyscanner)
{
Assert(startlocation <= endlocation);
- appendBinaryStringInfo(buf, scanorig + startlocation,
+ appendBinaryStringInfo(buf, yyextra->scanorig + startlocation,
endlocation - startlocation);
}
@@ -439,7 +455,7 @@ plpgsql_peek(yyscan_t yyscanner)
TokenAuxData aux1;
tok1 = internal_yylex(&aux1, yyscanner);
- push_back_token(tok1, &aux1);
+ push_back_token(tok1, &aux1, yyscanner);
return tok1;
}
@@ -469,8 +485,8 @@ plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc, yyscan_t y
if (tok2_loc)
*tok2_loc = aux2.lloc;
- push_back_token(tok2, &aux2);
- push_back_token(tok1, &aux1);
+ push_back_token(tok2, &aux2, yyscanner);
+ push_back_token(tok1, &aux1, yyscanner);
}
/*
@@ -485,19 +501,19 @@ plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc, yyscan_t y
* to still be available.
*/
int
-plpgsql_scanner_errposition(int location)
+plpgsql_scanner_errposition(int location, yyscan_t yyscanner)
{
int pos;
- if (location < 0 || scanorig == NULL)
+ if (location < 0 || yyextra->scanorig == NULL)
return 0; /* no-op if location is unknown */
/* Convert byte offset to character number */
- pos = pg_mbstrlen_with_len(scanorig, location) + 1;
+ pos = pg_mbstrlen_with_len(yyextra->scanorig, location) + 1;
/* And pass it to the ereport mechanism */
(void) internalerrposition(pos);
/* Also pass the function body string */
- return internalerrquery(scanorig);
+ return internalerrquery(yyextra->scanorig);
}
/*
@@ -514,7 +530,7 @@ plpgsql_scanner_errposition(int location)
void
plpgsql_yyerror(YYLTYPE *yyllocp, yyscan_t yyscanner, const char *message)
{
- char *yytext = core_yy_extra.scanbuf + *yyllocp;
+ char *yytext = yyextra->core_yy_extra.scanbuf + *yyllocp;
if (*yytext == '\0')
{
@@ -522,7 +538,7 @@ plpgsql_yyerror(YYLTYPE *yyllocp, yyscan_t yyscanner, const char *message)
(errcode(ERRCODE_SYNTAX_ERROR),
/* translator: %s is typically the translation of "syntax error" */
errmsg("%s at end of input", _(message)),
- plpgsql_scanner_errposition(*yyllocp)));
+ plpgsql_scanner_errposition(*yyllocp, yyscanner)));
}
else
{
@@ -532,13 +548,13 @@ plpgsql_yyerror(YYLTYPE *yyllocp, yyscan_t yyscanner, const char *message)
* only the single token here. This modifies scanbuf but we no longer
* care about that.
*/
- yytext[plpgsql_yyleng] = '\0';
+ yytext[yyextra->plpgsql_yyleng] = '\0';
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
/* translator: first %s is typically the translation of "syntax error" */
errmsg("%s at or near \"%s\"", _(message), yytext),
- plpgsql_scanner_errposition(*yyllocp)));
+ plpgsql_scanner_errposition(*yyllocp, yyscanner)));
}
}
@@ -551,43 +567,43 @@ plpgsql_yyerror(YYLTYPE *yyllocp, yyscan_t yyscanner, const char *message)
* of the "current" line.
*/
int
-plpgsql_location_to_lineno(int location)
+plpgsql_location_to_lineno(int location, yyscan_t yyscanner)
{
const char *loc;
- if (location < 0 || scanorig == NULL)
+ if (location < 0 || yyextra->scanorig == NULL)
return 0; /* garbage in, garbage out */
- loc = scanorig + location;
+ loc = yyextra->scanorig + location;
/* be correct, but not fast, if input location goes backwards */
- if (loc < cur_line_start)
- location_lineno_init();
+ if (loc < yyextra->cur_line_start)
+ location_lineno_init(yyscanner);
- while (cur_line_end != NULL && loc > cur_line_end)
+ while (yyextra->cur_line_end != NULL && loc > yyextra->cur_line_end)
{
- cur_line_start = cur_line_end + 1;
- cur_line_num++;
- cur_line_end = strchr(cur_line_start, '\n');
+ yyextra->cur_line_start = yyextra->cur_line_end + 1;
+ yyextra->cur_line_num++;
+ yyextra->cur_line_end = strchr(yyextra->cur_line_start, '\n');
}
- return cur_line_num;
+ return yyextra->cur_line_num;
}
/* initialize or reset the state for plpgsql_location_to_lineno */
static void
-location_lineno_init(void)
+location_lineno_init(yyscan_t yyscanner)
{
- cur_line_start = scanorig;
- cur_line_num = 1;
+ yyextra->cur_line_start = yyextra->scanorig;
+ yyextra->cur_line_num = 1;
- cur_line_end = strchr(cur_line_start, '\n');
+ yyextra->cur_line_end = strchr(yyextra->cur_line_start, '\n');
}
/* return the most recently computed lineno */
int
-plpgsql_latest_lineno(void)
+plpgsql_latest_lineno(yyscan_t yyscanner)
{
- return cur_line_num;
+ return yyextra->cur_line_num;
}
@@ -602,9 +618,10 @@ yyscan_t
plpgsql_scanner_init(const char *str)
{
yyscan_t yyscanner;
+ struct plpgsql_yy_extra_type *yyext = palloc0_object(struct plpgsql_yy_extra_type);
/* Start up the core scanner */
- yyscanner = scanner_init(str, &core_yy_extra,
+ yyscanner = scanner_init(str, (core_yy_extra_type *) yyext,
&ReservedPLKeywords, ReservedPLKeywordTokens);
/*
@@ -613,15 +630,15 @@ plpgsql_scanner_init(const char *str)
* yytext points into scanbuf, we rely on being able to apply locations
* (offsets from string start) to scanorig as well.
*/
- scanorig = str;
+ yyext->scanorig = str;
/* Other setup */
plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
- plpgsql_yytoken = 0;
+ yyext->plpgsql_yytoken = 0;
- num_pushbacks = 0;
+ yyext->num_pushbacks = 0;
- location_lineno_init();
+ location_lineno_init(yyscanner);
return yyscanner;
}
@@ -634,6 +651,4 @@ plpgsql_scanner_finish(yyscan_t yyscanner)
{
/* release storage */
scanner_finish(yyscanner);
- /* avoid leaving any dangling pointers */
- scanorig = NULL;
}
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 151ae7943df..2562c816a1b 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -1322,18 +1322,19 @@ union YYSTYPE;
typedef void *yyscan_t;
#endif
extern int plpgsql_yylex(union YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner);
-extern int plpgsql_token_length(void);
-extern void plpgsql_push_back_token(int token, union YYSTYPE *yylvalp, YYLTYPE *yyllocp);
+extern int plpgsql_token_length(yyscan_t yyscanner);
+extern void plpgsql_push_back_token(int token, union YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner);
extern bool plpgsql_token_is_unreserved_keyword(int token);
extern void plpgsql_append_source_text(StringInfo buf,
- int startlocation, int endlocation);
+ int startlocation, int endlocation,
+ yyscan_t yyscanner);
extern int plpgsql_peek(yyscan_t yyscanner);
extern void plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc,
int *tok2_loc, yyscan_t yyscanner);
-extern int plpgsql_scanner_errposition(int location);
+extern int plpgsql_scanner_errposition(int location, yyscan_t yyscanner);
extern void plpgsql_yyerror(YYLTYPE *yyllocp, yyscan_t yyscanner, const char *message) pg_attribute_noreturn();
-extern int plpgsql_location_to_lineno(int location);
-extern int plpgsql_latest_lineno(void);
+extern int plpgsql_location_to_lineno(int location, yyscan_t yyscanner);
+extern int plpgsql_latest_lineno(yyscan_t yyscanner);
extern yyscan_t plpgsql_scanner_init(const char *str);
extern void plpgsql_scanner_finish(yyscan_t yyscanner);
--
2.47.1