diff --git a/doc/src/sgml/bki.sgml b/doc/src/sgml/bki.sgml
index 5a4cd39342..e7acd652e7 100644
--- a/doc/src/sgml/bki.sgml
+++ b/doc/src/sgml/bki.sgml
@@ -382,8 +382,8 @@
through the catalog headers and .dat files
to see which ones do not appear. You can also use
the duplicate_oids script to check for mistakes.
- (That script is run automatically at compile time, and will stop the
- build if a duplicate is found.)
+ (genbki.pl will also detect duplicate OIDs
+ at compile time.)
diff --git a/src/backend/catalog/Catalog.pm b/src/backend/catalog/Catalog.pm
index 0b057a8f5a..67d17197f9 100644
--- a/src/backend/catalog/Catalog.pm
+++ b/src/backend/catalog/Catalog.pm
@@ -386,6 +386,8 @@ sub FindDefinedSymbolFromData
# Extract an array of all the OIDs assigned in the specified catalog headers
# and their associated data files (if any).
+# Caution: genbki.pl contains equivalent logic; change it too if you need to
+# touch this.
sub FindAllOidsFromHeaders
{
my @input_files = @_;
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index d25d98a40b..a54197da51 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -84,8 +84,7 @@ generated-header-symlinks: $(top_builddir)/src/include/catalog/header-stamp
# configure run, even in distribution tarballs. So depending on configure.in
# instead is cheating a bit, but it will achieve the goal of updating the
# version number when it changes.
-bki-stamp: genbki.pl Catalog.pm $(POSTGRES_BKI_SRCS) $(POSTGRES_BKI_DATA) $(top_srcdir)/configure.in $(top_srcdir)/src/include/catalog/duplicate_oids
- cd $(top_srcdir)/src/include/catalog && $(PERL) ./duplicate_oids
+bki-stamp: genbki.pl Catalog.pm $(POSTGRES_BKI_SRCS) $(POSTGRES_BKI_DATA) $(top_srcdir)/configure.in
$(PERL) -I $(catalogdir) $< --set-version=$(MAJORVERSION) $(POSTGRES_BKI_SRCS)
touch $@
diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl
index 83b6158a60..1d0fd1eb42 100644
--- a/src/backend/catalog/genbki.pl
+++ b/src/backend/catalog/genbki.pl
@@ -57,27 +57,14 @@ if ($output_path ne '' && substr($output_path, -1) ne '/')
$output_path .= '/';
}
-# Open temp files
-my $tmpext = ".tmp$$";
-my $bkifile = $output_path . 'postgres.bki';
-open my $bki, '>', $bkifile . $tmpext
- or die "can't open $bkifile$tmpext: $!";
-my $schemafile = $output_path . 'schemapg.h';
-open my $schemapg, '>', $schemafile . $tmpext
- or die "can't open $schemafile$tmpext: $!";
-my $descrfile = $output_path . 'postgres.description';
-open my $descr, '>', $descrfile . $tmpext
- or die "can't open $descrfile$tmpext: $!";
-my $shdescrfile = $output_path . 'postgres.shdescription';
-open my $shdescr, '>', $shdescrfile . $tmpext
- or die "can't open $shdescrfile$tmpext: $!";
-
# Read all the files into internal data structures.
my @catnames;
my %catalogs;
my %catalog_data;
my @toast_decls;
my @index_decls;
+my %oidcounts;
+
foreach my $header (@input_files)
{
$header =~ /(.+)\.h$/
@@ -94,10 +81,30 @@ foreach my $header (@input_files)
$catalogs{$catname} = $catalog;
}
+ # While checking for duplicated OIDs, we ignore the pg_class OID and
+ # rowtype OID of bootstrap catalogs, as those are expected to appear
+ # in the initial data for pg_class and pg_type. For regular catalogs,
+ # include these OIDs. (See also Catalog::FindAllOidsFromHeaders
+ # if you change this logic.)
+ if (!$catalog->{bootstrap})
+ {
+ $oidcounts{ $catalog->{relation_oid} }++
+ if ($catalog->{relation_oid});
+ $oidcounts{ $catalog->{rowtype_oid} }++
+ if ($catalog->{rowtype_oid});
+ }
+
# Not all catalogs have a data file.
if (-e $datfile)
{
- $catalog_data{$catname} = Catalog::ParseData($datfile, $schema, 0);
+ my $data = Catalog::ParseData($datfile, $schema, 0);
+ $catalog_data{$catname} = $data;
+
+ # Check for duplicated OIDs while we're at it.
+ foreach my $row (@$data)
+ {
+ $oidcounts{ $row->{oid} }++ if defined $row->{oid};
+ }
}
# If the header file contained toast or index info, build BKI
@@ -108,6 +115,8 @@ foreach my $header (@input_files)
sprintf "declare toast %s %s on %s\n",
$toast->{toast_oid}, $toast->{toast_index_oid},
$toast->{parent_table};
+ $oidcounts{ $toast->{toast_oid} }++;
+ $oidcounts{ $toast->{toast_index_oid} }++;
}
foreach my $index (@{ $catalog->{indexing} })
{
@@ -116,9 +125,24 @@ foreach my $header (@input_files)
$index->{is_unique} ? 'unique ' : '',
$index->{index_name}, $index->{index_oid},
$index->{index_decl};
+ $oidcounts{ $index->{index_oid} }++;
}
}
+# Complain and exit if we found any duplicate OIDs.
+# While duplicate OIDs would only cause a failure if they appear in
+# the same catalog, our project policy is that manually assigned OIDs
+# should be globally unique, to avoid confusion.
+my $found = 0;
+foreach my $oid (keys %oidcounts)
+{
+ next unless $oidcounts{$oid} > 1;
+ print "Duplicate oids detected:\n" if !$found;
+ print "$oid\n";
+ $found++;
+}
+die "found $found duplicate OID(s) in catalog data\n" if $found;
+
# Fetch some special data that we will substitute into the output file.
# CAUTION: be wary about what symbols you substitute into the .bki file here!
# It's okay to substitute things that are expected to be really constant
@@ -224,6 +248,21 @@ my %lookup_kind = (
pg_type => \%typeoids);
+# Open temp files
+my $tmpext = ".tmp$$";
+my $bkifile = $output_path . 'postgres.bki';
+open my $bki, '>', $bkifile . $tmpext
+ or die "can't open $bkifile$tmpext: $!";
+my $schemafile = $output_path . 'schemapg.h';
+open my $schemapg, '>', $schemafile . $tmpext
+ or die "can't open $schemafile$tmpext: $!";
+my $descrfile = $output_path . 'postgres.description';
+open my $descr, '>', $descrfile . $tmpext
+ or die "can't open $descrfile$tmpext: $!";
+my $shdescrfile = $output_path . 'postgres.shdescription';
+open my $shdescr, '>', $shdescrfile . $tmpext
+ or die "can't open $shdescrfile$tmpext: $!";
+
# Generate postgres.bki, postgres.description, postgres.shdescription,
# and pg_*_d.h headers.
print "Generating BKI files and symbol definition headers...\n";