From 707263542e571c9906549e196728ad39ecc0ca84 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 4 Oct 2012 17:14:59 -0400 Subject: [PATCH] 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. --- src/backend/parser/gram.y | 34 +++++++++++++++++++++---- src/test/regress/expected/namespace.out | 4 +-- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 7feadeac16..e4ff76e66e 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -67,15 +67,33 @@ #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 @@ -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; } ; /* diff --git a/src/test/regress/expected/namespace.out b/src/test/regress/expected/namespace.out index 5fcd46daf4..9187c8126a 100644 --- a/src/test/regress/expected/namespace.out +++ b/src/test/regress/expected/namespace.out @@ -47,8 +47,8 @@ CREATE SCHEMA IF NOT EXISTS test_schema_1 -- fail, disallowed b int UNIQUE ); ERROR: CREATE SCHEMA IF NOT EXISTS cannot include schema elements -LINE 1: CREATE SCHEMA IF NOT EXISTS test_schema_1 - ^ +LINE 2: CREATE TABLE abc ( + ^ DROP SCHEMA test_schema_1 CASCADE; NOTICE: drop cascades to 2 other objects DETAIL: drop cascades to table test_schema_1.abc -- 2.40.0