mirror of
https://github.com/postgres/postgres.git
synced 2025-07-11 10:01:57 +03:00
ecpg: add cross-checks to parse.pl for usage of internal tables.
parse.pl contains several constant tables that describe tweaks
to be made to the backend grammar. In the same spirit as
00b0e7204
, add cross-checks that each table entry is used at
least once (or exactly once if that's appropriate). This should
help catch cases where adjustments to the backend grammar cause
a table entry not to match as expected.
Per suggestion from Michael Paquier.
Discussion: https://postgr.es/m/ZsLVbjsc5x5Saesg@paquier.xyz
This commit is contained in:
@ -33,7 +33,9 @@ GetOptions(
|
|||||||
|
|
||||||
|
|
||||||
# These hash tables define additional transformations to apply to
|
# These hash tables define additional transformations to apply to
|
||||||
# grammar rules.
|
# grammar rules. For bug-detection purposes, we count usages of
|
||||||
|
# each hash table entry in a second hash table, and verify that
|
||||||
|
# all the entries get used.
|
||||||
|
|
||||||
# Substitutions to apply to tokens whenever they are seen in a rule.
|
# Substitutions to apply to tokens whenever they are seen in a rule.
|
||||||
my %replace_token = (
|
my %replace_token = (
|
||||||
@ -44,6 +46,8 @@ my %replace_token = (
|
|||||||
'IDENT' => 'ecpg_ident',
|
'IDENT' => 'ecpg_ident',
|
||||||
'PARAM' => 'ecpg_param',);
|
'PARAM' => 'ecpg_param',);
|
||||||
|
|
||||||
|
my %replace_token_used;
|
||||||
|
|
||||||
# This hash can provide a result type to override "void" for nonterminals
|
# This hash can provide a result type to override "void" for nonterminals
|
||||||
# that need that, or it can specify 'ignore' to cause us to skip the rule
|
# that need that, or it can specify 'ignore' to cause us to skip the rule
|
||||||
# for that nonterminal. (In either case, ecpg.trailer had better provide
|
# for that nonterminal. (In either case, ecpg.trailer had better provide
|
||||||
@ -68,6 +72,8 @@ my %replace_types = (
|
|||||||
'plassign_target' => 'ignore',
|
'plassign_target' => 'ignore',
|
||||||
'plassign_equals' => 'ignore',);
|
'plassign_equals' => 'ignore',);
|
||||||
|
|
||||||
|
my %replace_types_used;
|
||||||
|
|
||||||
# This hash provides an "ignore" option or substitute expansion for any
|
# This hash provides an "ignore" option or substitute expansion for any
|
||||||
# rule or rule alternative. The hash key is the same "concattokens" tag
|
# rule or rule alternative. The hash key is the same "concattokens" tag
|
||||||
# used for lookup in ecpg.addons.
|
# used for lookup in ecpg.addons.
|
||||||
@ -111,6 +117,8 @@ my %replace_line = (
|
|||||||
'PREPARE prepared_name prep_type_clause AS PreparableStmt',
|
'PREPARE prepared_name prep_type_clause AS PreparableStmt',
|
||||||
'var_nameColId' => 'ECPGColId');
|
'var_nameColId' => 'ECPGColId');
|
||||||
|
|
||||||
|
my %replace_line_used;
|
||||||
|
|
||||||
|
|
||||||
# Declare assorted state variables.
|
# Declare assorted state variables.
|
||||||
|
|
||||||
@ -198,6 +206,30 @@ foreach (keys %addons)
|
|||||||
die "addon rule $_ was matched multiple times\n" if $addons{$_}{used} > 1;
|
die "addon rule $_ was matched multiple times\n" if $addons{$_}{used} > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Likewise cross-check that entries in our internal hash tables match something.
|
||||||
|
foreach (keys %replace_token)
|
||||||
|
{
|
||||||
|
die "replace_token entry $_ was never used\n"
|
||||||
|
if !defined($replace_token_used{$_});
|
||||||
|
# multiple use of a replace_token entry is fine
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (keys %replace_types)
|
||||||
|
{
|
||||||
|
die "replace_types entry $_ was never used\n"
|
||||||
|
if !defined($replace_types_used{$_});
|
||||||
|
die "replace_types entry $_ was matched multiple times\n"
|
||||||
|
if $replace_types_used{$_} > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (keys %replace_line)
|
||||||
|
{
|
||||||
|
die "replace_line entry $_ was never used\n"
|
||||||
|
if !defined($replace_line_used{$_});
|
||||||
|
die "replace_line entry $_ was matched multiple times\n"
|
||||||
|
if $replace_line_used{$_} > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# Read the backend grammar.
|
# Read the backend grammar.
|
||||||
sub main
|
sub main
|
||||||
@ -399,6 +431,7 @@ sub main
|
|||||||
# Apply replace_token substitution if we have one.
|
# Apply replace_token substitution if we have one.
|
||||||
if (exists $replace_token{ $arr[$fieldIndexer] })
|
if (exists $replace_token{ $arr[$fieldIndexer] })
|
||||||
{
|
{
|
||||||
|
$replace_token_used{ $arr[$fieldIndexer] }++;
|
||||||
$arr[$fieldIndexer] = $replace_token{ $arr[$fieldIndexer] };
|
$arr[$fieldIndexer] = $replace_token{ $arr[$fieldIndexer] };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,6 +457,7 @@ sub main
|
|||||||
&& $replace_types{$non_term_id} eq 'ignore')
|
&& $replace_types{$non_term_id} eq 'ignore')
|
||||||
{
|
{
|
||||||
# We'll ignore this nonterminal and rule altogether.
|
# We'll ignore this nonterminal and rule altogether.
|
||||||
|
$replace_types_used{$non_term_id}++;
|
||||||
$copymode = 0;
|
$copymode = 0;
|
||||||
next line;
|
next line;
|
||||||
}
|
}
|
||||||
@ -450,6 +484,7 @@ sub main
|
|||||||
. $replace_types{$non_term_id} . ' '
|
. $replace_types{$non_term_id} . ' '
|
||||||
. $non_term_id;
|
. $non_term_id;
|
||||||
add_to_buffer('types', $tstr);
|
add_to_buffer('types', $tstr);
|
||||||
|
$replace_types_used{$non_term_id}++;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Emit the target part of the rule.
|
# Emit the target part of the rule.
|
||||||
@ -615,8 +650,10 @@ sub emit_rule
|
|||||||
|
|
||||||
# apply replace_line substitution if any
|
# apply replace_line substitution if any
|
||||||
my $rep = $replace_line{$tag};
|
my $rep = $replace_line{$tag};
|
||||||
if ($rep)
|
if (defined $rep)
|
||||||
{
|
{
|
||||||
|
$replace_line_used{$tag}++;
|
||||||
|
|
||||||
if ($rep eq 'ignore')
|
if ($rep eq 'ignore')
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
Reference in New Issue
Block a user