On Sat, Mar 9, 2019 at 1:14 AM Tom Lane <t...@sss.pgh.pa.us> wrote:
> I took a quick look at this.  I went ahead and pushed the parts that
> were just code cleanup in reformat_dat_file.pl, since that seemed
> pretty uncontroversial.  As far as the rest of it goes:

Okay, thanks.

> * I'm really not terribly happy with sticking this functionality into
> reformat_dat_file.pl.  First, there's an issue of discoverability:
> it's not obvious that a script named that way would have such an
> ability.  Second, it clutters the script in a way that seems to me
> to hinder its usefulness as a basis for one-off hacks.  So I'd really
> rather have a separate script named something like "renumber_oids.pl",
> even if there's a good deal of code duplication between it and
> reformat_dat_file.pl.

> * In my vision of what this might be good for, I think it's important
> that it be possible to specify a range of input OIDs to renumber, not
> just "everything above N".  I agree the output range only needs a
> starting OID.

Now it looks like:

perl  renumber_oids.pl  --first-mapped-oid 8000 --last-mapped-oid 8999
 --first-target-oid 2000  *.dat

To prevent a maintenance headache, I didn't copy any of the formatting
logic over. You'll also have to run reformat_dat_files.pl afterwards
to restore that. It seems to work, but I haven't tested thoroughly.

-- 
John Naylor                https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From c6f5a1f6016feeb7f7ea94e504be6d23a264ca07 Mon Sep 17 00:00:00 2001
From: John Naylor <jcnay...@gmail.com>
Date: Mon, 11 Mar 2019 01:05:15 +0800
Subject: [PATCH v2] Provide script to renumber OIDs.

Historically, It's been considered good practice to choose an OID that's
at the beginning of the range shown by the unused_oids script, but
nowadays that space is getting cramped, leading to merge conflicts.

Instead, allow developers to use high-numbered OIDs, and remap them
to a lower range at some future date.
---
 doc/src/sgml/bki.sgml                |  16 +++
 src/include/catalog/renumber_oids.pl | 193 +++++++++++++++++++++++++++
 2 files changed, 209 insertions(+)
 create mode 100644 src/include/catalog/renumber_oids.pl

diff --git a/doc/src/sgml/bki.sgml b/doc/src/sgml/bki.sgml
index 3c5830bc8a..7e553dc30d 100644
--- a/doc/src/sgml/bki.sgml
+++ b/doc/src/sgml/bki.sgml
@@ -392,6 +392,22 @@
     at compile time.)
    </para>
 
+   <para>
+    For a variety of reasons, newly assigned OIDs should occupy the lower
+    end of the reserved range.  Because multiple patches considered for
+    inclusion into <productname>PostgreSQL</productname> could be using
+    the same new OIDs, there is the possibilty of conflict.  To mitigate
+    this, there is a convention that OIDs 8000 and over are reserved for
+    development.  This reduces the effort in rebasing over the HEAD branch.
+    To enable committers to move these OIDs to the lower range easily,
+    <filename>renumber_oids.pl</filename> can map OIDs as in the following,
+    following, which maps any OIDs between 8000 and 8999, inclusive, to
+    unused OIDs starting at 2000:
+<programlisting>
+$ perl  renumber_oids.pl  --first-mapped-oid 8000 --last-mapped-oid 8999  --first-target-oid 2000  *.dat
+</programlisting>
+   </para>
+
    <para>
     The OID counter starts at 10000 at the beginning of a bootstrap run.
     If a row from a source other than <filename>postgres.bki</filename>
diff --git a/src/include/catalog/renumber_oids.pl b/src/include/catalog/renumber_oids.pl
new file mode 100644
index 0000000000..79537465bc
--- /dev/null
+++ b/src/include/catalog/renumber_oids.pl
@@ -0,0 +1,193 @@
+#!/usr/bin/perl
+#----------------------------------------------------------------------
+#
+# renumber_oids.pl
+#    Perl script that shifts a range of high-numbered OIDs in the given
+#    catalog data file(s) to a lower range.
+#
+#    Note: This does not format the output, so you will still need to
+#    run reformat_dat_file.pl.
+#
+# Portions Copyright (c) 1996-2019, 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;
+use Data::Dumper;
+$Data::Dumper::Terse = 1;
+
+# If you copy this script to somewhere other than src/include/catalog,
+# you'll need to modify this "use lib" or provide a suitable -I switch.
+use lib "$FindBin::RealBin/../../backend/catalog/";
+use Catalog;
+
+# Must run in src/include/catalog
+chdir $FindBin::RealBin or die "could not cd to $FindBin::RealBin: $!\n";
+
+my $FirstGenbkiObjectId =
+  Catalog::FindDefinedSymbol('access/transam.h', '..',
+	'FirstGenbkiObjectId');
+
+# Process command line switches.
+my $output_path = '';
+my $first_mapped_oid;
+my $last_mapped_oid = $FirstGenbkiObjectId - 1;
+my $first_target_oid = 1;
+
+GetOptions(
+	'output:s'           => \$output_path,
+	'first-mapped-oid:i' => \$first_mapped_oid,
+	'last-mapped-oid:i'  => \$last_mapped_oid,
+	'first-target-oid:i' => \$first_target_oid) || usage();
+
+my $next_oid = $first_target_oid;
+
+# Sanity check arguments.
+die "No input files.\n" unless @ARGV;
+die "output range is higher than input range"
+  if $first_target_oid > $first_mapped_oid;
+
+# Make sure output_path ends in a slash.
+if ($output_path ne '' && substr($output_path, -1) ne '/')
+{
+	$output_path .= '/';
+}
+
+# Read all the input files into internal data structures.
+# We pass data file names as arguments and then look for matching
+# headers to parse the schema from.
+my %catalogs;
+my %catalog_data;
+my @catnames;
+foreach my $datfile (@ARGV)
+{
+	$datfile =~ /(.+)\.dat$/
+	  or die "Input files need to be data (.dat) files.\n";
+
+	my $header = "$1.h";
+	die "There in no header file corresponding to $datfile"
+	  if !-e $header;
+
+	my $catalog = Catalog::ParseHeader($header);
+	my $catname = $catalog->{catname};
+	my $schema  = $catalog->{columns};
+
+	push @catnames, $catname;
+	$catalogs{$catname} = $catalog;
+
+	$catalog_data{$catname} = Catalog::ParseData($datfile, $schema, 1);
+}
+
+# Collect all the assigned OIDs in numerical order.
+my @header_files = (glob("pg_*.h"), qw(indexing.h toasting.h));
+my $oids = Catalog::FindAllOidsFromHeaders(@header_files);
+my @oids = sort { $a <=> $b } @$oids;
+
+# Write the data.
+foreach my $catname (@catnames)
+{
+	my $catalog = $catalogs{$catname};
+	my @attnames;
+	my $schema = $catalog->{columns};
+
+	foreach my $column (@$schema)
+	{
+		my $attname = $column->{name};
+		push @attnames, $attname
+	}
+
+	# Write output files to specified directory.
+	my $datfile = "$output_path$catname.dat";
+	open my $dat, '>', $datfile
+	  or die "can't open $datfile: $!";
+
+	foreach my $data (@{ $catalog_data{$catname} })
+	{
+		# Hash ref representing a data entry.
+		if (ref $data eq 'HASH')
+		{
+			my %values = %$data;
+
+			$values{oid} = get_lower_oid($values{oid})
+			  if defined $values{oid}
+			  && $values{oid} >= $first_mapped_oid
+			  && $values{oid} <= $last_mapped_oid;
+
+			$values{array_type_oid} = get_lower_oid($values{oid})
+			  if defined $values{array_type_oid}
+			  && $values{array_type_oid} >= $first_mapped_oid
+			  && $values{array_type_oid} <= $last_mapped_oid;
+
+			print $dat Dumper(\%values);
+			print $dat ",\n";
+		}
+
+		# Preserve blank lines.
+		elsif ($data =~ /^\s*$/)
+		{
+			print $dat "\n";
+		}
+
+		# Preserve comments or brackets that are on their own line.
+		elsif ($data =~ /^\s*(\[|\]|#.*?)\s*$/)
+		{
+			print $dat "$1\n";
+		}
+	}
+	close $dat;
+}
+
+# Return the next available OID above $first_target_oid.
+sub get_lower_oid
+{
+	my $old_oid = shift;
+	my $new_oid;
+
+	for (;;)
+	{
+		if (scalar @oids == 0 || $next_oid < $oids[0])
+		{
+			$new_oid = $next_oid;
+			warn sprintf "failed to map OID %d\n", $old_oid
+			  if $new_oid >= $first_mapped_oid;
+			$next_oid++;
+			return $new_oid;
+		}
+		elsif ($next_oid > $oids[0])
+		{
+			shift @oids;
+		}
+		elsif ($oids[0] == $next_oid)
+		{
+			shift @oids;
+			$next_oid++;
+		}
+		else
+		{
+			die "unreachable\n";
+		}
+	}
+}
+
+sub usage
+{
+	die <<EOM;
+Usage: renumber_oids.pl [--output <path>] --first-mapped-oid X --last-mapped-oid Y --first-target-oid Z  datafile...
+
+Options:
+    --output               output directory (default '.')
+    --first-mapped-oid     first OID to be mapped
+    --last-mapped-oid      last OID to be mapped
+    --first-target-oid     first OID to map to
+
+Expects a list of .dat files as arguments.
+
+EOM
+}

base-commit: 203749a8a66096171f808dd8e870d08d8ad57e5e
-- 
2.17.1

Reply via email to