Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7b27f5f

Browse files
committed
plpgsql: pure parser and reentrant scanner
The plpgsql scanner is a wrapper around the core scanner, which already uses the flex %option reentrant. This patch only pushes up a few levels the place where the scanner handle is allocated. Before, it was allocated in pl_scanner.c in a global variable, so to the outside the scanner was not reentrant. Now, it is allocated in pl_comp.c and is passed as an argument to yyparse(), similar to how it is handled in other reentrant scanners. Also use flex yyextra to handle context information, instead of global variables. Again, this uses the existing yyextra support in the core scanner. This complements the other changes to make the scanner reentrant. The bison option %pure-parser is used to make the generated parser pure. This happens in the usual way, since plpgsql has its own bison parser definition. Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi> Discussion: https://www.postgresql.org/message-id/flat/eb6faeac-2a8a-4b69-9189-c33c520e5b7b@eisentraut.org
1 parent b18464f commit 7b27f5f

File tree

5 files changed

+598
-537
lines changed

5 files changed

+598
-537
lines changed

src/pl/plpgsql/src/nls.mk

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ GETTEXT_FILES = pl_comp.c \
66
pl_funcs.c \
77
pl_handler.c \
88
pl_scanner.c
9-
GETTEXT_TRIGGERS = $(BACKEND_COMMON_GETTEXT_TRIGGERS) yyerror plpgsql_yyerror
9+
GETTEXT_TRIGGERS = $(BACKEND_COMMON_GETTEXT_TRIGGERS) yyerror:3 plpgsql_yyerror:3
1010
GETTEXT_FLAGS = $(BACKEND_COMMON_GETTEXT_FLAGS)

src/pl/plpgsql/src/pl_comp.c

+30-17
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,12 @@ plpgsql_compile(FunctionCallInfo fcinfo, bool forValidator)
237237
return function;
238238
}
239239

240+
struct compile_error_callback_arg
241+
{
242+
const char *proc_source;
243+
yyscan_t yyscanner;
244+
};
245+
240246
/*
241247
* This is the slow part of plpgsql_compile().
242248
*
@@ -269,13 +275,15 @@ do_compile(FunctionCallInfo fcinfo,
269275
Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);
270276
bool is_dml_trigger = CALLED_AS_TRIGGER(fcinfo);
271277
bool is_event_trigger = CALLED_AS_EVENT_TRIGGER(fcinfo);
278+
yyscan_t scanner;
272279
Datum prosrcdatum;
273280
char *proc_source;
274281
HeapTuple typeTup;
275282
Form_pg_type typeStruct;
276283
PLpgSQL_variable *var;
277284
PLpgSQL_rec *rec;
278285
int i;
286+
struct compile_error_callback_arg cbarg;
279287
ErrorContextCallback plerrcontext;
280288
int parse_rc;
281289
Oid rettypeid;
@@ -290,21 +298,21 @@ do_compile(FunctionCallInfo fcinfo,
290298
MemoryContext func_cxt;
291299

292300
/*
293-
* Setup the scanner input and error info. We assume that this function
294-
* cannot be invoked recursively, so there's no need to save and restore
295-
* the static variables used here.
301+
* Setup the scanner input and error info.
296302
*/
297303
prosrcdatum = SysCacheGetAttrNotNull(PROCOID, procTup, Anum_pg_proc_prosrc);
298304
proc_source = TextDatumGetCString(prosrcdatum);
299-
plpgsql_scanner_init(proc_source);
305+
scanner = plpgsql_scanner_init(proc_source);
300306

301307
plpgsql_error_funcname = pstrdup(NameStr(procStruct->proname));
302308

303309
/*
304310
* Setup error traceback support for ereport()
305311
*/
312+
cbarg.proc_source = forValidator ? proc_source : NULL;
313+
cbarg.yyscanner = scanner;
306314
plerrcontext.callback = plpgsql_compile_error_callback;
307-
plerrcontext.arg = forValidator ? proc_source : NULL;
315+
plerrcontext.arg = &cbarg;
308316
plerrcontext.previous = error_context_stack;
309317
error_context_stack = &plerrcontext;
310318

@@ -779,12 +787,12 @@ do_compile(FunctionCallInfo fcinfo,
779787
/*
780788
* Now parse the function's text
781789
*/
782-
parse_rc = plpgsql_yyparse();
790+
parse_rc = plpgsql_yyparse(scanner);
783791
if (parse_rc != 0)
784792
elog(ERROR, "plpgsql parser returned %d", parse_rc);
785793
function->action = plpgsql_parse_result;
786794

787-
plpgsql_scanner_finish();
795+
plpgsql_scanner_finish(scanner);
788796
pfree(proc_source);
789797

790798
/*
@@ -841,27 +849,29 @@ do_compile(FunctionCallInfo fcinfo,
841849
PLpgSQL_function *
842850
plpgsql_compile_inline(char *proc_source)
843851
{
852+
yyscan_t scanner;
844853
char *func_name = "inline_code_block";
845854
PLpgSQL_function *function;
855+
struct compile_error_callback_arg cbarg;
846856
ErrorContextCallback plerrcontext;
847857
PLpgSQL_variable *var;
848858
int parse_rc;
849859
MemoryContext func_cxt;
850860

851861
/*
852-
* Setup the scanner input and error info. We assume that this function
853-
* cannot be invoked recursively, so there's no need to save and restore
854-
* the static variables used here.
862+
* Setup the scanner input and error info.
855863
*/
856-
plpgsql_scanner_init(proc_source);
864+
scanner = plpgsql_scanner_init(proc_source);
857865

858866
plpgsql_error_funcname = func_name;
859867

860868
/*
861869
* Setup error traceback support for ereport()
862870
*/
871+
cbarg.proc_source = proc_source;
872+
cbarg.yyscanner = scanner;
863873
plerrcontext.callback = plpgsql_compile_error_callback;
864-
plerrcontext.arg = proc_source;
874+
plerrcontext.arg = &cbarg;
865875
plerrcontext.previous = error_context_stack;
866876
error_context_stack = &plerrcontext;
867877

@@ -935,12 +945,12 @@ plpgsql_compile_inline(char *proc_source)
935945
/*
936946
* Now parse the function's text
937947
*/
938-
parse_rc = plpgsql_yyparse();
948+
parse_rc = plpgsql_yyparse(scanner);
939949
if (parse_rc != 0)
940950
elog(ERROR, "plpgsql parser returned %d", parse_rc);
941951
function->action = plpgsql_parse_result;
942952

943-
plpgsql_scanner_finish();
953+
plpgsql_scanner_finish(scanner);
944954

945955
/*
946956
* If it returns VOID (always true at the moment), we allow control to
@@ -978,13 +988,16 @@ plpgsql_compile_inline(char *proc_source)
978988
static void
979989
plpgsql_compile_error_callback(void *arg)
980990
{
981-
if (arg)
991+
struct compile_error_callback_arg *cbarg = (struct compile_error_callback_arg *) arg;
992+
yyscan_t yyscanner = cbarg->yyscanner;
993+
994+
if (cbarg->proc_source)
982995
{
983996
/*
984997
* Try to convert syntax error position to reference text of original
985998
* CREATE FUNCTION or DO command.
986999
*/
987-
if (function_parse_error_transpose((const char *) arg))
1000+
if (function_parse_error_transpose(cbarg->proc_source))
9881001
return;
9891002

9901003
/*
@@ -995,7 +1008,7 @@ plpgsql_compile_error_callback(void *arg)
9951008

9961009
if (plpgsql_error_funcname)
9971010
errcontext("compilation of PL/pgSQL function \"%s\" near line %d",
998-
plpgsql_error_funcname, plpgsql_latest_lineno());
1011+
plpgsql_error_funcname, plpgsql_latest_lineno(yyscanner));
9991012
}
10001013

10011014

0 commit comments

Comments
 (0)