diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2012-10-04 17:14:59 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2012-10-04 17:15:29 -0400 |
commit | 707263542e571c9906549e196728ad39ecc0ca84 (patch) | |
tree | 2db731b1ed9f8eeb9b78d1d0a5cd41f542461600 /src/backend/parser | |
parent | 7e389f73d1556fb21487cd28fe56cba1a91126e6 (diff) | |
download | postgresql-707263542e571c9906549e196728ad39ecc0ca84.tar.gz postgresql-707263542e571c9906549e196728ad39ecc0ca84.zip |
Fix parse location tracking for lists that can be empty.
The previous coding of the YYLLOC_DEFAULT macro behaved strangely for empty
productions, assigning the previous nonterminal's location as the parse
location of the result. The usefulness of that was (at best) debatable
already, but the real problem is that in list-generating nonterminals like
OptFooList: /* EMPTY */ { ... } | OptFooList Foo { ... } ;
the initially-identified location would get copied up, so that even a
nonempty list would be given a bogus parse location. Document how to work
around that, and do so for OptSchemaEltList, so that the error condition
just added for CREATE SCHEMA IF NOT EXISTS produces a sane error cursor.
So far as I can tell, there are currently no other cases where the
situation arises, so we don't need other instances of this coding yet.
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/gram.y | 34 |
1 files changed, 29 insertions, 5 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 7feadeac169..e4ff76e66e0 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -67,16 +67,34 @@ #include "utils/xml.h" -/* Location tracking support --- simpler than bison's default */ +/* + * Location tracking support --- simpler than bison's default, since we only + * want to track the start position not the end position of each nonterminal. + */ #define YYLLOC_DEFAULT(Current, Rhs, N) \ do { \ - if (N) \ + if ((N) > 0) \ (Current) = (Rhs)[1]; \ else \ - (Current) = (Rhs)[0]; \ + (Current) = (-1); \ } while (0) /* + * The above macro assigns -1 (unknown) as the parse location of any + * nonterminal that was reduced from an empty rule. This is problematic + * for nonterminals defined like + * OptFooList: / * EMPTY * / { ... } | OptFooList Foo { ... } ; + * because we'll set -1 as the location during the first reduction and then + * copy it during each subsequent reduction, leaving us with -1 for the + * location even when the list is not empty. To fix that, do this in the + * action for the nonempty rule(s): + * if (@$ < 0) @$ = @2; + * (Although we have many nonterminals that follow this pattern, we only + * bother with fixing @$ like this when the nonterminal's parse location + * is actually referenced in some rule.) + */ + +/* * Bison doesn't allocate anything that needs to live across parser calls, * so we can easily have it use palloc instead of malloc. This prevents * memory leaks if we error out during parsing. Note this only works with @@ -1223,8 +1241,14 @@ OptSchemaName: ; OptSchemaEltList: - OptSchemaEltList schema_stmt { $$ = lappend($1, $2); } - | /* EMPTY */ { $$ = NIL; } + OptSchemaEltList schema_stmt + { + if (@$ < 0) /* see comments for YYLLOC_DEFAULT */ + @$ = @2; + $$ = lappend($1, $2); + } + | /* EMPTY */ + { $$ = NIL; } ; /* |