diff options
Diffstat (limited to '')
-rwxr-xr-x | src/include/catalog/renumber_oids.pl | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/src/include/catalog/renumber_oids.pl b/src/include/catalog/renumber_oids.pl new file mode 100755 index 0000000..690869d --- /dev/null +++ b/src/include/catalog/renumber_oids.pl @@ -0,0 +1,291 @@ +#!/usr/bin/perl +#---------------------------------------------------------------------- +# +# renumber_oids.pl +# Perl script that shifts a range of OIDs in the Postgres catalog data +# to a different range, skipping any OIDs that are already in use. +# +# Note: This does not reformat the .dat files, so you may want +# to run reformat_dat_file.pl afterwards. +# +# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/renumber_oids.pl +# +#---------------------------------------------------------------------- + +use strict; +use warnings; + +use FindBin; +use Getopt::Long; + +# Must run in src/include/catalog +chdir $FindBin::RealBin or die "could not cd to $FindBin::RealBin: $!\n"; + +use lib "$FindBin::RealBin/../../backend/catalog/"; +use Catalog; + +# We'll need this number. +my $FirstGenbkiObjectId = + Catalog::FindDefinedSymbol('access/transam.h', '..', 'FirstGenbkiObjectId'); + +# Process command line switches. +my $output_path = ''; +my $first_mapped_oid = 0; +my $last_mapped_oid = $FirstGenbkiObjectId - 1; +my $target_oid = 0; + +GetOptions( + 'output=s' => \$output_path, + 'first-mapped-oid=i' => \$first_mapped_oid, + 'last-mapped-oid=i' => \$last_mapped_oid, + 'target-oid=i' => \$target_oid) || usage(); + +# Sanity check arguments. +die "Unexpected non-switch arguments.\n" if @ARGV; +die "--first-mapped-oid must be specified.\n" + if $first_mapped_oid <= 0; +die "Empty mapped OID range.\n" + if $last_mapped_oid < $first_mapped_oid; +die "--target-oid must be specified.\n" + if $target_oid <= 0; +die "--target-oid must not be within mapped OID range.\n" + if $target_oid >= $first_mapped_oid && $target_oid <= $last_mapped_oid; + +# Make sure output_path ends in a slash. +if ($output_path ne '' && substr($output_path, -1) ne '/') +{ + $output_path .= '/'; +} + +# Collect all the existing assigned OIDs (including those to be remapped). +my @header_files = (glob("pg_*.h"), qw(indexing.h toasting.h)); +my $oids = Catalog::FindAllOidsFromHeaders(@header_files); + +# Hash-ify the existing OIDs for convenient lookup. +my %oidhash; +@oidhash{@$oids} = undef; + +# Select new OIDs for existing OIDs in the mapped range. +# We do this first so that we preserve the ordering of the mapped OIDs +# (for reproducibility's sake), and so that if we fail due to running out +# of OID room, that happens before we've overwritten any files. +my %maphash; +my $next_oid = $target_oid; + +for ( + my $mapped_oid = $first_mapped_oid; + $mapped_oid <= $last_mapped_oid; + $mapped_oid++) +{ + next if !exists $oidhash{$mapped_oid}; + $next_oid++ + while ( + exists $oidhash{$next_oid} + || ( $next_oid >= $first_mapped_oid + && $next_oid <= $last_mapped_oid)); + die "Reached FirstGenbkiObjectId before assigning all OIDs.\n" + if $next_oid >= $FirstGenbkiObjectId; + $maphash{$mapped_oid} = $next_oid; + $next_oid++; +} + +die "There are no OIDs in the mapped range.\n" if $next_oid == $target_oid; + +# Read each .h file and write out modified data. +foreach my $input_file (@header_files) +{ + $input_file =~ /(\w+)\.h$/ + or die "Input file $input_file needs to be a .h file.\n"; + my $catname = $1; + + # Ignore generated *_d.h files. + next if $catname =~ /_d$/; + + open(my $ifd, '<', $input_file) || die "$input_file: $!"; + + # Write output files to specified directory. + # Use a .tmp suffix, then rename into place, in case we're overwriting. + my $output_file = "$output_path$catname.h"; + my $tmp_output_file = "$output_file.tmp"; + open my $ofd, '>', $tmp_output_file + or die "can't open $tmp_output_file: $!"; + my $changed = 0; + + # Scan the input file. + while (<$ifd>) + { + my $line = $_; + + # Check for OID-defining macros that Catalog::ParseHeader knows about, + # and update OIDs as needed. + if ($line =~ m/^(DECLARE_TOAST\(\s*\w+,\s*)(\d+)(,\s*)(\d+)\)/) + { + my $oid2 = $2; + my $oid4 = $4; + if (exists $maphash{$oid2}) + { + $oid2 = $maphash{$oid2}; + my $repl = $1 . $oid2 . $3 . $oid4 . ")"; + $line =~ s/^DECLARE_TOAST\(\s*\w+,\s*\d+,\s*\d+\)/$repl/; + $changed = 1; + } + if (exists $maphash{$oid4}) + { + $oid4 = $maphash{$oid4}; + my $repl = $1 . $oid2 . $3 . $oid4 . ")"; + $line =~ s/^DECLARE_TOAST\(\s*\w+,\s*\d+,\s*\d+\)/$repl/; + $changed = 1; + } + } + elsif ( + $line =~ m/^(DECLARE_(UNIQUE_)?INDEX\(\s*\w+,\s*)(\d+)(,\s*.+)\)/) + { + if (exists $maphash{$3}) + { + my $repl = $1 . $maphash{$3} . $4 . ")"; + $line =~ + s/^DECLARE_(UNIQUE_)?INDEX\(\s*\w+,\s*\d+,\s*.+\)/$repl/; + $changed = 1; + } + } + elsif ($line =~ m/^CATALOG\((\w+),(\d+),(\w+)\)/) + { + if (exists $maphash{$2}) + { + my $repl = + "CATALOG(" . $1 . "," . $maphash{$2} . "," . $3 . ")"; + $line =~ s/^CATALOG\(\w+,\d+,\w+\)/$repl/; + $changed = 1; + } + + if ($line =~ m/BKI_ROWTYPE_OID\((\d+),(\w+)\)/) + { + if (exists $maphash{$1}) + { + my $repl = + "BKI_ROWTYPE_OID(" . $maphash{$1} . "," . $2 . ")"; + $line =~ s/BKI_ROWTYPE_OID\(\d+,\w+\)/$repl/; + $changed = 1; + } + } + } + + # In indexing.h and toasting.h only, check for #define SYM nnnn, + # and replace if within mapped range. + elsif ($line =~ m/^(\s*#\s*define\s+\w+\s+)(\d+)\b/) + { + if (($catname eq 'indexing' || $catname eq 'toasting') + && exists $maphash{$2}) + { + my $repl = $1 . $maphash{$2}; + $line =~ s/^\s*#\s*define\s+\w+\s+\d+\b/$repl/; + $changed = 1; + } + } + + print $ofd $line; + } + + close $ifd; + close $ofd; + + # Avoid updating files if we didn't change them. + if ($changed || $output_path ne '') + { + rename $tmp_output_file, $output_file + or die "can't rename $tmp_output_file to $output_file: $!"; + } + else + { + unlink $tmp_output_file + or die "can't unlink $tmp_output_file: $!"; + } +} + +# Likewise, read each .dat file and write out modified data. +foreach my $input_file (glob("pg_*.dat")) +{ + $input_file =~ /(\w+)\.dat$/ + or die "Input file $input_file needs to be a .dat file.\n"; + my $catname = $1; + + open(my $ifd, '<', $input_file) || die "$input_file: $!"; + + # Write output files to specified directory. + # Use a .tmp suffix, then rename into place, in case we're overwriting. + my $output_file = "$output_path$catname.dat"; + my $tmp_output_file = "$output_file.tmp"; + open my $ofd, '>', $tmp_output_file + or die "can't open $tmp_output_file: $!"; + my $changed = 0; + + # Scan the input file. + while (<$ifd>) + { + my $line = $_; + + # Check for oid => 'nnnn', and replace if within mapped range. + if ($line =~ m/\b(oid\s*=>\s*)'(\d+)'/) + { + if (exists $maphash{$2}) + { + my $repl = $1 . "'" . $maphash{$2} . "'"; + $line =~ s/\boid\s*=>\s*'\d+'/$repl/; + $changed = 1; + } + } + + # Likewise for array_type_oid. + if ($line =~ m/\b(array_type_oid\s*=>\s*)'(\d+)'/) + { + if (exists $maphash{$2}) + { + my $repl = $1 . "'" . $maphash{$2} . "'"; + $line =~ s/\barray_type_oid\s*=>\s*'\d+'/$repl/; + $changed = 1; + } + } + + print $ofd $line; + } + + close $ifd; + close $ofd; + + # Avoid updating files if we didn't change them. + if ($changed || $output_path ne '') + { + rename $tmp_output_file, $output_file + or die "can't rename $tmp_output_file to $output_file: $!"; + } + else + { + unlink $tmp_output_file + or die "can't unlink $tmp_output_file: $!"; + } +} + +sub usage +{ + my $last = $FirstGenbkiObjectId - 1; + die <<EOM; +Usage: renumber_oids.pl [--output PATH] --first-mapped-oid X [--last-mapped-oid Y] --target-oid Z + +Options: + --output PATH output directory (default '.') + --first-mapped-oid X first OID to be moved + --last-mapped-oid Y last OID to be moved (default $last) + --target-oid Z first OID to move to + +Catalog *.h and *.dat files are updated and written to the +output directory; by default, this overwrites the input files. + +Caution: the output PATH will be interpreted relative to +src/include/catalog, even if you start the script +in some other directory. + +EOM +} |