]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix ecpg bugs caused by missing semicolons in the backend grammar.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 24 Feb 2019 17:51:50 +0000 (12:51 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 24 Feb 2019 17:51:50 +0000 (12:51 -0500)
The Bison documentation clearly states that a semicolon is required
after every grammar rule, and our scripts that generate ecpg's
grammar from the backend's implicitly assumed this is true.  But it
turns out that only ancient versions of Bison actually enforce that.
There have been a couple of rules without trailing semicolons in
gram.y for some time, and as a consequence, ecpg's grammar was faulty
and produced wrong output for the affected statements.

To fix, add the missing semis, and add some cross-checks to ecpg's
scripts so that they'll bleat if we mess this up again.

The cases that were broken were:
* "SET variable = DEFAULT" (but not "SET variable TO DEFAULT"),
  as well as allied syntaxes such as ALTER SYSTEM SET ... DEFAULT.
  These produced syntactically invalid output that the server
  would reject.
* Multiple type names in DROP TYPE/DOMAIN commands.  Only the
  first type name would be listed in the emitted command.

Per report from Daisuke Higuchi.  Back-patch to all supported versions.

Discussion: https://postgr.es/m/1803D792815FC24D871C00D17AE95905DB51CE@g01jpexmbkw24

src/backend/parser/gram.y
src/interfaces/ecpg/preproc/check_rules.pl
src/interfaces/ecpg/preproc/parse.pl

index ced7f814f77ae6839e812e303e631d17c8e83c81..ae800d565fa55402d2fbd231b8ac58e51b06a53e 100644 (file)
@@ -1417,6 +1417,7 @@ generic_set:
                                        n->name = $1;
                                        $$ = n;
                                }
+               ;
 
 set_rest_more: /* Generic SET syntaxes: */
                        generic_set                                             {$$ = $1;}
@@ -5681,6 +5682,7 @@ attrs:            '.' attr_name
 type_name_list:
                        Typename                                                                { $$ = list_make1(list_make1($1)); }
                        | type_name_list ',' Typename                   { $$ = lappend($1, list_make1($3)); }
+               ;
 
 /*****************************************************************************
  *
index 4c981e0dea517aef30e7ad43a295be97e86da0e6..87fa70955f924d86865ac1456b68e9c9511befb8 100644 (file)
@@ -1,7 +1,7 @@
 #!/usr/bin/perl
 # src/interfaces/ecpg/preproc/check_rules.pl
-# test parser generater for ecpg
-# call with backend parser as stdin
+# test parser generator for ecpg
+# call with backend grammar as stdin
 #
 # Copyright (c) 2009-2016, PostgreSQL Global Development Group
 #
@@ -47,6 +47,7 @@ my %replace_line = (
 
 my $block        = '';
 my $yaccmode     = 0;
+my $in_rule      = 0;
 my $brace_indent = 0;
 my (@arr, %found);
 my $comment     = 0;
@@ -131,10 +132,14 @@ while (<GRAM>)
                        $found{$block} = 1;
                        $cc++;
                        $block = '';
+                       $in_rule = 0 if $arr[$fieldIndexer] eq ';';
                }
                elsif (($arr[$fieldIndexer] =~ '[A-Za-z0-9]+:')
                        || $arr[ $fieldIndexer + 1 ] eq ':')
                {
+                       die "unterminated rule at grammar line $.\n"
+                         if $in_rule;
+                       $in_rule     = 1;
                        $non_term_id = $arr[$fieldIndexer];
                        $non_term_id =~ tr/://d;
                }
@@ -145,6 +150,9 @@ while (<GRAM>)
        }
 }
 
+die "unterminated rule at end of grammar\n"
+  if $in_rule;
+
 close GRAM;
 if ($verbose)
 {
index 6dd55fcfe4280e412c96b55a5d1a43eb02110f84..38afdfb0ad2551c72190dffe0a96cf2060a44295 100644 (file)
@@ -22,6 +22,7 @@ $path = "." unless $path;
 my $copymode              = 0;
 my $brace_indent          = 0;
 my $yaccmode              = 0;
+my $in_rule               = 0;
 my $header_included       = 0;
 my $feature_not_supported = 0;
 my $tokenmode             = 0;
@@ -288,6 +289,7 @@ sub main
                                @fields  = ();
                                $infield = 0;
                                $line    = '';
+                               $in_rule = 0;
                                next;
                        }
 
@@ -365,6 +367,9 @@ sub main
                                $line    = '';
                                @fields  = ();
                                $infield = 1;
+                               die "unterminated rule at grammar line $.\n"
+                                 if $in_rule;
+                               $in_rule = 1;
                                next;
                        }
                        elsif ($copymode)
@@ -415,6 +420,9 @@ sub main
                        }
                }
        }
+       die "unterminated rule at end of grammar\n"
+         if $in_rule;
+       return;
 }