From c2154a348f9edbb48cccb2e04f40a5ee1747a93c Mon Sep 17 00:00:00 2001 From: John Naylor Date: Sun, 21 Jan 2018 16:14:06 +0700 Subject: [PATCH v7] Reduce indentation level A previous commit removed a logical block level from Catalog.pm, but kept the indentation for the sake of patch readability. Fix that here. Separate out the pg_attribute logic of genbki.pl into its own function and skip checking if the data is defined. This both narrows and shortens the data writing loop of the script. --- src/backend/catalog/Catalog.pm | 213 ++++++++++++++++---------------- src/backend/catalog/genbki.pl | 272 +++++++++++++++++++++-------------------- 2 files changed, 248 insertions(+), 237 deletions(-) diff --git a/src/backend/catalog/Catalog.pm b/src/backend/catalog/Catalog.pm index c3b663b..de64002 100644 --- a/src/backend/catalog/Catalog.pm +++ b/src/backend/catalog/Catalog.pm @@ -33,140 +33,139 @@ sub ParseHeader 'TransactionId' => 'xid', 'XLogRecPtr' => 'pg_lsn'); - my %catalog; - my $declaring_attributes = 0; - my $is_varlen = 0; + my %catalog; + my $declaring_attributes = 0; + my $is_varlen = 0; - $catalog{columns} = []; - $catalog{toasting} = []; - $catalog{indexing} = []; + $catalog{columns} = []; + $catalog{toasting} = []; + $catalog{indexing} = []; - open(my $ifh, '<', $input_file) || die "$input_file: $!"; + open(my $ifh, '<', $input_file) || die "$input_file: $!"; - # Scan the input file. - while (<$ifh>) - { + # Scan the input file. + while (<$ifh>) + { - # Strip C-style comments. - s;/\*(.|\n)*\*/;;g; - if (m;/\*;) - { + # Strip C-style comments. + s;/\*(.|\n)*\*/;;g; + if (m;/\*;) + { - # handle multi-line comments properly. - my $next_line = <$ifh>; - die "$input_file: ends within C-style comment\n" - if !defined $next_line; - $_ .= $next_line; - redo; - } + # handle multi-line comments properly. + my $next_line = <$ifh>; + die "$input_file: ends within C-style comment\n" + if !defined $next_line; + $_ .= $next_line; + redo; + } - # Strip useless whitespace and trailing semicolons. - chomp; - s/^\s+//; - s/;\s*$//; - s/\s+/ /g; + # Strip useless whitespace and trailing semicolons. + chomp; + s/^\s+//; + s/;\s*$//; + s/\s+/ /g; - # Push the data into the appropriate data structure. - if (/^DECLARE_TOAST\(\s*(\w+),\s*(\d+),\s*(\d+)\)/) - { - my ($toast_name, $toast_oid, $index_oid) = ($1, $2, $3); - push @{ $catalog{toasting} }, - "declare toast $toast_oid $index_oid on $toast_name\n"; - } - elsif (/^DECLARE_(UNIQUE_)?INDEX\(\s*(\w+),\s*(\d+),\s*(.+)\)/) - { - my ($is_unique, $index_name, $index_oid, $using) = - ($1, $2, $3, $4); - push @{ $catalog{indexing} }, - sprintf( - "declare %sindex %s %s %s\n", - $is_unique ? 'unique ' : '', - $index_name, $index_oid, $using); - } - elsif (/^BUILD_INDICES/) + # Push the data into the appropriate data structure. + if (/^DECLARE_TOAST\(\s*(\w+),\s*(\d+),\s*(\d+)\)/) + { + my ($toast_name, $toast_oid, $index_oid) = ($1, $2, $3); + push @{ $catalog{toasting} }, + "declare toast $toast_oid $index_oid on $toast_name\n"; + } + elsif (/^DECLARE_(UNIQUE_)?INDEX\(\s*(\w+),\s*(\d+),\s*(.+)\)/) + { + my ($is_unique, $index_name, $index_oid, $using) = + ($1, $2, $3, $4); + push @{ $catalog{indexing} }, + sprintf( + "declare %sindex %s %s %s\n", + $is_unique ? 'unique ' : '', + $index_name, $index_oid, $using); + } + elsif (/^BUILD_INDICES/) + { + push @{ $catalog{indexing} }, "build indices\n"; + } + elsif (/^CATALOG\(([^,]*),(\d+)\)/) + { + $catalog{catname} = $1; + $catalog{relation_oid} = $2; + + $catalog{bootstrap} = /BKI_BOOTSTRAP/ ? ' bootstrap' : ''; + $catalog{shared_relation} = + /BKI_SHARED_RELATION/ ? ' shared_relation' : ''; + $catalog{without_oids} = + /BKI_WITHOUT_OIDS/ ? ' without_oids' : ''; + $catalog{rowtype_oid} = + /BKI_ROWTYPE_OID\((\d+)\)/ ? " rowtype_oid $1" : ''; + $catalog{schema_macro} = /BKI_SCHEMA_MACRO/ ? 1 : 0; + $declaring_attributes = 1; + } + elsif ($declaring_attributes) + { + next if (/^{|^$/); + if (/^#/) { - push @{ $catalog{indexing} }, "build indices\n"; + $is_varlen = 1 if /^#ifdef\s+CATALOG_VARLEN/; + next; } - elsif (/^CATALOG\(([^,]*),(\d+)\)/) + if (/^}/) { - $catalog{catname} = $1; - $catalog{relation_oid} = $2; - - $catalog{bootstrap} = /BKI_BOOTSTRAP/ ? ' bootstrap' : ''; - $catalog{shared_relation} = - /BKI_SHARED_RELATION/ ? ' shared_relation' : ''; - $catalog{without_oids} = - /BKI_WITHOUT_OIDS/ ? ' without_oids' : ''; - $catalog{rowtype_oid} = - /BKI_ROWTYPE_OID\((\d+)\)/ ? " rowtype_oid $1" : ''; - $catalog{schema_macro} = /BKI_SCHEMA_MACRO/ ? 1 : 0; - $declaring_attributes = 1; + $declaring_attributes = 0; } - elsif ($declaring_attributes) + else { - next if (/^{|^$/); - if (/^#/) + my %column; + my @attopts = split /\s+/, $_; + my $atttype = shift @attopts; + my $attname = shift @attopts; + die "parse error ($input_file)" + unless ($attname and $atttype); + + if (exists $RENAME_ATTTYPE{$atttype}) { - $is_varlen = 1 if /^#ifdef\s+CATALOG_VARLEN/; - next; + $atttype = $RENAME_ATTTYPE{$atttype}; } - if (/^}/) + if ($attname =~ /(.*)\[.*\]/) # array attribute { - $declaring_attributes = 0; + $attname = $1; + $atttype .= '[]'; } - else + + $column{type} = $atttype; + $column{name} = $attname; + $column{is_varlen} = 1 if $is_varlen; + + foreach my $attopt (@attopts) { - my %column; - my @attopts = split /\s+/, $_; - my $atttype = shift @attopts; - my $attname = shift @attopts; - die "parse error ($input_file)" - unless ($attname and $atttype); - - if (exists $RENAME_ATTTYPE{$atttype}) + if ($attopt eq 'BKI_FORCE_NULL') { - $atttype = $RENAME_ATTTYPE{$atttype}; + $column{forcenull} = 1; } - if ($attname =~ /(.*)\[.*\]/) # array attribute + elsif ($attopt eq 'BKI_FORCE_NOT_NULL') { - $attname = $1; - $atttype .= '[]'; + $column{forcenotnull} = 1; + } + elsif ($attopt =~ /BKI_DEFAULT\((\S+)\)/) + { + $column{default} = $1; + } + else + { + die "unknown column option $attopt on column $attname"; } - $column{type} = $atttype; - $column{name} = $attname; - $column{is_varlen} = 1 if $is_varlen; - - foreach my $attopt (@attopts) + if ($column{forcenull} and $column{forcenotnull}) { - if ($attopt eq 'BKI_FORCE_NULL') - { - $column{forcenull} = 1; - } - elsif ($attopt eq 'BKI_FORCE_NOT_NULL') - { - $column{forcenotnull} = 1; - } - elsif ($attopt =~ /BKI_DEFAULT\((\S+)\)/) - { - $column{default} = $1; - } - else - { - die -"unknown column option $attopt on column $attname"; - } - - if ($column{forcenull} and $column{forcenotnull}) - { - die "$attname is forced both null and not null"; - } + die "$attname is forced both null and not null"; } - push @{ $catalog{columns} }, \%column; } + push @{ $catalog{columns} }, \%column; } } - close $ifh; + } + close $ifh; return \%catalog; } diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl index ed90a02..8d740c3 100644 --- a/src/backend/catalog/genbki.pl +++ b/src/backend/catalog/genbki.pl @@ -156,154 +156,85 @@ foreach my $catname (@{ $catalogs->{names} }) print $bki "open $catname\n"; } - if (defined $catalog->{data}) + # For pg_attribute.h, we generate data entries ourselves. + # NB: pg_type.h must come before pg_attribute.h in the input list + # of catalog names, since we use info from pg_type.h here. + if ($catname eq 'pg_attribute') { + gen_pg_attribute($schema); + } - # Ordinary catalog with DATA line(s) - foreach my $row (@{ $catalog->{data} }) - { - - # Split line into tokens without interpreting their meaning. - my %bki_values; - @bki_values{@attnames} = - Catalog::SplitDataLine($row->{bki_values}); - - # Perform required substitutions on fields - foreach my $column (@$schema) - { - my $attname = $column->{name}; - my $atttype = $column->{type}; - - # Substitute constant values we acquired above. - # (It's intentional that this can apply to parts of a field). - $bki_values{$attname} =~ s/\bPGUID\b/$BOOTSTRAP_SUPERUSERID/g; - $bki_values{$attname} =~ s/\bPGNSP\b/$PG_CATALOG_NAMESPACE/g; - - # Replace regproc columns' values with OIDs. - # If we don't have a unique value to substitute, - # just do nothing (regprocin will complain). - if ($atttype eq 'regproc') - { - my $procoid = $regprocoids{ $bki_values{$attname} }; - $bki_values{$attname} = $procoid - if defined($procoid) && $procoid ne 'MULTIPLE'; - } - } + # Ordinary catalog with DATA line(s) + foreach my $row (@{ $catalog->{data} }) + { - # Save pg_proc oids for use in later regproc substitutions. - # This relies on the order we process the files in! - if ($catname eq 'pg_proc') - { - if (defined($regprocoids{ $bki_values{proname} })) - { - $regprocoids{ $bki_values{proname} } = 'MULTIPLE'; - } - else - { - $regprocoids{ $bki_values{proname} } = $row->{oid}; - } - } + # Split line into tokens without interpreting their meaning. + my %bki_values; + @bki_values{@attnames} = + Catalog::SplitDataLine($row->{bki_values}); - # Save pg_type info for pg_attribute processing below - if ($catname eq 'pg_type') + # Perform required substitutions on fields + foreach my $column (@$schema) + { + my $attname = $column->{name}; + my $atttype = $column->{type}; + + # Substitute constant values we acquired above. + # (It's intentional that this can apply to parts of a field). + $bki_values{$attname} =~ s/\bPGUID\b/$BOOTSTRAP_SUPERUSERID/g; + $bki_values{$attname} =~ s/\bPGNSP\b/$PG_CATALOG_NAMESPACE/g; + + # Replace regproc columns' values with OIDs. + # If we don't have a unique value to substitute, + # just do nothing (regprocin will complain). + if ($atttype eq 'regproc') { - my %type = %bki_values; - $type{oid} = $row->{oid}; - $types{ $type{typname} } = \%type; + my $procoid = $regprocoids{ $bki_values{$attname} }; + $bki_values{$attname} = $procoid + if defined($procoid) && $procoid ne 'MULTIPLE'; } + } - # Write to postgres.bki - my $oid = $row->{oid} ? "OID = $row->{oid} " : ''; - printf $bki "insert %s( %s )\n", $oid, - join(' ', @bki_values{@attnames}); - - # Write comments to postgres.description and - # postgres.shdescription - if (defined $row->{descr}) + # Save pg_proc oids for use in later regproc substitutions. + # This relies on the order we process the files in! + if ($catname eq 'pg_proc') + { + if (defined($regprocoids{ $bki_values{proname} })) { - printf $descr "%s\t%s\t0\t%s\n", - $row->{oid}, $catname, $row->{descr}; + $regprocoids{ $bki_values{proname} } = 'MULTIPLE'; } - if (defined $row->{shdescr}) + else { - printf $shdescr "%s\t%s\t%s\n", - $row->{oid}, $catname, $row->{shdescr}; + $regprocoids{ $bki_values{proname} } = $row->{oid}; } } - } - if ($catname eq 'pg_attribute') - { - # For pg_attribute.h, we generate DATA entries ourselves. - # NB: pg_type.h must come before pg_attribute.h in the input list - # of catalog names, since we use info from pg_type.h here. - foreach my $table_name (@{ $catalogs->{names} }) + # Save pg_type info for pg_attribute processing below + if ($catname eq 'pg_type') { - my $table = $catalogs->{$table_name}; - - # Currently, all bootstrapped relations also need schemapg.h - # entries, so skip if the relation isn't to be in schemapg.h. - next if !$table->{schema_macro}; - - $schemapg_entries{$table_name} = []; - push @tables_needing_macros, $table_name; - - # Generate entries for user attributes. - my $attnum = 0; - my $priornotnull = 1; - foreach my $attr (@{ $table->{columns} }) - { - $attnum++; - my %row; - $row{attnum} = $attnum; - $row{attrelid} = $table->{relation_oid}; - - morph_row_for_pgattr(\%row, $schema, $attr, $priornotnull); - $priornotnull &= ($row{attnotnull} eq 't'); + my %type = %bki_values; + $type{oid} = $row->{oid}; + $types{ $type{typname} } = \%type; + } - # If it's bootstrapped, put an entry in postgres.bki. - print_bki_insert(\%row, @attnames) if $table->{bootstrap}; + # Write to postgres.bki + my $oid = $row->{oid} ? "OID = $row->{oid} " : ''; + printf $bki "insert %s( %s )\n", $oid, + join(' ', @bki_values{@attnames}); - # Store schemapg entries for later. - morph_row_for_schemapg(\%row, $schema); - push @{ $schemapg_entries{$table_name} }, - sprintf "{ %s }", - join(', ', grep { defined $_ } @row{@attnames}); - } - - # Generate entries for system attributes. - # We only need postgres.bki entries, not schemapg.h entries. - if ($table->{bootstrap}) - { - $attnum = 0; - my @SYS_ATTRS = ( - { name => 'ctid', type => 'tid' }, - { name => 'oid', type => 'oid' }, - { name => 'xmin', type => 'xid' }, - { name => 'cmin', type => 'cid' }, - { name => 'xmax', type => 'xid' }, - { name => 'cmax', type => 'cid' }, - { name => 'tableoid', type => 'oid' }); - foreach my $attr (@SYS_ATTRS) - { - $attnum--; - my %row; - $row{attnum} = $attnum; - $row{attrelid} = $table->{relation_oid}; - $row{attstattarget} = '0'; - - # Omit the oid column if the catalog doesn't have them - next - if $table->{without_oids} - && $attr->{name} eq 'oid'; - - morph_row_for_pgattr(\%row, $schema, $attr, 1); - print_bki_insert(\%row, @attnames); - } - } + # Write comments to postgres.description and + # postgres.shdescription + if (defined $row->{descr}) + { + printf $descr "%s\t%s\t0\t%s\n", + $row->{oid}, $catname, $row->{descr}; + } + if (defined $row->{shdescr}) + { + printf $shdescr "%s\t%s\t%s\n", + $row->{oid}, $catname, $row->{shdescr}; } } - print $bki "close $catname\n"; } @@ -375,6 +306,87 @@ exit 0; #################### Subroutines ######################## +# Iterate over all the catalogs. Where specified in the given header, build +# a hard-coded tuple descriptor for utils/relcache.c. Some of these are +# also bootstrap tables, which require pg_attribute entries in .bki for +# both user and system attributes. +sub gen_pg_attribute +{ + my $schema = shift; + + my @attnames; + foreach my $column (@$schema) + { + push @attnames, $column->{name}; + } + + foreach my $table_name (@{ $catalogs->{names} }) + { + my $table = $catalogs->{$table_name}; + + # Currently, all bootstrapped relations also need schemapg.h + # entries, so skip if the relation isn't to be in schemapg.h. + next if !$table->{schema_macro}; + + $schemapg_entries{$table_name} = []; + push @tables_needing_macros, $table_name; + + # Generate entries for user attributes. + my $attnum = 0; + my $priornotnull = 1; + foreach my $attr (@{ $table->{columns} }) + { + $attnum++; + my %row; + $row{attnum} = $attnum; + $row{attrelid} = $table->{relation_oid}; + + morph_row_for_pgattr(\%row, $schema, $attr, $priornotnull); + $priornotnull &= ($row{attnotnull} eq 't'); + + # If it's bootstrapped, put an entry in postgres.bki. + print_bki_insert(\%row, @attnames) if $table->{bootstrap}; + + # Store schemapg entries for later. + morph_row_for_schemapg(\%row, $schema); + push @{ $schemapg_entries{$table_name} }, + sprintf "{ %s }", + join(', ', grep { defined $_ } @row{@attnames}); + } + + # Generate entries for system attributes. + # We only need postgres.bki entries, not schemapg.h entries. + if ($table->{bootstrap}) + { + $attnum = 0; + my @SYS_ATTRS = ( + { name => 'ctid', type => 'tid' }, + { name => 'oid', type => 'oid' }, + { name => 'xmin', type => 'xid' }, + { name => 'cmin', type => 'cid' }, + { name => 'xmax', type => 'xid' }, + { name => 'cmax', type => 'cid' }, + { name => 'tableoid', type => 'oid' }); + foreach my $attr (@SYS_ATTRS) + { + $attnum--; + my %row; + $row{attnum} = $attnum; + $row{attrelid} = $table->{relation_oid}; + $row{attstattarget} = '0'; + + # Omit the oid column if the catalog doesn't have them + next + if $table->{without_oids} + && $attr->{name} eq 'oid'; + + morph_row_for_pgattr(\%row, $schema, $attr, 1); + print_bki_insert(\%row, @attnames); + } + } + } +} + # Given $pgattr_schema (the pg_attribute schema for a catalog sufficient for # AddDefaultValues), $attr (the description of a catalog row), and # $priornotnull (whether all prior attributes in this catalog are not null), -- 2.7.4