Commit f2b7692e authored by Tom Lane's avatar Tom Lane

Rearrange plpgsql parsing to simplify and speed it up a bit.

* Pull the responsibility for %TYPE and %ROWTYPE out of the scanner,
letting read_datatype manage it instead.

* Avoid unnecessary scanner-driven lookups of plpgsql variables in
places where it's not needed, which is actually most of the time;
we do not need it in DECLARE sections nor in text that is a SQL
query or expression.

* Rationalize the set of token types returned by the scanner:
distinguishing T_SCALAR, T_RECORD, T_ROW seems to complicate the grammar
in more places than it simplifies it, so merge these into one
token type T_DATUM; but split T_ERROR into T_DBLWORD and T_TRIPWORD
for clarity and simplicity of later processing.

Some of this will need to be revisited again when we try to make
plpgsql use the core scanner, but this patch gets some of the bigger
stumbling blocks out of the way.
parent b79f49c7
This diff is collapsed.
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.84 2009/11/06 18:37:54 tgl Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.85 2009/11/07 00:52:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
* ---------- * ----------
*/ */
static PLpgSQL_nsitem *ns_top = NULL; static PLpgSQL_nsitem *ns_top = NULL;
static bool ns_localmode = false;
/* ---------- /* ----------
...@@ -46,32 +45,6 @@ void ...@@ -46,32 +45,6 @@ void
plpgsql_ns_init(void) plpgsql_ns_init(void)
{ {
ns_top = NULL; ns_top = NULL;
ns_localmode = false;
}
/* ----------
* plpgsql_ns_setlocal Tell plpgsql_ns_lookup whether to
* look into the current level only.
*
* This is a crock, but in the current design we need it because scan.l
* initiates name lookup, and the scanner does not know whether we are
* examining a name being declared in a DECLARE section. For that case
* we only want to know if there is a conflicting name earlier in the
* same DECLARE section. So the grammar must temporarily set local mode
* before scanning decl_varnames. This should eventually go away in favor
* of a localmode argument to plpgsql_ns_lookup, or perhaps some less
* indirect method of dealing with duplicate namespace entries.
* ----------
*/
bool
plpgsql_ns_setlocal(bool flag)
{
bool oldstate;
oldstate = ns_localmode;
ns_localmode = flag;
return oldstate;
} }
...@@ -140,6 +113,8 @@ plpgsql_ns_additem(int itemtype, int itemno, const char *name) ...@@ -140,6 +113,8 @@ plpgsql_ns_additem(int itemtype, int itemno, const char *name)
* *
* Note that this only searches for variables, not labels. * Note that this only searches for variables, not labels.
* *
* If localmode is TRUE, only the topmost block level is searched.
*
* name1 must be non-NULL. Pass NULL for name2 and/or name3 if parsing a name * name1 must be non-NULL. Pass NULL for name2 and/or name3 if parsing a name
* with fewer than three components. * with fewer than three components.
* *
...@@ -154,7 +129,7 @@ plpgsql_ns_additem(int itemtype, int itemno, const char *name) ...@@ -154,7 +129,7 @@ plpgsql_ns_additem(int itemtype, int itemno, const char *name)
* ---------- * ----------
*/ */
PLpgSQL_nsitem * PLpgSQL_nsitem *
plpgsql_ns_lookup(PLpgSQL_nsitem *ns_cur, plpgsql_ns_lookup(PLpgSQL_nsitem *ns_cur, bool localmode,
const char *name1, const char *name2, const char *name3, const char *name1, const char *name2, const char *name3,
int *names_used) int *names_used)
{ {
...@@ -201,7 +176,7 @@ plpgsql_ns_lookup(PLpgSQL_nsitem *ns_cur, ...@@ -201,7 +176,7 @@ plpgsql_ns_lookup(PLpgSQL_nsitem *ns_cur,
} }
} }
if (ns_localmode) if (localmode)
break; /* do not look into upper levels */ break; /* do not look into upper levels */
ns_cur = nsitem->prev; ns_cur = nsitem->prev;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.120 2009/11/06 18:37:54 tgl Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.121 2009/11/07 00:52:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -773,6 +773,7 @@ typedef struct ...@@ -773,6 +773,7 @@ typedef struct
**********************************************************************/ **********************************************************************/
extern bool plpgsql_DumpExecTree; extern bool plpgsql_DumpExecTree;
extern bool plpgsql_LookupIdentifiers;
extern bool plpgsql_SpaceScanned; extern bool plpgsql_SpaceScanned;
extern int plpgsql_nDatums; extern int plpgsql_nDatums;
extern PLpgSQL_datum **plpgsql_Datums; extern PLpgSQL_datum **plpgsql_Datums;
...@@ -807,11 +808,11 @@ extern void plpgsql_parser_setup(struct ParseState *pstate, ...@@ -807,11 +808,11 @@ extern void plpgsql_parser_setup(struct ParseState *pstate,
extern int plpgsql_parse_word(const char *word); extern int plpgsql_parse_word(const char *word);
extern int plpgsql_parse_dblword(const char *word); extern int plpgsql_parse_dblword(const char *word);
extern int plpgsql_parse_tripword(const char *word); extern int plpgsql_parse_tripword(const char *word);
extern int plpgsql_parse_wordtype(char *word); extern PLpgSQL_type *plpgsql_parse_wordtype(const char *word);
extern int plpgsql_parse_dblwordtype(char *word); extern PLpgSQL_type *plpgsql_parse_dblwordtype(const char *word);
extern int plpgsql_parse_tripwordtype(char *word); extern PLpgSQL_type *plpgsql_parse_tripwordtype(const char *word);
extern int plpgsql_parse_wordrowtype(char *word); extern PLpgSQL_type *plpgsql_parse_wordrowtype(const char *word);
extern int plpgsql_parse_dblwordrowtype(char *word); extern PLpgSQL_type *plpgsql_parse_dblwordrowtype(const char *word);
extern PLpgSQL_type *plpgsql_parse_datatype(const char *string); extern PLpgSQL_type *plpgsql_parse_datatype(const char *string);
extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod); extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod);
extern PLpgSQL_variable *plpgsql_build_variable(const char *refname, int lineno, extern PLpgSQL_variable *plpgsql_build_variable(const char *refname, int lineno,
...@@ -857,12 +858,11 @@ extern Oid exec_get_rec_fieldtype(PLpgSQL_rec *rec, const char *fieldname, ...@@ -857,12 +858,11 @@ extern Oid exec_get_rec_fieldtype(PLpgSQL_rec *rec, const char *fieldname,
* ---------- * ----------
*/ */
extern void plpgsql_ns_init(void); extern void plpgsql_ns_init(void);
extern bool plpgsql_ns_setlocal(bool flag);
extern void plpgsql_ns_push(const char *label); extern void plpgsql_ns_push(const char *label);
extern void plpgsql_ns_pop(void); extern void plpgsql_ns_pop(void);
extern PLpgSQL_nsitem *plpgsql_ns_top(void); extern PLpgSQL_nsitem *plpgsql_ns_top(void);
extern void plpgsql_ns_additem(int itemtype, int itemno, const char *name); extern void plpgsql_ns_additem(int itemtype, int itemno, const char *name);
extern PLpgSQL_nsitem *plpgsql_ns_lookup(PLpgSQL_nsitem *ns_cur, extern PLpgSQL_nsitem *plpgsql_ns_lookup(PLpgSQL_nsitem *ns_cur, bool localmode,
const char *name1, const char *name2, const char *name1, const char *name2,
const char *name3, int *names_used); const char *name3, int *names_used);
extern PLpgSQL_nsitem *plpgsql_ns_lookup_label(PLpgSQL_nsitem *ns_cur, extern PLpgSQL_nsitem *plpgsql_ns_lookup_label(PLpgSQL_nsitem *ns_cur,
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.73 2009/11/05 16:58:36 tgl Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.74 2009/11/07 00:52:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -43,6 +43,7 @@ static int cur_line_num; ...@@ -43,6 +43,7 @@ static int cur_line_num;
static int xcdepth = 0; /* depth of nesting in slash-star comments */ static int xcdepth = 0; /* depth of nesting in slash-star comments */
static char *dolqstart; /* current $foo$ quote start string */ static char *dolqstart; /* current $foo$ quote start string */
bool plpgsql_LookupIdentifiers = true;
bool plpgsql_SpaceScanned = false; bool plpgsql_SpaceScanned = false;
%} %}
...@@ -209,52 +210,28 @@ dump { return O_DUMP; } ...@@ -209,52 +210,28 @@ dump { return O_DUMP; }
*/ */
{identifier} { {identifier} {
plpgsql_error_lineno = plpgsql_scanner_lineno(); plpgsql_error_lineno = plpgsql_scanner_lineno();
if (!plpgsql_LookupIdentifiers) return T_WORD;
return plpgsql_parse_word(yytext); } return plpgsql_parse_word(yytext); }
{identifier}{space}*\.{space}*{identifier} { {identifier}{space}*\.{space}*{identifier} {
plpgsql_error_lineno = plpgsql_scanner_lineno(); plpgsql_error_lineno = plpgsql_scanner_lineno();
if (!plpgsql_LookupIdentifiers) return T_DBLWORD;
return plpgsql_parse_dblword(yytext); } return plpgsql_parse_dblword(yytext); }
{identifier}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier} { {identifier}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier} {
plpgsql_error_lineno = plpgsql_scanner_lineno(); plpgsql_error_lineno = plpgsql_scanner_lineno();
if (!plpgsql_LookupIdentifiers) return T_TRIPWORD;
return plpgsql_parse_tripword(yytext); } return plpgsql_parse_tripword(yytext); }
{identifier}{space}*%TYPE {
plpgsql_error_lineno = plpgsql_scanner_lineno();
return plpgsql_parse_wordtype(yytext); }
{identifier}{space}*\.{space}*{identifier}{space}*%TYPE {
plpgsql_error_lineno = plpgsql_scanner_lineno();
return plpgsql_parse_dblwordtype(yytext); }
{identifier}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier}{space}*%TYPE {
plpgsql_error_lineno = plpgsql_scanner_lineno();
return plpgsql_parse_tripwordtype(yytext); }
{identifier}{space}*%ROWTYPE {
plpgsql_error_lineno = plpgsql_scanner_lineno();
return plpgsql_parse_wordrowtype(yytext); }
{identifier}{space}*\.{space}*{identifier}{space}*%ROWTYPE {
plpgsql_error_lineno = plpgsql_scanner_lineno();
return plpgsql_parse_dblwordrowtype(yytext); }
{param} { {param} {
plpgsql_error_lineno = plpgsql_scanner_lineno(); plpgsql_error_lineno = plpgsql_scanner_lineno();
if (!plpgsql_LookupIdentifiers) return T_WORD;
return plpgsql_parse_word(yytext); } return plpgsql_parse_word(yytext); }
{param}{space}*\.{space}*{identifier} { {param}{space}*\.{space}*{identifier} {
plpgsql_error_lineno = plpgsql_scanner_lineno(); plpgsql_error_lineno = plpgsql_scanner_lineno();
if (!plpgsql_LookupIdentifiers) return T_DBLWORD;
return plpgsql_parse_dblword(yytext); } return plpgsql_parse_dblword(yytext); }
{param}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier} { {param}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier} {
plpgsql_error_lineno = plpgsql_scanner_lineno(); plpgsql_error_lineno = plpgsql_scanner_lineno();
if (!plpgsql_LookupIdentifiers) return T_TRIPWORD;
return plpgsql_parse_tripword(yytext); } return plpgsql_parse_tripword(yytext); }
{param}{space}*%TYPE {
plpgsql_error_lineno = plpgsql_scanner_lineno();
return plpgsql_parse_wordtype(yytext); }
{param}{space}*\.{space}*{identifier}{space}*%TYPE {
plpgsql_error_lineno = plpgsql_scanner_lineno();
return plpgsql_parse_dblwordtype(yytext); }
{param}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier}{space}*%TYPE {
plpgsql_error_lineno = plpgsql_scanner_lineno();
return plpgsql_parse_tripwordtype(yytext); }
{param}{space}*%ROWTYPE {
plpgsql_error_lineno = plpgsql_scanner_lineno();
return plpgsql_parse_wordrowtype(yytext); }
{param}{space}*\.{space}*{identifier}{space}*%ROWTYPE {
plpgsql_error_lineno = plpgsql_scanner_lineno();
return plpgsql_parse_dblwordrowtype(yytext); }
{digit}+ { return T_NUMBER; } {digit}+ { return T_NUMBER; }
...@@ -527,6 +504,8 @@ plpgsql_scanner_init(const char *str) ...@@ -527,6 +504,8 @@ plpgsql_scanner_init(const char *str)
cur_line_start++; cur_line_start++;
BEGIN(INITIAL); BEGIN(INITIAL);
plpgsql_LookupIdentifiers = true;
plpgsql_SpaceScanned = false;
} }
/* /*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment