Recording foreign key relationships for the system catalogs

Started by Tom Lanealmost 5 years ago14 messages
#1Tom Lane
tgl@sss.pgh.pa.us
1 attachment(s)

Now that dfb75e478 is in, I looked into whether we can have some
machine-readable representation of the catalogs' foreign key
relationships. As per the previous discussion [1]/messages/by-id/dc5f44d9-5ec1-a596-0251-dadadcdede98@2ndquadrant.com, it's not
practical to have "real" SQL foreign key constraints, because
the semantics we use aren't quite right (i.e., using 0 instead
of NULL in rows with no reference). Nonetheless it would be
nice to have the knowledge available in some form, and we agreed
that a set-returning function returning the data would be useful.

The attached patch creates that function, and rewrites the oidjoins.sql
regression test to use it, in place of the very incomplete info that's
reverse-engineered by findoidjoins. It's mostly straightforward.

My original thought had been to add DECLARE_FOREIGN_KEY() macros
for all references, but I soon realized that in a large majority of
the cases, that's redundant with the BKI_LOOKUP() annotations we
already have. So I taught genbki.pl to extract FK data from
BKI_LOOKUP() as well as the explicit DECLARE macros. That didn't
remove the work entirely, because it turned out that we hadn't
bothered to apply BKI_LOOKUP() labels to most of the catalogs that
have no hand-made data. A big chunk of the patch consists in
adding those as needed. Also, I had to make the BKI_LOOKUP()
mechanism a little more complete, because it failed on pg_namespace
and pg_authid references. (It will still fail on some other
cases such as BKI_LOOKUP(pg_foreign_server), but I think there's
no need to fill that in until/unless we have some built-in data
that needs it.)

There are various loose ends yet to be cleaned up:

* I'm unsure whether it's better for the SRF to return the
column names as textual names, or as column numbers. Names was
a bit easier for all the parts of the current patch so I did
it that way, but maybe there's a case for the other way.
Actually the whole API for the SRF is just spur-of-the-moment,
so maybe a different API would be better.

* It would now be possible to remove the PGNSP and PGUID kluges
entirely in favor of plain BKI_LOOKUP references to pg_namespace
and pg_authid. The catalog header usage would get a little
more verbose: BKI_DEFAULT(PGNSP) becomes BKI_DEFAULT(pg_catalog)
and BKI_DEFAULT(PGUID) becomes BKI_DEFAULT(POSTGRES). I'm a bit
inclined to do it, simply to remove one bit of mechanism that has
to be documented; but it's material for a separate patch perhaps.

* src/tools/findoidjoins should be nuked entirely, AFAICS.
Again, that could be a follow-on patch.

* I've not touched the SGML docs. Certainly
pg_get_catalog_foreign_keys() should be documented, and some
adjustments in bki.sgml might be appropriate.

regards, tom lane

[1]: /messages/by-id/dc5f44d9-5ec1-a596-0251-dadadcdede98@2ndquadrant.com

Attachments:

add-catalog-foreign-key-info-1.patchtext/x-diff; charset=us-ascii; name=add-catalog-foreign-key-info-1.patchDownload
diff --git a/src/backend/catalog/.gitignore b/src/backend/catalog/.gitignore
index 4bd3ee9d7f..237ff54165 100644
--- a/src/backend/catalog/.gitignore
+++ b/src/backend/catalog/.gitignore
@@ -1,5 +1,6 @@
 /postgres.bki
 /schemapg.h
+/system_fk_info.h
 /system_constraints.sql
 /pg_*_d.h
 /bki-stamp
diff --git a/src/backend/catalog/Catalog.pm b/src/backend/catalog/Catalog.pm
index 061f3d8c21..c597526f1f 100644
--- a/src/backend/catalog/Catalog.pm
+++ b/src/backend/catalog/Catalog.pm
@@ -105,6 +105,16 @@ sub ParseHeader
 				index_decl => $5
 			  };
 		}
+		elsif (/^DECLARE_(ARRAY_)?FOREIGN_KEY\(\s*\(([^)]+)\),\s*(\w+),\s*\(([^)]+)\)\)/)
+		{
+			push @{ $catalog{foreign_keys} },
+			  {
+				is_array => $1 ? 1 : 0,
+				fk_cols  => $2,
+				pk_table => $3,
+				pk_cols  => $4
+			  };
+		}
 		elsif (/^CATALOG\((\w+),(\d+),(\w+)\)/)
 		{
 			$catalog{catname}            = $1;
@@ -200,6 +210,17 @@ sub ParseHeader
 					elsif ($attopt =~ /BKI_LOOKUP\((\w+)\)/)
 					{
 						$column{lookup} = $1;
+						# BKI_LOOKUP implicitly makes an FK reference
+						push @{ $catalog{foreign_keys} },
+						  {
+							is_array =>
+							  ($atttype eq 'oidvector' || $atttype eq '_oid')
+							? 1
+							: 0,
+							fk_cols  => $attname,
+							pk_table => $1,
+							pk_cols  => 'oid'
+						  };
 					}
 					else
 					{
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index 995ddf1285..70bc2123df 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -70,7 +70,7 @@ CATALOG_HEADERS := \
 	pg_sequence.h pg_publication.h pg_publication_rel.h pg_subscription.h \
 	pg_subscription_rel.h
 
-GENERATED_HEADERS := $(CATALOG_HEADERS:%.h=%_d.h) schemapg.h
+GENERATED_HEADERS := $(CATALOG_HEADERS:%.h=%_d.h) schemapg.h system_fk_info.h
 
 POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/, $(CATALOG_HEADERS))
 
diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl
index b68c1752c0..caa637e1cd 100644
--- a/src/backend/catalog/genbki.pl
+++ b/src/backend/catalog/genbki.pl
@@ -213,6 +213,12 @@ foreach my $row (@{ $catalog_data{pg_am} })
 	$amoids{ $row->{amname} } = $row->{oid};
 }
 
+# There is only one authid at bootstrap time, and we handle it specially:
+# the usually-defaulted symbol PGUID becomes the bootstrap superuser's OID.
+# (We could drop this in favor of writing out BKI_DEFAULT(POSTGRES) ...)
+my %authidoids;
+$authidoids{'PGUID'} = $BOOTSTRAP_SUPERUSERID;
+
 # class (relation) OID lookup (note this only covers bootstrap catalogs!)
 my %classoids;
 foreach my $row (@{ $catalog_data{pg_class} })
@@ -234,6 +240,12 @@ foreach my $row (@{ $catalog_data{pg_language} })
 	$langoids{ $row->{lanname} } = $row->{oid};
 }
 
+# There is only one namespace at bootstrap time, and we handle it specially:
+# the usually-defaulted symbol PGNSP becomes the pg_catalog namespace's OID.
+# (We could drop this in favor of writing out BKI_DEFAULT(pg_catalog) ...)
+my %namespaceoids;
+$namespaceoids{'PGNSP'} = $PG_CATALOG_NAMESPACE;
+
 # opclass OID lookup
 my %opcoids;
 foreach my $row (@{ $catalog_data{pg_opclass} })
@@ -376,9 +388,11 @@ close $ef;
 # Map lookup name to the corresponding hash table.
 my %lookup_kind = (
 	pg_am          => \%amoids,
+	pg_authid      => \%authidoids,
 	pg_class       => \%classoids,
 	pg_collation   => \%collationoids,
 	pg_language    => \%langoids,
+	pg_namespace   => \%namespaceoids,
 	pg_opclass     => \%opcoids,
 	pg_operator    => \%operoids,
 	pg_opfamily    => \%opfoids,
@@ -400,6 +414,9 @@ open my $bki, '>', $bkifile . $tmpext
 my $schemafile = $output_path . 'schemapg.h';
 open my $schemapg, '>', $schemafile . $tmpext
   or die "can't open $schemafile$tmpext: $!";
+my $fk_info_file = $output_path . 'system_fk_info.h';
+open my $fk_info, '>', $fk_info_file . $tmpext
+  or die "can't open $fk_info_file$tmpext: $!";
 my $constraints_file = $output_path . 'system_constraints.sql';
 open my $constraints, '>', $constraints_file . $tmpext
   or die "can't open $constraints_file$tmpext: $!";
@@ -554,11 +571,6 @@ EOM
 				$GenbkiNextOid++;
 			}
 
-			# 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 OID synonyms with OIDs per the appropriate lookup rule.
 			#
 			# If the column type is oidvector or _oid, we have to replace
@@ -706,14 +718,74 @@ foreach my $table_name (@tables_needing_macros)
 # Closing boilerplate for schemapg.h
 print $schemapg "\n#endif\t\t\t\t\t\t\t/* SCHEMAPG_H */\n";
 
+# Now generate system_fk_info.h
+
+# Opening boilerplate for system_fk_info.h
+print $fk_info <<EOM;
+/*-------------------------------------------------------------------------
+ *
+ * system_fk_info.h
+ *    Data about the foreign-key relationships in the system catalogs
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * NOTES
+ *  ******************************
+ *  *** DO NOT EDIT THIS FILE! ***
+ *  ******************************
+ *
+ *  It has been GENERATED by src/backend/catalog/genbki.pl
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef SYSTEM_FK_INFO_H
+#define SYSTEM_FK_INFO_H
+
+typedef struct SysFKRelationship
+{
+	Oid			fk_table;		/* referencing catalog */
+	Oid			pk_table;		/* referenced catalog */
+	const char *fk_columns;		/* referencing column name(s) */
+	const char *pk_columns;		/* referenced column name(s) */
+	bool		is_array;		/* if true, last fk_column is an array */
+} SysFKRelationship;
+
+static const SysFKRelationship sys_fk_relationships[] = {
+EOM
+
+# Emit system_fk_info data
+foreach my $catname (@catnames)
+{
+	my $catalog = $catalogs{$catname};
+	foreach my $fkinfo (@{ $catalog->{foreign_keys} })
+	{
+		my $pktabname = $fkinfo->{pk_table};
+		# We use BKI_LOOKUP for encodings, but there's no real catalog
+		next if $pktabname eq 'encoding';
+		printf $fk_info
+		  "\t{ /* %s */ %s, /* %s */ %s, \"{%s}\", \"{%s}\", %s},\n",
+		  $catname,   $catalog->{relation_oid},
+		  $pktabname, $catalogs{$pktabname}->{relation_oid},
+		  $fkinfo->{fk_cols},
+		  $fkinfo->{pk_cols},
+		  ($fkinfo->{is_array} ? "true" : "false");
+	}
+}
+
+# Closing boilerplate for system_fk_info.h
+print $fk_info "};\n\n#endif\t\t\t\t\t\t\t/* SYSTEM_FK_INFO_H */\n";
+
 # We're done emitting data
 close $bki;
 close $schemapg;
+close $fk_info;
 close $constraints;
 
 # Finally, rename the completed files into place.
 Catalog::RenameTempFile($bkifile,    $tmpext);
 Catalog::RenameTempFile($schemafile, $tmpext);
+Catalog::RenameTempFile($fk_info_file, $tmpext);
 Catalog::RenameTempFile($constraints_file, $tmpext);
 
 exit 0;
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 4096faff9a..4a57ed4882 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -25,6 +25,7 @@
 #include "catalog/catalog.h"
 #include "catalog/pg_tablespace.h"
 #include "catalog/pg_type.h"
+#include "catalog/system_fk_info.h"
 #include "commands/dbcommands.h"
 #include "commands/tablespace.h"
 #include "common/keywords.h"
@@ -37,6 +38,7 @@
 #include "storage/fd.h"
 #include "tcop/tcopprot.h"
 #include "utils/builtins.h"
+#include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/ruleutils.h"
 #include "utils/timestamp.h"
@@ -489,6 +491,81 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 }
 
 
+/* Function to return the list of catalog foreign key relationships */
+Datum
+pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
+{
+	FuncCallContext *funcctx;
+	FmgrInfo   *arrayinp;
+
+	if (SRF_IS_FIRSTCALL())
+	{
+		MemoryContext oldcontext;
+		TupleDesc	tupdesc;
+
+		funcctx = SRF_FIRSTCALL_INIT();
+		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+		tupdesc = CreateTemplateTupleDesc(5);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "fktable",
+						   REGCLASSOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "fkcols",
+						   TEXTARRAYOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "pktable",
+						   REGCLASSOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pkcols",
+						   TEXTARRAYOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 5, "is_array",
+						   BOOLOID, -1, 0);
+
+		funcctx->tuple_desc = BlessTupleDesc(tupdesc);
+
+		/*
+		 * We use array_in to convert the C strings in sys_fk_relationships[]
+		 * to text arrays.  But we cannot use DirectFunctionCallN to call
+		 * array_in, and it wouldn't be very efficient if we could.  Fill an
+		 * FmgrInfo to use for the call.
+		 */
+		arrayinp = (FmgrInfo *) palloc(sizeof(FmgrInfo));
+		fmgr_info(F_ARRAY_IN, arrayinp);
+		funcctx->user_fctx = arrayinp;
+
+		MemoryContextSwitchTo(oldcontext);
+	}
+
+	funcctx = SRF_PERCALL_SETUP();
+	arrayinp = (FmgrInfo *) funcctx->user_fctx;
+
+	if (funcctx->call_cntr < lengthof(sys_fk_relationships))
+	{
+		const SysFKRelationship *fkrel = &sys_fk_relationships[funcctx->call_cntr];
+		Datum		values[5];
+		bool		nulls[5];
+		HeapTuple	tuple;
+
+		memset(nulls, false, sizeof(nulls));
+
+		values[0] = ObjectIdGetDatum(fkrel->fk_table);
+		values[1] = FunctionCall3(arrayinp,
+								  CStringGetDatum(fkrel->fk_columns),
+								  ObjectIdGetDatum(TEXTOID),
+								  Int32GetDatum(-1));
+		values[2] = ObjectIdGetDatum(fkrel->pk_table);
+		values[3] = FunctionCall3(arrayinp,
+								  CStringGetDatum(fkrel->pk_columns),
+								  ObjectIdGetDatum(TEXTOID),
+								  Int32GetDatum(-1));
+		values[4] = BoolGetDatum(fkrel->is_array);
+
+		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
+
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+	}
+
+	SRF_RETURN_DONE(funcctx);
+}
+
+
 /*
  * Return the type of the argument.
  */
diff --git a/src/include/Makefile b/src/include/Makefile
index c557375ae3..5f257a958c 100644
--- a/src/include/Makefile
+++ b/src/include/Makefile
@@ -54,7 +54,7 @@ install: all installdirs
 	  cp $(srcdir)/$$dir/*.h '$(DESTDIR)$(includedir_server)'/$$dir/ || exit; \
 	done
 ifeq ($(vpath_build),yes)
-	for file in catalog/schemapg.h catalog/pg_*_d.h parser/gram.h storage/lwlocknames.h utils/probes.h; do \
+	for file in catalog/schemapg.h catalog/system_fk_info.h catalog/pg_*_d.h parser/gram.h storage/lwlocknames.h utils/probes.h; do \
 	  cp $$file '$(DESTDIR)$(includedir_server)'/$$file || exit; \
 	done
 endif
@@ -79,7 +79,8 @@ uninstall:
 clean:
 	rm -f utils/fmgroids.h utils/fmgrprotos.h utils/errcodes.h utils/header-stamp
 	rm -f parser/gram.h storage/lwlocknames.h utils/probes.h
-	rm -f catalog/schemapg.h catalog/pg_*_d.h catalog/header-stamp
+	rm -f catalog/schemapg.h catalog/system_fk_info.h
+	rm -f catalog/pg_*_d.h catalog/header-stamp
 
 distclean maintainer-clean: clean
 	rm -f pg_config.h pg_config_ext.h pg_config_os.h stamp-h stamp-ext-h
diff --git a/src/include/catalog/.gitignore b/src/include/catalog/.gitignore
index 6c8da5401d..6b83d4c7e6 100644
--- a/src/include/catalog/.gitignore
+++ b/src/include/catalog/.gitignore
@@ -1,3 +1,4 @@
 /schemapg.h
+/system_fk_info.h
 /pg_*_d.h
 /header-stamp
diff --git a/src/include/catalog/genbki.h b/src/include/catalog/genbki.h
index 5d05fafb5d..dfd68ab75c 100644
--- a/src/include/catalog/genbki.h
+++ b/src/include/catalog/genbki.h
@@ -75,6 +75,29 @@
 #define DECLARE_UNIQUE_INDEX(name,oid,decl) extern int no_such_variable
 #define DECLARE_UNIQUE_INDEX_PKEY(name,oid,decl) extern int no_such_variable
 
+/*
+ * These lines are processed by genbki.pl to create a table for use
+ * by the pg_get_catalog_foreign_keys() function.  We do not have any
+ * mechanism that actually enforces foreign-key relationships in the
+ * system catalogs, but it is still useful to record the intended
+ * relationships in a machine-readable form.
+ *
+ * The keyword is DECLARE_FOREIGN_KEY or DECLARE_ARRAY_FOREIGN_KEY.
+ * The first argument is a parenthesized list of the referencing columns;
+ * the second, the name of the referenced table; the third, a parenthesized
+ * list of the referenced columns.  Use of the ARRAY macro means that the
+ * last referencing column is an array, each of whose elements is supposed
+ * to match some entry in the last referenced column.
+ *
+ * Columns that are marked with a BKI_LOOKUP rule do not need an explicit
+ * DECLARE_FOREIGN_KEY macro, as genbki.pl can infer the FK relationship
+ * from that.  Thus, these macros are only needed in special cases.
+ *
+ * The macro definitions are just to keep the C compiler from spitting up.
+ */
+#define DECLARE_FOREIGN_KEY(cols,reftbl,refcols) extern int no_such_variable
+#define DECLARE_ARRAY_FOREIGN_KEY(cols,reftbl,refcols) extern int no_such_variable
+
 /* The following are never defined; they are here only for documentation. */
 
 /*
diff --git a/src/include/catalog/pg_attrdef.h b/src/include/catalog/pg_attrdef.h
index 03efaaded9..d689ca20c8 100644
--- a/src/include/catalog/pg_attrdef.h
+++ b/src/include/catalog/pg_attrdef.h
@@ -30,7 +30,8 @@ CATALOG(pg_attrdef,2604,AttrDefaultRelationId)
 {
 	Oid			oid;			/* oid */
 
-	Oid			adrelid;		/* OID of table containing attribute */
+	Oid			adrelid BKI_LOOKUP(pg_class);	/* OID of table containing
+												 * attribute */
 	int16		adnum;			/* attnum of attribute */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
@@ -53,4 +54,6 @@ DECLARE_UNIQUE_INDEX(pg_attrdef_adrelid_adnum_index, 2656, on pg_attrdef using b
 DECLARE_UNIQUE_INDEX_PKEY(pg_attrdef_oid_index, 2657, on pg_attrdef using btree(oid oid_ops));
 #define AttrDefaultOidIndexId  2657
 
+DECLARE_FOREIGN_KEY((adrelid, adnum), pg_attribute, (attrelid, attnum));
+
 #endif							/* PG_ATTRDEF_H */
diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h
index ba0efff08c..3db0ca07e1 100644
--- a/src/include/catalog/pg_attribute.h
+++ b/src/include/catalog/pg_attribute.h
@@ -36,7 +36,8 @@
  */
 CATALOG(pg_attribute,1249,AttributeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(75,AttributeRelation_Rowtype_Id) BKI_SCHEMA_MACRO
 {
-	Oid			attrelid;		/* OID of relation containing this attribute */
+	Oid			attrelid BKI_LOOKUP(pg_class);	/* OID of relation containing
+												 * this attribute */
 	NameData	attname;		/* name of attribute */
 
 	/*
@@ -46,7 +47,7 @@ CATALOG(pg_attribute,1249,AttributeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(75,
 	 * attributes of this instance, so they had better match or Postgres will
 	 * fail.
 	 */
-	Oid			atttypid;
+	Oid			atttypid BKI_LOOKUP(pg_type);
 
 	/*
 	 * attstattarget is the target number of statistics datapoints to collect
@@ -154,7 +155,7 @@ CATALOG(pg_attribute,1249,AttributeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(75,
 	int32		attinhcount BKI_DEFAULT(0);
 
 	/* attribute's collation */
-	Oid			attcollation;
+	Oid			attcollation BKI_LOOKUP(pg_collation);
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	/* NOTE: The following fields are not present in tuple descriptors. */
diff --git a/src/include/catalog/pg_auth_members.h b/src/include/catalog/pg_auth_members.h
index e90c395640..76ab90c939 100644
--- a/src/include/catalog/pg_auth_members.h
+++ b/src/include/catalog/pg_auth_members.h
@@ -29,9 +29,9 @@
  */
 CATALOG(pg_auth_members,1261,AuthMemRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID(2843,AuthMemRelation_Rowtype_Id) BKI_SCHEMA_MACRO
 {
-	Oid			roleid;			/* ID of a role */
-	Oid			member;			/* ID of a member of that role */
-	Oid			grantor;		/* who granted the membership */
+	Oid			roleid BKI_LOOKUP(pg_authid);	/* ID of a role */
+	Oid			member BKI_LOOKUP(pg_authid);	/* ID of a member of that role */
+	Oid			grantor BKI_LOOKUP(pg_authid);	/* who granted the membership */
 	bool		admin_option;	/* granted with admin option? */
 } FormData_pg_auth_members;
 
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index eca306ca98..22257b81ce 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -38,7 +38,7 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat
 	NameData	relname;
 
 	/* OID of namespace containing this class */
-	Oid			relnamespace BKI_DEFAULT(PGNSP);
+	Oid			relnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* OID of entry in pg_type for table's implicit row type */
 	Oid			reltype BKI_LOOKUP(pg_type);
@@ -47,7 +47,7 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat
 	Oid			reloftype BKI_DEFAULT(0) BKI_LOOKUP(pg_type);
 
 	/* class owner */
-	Oid			relowner BKI_DEFAULT(PGUID);
+	Oid			relowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/* access method; 0 if not a table / index */
 	Oid			relam BKI_DEFAULT(heap) BKI_LOOKUP(pg_am);
@@ -69,7 +69,7 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat
 	int32		relallvisible BKI_DEFAULT(0);
 
 	/* OID of toast table; 0 if none */
-	Oid			reltoastrelid BKI_DEFAULT(0);
+	Oid			reltoastrelid BKI_DEFAULT(0) BKI_LOOKUP(pg_class);
 
 	/* T if has (or has had) any indexes */
 	bool		relhasindex BKI_DEFAULT(f);
@@ -120,7 +120,7 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat
 	bool		relispartition BKI_DEFAULT(f);
 
 	/* heap for rewrite during DDL, link to original rel */
-	Oid			relrewrite BKI_DEFAULT(0);
+	Oid			relrewrite BKI_DEFAULT(0) BKI_LOOKUP(pg_class);
 
 	/* all Xids < this are frozen in this rel */
 	TransactionId relfrozenxid BKI_DEFAULT(3);	/* FirstNormalTransactionId */
diff --git a/src/include/catalog/pg_collation.dat b/src/include/catalog/pg_collation.dat
index ad57b0fa6d..6e0ab1ab4b 100644
--- a/src/include/catalog/pg_collation.dat
+++ b/src/include/catalog/pg_collation.dat
@@ -14,18 +14,15 @@
 
 { oid => '100', oid_symbol => 'DEFAULT_COLLATION_OID',
   descr => 'database\'s default collation',
-  collname => 'default', collnamespace => 'PGNSP', collowner => 'PGUID',
-  collprovider => 'd', collencoding => '-1', collcollate => '',
-  collctype => '' },
+  collname => 'default', collprovider => 'd', collencoding => '-1',
+  collcollate => '', collctype => '' },
 { oid => '950', oid_symbol => 'C_COLLATION_OID',
   descr => 'standard C collation',
-  collname => 'C', collnamespace => 'PGNSP', collowner => 'PGUID',
-  collprovider => 'c', collencoding => '-1', collcollate => 'C',
-  collctype => 'C' },
+  collname => 'C', collprovider => 'c', collencoding => '-1',
+  collcollate => 'C', collctype => 'C' },
 { oid => '951', oid_symbol => 'POSIX_COLLATION_OID',
   descr => 'standard POSIX collation',
-  collname => 'POSIX', collnamespace => 'PGNSP', collowner => 'PGUID',
-  collprovider => 'c', collencoding => '-1', collcollate => 'POSIX',
-  collctype => 'POSIX' },
+  collname => 'POSIX', collprovider => 'c', collencoding => '-1',
+  collcollate => 'POSIX', collctype => 'POSIX' },
 
 ]
diff --git a/src/include/catalog/pg_collation.h b/src/include/catalog/pg_collation.h
index 3c496ea914..3bd7873c68 100644
--- a/src/include/catalog/pg_collation.h
+++ b/src/include/catalog/pg_collation.h
@@ -30,8 +30,9 @@ CATALOG(pg_collation,3456,CollationRelationId)
 {
 	Oid			oid;			/* oid */
 	NameData	collname;		/* collation name */
-	Oid			collnamespace;	/* OID of namespace containing collation */
-	Oid			collowner;		/* owner of collation */
+	Oid			collnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);	/* OID of namespace
+																			 * containing collation */
+	Oid			collowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); /* owner of collation */
 	char		collprovider;	/* see constants below */
 	bool		collisdeterministic BKI_DEFAULT(t);
 	int32		collencoding;	/* encoding for this collation; -1 = "all" */
diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h
index 6449937b35..67980c5824 100644
--- a/src/include/catalog/pg_constraint.h
+++ b/src/include/catalog/pg_constraint.h
@@ -46,7 +46,8 @@ CATALOG(pg_constraint,2606,ConstraintRelationId)
 	 * conrelid + contypid + conname.
 	 */
 	NameData	conname;		/* name of this constraint */
-	Oid			connamespace;	/* OID of namespace containing constraint */
+	Oid			connamespace BKI_LOOKUP(pg_namespace);	/* OID of namespace
+														 * containing constraint */
 	char		contype;		/* constraint type; see codes below */
 	bool		condeferrable;	/* deferrable constraint? */
 	bool		condeferred;	/* deferred by default? */
@@ -57,7 +58,8 @@ CATALOG(pg_constraint,2606,ConstraintRelationId)
 	 * specific relation (this excludes domain constraints and assertions).
 	 * Otherwise conrelid is 0 and conkey is NULL.
 	 */
-	Oid			conrelid;		/* relation this constraint constrains */
+	Oid			conrelid BKI_LOOKUP(pg_class);	/* relation this constraint
+												 * constrains */
 
 	/*
 	 * contypid links to the pg_type row for a domain if this is a domain
@@ -66,7 +68,8 @@ CATALOG(pg_constraint,2606,ConstraintRelationId)
 	 * For SQL-style global ASSERTIONs, both conrelid and contypid would be
 	 * zero. This is not presently supported, however.
 	 */
-	Oid			contypid;		/* domain this constraint constrains */
+	Oid			contypid BKI_LOOKUP(pg_type);	/* domain this constraint
+												 * constrains */
 
 	/*
 	 * conindid links to the index supporting the constraint, if any;
@@ -76,19 +79,21 @@ CATALOG(pg_constraint,2606,ConstraintRelationId)
 	 * columns).  Notice that the index is on conrelid in the first case but
 	 * confrelid in the second.
 	 */
-	Oid			conindid;		/* index supporting this constraint */
+	Oid			conindid BKI_LOOKUP(pg_class);	/* index supporting this
+												 * constraint */
 
 	/*
 	 * If this constraint is on a partition inherited from a partitioned
 	 * table, this is the OID of the corresponding constraint in the parent.
 	 */
-	Oid			conparentid;
+	Oid			conparentid BKI_LOOKUP(pg_constraint);
 
 	/*
 	 * These fields, plus confkey, are only meaningful for a foreign-key
 	 * constraint.  Otherwise confrelid is 0 and the char fields are spaces.
 	 */
-	Oid			confrelid;		/* relation referenced by foreign key */
+	Oid			confrelid BKI_LOOKUP(pg_class); /* relation referenced by
+												 * foreign key */
 	char		confupdtype;	/* foreign key's ON UPDATE action */
 	char		confdeltype;	/* foreign key's ON DELETE action */
 	char		confmatchtype;	/* foreign key's match type */
@@ -119,25 +124,25 @@ CATALOG(pg_constraint,2606,ConstraintRelationId)
 	 * If a foreign key, the OIDs of the PK = FK equality operators for each
 	 * column of the constraint
 	 */
-	Oid			conpfeqop[1];
+	Oid			conpfeqop[1] BKI_LOOKUP(pg_operator);
 
 	/*
 	 * If a foreign key, the OIDs of the PK = PK equality operators for each
 	 * column of the constraint (i.e., equality for the referenced columns)
 	 */
-	Oid			conppeqop[1];
+	Oid			conppeqop[1] BKI_LOOKUP(pg_operator);
 
 	/*
 	 * If a foreign key, the OIDs of the FK = FK equality operators for each
 	 * column of the constraint (i.e., equality for the referencing columns)
 	 */
-	Oid			conffeqop[1];
+	Oid			conffeqop[1] BKI_LOOKUP(pg_operator);
 
 	/*
 	 * If an exclusion constraint, the OIDs of the exclusion operators for
 	 * each column of the constraint
 	 */
-	Oid			conexclop[1];
+	Oid			conexclop[1] BKI_LOOKUP(pg_operator);
 
 	/*
 	 * If a check constraint, nodeToString representation of expression
@@ -166,6 +171,9 @@ DECLARE_UNIQUE_INDEX_PKEY(pg_constraint_oid_index, 2667, on pg_constraint using
 DECLARE_INDEX(pg_constraint_conparentid_index, 2579, on pg_constraint using btree(conparentid oid_ops));
 #define ConstraintParentIndexId	2579
 
+DECLARE_ARRAY_FOREIGN_KEY((conrelid, conkey), pg_attribute, (attrelid, attnum));
+DECLARE_ARRAY_FOREIGN_KEY((confrelid, confkey), pg_attribute, (attrelid, attnum));
+
 #ifdef EXPOSE_TO_CLIENT_CODE
 
 /* Valid values for contype */
diff --git a/src/include/catalog/pg_conversion.h b/src/include/catalog/pg_conversion.h
index b02dfe0c3f..96bb92f251 100644
--- a/src/include/catalog/pg_conversion.h
+++ b/src/include/catalog/pg_conversion.h
@@ -35,10 +35,10 @@ CATALOG(pg_conversion,2607,ConversionRelationId)
 	NameData	conname;
 
 	/* namespace that the conversion belongs to */
-	Oid			connamespace BKI_DEFAULT(PGNSP);
+	Oid			connamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* owner of the conversion */
-	Oid			conowner BKI_DEFAULT(PGUID);
+	Oid			conowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/* FOR encoding id */
 	int32		conforencoding BKI_LOOKUP(encoding);
diff --git a/src/include/catalog/pg_database.h b/src/include/catalog/pg_database.h
index b7a0b6a381..f0240c58cf 100644
--- a/src/include/catalog/pg_database.h
+++ b/src/include/catalog/pg_database.h
@@ -35,7 +35,7 @@ CATALOG(pg_database,1262,DatabaseRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID
 	NameData	datname;
 
 	/* owner of database */
-	Oid			datdba BKI_DEFAULT(PGUID);
+	Oid			datdba BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/* character encoding */
 	int32		encoding;
diff --git a/src/include/catalog/pg_db_role_setting.h b/src/include/catalog/pg_db_role_setting.h
index f18819d670..13d5a80021 100644
--- a/src/include/catalog/pg_db_role_setting.h
+++ b/src/include/catalog/pg_db_role_setting.h
@@ -33,8 +33,11 @@
  */
 CATALOG(pg_db_role_setting,2964,DbRoleSettingRelationId) BKI_SHARED_RELATION
 {
-	Oid			setdatabase;	/* database */
-	Oid			setrole;		/* role */
+	/* database, or 0 for a role-specific setting */
+	Oid			setdatabase BKI_LOOKUP(pg_database);
+
+	/* role, or 0 for a database-specific setting */
+	Oid			setrole BKI_LOOKUP(pg_authid);
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	text		setconfig[1];	/* GUC settings to apply at login */
diff --git a/src/include/catalog/pg_default_acl.h b/src/include/catalog/pg_default_acl.h
index bb7db32cd6..91c164bbea 100644
--- a/src/include/catalog/pg_default_acl.h
+++ b/src/include/catalog/pg_default_acl.h
@@ -30,8 +30,10 @@
 CATALOG(pg_default_acl,826,DefaultAclRelationId)
 {
 	Oid			oid;			/* oid */
-	Oid			defaclrole;		/* OID of role owning this ACL */
-	Oid			defaclnamespace;	/* OID of namespace, or 0 for all */
+	Oid			defaclrole BKI_LOOKUP(pg_authid);	/* OID of role owning this
+													 * ACL */
+	Oid			defaclnamespace BKI_LOOKUP(pg_namespace);	/* OID of namespace, or
+															 * 0 for all */
 	char		defaclobjtype;	/* see DEFACLOBJ_xxx constants below */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
diff --git a/src/include/catalog/pg_depend.h b/src/include/catalog/pg_depend.h
index b083790180..1d5b16db3d 100644
--- a/src/include/catalog/pg_depend.h
+++ b/src/include/catalog/pg_depend.h
@@ -45,14 +45,16 @@ CATALOG(pg_depend,2608,DependRelationId)
 	 *
 	 * These fields are all zeroes for a DEPENDENCY_PIN entry.
 	 */
-	Oid			classid;		/* OID of table containing object */
+	Oid			classid BKI_LOOKUP(pg_class);	/* OID of table containing
+												 * object */
 	Oid			objid;			/* OID of object itself */
 	int32		objsubid;		/* column number, or 0 if not used */
 
 	/*
 	 * Identification of the independent (referenced) object.
 	 */
-	Oid			refclassid;		/* OID of table containing object */
+	Oid			refclassid BKI_LOOKUP(pg_class);	/* OID of table containing
+													 * object */
 	Oid			refobjid;		/* OID of object itself */
 	int32		refobjsubid;	/* column number, or 0 if not used */
 
diff --git a/src/include/catalog/pg_description.h b/src/include/catalog/pg_description.h
index ad9de5e0a0..adc06a854d 100644
--- a/src/include/catalog/pg_description.h
+++ b/src/include/catalog/pg_description.h
@@ -68,4 +68,7 @@ DECLARE_TOAST(pg_description, 2834, 2835);
 DECLARE_UNIQUE_INDEX_PKEY(pg_description_o_c_o_index, 2675, on pg_description using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops));
 #define DescriptionObjIndexId  2675
 
+/* We do not use BKI_LOOKUP here because it causes problems for genbki.pl */
+DECLARE_FOREIGN_KEY((classoid), pg_class, (oid));
+
 #endif							/* PG_DESCRIPTION_H */
diff --git a/src/include/catalog/pg_enum.h b/src/include/catalog/pg_enum.h
index 5eaf70772c..78a183b27d 100644
--- a/src/include/catalog/pg_enum.h
+++ b/src/include/catalog/pg_enum.h
@@ -31,7 +31,7 @@
 CATALOG(pg_enum,3501,EnumRelationId)
 {
 	Oid			oid;			/* oid */
-	Oid			enumtypid;		/* OID of owning enum type */
+	Oid			enumtypid BKI_LOOKUP(pg_type);	/* OID of owning enum type */
 	float4		enumsortorder;	/* sort position of this enum value */
 	NameData	enumlabel;		/* text representation of enum value */
 } FormData_pg_enum;
diff --git a/src/include/catalog/pg_event_trigger.h b/src/include/catalog/pg_event_trigger.h
index 6f0266ed0f..eeaa6be518 100644
--- a/src/include/catalog/pg_event_trigger.h
+++ b/src/include/catalog/pg_event_trigger.h
@@ -31,8 +31,9 @@ CATALOG(pg_event_trigger,3466,EventTriggerRelationId)
 	Oid			oid;			/* oid */
 	NameData	evtname;		/* trigger's name */
 	NameData	evtevent;		/* trigger's event */
-	Oid			evtowner;		/* trigger's owner */
-	Oid			evtfoid;		/* OID of function to be called */
+	Oid			evtowner BKI_LOOKUP(pg_authid); /* trigger's owner */
+	Oid			evtfoid BKI_LOOKUP(pg_proc);	/* OID of function to be
+												 * called */
 	char		evtenabled;		/* trigger's firing configuration WRT
 								 * session_replication_role */
 
diff --git a/src/include/catalog/pg_extension.h b/src/include/catalog/pg_extension.h
index af119bfea7..2d6ad9fa88 100644
--- a/src/include/catalog/pg_extension.h
+++ b/src/include/catalog/pg_extension.h
@@ -30,14 +30,16 @@ CATALOG(pg_extension,3079,ExtensionRelationId)
 {
 	Oid			oid;			/* oid */
 	NameData	extname;		/* extension name */
-	Oid			extowner;		/* extension owner */
-	Oid			extnamespace;	/* namespace of contained objects */
+	Oid			extowner BKI_LOOKUP(pg_authid); /* extension owner */
+	Oid			extnamespace BKI_LOOKUP(pg_namespace);	/* namespace of
+														 * contained objects */
 	bool		extrelocatable; /* if true, allow ALTER EXTENSION SET SCHEMA */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	/* extversion may never be null, but the others can be. */
 	text		extversion BKI_FORCE_NOT_NULL;	/* extension version name */
-	Oid			extconfig[1];	/* dumpable configuration tables */
+	Oid			extconfig[1] BKI_LOOKUP(pg_class);	/* dumpable configuration
+													 * tables */
 	text		extcondition[1];	/* WHERE clauses for config tables */
 #endif
 } FormData_pg_extension;
diff --git a/src/include/catalog/pg_foreign_data_wrapper.h b/src/include/catalog/pg_foreign_data_wrapper.h
index 0f523a26b9..ad17b7d47f 100644
--- a/src/include/catalog/pg_foreign_data_wrapper.h
+++ b/src/include/catalog/pg_foreign_data_wrapper.h
@@ -30,9 +30,11 @@ CATALOG(pg_foreign_data_wrapper,2328,ForeignDataWrapperRelationId)
 {
 	Oid			oid;			/* oid */
 	NameData	fdwname;		/* foreign-data wrapper name */
-	Oid			fdwowner;		/* FDW owner */
-	Oid			fdwhandler;		/* handler function, or 0 if none */
-	Oid			fdwvalidator;	/* option validation function, or 0 if none */
+	Oid			fdwowner BKI_LOOKUP(pg_authid); /* FDW owner */
+	Oid			fdwhandler BKI_LOOKUP(pg_proc); /* handler function, or 0 if
+												 * none */
+	Oid			fdwvalidator BKI_LOOKUP(pg_proc);	/* option validation
+													 * function, or 0 if none */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	aclitem		fdwacl[1];		/* access permissions */
diff --git a/src/include/catalog/pg_foreign_server.h b/src/include/catalog/pg_foreign_server.h
index 385b896e97..a173699aef 100644
--- a/src/include/catalog/pg_foreign_server.h
+++ b/src/include/catalog/pg_foreign_server.h
@@ -29,8 +29,8 @@ CATALOG(pg_foreign_server,1417,ForeignServerRelationId)
 {
 	Oid			oid;			/* oid */
 	NameData	srvname;		/* foreign server name */
-	Oid			srvowner;		/* server owner */
-	Oid			srvfdw;			/* server FDW */
+	Oid			srvowner BKI_LOOKUP(pg_authid); /* server owner */
+	Oid			srvfdw BKI_LOOKUP(pg_foreign_data_wrapper); /* server FDW */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	text		srvtype;
diff --git a/src/include/catalog/pg_foreign_table.h b/src/include/catalog/pg_foreign_table.h
index 24f7f2998e..3b6221b0e6 100644
--- a/src/include/catalog/pg_foreign_table.h
+++ b/src/include/catalog/pg_foreign_table.h
@@ -27,8 +27,8 @@
  */
 CATALOG(pg_foreign_table,3118,ForeignTableRelationId)
 {
-	Oid			ftrelid;		/* OID of foreign table */
-	Oid			ftserver;		/* OID of foreign server */
+	Oid			ftrelid BKI_LOOKUP(pg_class);	/* OID of foreign table */
+	Oid			ftserver BKI_LOOKUP(pg_foreign_server); /* OID of foreign server */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	text		ftoptions[1];	/* FDW-specific options */
diff --git a/src/include/catalog/pg_index.h b/src/include/catalog/pg_index.h
index 1a7aef18ce..eb4e1cec36 100644
--- a/src/include/catalog/pg_index.h
+++ b/src/include/catalog/pg_index.h
@@ -28,8 +28,9 @@
  */
 CATALOG(pg_index,2610,IndexRelationId) BKI_SCHEMA_MACRO
 {
-	Oid			indexrelid;		/* OID of the index */
-	Oid			indrelid;		/* OID of the relation it indexes */
+	Oid			indexrelid BKI_LOOKUP(pg_class);	/* OID of the index */
+	Oid			indrelid BKI_LOOKUP(pg_class);	/* OID of the relation it
+												 * indexes */
 	int16		indnatts;		/* total number of columns in index */
 	int16		indnkeyatts;	/* number of key columns in index */
 	bool		indisunique;	/* is this a unique index? */
@@ -48,8 +49,8 @@ CATALOG(pg_index,2610,IndexRelationId) BKI_SCHEMA_MACRO
 											 * or 0 */
 
 #ifdef CATALOG_VARLEN
-	oidvector	indcollation BKI_FORCE_NOT_NULL;	/* collation identifiers */
-	oidvector	indclass BKI_FORCE_NOT_NULL;	/* opclass identifiers */
+	oidvector	indcollation BKI_LOOKUP(pg_collation) BKI_FORCE_NOT_NULL;	/* collation identifiers */
+	oidvector	indclass BKI_LOOKUP(pg_opclass) BKI_FORCE_NOT_NULL; /* opclass identifiers */
 	int2vector	indoption BKI_FORCE_NOT_NULL;	/* per-column flags
 												 * (AM-specific meanings) */
 	pg_node_tree indexprs;		/* expression trees for index attributes that
@@ -72,6 +73,8 @@ DECLARE_INDEX(pg_index_indrelid_index, 2678, on pg_index using btree(indrelid oi
 DECLARE_UNIQUE_INDEX_PKEY(pg_index_indexrelid_index, 2679, on pg_index using btree(indexrelid oid_ops));
 #define IndexRelidIndexId  2679
 
+DECLARE_ARRAY_FOREIGN_KEY((indrelid, indkey), pg_attribute, (attrelid, attnum));
+
 #ifdef EXPOSE_TO_CLIENT_CODE
 
 /*
diff --git a/src/include/catalog/pg_inherits.h b/src/include/catalog/pg_inherits.h
index b8147796d8..2b71cad9a2 100644
--- a/src/include/catalog/pg_inherits.h
+++ b/src/include/catalog/pg_inherits.h
@@ -31,8 +31,8 @@
  */
 CATALOG(pg_inherits,2611,InheritsRelationId)
 {
-	Oid			inhrelid;
-	Oid			inhparent;
+	Oid			inhrelid BKI_LOOKUP(pg_class);
+	Oid			inhparent BKI_LOOKUP(pg_class);
 	int32		inhseqno;
 } FormData_pg_inherits;
 
diff --git a/src/include/catalog/pg_init_privs.h b/src/include/catalog/pg_init_privs.h
index 983b1857c0..4aafeb246d 100644
--- a/src/include/catalog/pg_init_privs.h
+++ b/src/include/catalog/pg_init_privs.h
@@ -46,7 +46,8 @@
 CATALOG(pg_init_privs,3394,InitPrivsRelationId)
 {
 	Oid			objoid;			/* OID of object itself */
-	Oid			classoid;		/* OID of table containing object */
+	Oid			classoid BKI_LOOKUP(pg_class);	/* OID of table containing
+												 * object */
 	int32		objsubid;		/* column number, or 0 if not used */
 	char		privtype;		/* from initdb or extension? */
 
diff --git a/src/include/catalog/pg_language.h b/src/include/catalog/pg_language.h
index b1dcd0a4f5..0a86768447 100644
--- a/src/include/catalog/pg_language.h
+++ b/src/include/catalog/pg_language.h
@@ -34,7 +34,7 @@ CATALOG(pg_language,2612,LanguageRelationId)
 	NameData	lanname;
 
 	/* Language's owner */
-	Oid			lanowner BKI_DEFAULT(PGUID);
+	Oid			lanowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/* Is a procedural language */
 	bool		lanispl BKI_DEFAULT(f);
diff --git a/src/include/catalog/pg_largeobject.h b/src/include/catalog/pg_largeobject.h
index f453319322..32225f4de7 100644
--- a/src/include/catalog/pg_largeobject.h
+++ b/src/include/catalog/pg_largeobject.h
@@ -28,7 +28,8 @@
  */
 CATALOG(pg_largeobject,2613,LargeObjectRelationId)
 {
-	Oid			loid;			/* Identifier of large object */
+	Oid			loid BKI_LOOKUP(pg_largeobject_metadata);	/* Identifier of large
+															 * object */
 	int32		pageno;			/* Page number (starting from 0) */
 
 	/* data has variable length, but we allow direct access; see inv_api.c */
diff --git a/src/include/catalog/pg_largeobject_metadata.h b/src/include/catalog/pg_largeobject_metadata.h
index 220988b0ad..9b689bab84 100644
--- a/src/include/catalog/pg_largeobject_metadata.h
+++ b/src/include/catalog/pg_largeobject_metadata.h
@@ -31,7 +31,8 @@ CATALOG(pg_largeobject_metadata,2995,LargeObjectMetadataRelationId)
 {
 	Oid			oid;			/* oid */
 
-	Oid			lomowner;		/* OID of the largeobject owner */
+	Oid			lomowner BKI_LOOKUP(pg_authid); /* OID of the largeobject
+												 * owner */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	aclitem		lomacl[1];		/* access permissions */
diff --git a/src/include/catalog/pg_namespace.dat b/src/include/catalog/pg_namespace.dat
index 76257e98fc..2ed136b787 100644
--- a/src/include/catalog/pg_namespace.dat
+++ b/src/include/catalog/pg_namespace.dat
@@ -14,12 +14,12 @@
 
 { oid => '11', oid_symbol => 'PG_CATALOG_NAMESPACE',
   descr => 'system catalog schema',
-  nspname => 'pg_catalog', nspowner => 'PGUID', nspacl => '_null_' },
+  nspname => 'pg_catalog', nspacl => '_null_' },
 { oid => '99', oid_symbol => 'PG_TOAST_NAMESPACE',
   descr => 'reserved schema for TOAST tables',
-  nspname => 'pg_toast', nspowner => 'PGUID', nspacl => '_null_' },
+  nspname => 'pg_toast', nspacl => '_null_' },
 { oid => '2200', oid_symbol => 'PG_PUBLIC_NAMESPACE',
   descr => 'standard public schema',
-  nspname => 'public', nspowner => 'PGUID', nspacl => '_null_' },
+  nspname => 'public', nspacl => '_null_' },
 
 ]
diff --git a/src/include/catalog/pg_namespace.h b/src/include/catalog/pg_namespace.h
index 0a68958b1c..d920c6cfc6 100644
--- a/src/include/catalog/pg_namespace.h
+++ b/src/include/catalog/pg_namespace.h
@@ -37,7 +37,7 @@ CATALOG(pg_namespace,2615,NamespaceRelationId)
 	Oid			oid;			/* oid */
 
 	NameData	nspname;
-	Oid			nspowner;
+	Oid			nspowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	aclitem		nspacl[1];
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index d132df1f2f..ddeb21ad21 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -57,10 +57,10 @@ CATALOG(pg_opclass,2616,OperatorClassRelationId)
 	NameData	opcname;
 
 	/* namespace of this opclass */
-	Oid			opcnamespace BKI_DEFAULT(PGNSP);
+	Oid			opcnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* opclass owner */
-	Oid			opcowner BKI_DEFAULT(PGUID);
+	Oid			opcowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/* containing operator family */
 	Oid			opcfamily BKI_LOOKUP(pg_opfamily);
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 3ca57e7c1b..6277a6edfe 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -36,10 +36,10 @@ CATALOG(pg_operator,2617,OperatorRelationId)
 	NameData	oprname;
 
 	/* OID of namespace containing this oper */
-	Oid			oprnamespace BKI_DEFAULT(PGNSP);
+	Oid			oprnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* operator owner */
-	Oid			oprowner BKI_DEFAULT(PGUID);
+	Oid			oprowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/* 'l' for prefix or 'b' for infix */
 	char		oprkind BKI_DEFAULT(b);
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index 18385a6fd6..1a723b76f6 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -37,10 +37,10 @@ CATALOG(pg_opfamily,2753,OperatorFamilyRelationId)
 	NameData	opfname;
 
 	/* namespace of this opfamily */
-	Oid			opfnamespace BKI_DEFAULT(PGNSP);
+	Oid			opfnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* opfamily owner */
-	Oid			opfowner BKI_DEFAULT(PGUID);
+	Oid			opfowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 } FormData_pg_opfamily;
 
 /* ----------------
diff --git a/src/include/catalog/pg_partitioned_table.h b/src/include/catalog/pg_partitioned_table.h
index 038730b005..2ccf2e36bc 100644
--- a/src/include/catalog/pg_partitioned_table.h
+++ b/src/include/catalog/pg_partitioned_table.h
@@ -29,11 +29,12 @@
  */
 CATALOG(pg_partitioned_table,3350,PartitionedRelationId)
 {
-	Oid			partrelid;		/* partitioned table oid */
+	Oid			partrelid BKI_LOOKUP(pg_class); /* partitioned table oid */
 	char		partstrat;		/* partitioning strategy */
 	int16		partnatts;		/* number of partition key columns */
-	Oid			partdefid;		/* default partition oid; InvalidOid if there
-								 * isn't one */
+	Oid			partdefid BKI_LOOKUP(pg_class); /* default partition oid;
+												 * InvalidOid if there isn't
+												 * one */
 
 	/*
 	 * variable-length fields start here, but we allow direct access to
@@ -48,10 +49,10 @@ CATALOG(pg_partitioned_table,3350,PartitionedRelationId)
 												 * an expression */
 
 #ifdef CATALOG_VARLEN
-	oidvector	partclass BKI_FORCE_NOT_NULL;	/* operator class to compare
-												 * keys */
-	oidvector	partcollation BKI_FORCE_NOT_NULL;	/* user-specified
-													 * collation for keys */
+	oidvector	partclass BKI_LOOKUP(pg_opclass) BKI_FORCE_NOT_NULL;	/* operator class to
+																		 * compare keys */
+	oidvector	partcollation BKI_LOOKUP(pg_collation) BKI_FORCE_NOT_NULL;	/* user-specified
+																			 * collation for keys */
 	pg_node_tree partexprs;		/* list of expressions in the partition key;
 								 * one item for each zero entry in partattrs[] */
 #endif
@@ -69,4 +70,6 @@ DECLARE_TOAST(pg_partitioned_table, 4165, 4166);
 DECLARE_UNIQUE_INDEX_PKEY(pg_partitioned_table_partrelid_index, 3351, on pg_partitioned_table using btree(partrelid oid_ops));
 #define PartitionedRelidIndexId			 3351
 
+DECLARE_ARRAY_FOREIGN_KEY((partrelid, partattrs), pg_attribute, (attrelid, attnum));
+
 #endif							/* PG_PARTITIONED_TABLE_H */
diff --git a/src/include/catalog/pg_policy.h b/src/include/catalog/pg_policy.h
index 44197613e0..77312840f0 100644
--- a/src/include/catalog/pg_policy.h
+++ b/src/include/catalog/pg_policy.h
@@ -30,13 +30,14 @@ CATALOG(pg_policy,3256,PolicyRelationId)
 {
 	Oid			oid;			/* oid */
 	NameData	polname;		/* Policy name. */
-	Oid			polrelid;		/* Oid of the relation with policy. */
+	Oid			polrelid BKI_LOOKUP(pg_class);	/* Oid of the relation with
+												 * policy. */
 	char		polcmd;			/* One of ACL_*_CHR, or '*' for all */
 	bool		polpermissive;	/* restrictive or permissive policy */
 
 #ifdef CATALOG_VARLEN
-	Oid			polroles[1] BKI_FORCE_NOT_NULL; /* Roles associated with
-												 * policy */
+	Oid			polroles[1] BKI_LOOKUP(pg_authid) BKI_FORCE_NOT_NULL;	/* Roles associated with
+																		 * policy */
 	pg_node_tree polqual;		/* Policy quals. */
 	pg_node_tree polwithcheck;	/* WITH CHECK quals. */
 #endif
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index b5f52d4e4a..213ee54e2a 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -2405,7 +2405,7 @@
 { oid => '1215', descr => 'get description for object id and catalog name',
   proname => 'obj_description', prolang => 'sql', procost => '100',
   provolatile => 's', prorettype => 'text', proargtypes => 'oid name',
-  prosrc => 'select description from pg_catalog.pg_description where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = PGNSP) and objsubid = 0' },
+  prosrc => 'select description from pg_catalog.pg_description where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = \'pg_catalog\'::pg_catalog.regnamespace) and objsubid = 0' },
 { oid => '1216', descr => 'get description for table column',
   proname => 'col_description', prolang => 'sql', procost => '100',
   provolatile => 's', prorettype => 'text', proargtypes => 'oid int4',
@@ -2414,7 +2414,7 @@
   descr => 'get description for object id and shared catalog name',
   proname => 'shobj_description', prolang => 'sql', procost => '100',
   provolatile => 's', prorettype => 'text', proargtypes => 'oid name',
-  prosrc => 'select description from pg_catalog.pg_shdescription where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = PGNSP)' },
+  prosrc => 'select description from pg_catalog.pg_shdescription where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = \'pg_catalog\'::pg_catalog.regnamespace)' },
 
 { oid => '1217',
   descr => 'truncate timestamp with time zone to specified units',
@@ -3698,6 +3698,14 @@
   proargnames => '{word,catcode,barelabel,catdesc,baredesc}',
   prosrc => 'pg_get_keywords' },
 
+{ oid => '8103', descr => 'list of catalog foreign key relationships',
+  proname => 'pg_get_catalog_foreign_keys', procost => '10', prorows => '250',
+  proretset => 't', provolatile => 's', prorettype => 'record',
+  proargtypes => '', proallargtypes => '{regclass,_text,regclass,_text,bool}',
+  proargmodes => '{o,o,o,o,o}',
+  proargnames => '{fktable,fkcols,pktable,pkcols,is_array}',
+  prosrc => 'pg_get_catalog_foreign_keys' },
+
 { oid => '2289', descr => 'convert generic options array to name/value table',
   proname => 'pg_options_to_table', prorows => '3', proretset => 't',
   provolatile => 's', prorettype => 'record', proargtypes => '_text',
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 03c8bef422..4692e90403 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -35,10 +35,10 @@ CATALOG(pg_proc,1255,ProcedureRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81,Proce
 	NameData	proname;
 
 	/* OID of namespace containing this proc */
-	Oid			pronamespace BKI_DEFAULT(PGNSP);
+	Oid			pronamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* procedure owner */
-	Oid			proowner BKI_DEFAULT(PGUID);
+	Oid			proowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/* OID of pg_language entry */
 	Oid			prolang BKI_DEFAULT(internal) BKI_LOOKUP(pg_language);
@@ -109,7 +109,7 @@ CATALOG(pg_proc,1255,ProcedureRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81,Proce
 	pg_node_tree proargdefaults BKI_DEFAULT(_null_);
 
 	/* types for which to apply transforms */
-	Oid			protrftypes[1] BKI_DEFAULT(_null_);
+	Oid			protrftypes[1] BKI_DEFAULT(_null_) BKI_LOOKUP(pg_type);
 
 	/* procedure source text */
 	text		prosrc BKI_FORCE_NOT_NULL;
diff --git a/src/include/catalog/pg_publication.h b/src/include/catalog/pg_publication.h
index 4127611f5a..1b31fee9e3 100644
--- a/src/include/catalog/pg_publication.h
+++ b/src/include/catalog/pg_publication.h
@@ -32,7 +32,7 @@ CATALOG(pg_publication,6104,PublicationRelationId)
 
 	NameData	pubname;		/* name of the publication */
 
-	Oid			pubowner;		/* publication owner */
+	Oid			pubowner BKI_LOOKUP(pg_authid); /* publication owner */
 
 	/*
 	 * indicates that this is special publication which should encompass all
diff --git a/src/include/catalog/pg_publication_rel.h b/src/include/catalog/pg_publication_rel.h
index c79b7fb487..aecf53b3b3 100644
--- a/src/include/catalog/pg_publication_rel.h
+++ b/src/include/catalog/pg_publication_rel.h
@@ -29,8 +29,8 @@
 CATALOG(pg_publication_rel,6106,PublicationRelRelationId)
 {
 	Oid			oid;			/* oid */
-	Oid			prpubid;		/* Oid of the publication */
-	Oid			prrelid;		/* Oid of the relation */
+	Oid			prpubid BKI_LOOKUP(pg_publication); /* Oid of the publication */
+	Oid			prrelid BKI_LOOKUP(pg_class);	/* Oid of the relation */
 } FormData_pg_publication_rel;
 
 /* ----------------
diff --git a/src/include/catalog/pg_range.h b/src/include/catalog/pg_range.h
index 2ec6a4b126..deac5cb7eb 100644
--- a/src/include/catalog/pg_range.h
+++ b/src/include/catalog/pg_range.h
@@ -38,7 +38,7 @@ CATALOG(pg_range,3541,RangeRelationId)
 	Oid			rngmultitypid BKI_LOOKUP(pg_type);
 
 	/* collation for this range type, or 0 */
-	Oid			rngcollation BKI_DEFAULT(0);
+	Oid			rngcollation BKI_DEFAULT(0) BKI_LOOKUP(pg_collation);
 
 	/* subtype's btree opclass */
 	Oid			rngsubopc BKI_LOOKUP(pg_opclass);
diff --git a/src/include/catalog/pg_rewrite.h b/src/include/catalog/pg_rewrite.h
index 36f92b1cf1..89c72545d0 100644
--- a/src/include/catalog/pg_rewrite.h
+++ b/src/include/catalog/pg_rewrite.h
@@ -33,7 +33,7 @@ CATALOG(pg_rewrite,2618,RewriteRelationId)
 {
 	Oid			oid;			/* oid */
 	NameData	rulename;
-	Oid			ev_class;
+	Oid			ev_class BKI_LOOKUP(pg_class);
 	char		ev_type;
 	char		ev_enabled;
 	bool		is_instead;
diff --git a/src/include/catalog/pg_seclabel.h b/src/include/catalog/pg_seclabel.h
index b14fd7febe..0a12225eb7 100644
--- a/src/include/catalog/pg_seclabel.h
+++ b/src/include/catalog/pg_seclabel.h
@@ -28,7 +28,8 @@
 CATALOG(pg_seclabel,3596,SecLabelRelationId)
 {
 	Oid			objoid;			/* OID of the object itself */
-	Oid			classoid;		/* OID of table containing the object */
+	Oid			classoid BKI_LOOKUP(pg_class);	/* OID of table containing the
+												 * object */
 	int32		objsubid;		/* column number, or 0 if not used */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
diff --git a/src/include/catalog/pg_sequence.h b/src/include/catalog/pg_sequence.h
index addf21abce..8d0a00baf6 100644
--- a/src/include/catalog/pg_sequence.h
+++ b/src/include/catalog/pg_sequence.h
@@ -22,8 +22,8 @@
 
 CATALOG(pg_sequence,2224,SequenceRelationId)
 {
-	Oid			seqrelid;
-	Oid			seqtypid;
+	Oid			seqrelid BKI_LOOKUP(pg_class);
+	Oid			seqtypid BKI_LOOKUP(pg_type);
 	int64		seqstart;
 	int64		seqincrement;
 	int64		seqmax;
diff --git a/src/include/catalog/pg_shdepend.h b/src/include/catalog/pg_shdepend.h
index f5863954e9..ae842526bb 100644
--- a/src/include/catalog/pg_shdepend.h
+++ b/src/include/catalog/pg_shdepend.h
@@ -42,8 +42,10 @@ CATALOG(pg_shdepend,1214,SharedDependRelationId) BKI_SHARED_RELATION
 	 * These fields are all zeroes for a DEPENDENCY_PIN entry.  Also, dbid can
 	 * be zero to denote a shared object.
 	 */
-	Oid			dbid;			/* OID of database containing object */
-	Oid			classid;		/* OID of table containing object */
+	Oid			dbid BKI_LOOKUP(pg_database);	/* OID of database containing
+												 * object */
+	Oid			classid BKI_LOOKUP(pg_class);	/* OID of table containing
+												 * object */
 	Oid			objid;			/* OID of object itself */
 	int32		objsubid;		/* column number, or 0 if not used */
 
@@ -52,7 +54,8 @@ CATALOG(pg_shdepend,1214,SharedDependRelationId) BKI_SHARED_RELATION
 	 * a shared object, so we need no database ID field.  We don't bother with
 	 * a sub-object ID either.
 	 */
-	Oid			refclassid;		/* OID of table containing object */
+	Oid			refclassid BKI_LOOKUP(pg_class);	/* OID of table containing
+													 * object */
 	Oid			refobjid;		/* OID of object itself */
 
 	/*
diff --git a/src/include/catalog/pg_shdescription.h b/src/include/catalog/pg_shdescription.h
index a37db4fa0b..543e216710 100644
--- a/src/include/catalog/pg_shdescription.h
+++ b/src/include/catalog/pg_shdescription.h
@@ -62,4 +62,7 @@ DECLARE_TOAST(pg_shdescription, 2846, 2847);
 DECLARE_UNIQUE_INDEX_PKEY(pg_shdescription_o_c_index, 2397, on pg_shdescription using btree(objoid oid_ops, classoid oid_ops));
 #define SharedDescriptionObjIndexId 2397
 
+/* We do not use BKI_LOOKUP here because it causes problems for genbki.pl */
+DECLARE_FOREIGN_KEY((classoid), pg_class, (oid));
+
 #endif							/* PG_SHDESCRIPTION_H */
diff --git a/src/include/catalog/pg_shseclabel.h b/src/include/catalog/pg_shseclabel.h
index 406f5328a7..5d6864cf8c 100644
--- a/src/include/catalog/pg_shseclabel.h
+++ b/src/include/catalog/pg_shseclabel.h
@@ -28,7 +28,8 @@
 CATALOG(pg_shseclabel,3592,SharedSecLabelRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID(4066,SharedSecLabelRelation_Rowtype_Id) BKI_SCHEMA_MACRO
 {
 	Oid			objoid;			/* OID of the shared object itself */
-	Oid			classoid;		/* OID of table containing the shared object */
+	Oid			classoid BKI_LOOKUP(pg_class);	/* OID of table containing the
+												 * shared object */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	text		provider BKI_FORCE_NOT_NULL;	/* name of label provider */
diff --git a/src/include/catalog/pg_statistic.h b/src/include/catalog/pg_statistic.h
index 4a66bda879..08f3ef3d3a 100644
--- a/src/include/catalog/pg_statistic.h
+++ b/src/include/catalog/pg_statistic.h
@@ -29,7 +29,8 @@
 CATALOG(pg_statistic,2619,StatisticRelationId)
 {
 	/* These fields form the unique key for the entry: */
-	Oid			starelid;		/* relation containing attribute */
+	Oid			starelid BKI_LOOKUP(pg_class);	/* relation containing
+												 * attribute */
 	int16		staattnum;		/* attribute (column) stats are for */
 	bool		stainherit;		/* true if inheritance children are included */
 
@@ -90,17 +91,17 @@ CATALOG(pg_statistic,2619,StatisticRelationId)
 	int16		stakind4;
 	int16		stakind5;
 
-	Oid			staop1;
-	Oid			staop2;
-	Oid			staop3;
-	Oid			staop4;
-	Oid			staop5;
+	Oid			staop1 BKI_LOOKUP(pg_operator);
+	Oid			staop2 BKI_LOOKUP(pg_operator);
+	Oid			staop3 BKI_LOOKUP(pg_operator);
+	Oid			staop4 BKI_LOOKUP(pg_operator);
+	Oid			staop5 BKI_LOOKUP(pg_operator);
 
-	Oid			stacoll1;
-	Oid			stacoll2;
-	Oid			stacoll3;
-	Oid			stacoll4;
-	Oid			stacoll5;
+	Oid			stacoll1 BKI_LOOKUP(pg_collation);
+	Oid			stacoll2 BKI_LOOKUP(pg_collation);
+	Oid			stacoll3 BKI_LOOKUP(pg_collation);
+	Oid			stacoll4 BKI_LOOKUP(pg_collation);
+	Oid			stacoll5 BKI_LOOKUP(pg_collation);
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	float4		stanumbers1[1];
@@ -138,6 +139,8 @@ DECLARE_TOAST(pg_statistic, 2840, 2841);
 DECLARE_UNIQUE_INDEX_PKEY(pg_statistic_relid_att_inh_index, 2696, on pg_statistic using btree(starelid oid_ops, staattnum int2_ops, stainherit bool_ops));
 #define StatisticRelidAttnumInhIndexId	2696
 
+DECLARE_FOREIGN_KEY((starelid, staattnum), pg_attribute, (attrelid, attnum));
+
 #ifdef EXPOSE_TO_CLIENT_CODE
 
 /*
diff --git a/src/include/catalog/pg_statistic_ext.h b/src/include/catalog/pg_statistic_ext.h
index 10f52f912c..29649f5814 100644
--- a/src/include/catalog/pg_statistic_ext.h
+++ b/src/include/catalog/pg_statistic_ext.h
@@ -34,13 +34,15 @@ CATALOG(pg_statistic_ext,3381,StatisticExtRelationId)
 {
 	Oid			oid;			/* oid */
 
-	Oid			stxrelid;		/* relation containing attributes */
+	Oid			stxrelid BKI_LOOKUP(pg_class);	/* relation containing
+												 * attributes */
 
 	/* These two fields form the unique key for the entry: */
 	NameData	stxname;		/* statistics object name */
-	Oid			stxnamespace;	/* OID of statistics object's namespace */
+	Oid			stxnamespace BKI_LOOKUP(pg_namespace);	/* OID of statistics
+														 * object's namespace */
 
-	Oid			stxowner;		/* statistics object's owner */
+	Oid			stxowner BKI_LOOKUP(pg_authid); /* statistics object's owner */
 	int32		stxstattarget BKI_DEFAULT(-1);	/* statistics target */
 
 	/*
@@ -72,6 +74,8 @@ DECLARE_UNIQUE_INDEX(pg_statistic_ext_name_index, 3997, on pg_statistic_ext usin
 DECLARE_INDEX(pg_statistic_ext_relid_index, 3379, on pg_statistic_ext using btree(stxrelid oid_ops));
 #define StatisticExtRelidIndexId 3379
 
+DECLARE_ARRAY_FOREIGN_KEY((stxrelid, stxkeys), pg_attribute, (attrelid, attnum));
+
 #ifdef EXPOSE_TO_CLIENT_CODE
 
 #define STATS_EXT_NDISTINCT			'd'
diff --git a/src/include/catalog/pg_statistic_ext_data.h b/src/include/catalog/pg_statistic_ext_data.h
index 6f7a36c141..2f2577c218 100644
--- a/src/include/catalog/pg_statistic_ext_data.h
+++ b/src/include/catalog/pg_statistic_ext_data.h
@@ -30,7 +30,8 @@
  */
 CATALOG(pg_statistic_ext_data,3429,StatisticExtDataRelationId)
 {
-	Oid			stxoid;			/* statistics object this data is for */
+	Oid			stxoid BKI_LOOKUP(pg_statistic_ext);	/* statistics object
+														 * this data is for */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 
diff --git a/src/include/catalog/pg_subscription.h b/src/include/catalog/pg_subscription.h
index 4e44c29149..a5d6efdf20 100644
--- a/src/include/catalog/pg_subscription.h
+++ b/src/include/catalog/pg_subscription.h
@@ -40,10 +40,11 @@ CATALOG(pg_subscription,6100,SubscriptionRelationId) BKI_SHARED_RELATION BKI_ROW
 {
 	Oid			oid;			/* oid */
 
-	Oid			subdbid;		/* Database the subscription is in. */
+	Oid			subdbid BKI_LOOKUP(pg_database);	/* Database the
+													 * subscription is in. */
 	NameData	subname;		/* Name of the subscription */
 
-	Oid			subowner;		/* Owner of the subscription */
+	Oid			subowner BKI_LOOKUP(pg_authid); /* Owner of the subscription */
 
 	bool		subenabled;		/* True if the subscription is enabled (the
 								 * worker should be running) */
diff --git a/src/include/catalog/pg_subscription_rel.h b/src/include/catalog/pg_subscription_rel.h
index ab1202cf9b..2bea2c52aa 100644
--- a/src/include/catalog/pg_subscription_rel.h
+++ b/src/include/catalog/pg_subscription_rel.h
@@ -30,8 +30,8 @@
  */
 CATALOG(pg_subscription_rel,6102,SubscriptionRelRelationId)
 {
-	Oid			srsubid;		/* Oid of subscription */
-	Oid			srrelid;		/* Oid of relation */
+	Oid			srsubid BKI_LOOKUP(pg_subscription);	/* Oid of subscription */
+	Oid			srrelid BKI_LOOKUP(pg_class);	/* Oid of relation */
 	char		srsubstate;		/* state of the relation in subscription */
 
 	/*
diff --git a/src/include/catalog/pg_tablespace.dat b/src/include/catalog/pg_tablespace.dat
index 212a0ad07f..bf0d81d306 100644
--- a/src/include/catalog/pg_tablespace.dat
+++ b/src/include/catalog/pg_tablespace.dat
@@ -13,10 +13,8 @@
 [
 
 { oid => '1663', oid_symbol => 'DEFAULTTABLESPACE_OID',
-  spcname => 'pg_default', spcowner => 'PGUID', spcacl => '_null_',
-  spcoptions => '_null_' },
+  spcname => 'pg_default', spcacl => '_null_', spcoptions => '_null_' },
 { oid => '1664', oid_symbol => 'GLOBALTABLESPACE_OID',
-  spcname => 'pg_global', spcowner => 'PGUID', spcacl => '_null_',
-  spcoptions => '_null_' },
+  spcname => 'pg_global', spcacl => '_null_', spcoptions => '_null_' },
 
 ]
diff --git a/src/include/catalog/pg_tablespace.h b/src/include/catalog/pg_tablespace.h
index 6a6c66a61c..ed38e6950d 100644
--- a/src/include/catalog/pg_tablespace.h
+++ b/src/include/catalog/pg_tablespace.h
@@ -30,7 +30,7 @@ CATALOG(pg_tablespace,1213,TableSpaceRelationId) BKI_SHARED_RELATION
 {
 	Oid			oid;			/* oid */
 	NameData	spcname;		/* tablespace name */
-	Oid			spcowner;		/* owner of tablespace */
+	Oid			spcowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);	/* owner of tablespace */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	aclitem		spcacl[1];		/* access permissions */
diff --git a/src/include/catalog/pg_transform.h b/src/include/catalog/pg_transform.h
index ad25db1841..2eec22e3b5 100644
--- a/src/include/catalog/pg_transform.h
+++ b/src/include/catalog/pg_transform.h
@@ -29,10 +29,10 @@
 CATALOG(pg_transform,3576,TransformRelationId)
 {
 	Oid			oid;			/* oid */
-	Oid			trftype;
-	Oid			trflang;
-	regproc		trffromsql;
-	regproc		trftosql;
+	Oid			trftype BKI_LOOKUP(pg_type);
+	Oid			trflang BKI_LOOKUP(pg_language);
+	regproc		trffromsql BKI_LOOKUP(pg_proc);
+	regproc		trftosql BKI_LOOKUP(pg_proc);
 } FormData_pg_transform;
 
 /* ----------------
diff --git a/src/include/catalog/pg_trigger.h b/src/include/catalog/pg_trigger.h
index 55111ed864..814508e564 100644
--- a/src/include/catalog/pg_trigger.h
+++ b/src/include/catalog/pg_trigger.h
@@ -34,18 +34,24 @@
 CATALOG(pg_trigger,2620,TriggerRelationId)
 {
 	Oid			oid;			/* oid */
-	Oid			tgrelid;		/* relation trigger is attached to */
-	Oid			tgparentid;		/* OID of parent trigger, if any */
+	Oid			tgrelid BKI_LOOKUP(pg_class);	/* relation trigger is
+												 * attached to */
+	Oid			tgparentid BKI_LOOKUP(pg_trigger);	/* OID of parent trigger,
+													 * if any */
 	NameData	tgname;			/* trigger's name */
-	Oid			tgfoid;			/* OID of function to be called */
+	Oid			tgfoid BKI_LOOKUP(pg_proc); /* OID of function to be called */
 	int16		tgtype;			/* BEFORE/AFTER/INSTEAD, UPDATE/DELETE/INSERT,
 								 * ROW/STATEMENT; see below */
 	char		tgenabled;		/* trigger's firing configuration WRT
 								 * session_replication_role */
 	bool		tgisinternal;	/* trigger is system-generated */
-	Oid			tgconstrrelid;	/* constraint's FROM table, if any */
-	Oid			tgconstrindid;	/* constraint's supporting index, if any */
-	Oid			tgconstraint;	/* associated pg_constraint entry, if any */
+	Oid			tgconstrrelid BKI_LOOKUP(pg_class); /* constraint's FROM
+													 * table, if any */
+	Oid			tgconstrindid BKI_LOOKUP(pg_class); /* constraint's supporting
+													 * index, if any */
+	Oid			tgconstraint BKI_LOOKUP(pg_constraint); /* associated
+														 * pg_constraint entry,
+														 * if any */
 	bool		tgdeferrable;	/* constraint trigger is deferrable */
 	bool		tginitdeferred; /* constraint trigger is deferred initially */
 	int16		tgnargs;		/* # of extra arguments in tgargs */
@@ -81,6 +87,8 @@ DECLARE_UNIQUE_INDEX(pg_trigger_tgrelid_tgname_index, 2701, on pg_trigger using
 DECLARE_UNIQUE_INDEX_PKEY(pg_trigger_oid_index, 2702, on pg_trigger using btree(oid oid_ops));
 #define TriggerOidIndexId  2702
 
+DECLARE_ARRAY_FOREIGN_KEY((tgrelid, tgattr), pg_attribute, (attrelid, attnum));
+
 #ifdef EXPOSE_TO_CLIENT_CODE
 
 /* Bits within tgtype */
diff --git a/src/include/catalog/pg_ts_config.h b/src/include/catalog/pg_ts_config.h
index 02ef1a1554..e705899b17 100644
--- a/src/include/catalog/pg_ts_config.h
+++ b/src/include/catalog/pg_ts_config.h
@@ -36,10 +36,10 @@ CATALOG(pg_ts_config,3602,TSConfigRelationId)
 	NameData	cfgname;
 
 	/* name space */
-	Oid			cfgnamespace BKI_DEFAULT(PGNSP);
+	Oid			cfgnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* owner */
-	Oid			cfgowner BKI_DEFAULT(PGUID);
+	Oid			cfgowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/* OID of parser */
 	Oid			cfgparser BKI_LOOKUP(pg_ts_parser);
diff --git a/src/include/catalog/pg_ts_dict.h b/src/include/catalog/pg_ts_dict.h
index bfe3378ff8..57f626e7b5 100644
--- a/src/include/catalog/pg_ts_dict.h
+++ b/src/include/catalog/pg_ts_dict.h
@@ -35,10 +35,10 @@ CATALOG(pg_ts_dict,3600,TSDictionaryRelationId)
 	NameData	dictname;
 
 	/* name space */
-	Oid			dictnamespace BKI_DEFAULT(PGNSP);
+	Oid			dictnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* owner */
-	Oid			dictowner BKI_DEFAULT(PGUID);
+	Oid			dictowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/* dictionary's template */
 	Oid			dicttemplate BKI_LOOKUP(pg_ts_template);
diff --git a/src/include/catalog/pg_ts_parser.h b/src/include/catalog/pg_ts_parser.h
index f9f22716fd..02495434b9 100644
--- a/src/include/catalog/pg_ts_parser.h
+++ b/src/include/catalog/pg_ts_parser.h
@@ -34,7 +34,7 @@ CATALOG(pg_ts_parser,3601,TSParserRelationId)
 	NameData	prsname;
 
 	/* name space */
-	Oid			prsnamespace BKI_DEFAULT(PGNSP);
+	Oid			prsnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* init parsing session */
 	regproc		prsstart BKI_LOOKUP(pg_proc);
diff --git a/src/include/catalog/pg_ts_template.h b/src/include/catalog/pg_ts_template.h
index ae91922688..f4b8418846 100644
--- a/src/include/catalog/pg_ts_template.h
+++ b/src/include/catalog/pg_ts_template.h
@@ -34,7 +34,7 @@ CATALOG(pg_ts_template,3764,TSTemplateRelationId)
 	NameData	tmplname;
 
 	/* name space */
-	Oid			tmplnamespace BKI_DEFAULT(PGNSP);
+	Oid			tmplnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* initialization method of dict (may be 0) */
 	regproc		tmplinit BKI_LOOKUP(pg_proc);
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 0d6981bc87..1f5c3d9af2 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -41,10 +41,10 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati
 	NameData	typname;
 
 	/* OID of namespace containing this type */
-	Oid			typnamespace BKI_DEFAULT(PGNSP);
+	Oid			typnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* type owner */
-	Oid			typowner BKI_DEFAULT(PGUID);
+	Oid			typowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/*
 	 * For a fixed-size type, typlen is the number of bytes we use to
@@ -205,7 +205,7 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati
 	 * Domains use typbasetype to show the base (or domain) type that the
 	 * domain is based on.  Zero if the type is not a domain.
 	 */
-	Oid			typbasetype BKI_DEFAULT(0);
+	Oid			typbasetype BKI_DEFAULT(0) BKI_LOOKUP(pg_type);
 
 	/*
 	 * Domains use typtypmod to record the typmod to be applied to their base
diff --git a/src/include/catalog/pg_user_mapping.h b/src/include/catalog/pg_user_mapping.h
index cabca048a9..c7fc34cea5 100644
--- a/src/include/catalog/pg_user_mapping.h
+++ b/src/include/catalog/pg_user_mapping.h
@@ -29,9 +29,10 @@ CATALOG(pg_user_mapping,1418,UserMappingRelationId)
 {
 	Oid			oid;			/* oid */
 
-	Oid			umuser;			/* Id of the user, InvalidOid if PUBLIC is
-								 * wanted */
-	Oid			umserver;		/* server of this mapping */
+	Oid			umuser BKI_LOOKUP(pg_authid);	/* Id of the user, InvalidOid
+												 * if PUBLIC is wanted */
+	Oid			umserver BKI_LOOKUP(pg_foreign_server); /* server of this
+														 * mapping */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	text		umoptions[1];	/* user mapping options */
diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out
index 4731dacfbf..fd31085e59 100644
--- a/src/test/regress/expected/oidjoins.out
+++ b/src/test/regress/expected/oidjoins.out
@@ -1,1451 +1,265 @@
 --
--- This is created by pgsql/src/tools/findoidjoins/make_oidjoins_check
+-- Verify system catalog foreign key relationships
 --
-SELECT	ctid, aggfnoid
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggfnoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggfnoid);
- ctid | aggfnoid 
-------+----------
-(0 rows)
-
-SELECT	ctid, aggtransfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggtransfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggtransfn);
- ctid | aggtransfn 
-------+------------
-(0 rows)
-
-SELECT	ctid, aggfinalfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggfinalfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggfinalfn);
- ctid | aggfinalfn 
-------+------------
-(0 rows)
-
-SELECT	ctid, aggcombinefn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggcombinefn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggcombinefn);
- ctid | aggcombinefn 
-------+--------------
-(0 rows)
-
-SELECT	ctid, aggserialfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggserialfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggserialfn);
- ctid | aggserialfn 
-------+-------------
-(0 rows)
-
-SELECT	ctid, aggdeserialfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggdeserialfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggdeserialfn);
- ctid | aggdeserialfn 
-------+---------------
-(0 rows)
-
-SELECT	ctid, aggmtransfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggmtransfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggmtransfn);
- ctid | aggmtransfn 
-------+-------------
-(0 rows)
-
-SELECT	ctid, aggminvtransfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggminvtransfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggminvtransfn);
- ctid | aggminvtransfn 
-------+----------------
-(0 rows)
-
-SELECT	ctid, aggmfinalfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggmfinalfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggmfinalfn);
- ctid | aggmfinalfn 
-------+-------------
-(0 rows)
-
-SELECT	ctid, aggsortop
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggsortop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.aggsortop);
- ctid | aggsortop 
-------+-----------
-(0 rows)
-
-SELECT	ctid, aggtranstype
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggtranstype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggtranstype);
- ctid | aggtranstype 
-------+--------------
-(0 rows)
-
-SELECT	ctid, aggmtranstype
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggmtranstype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype);
- ctid | aggmtranstype 
-------+---------------
-(0 rows)
-
-SELECT	ctid, amhandler
-FROM	pg_catalog.pg_am fk
-WHERE	amhandler != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amhandler);
- ctid | amhandler 
-------+-----------
-(0 rows)
-
-SELECT	ctid, amopfamily
-FROM	pg_catalog.pg_amop fk
-WHERE	amopfamily != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amopfamily);
- ctid | amopfamily 
-------+------------
-(0 rows)
-
-SELECT	ctid, amoplefttype
-FROM	pg_catalog.pg_amop fk
-WHERE	amoplefttype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amoplefttype);
- ctid | amoplefttype 
-------+--------------
-(0 rows)
-
-SELECT	ctid, amoprighttype
-FROM	pg_catalog.pg_amop fk
-WHERE	amoprighttype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amoprighttype);
- ctid | amoprighttype 
-------+---------------
-(0 rows)
-
-SELECT	ctid, amopopr
-FROM	pg_catalog.pg_amop fk
-WHERE	amopopr != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.amopopr);
- ctid | amopopr 
-------+---------
-(0 rows)
-
-SELECT	ctid, amopmethod
-FROM	pg_catalog.pg_amop fk
-WHERE	amopmethod != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.amopmethod);
- ctid | amopmethod 
-------+------------
-(0 rows)
-
-SELECT	ctid, amopsortfamily
-FROM	pg_catalog.pg_amop fk
-WHERE	amopsortfamily != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amopsortfamily);
- ctid | amopsortfamily 
-------+----------------
-(0 rows)
-
-SELECT	ctid, amprocfamily
-FROM	pg_catalog.pg_amproc fk
-WHERE	amprocfamily != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amprocfamily);
- ctid | amprocfamily 
-------+--------------
-(0 rows)
-
-SELECT	ctid, amproclefttype
-FROM	pg_catalog.pg_amproc fk
-WHERE	amproclefttype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amproclefttype);
- ctid | amproclefttype 
-------+----------------
-(0 rows)
-
-SELECT	ctid, amprocrighttype
-FROM	pg_catalog.pg_amproc fk
-WHERE	amprocrighttype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amprocrighttype);
- ctid | amprocrighttype 
-------+-----------------
-(0 rows)
-
-SELECT	ctid, amproc
-FROM	pg_catalog.pg_amproc fk
-WHERE	amproc != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amproc);
- ctid | amproc 
-------+--------
-(0 rows)
-
-SELECT	ctid, adrelid
-FROM	pg_catalog.pg_attrdef fk
-WHERE	adrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.adrelid);
- ctid | adrelid 
-------+---------
-(0 rows)
-
-SELECT	ctid, attrelid
-FROM	pg_catalog.pg_attribute fk
-WHERE	attrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.attrelid);
- ctid | attrelid 
-------+----------
-(0 rows)
-
-SELECT	ctid, atttypid
-FROM	pg_catalog.pg_attribute fk
-WHERE	atttypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.atttypid);
- ctid | atttypid 
-------+----------
-(0 rows)
-
-SELECT	ctid, attcollation
-FROM	pg_catalog.pg_attribute fk
-WHERE	attcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.attcollation);
- ctid | attcollation 
-------+--------------
-(0 rows)
-
-SELECT	ctid, roleid
-FROM	pg_catalog.pg_auth_members fk
-WHERE	roleid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.roleid);
- ctid | roleid 
-------+--------
-(0 rows)
-
-SELECT	ctid, member
-FROM	pg_catalog.pg_auth_members fk
-WHERE	member != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.member);
- ctid | member 
-------+--------
-(0 rows)
-
-SELECT	ctid, grantor
-FROM	pg_catalog.pg_auth_members fk
-WHERE	grantor != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.grantor);
- ctid | grantor 
-------+---------
-(0 rows)
-
-SELECT	ctid, castsource
-FROM	pg_catalog.pg_cast fk
-WHERE	castsource != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.castsource);
- ctid | castsource 
-------+------------
-(0 rows)
-
-SELECT	ctid, casttarget
-FROM	pg_catalog.pg_cast fk
-WHERE	casttarget != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.casttarget);
- ctid | casttarget 
-------+------------
-(0 rows)
-
-SELECT	ctid, castfunc
-FROM	pg_catalog.pg_cast fk
-WHERE	castfunc != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.castfunc);
- ctid | castfunc 
-------+----------
-(0 rows)
-
-SELECT	ctid, relnamespace
-FROM	pg_catalog.pg_class fk
-WHERE	relnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.relnamespace);
- ctid | relnamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, reltype
-FROM	pg_catalog.pg_class fk
-WHERE	reltype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.reltype);
- ctid | reltype 
-------+---------
-(0 rows)
-
-SELECT	ctid, reloftype
-FROM	pg_catalog.pg_class fk
-WHERE	reloftype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.reloftype);
- ctid | reloftype 
-------+-----------
-(0 rows)
-
-SELECT	ctid, relowner
-FROM	pg_catalog.pg_class fk
-WHERE	relowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.relowner);
- ctid | relowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, relam
-FROM	pg_catalog.pg_class fk
-WHERE	relam != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.relam);
- ctid | relam 
-------+-------
-(0 rows)
-
-SELECT	ctid, reltablespace
-FROM	pg_catalog.pg_class fk
-WHERE	reltablespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_tablespace pk WHERE pk.oid = fk.reltablespace);
- ctid | reltablespace 
-------+---------------
-(0 rows)
-
-SELECT	ctid, reltoastrelid
-FROM	pg_catalog.pg_class fk
-WHERE	reltoastrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.reltoastrelid);
- ctid | reltoastrelid 
-------+---------------
-(0 rows)
-
-SELECT	ctid, collnamespace
-FROM	pg_catalog.pg_collation fk
-WHERE	collnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.collnamespace);
- ctid | collnamespace 
-------+---------------
-(0 rows)
-
-SELECT	ctid, collowner
-FROM	pg_catalog.pg_collation fk
-WHERE	collowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.collowner);
- ctid | collowner 
-------+-----------
-(0 rows)
-
-SELECT	ctid, connamespace
-FROM	pg_catalog.pg_constraint fk
-WHERE	connamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.connamespace);
- ctid | connamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, conrelid
-FROM	pg_catalog.pg_constraint fk
-WHERE	conrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.conrelid);
- ctid | conrelid 
-------+----------
-(0 rows)
-
-SELECT	ctid, contypid
-FROM	pg_catalog.pg_constraint fk
-WHERE	contypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.contypid);
- ctid | contypid 
-------+----------
-(0 rows)
-
-SELECT	ctid, conindid
-FROM	pg_catalog.pg_constraint fk
-WHERE	conindid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.conindid);
- ctid | conindid 
-------+----------
-(0 rows)
-
-SELECT	ctid, conparentid
-FROM	pg_catalog.pg_constraint fk
-WHERE	conparentid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_constraint pk WHERE pk.oid = fk.conparentid);
- ctid | conparentid 
-------+-------------
-(0 rows)
-
-SELECT	ctid, confrelid
-FROM	pg_catalog.pg_constraint fk
-WHERE	confrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.confrelid);
- ctid | confrelid 
-------+-----------
-(0 rows)
-
-SELECT	ctid, connamespace
-FROM	pg_catalog.pg_conversion fk
-WHERE	connamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.connamespace);
- ctid | connamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, conowner
-FROM	pg_catalog.pg_conversion fk
-WHERE	conowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.conowner);
- ctid | conowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, conproc
-FROM	pg_catalog.pg_conversion fk
-WHERE	conproc != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.conproc);
- ctid | conproc 
-------+---------
-(0 rows)
-
-SELECT	ctid, datdba
-FROM	pg_catalog.pg_database fk
-WHERE	datdba != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.datdba);
- ctid | datdba 
-------+--------
-(0 rows)
-
-SELECT	ctid, dattablespace
-FROM	pg_catalog.pg_database fk
-WHERE	dattablespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_tablespace pk WHERE pk.oid = fk.dattablespace);
- ctid | dattablespace 
-------+---------------
-(0 rows)
-
-SELECT	ctid, setdatabase
-FROM	pg_catalog.pg_db_role_setting fk
-WHERE	setdatabase != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_database pk WHERE pk.oid = fk.setdatabase);
- ctid | setdatabase 
-------+-------------
-(0 rows)
-
-SELECT	ctid, classid
-FROM	pg_catalog.pg_depend fk
-WHERE	classid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classid);
- ctid | classid 
-------+---------
-(0 rows)
-
-SELECT	ctid, refclassid
-FROM	pg_catalog.pg_depend fk
-WHERE	refclassid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.refclassid);
- ctid | refclassid 
-------+------------
-(0 rows)
-
-SELECT	ctid, classoid
-FROM	pg_catalog.pg_description fk
-WHERE	classoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid);
- ctid | classoid 
-------+----------
-(0 rows)
-
-SELECT	ctid, enumtypid
-FROM	pg_catalog.pg_enum fk
-WHERE	enumtypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.enumtypid);
- ctid | enumtypid 
-------+-----------
-(0 rows)
-
-SELECT	ctid, extowner
-FROM	pg_catalog.pg_extension fk
-WHERE	extowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.extowner);
- ctid | extowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, extnamespace
-FROM	pg_catalog.pg_extension fk
-WHERE	extnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.extnamespace);
- ctid | extnamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, fdwowner
-FROM	pg_catalog.pg_foreign_data_wrapper fk
-WHERE	fdwowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.fdwowner);
- ctid | fdwowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, srvowner
-FROM	pg_catalog.pg_foreign_server fk
-WHERE	srvowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.srvowner);
- ctid | srvowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, srvfdw
-FROM	pg_catalog.pg_foreign_server fk
-WHERE	srvfdw != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_foreign_data_wrapper pk WHERE pk.oid = fk.srvfdw);
- ctid | srvfdw 
-------+--------
-(0 rows)
-
-SELECT	ctid, indexrelid
-FROM	pg_catalog.pg_index fk
-WHERE	indexrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.indexrelid);
- ctid | indexrelid 
-------+------------
-(0 rows)
-
-SELECT	ctid, indrelid
-FROM	pg_catalog.pg_index fk
-WHERE	indrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.indrelid);
- ctid | indrelid 
-------+----------
-(0 rows)
-
-SELECT	ctid, inhrelid
-FROM	pg_catalog.pg_inherits fk
-WHERE	inhrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.inhrelid);
- ctid | inhrelid 
-------+----------
-(0 rows)
-
-SELECT	ctid, inhparent
-FROM	pg_catalog.pg_inherits fk
-WHERE	inhparent != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.inhparent);
- ctid | inhparent 
-------+-----------
-(0 rows)
-
-SELECT	ctid, classoid
-FROM	pg_catalog.pg_init_privs fk
-WHERE	classoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid);
- ctid | classoid 
-------+----------
-(0 rows)
-
-SELECT	ctid, lanowner
-FROM	pg_catalog.pg_language fk
-WHERE	lanowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.lanowner);
- ctid | lanowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, lanplcallfoid
-FROM	pg_catalog.pg_language fk
-WHERE	lanplcallfoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.lanplcallfoid);
- ctid | lanplcallfoid 
-------+---------------
-(0 rows)
-
-SELECT	ctid, laninline
-FROM	pg_catalog.pg_language fk
-WHERE	laninline != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.laninline);
- ctid | laninline 
-------+-----------
-(0 rows)
-
-SELECT	ctid, lanvalidator
-FROM	pg_catalog.pg_language fk
-WHERE	lanvalidator != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.lanvalidator);
- ctid | lanvalidator 
-------+--------------
-(0 rows)
-
-SELECT	ctid, loid
-FROM	pg_catalog.pg_largeobject fk
-WHERE	loid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_largeobject_metadata pk WHERE pk.oid = fk.loid);
- ctid | loid 
-------+------
-(0 rows)
-
-SELECT	ctid, lomowner
-FROM	pg_catalog.pg_largeobject_metadata fk
-WHERE	lomowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.lomowner);
- ctid | lomowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, nspowner
-FROM	pg_catalog.pg_namespace fk
-WHERE	nspowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.nspowner);
- ctid | nspowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, opcmethod
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcmethod != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opcmethod);
- ctid | opcmethod 
-------+-----------
-(0 rows)
-
-SELECT	ctid, opcnamespace
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.opcnamespace);
- ctid | opcnamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, opcowner
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.opcowner);
- ctid | opcowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, opcfamily
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcfamily != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.opcfamily);
- ctid | opcfamily 
-------+-----------
-(0 rows)
-
-SELECT	ctid, opcintype
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcintype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.opcintype);
- ctid | opcintype 
-------+-----------
-(0 rows)
-
-SELECT	ctid, opckeytype
-FROM	pg_catalog.pg_opclass fk
-WHERE	opckeytype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.opckeytype);
- ctid | opckeytype 
-------+------------
-(0 rows)
-
-SELECT	ctid, oprnamespace
-FROM	pg_catalog.pg_operator fk
-WHERE	oprnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.oprnamespace);
- ctid | oprnamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, oprowner
-FROM	pg_catalog.pg_operator fk
-WHERE	oprowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.oprowner);
- ctid | oprowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, oprleft
-FROM	pg_catalog.pg_operator fk
-WHERE	oprleft != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.oprleft);
- ctid | oprleft 
-------+---------
-(0 rows)
-
-SELECT	ctid, oprright
-FROM	pg_catalog.pg_operator fk
-WHERE	oprright != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.oprright);
- ctid | oprright 
-------+----------
-(0 rows)
-
-SELECT	ctid, oprresult
-FROM	pg_catalog.pg_operator fk
-WHERE	oprresult != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.oprresult);
- ctid | oprresult 
-------+-----------
-(0 rows)
-
-SELECT	ctid, oprcom
-FROM	pg_catalog.pg_operator fk
-WHERE	oprcom != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprcom);
- ctid | oprcom 
-------+--------
-(0 rows)
-
-SELECT	ctid, oprnegate
-FROM	pg_catalog.pg_operator fk
-WHERE	oprnegate != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprnegate);
- ctid | oprnegate 
-------+-----------
-(0 rows)
-
-SELECT	ctid, oprcode
-FROM	pg_catalog.pg_operator fk
-WHERE	oprcode != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprcode);
- ctid | oprcode 
-------+---------
-(0 rows)
-
-SELECT	ctid, oprrest
-FROM	pg_catalog.pg_operator fk
-WHERE	oprrest != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprrest);
- ctid | oprrest 
-------+---------
-(0 rows)
-
-SELECT	ctid, oprjoin
-FROM	pg_catalog.pg_operator fk
-WHERE	oprjoin != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprjoin);
- ctid | oprjoin 
-------+---------
-(0 rows)
-
-SELECT	ctid, opfmethod
-FROM	pg_catalog.pg_opfamily fk
-WHERE	opfmethod != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opfmethod);
- ctid | opfmethod 
-------+-----------
-(0 rows)
-
-SELECT	ctid, opfnamespace
-FROM	pg_catalog.pg_opfamily fk
-WHERE	opfnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.opfnamespace);
- ctid | opfnamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, opfowner
-FROM	pg_catalog.pg_opfamily fk
-WHERE	opfowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.opfowner);
- ctid | opfowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, partrelid
-FROM	pg_catalog.pg_partitioned_table fk
-WHERE	partrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.partrelid);
- ctid | partrelid 
-------+-----------
-(0 rows)
-
-SELECT	ctid, partdefid
-FROM	pg_catalog.pg_partitioned_table fk
-WHERE	partdefid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.partdefid);
- ctid | partdefid 
-------+-----------
-(0 rows)
-
-SELECT	ctid, polrelid
-FROM	pg_catalog.pg_policy fk
-WHERE	polrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.polrelid);
- ctid | polrelid 
-------+----------
-(0 rows)
-
-SELECT	ctid, pronamespace
-FROM	pg_catalog.pg_proc fk
-WHERE	pronamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.pronamespace);
- ctid | pronamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, proowner
-FROM	pg_catalog.pg_proc fk
-WHERE	proowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.proowner);
- ctid | proowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, prolang
-FROM	pg_catalog.pg_proc fk
-WHERE	prolang != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_language pk WHERE pk.oid = fk.prolang);
- ctid | prolang 
-------+---------
-(0 rows)
-
-SELECT	ctid, provariadic
-FROM	pg_catalog.pg_proc fk
-WHERE	provariadic != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.provariadic);
- ctid | provariadic 
-------+-------------
-(0 rows)
-
-SELECT	ctid, prosupport
-FROM	pg_catalog.pg_proc fk
-WHERE	prosupport != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prosupport);
- ctid | prosupport 
-------+------------
-(0 rows)
-
-SELECT	ctid, prorettype
-FROM	pg_catalog.pg_proc fk
-WHERE	prorettype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.prorettype);
- ctid | prorettype 
-------+------------
-(0 rows)
-
-SELECT	ctid, rngtypid
-FROM	pg_catalog.pg_range fk
-WHERE	rngtypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.rngtypid);
- ctid | rngtypid 
-------+----------
-(0 rows)
-
-SELECT	ctid, rngsubtype
-FROM	pg_catalog.pg_range fk
-WHERE	rngsubtype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.rngsubtype);
- ctid | rngsubtype 
-------+------------
-(0 rows)
-
-SELECT	ctid, rngcollation
-FROM	pg_catalog.pg_range fk
-WHERE	rngcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.rngcollation);
- ctid | rngcollation 
-------+--------------
-(0 rows)
-
-SELECT	ctid, rngsubopc
-FROM	pg_catalog.pg_range fk
-WHERE	rngsubopc != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.rngsubopc);
- ctid | rngsubopc 
-------+-----------
-(0 rows)
-
-SELECT	ctid, rngcanonical
-FROM	pg_catalog.pg_range fk
-WHERE	rngcanonical != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.rngcanonical);
- ctid | rngcanonical 
-------+--------------
-(0 rows)
-
-SELECT	ctid, rngsubdiff
-FROM	pg_catalog.pg_range fk
-WHERE	rngsubdiff != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.rngsubdiff);
- ctid | rngsubdiff 
-------+------------
-(0 rows)
-
-SELECT	ctid, ev_class
-FROM	pg_catalog.pg_rewrite fk
-WHERE	ev_class != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.ev_class);
- ctid | ev_class 
-------+----------
-(0 rows)
-
-SELECT	ctid, seqrelid
-FROM	pg_catalog.pg_sequence fk
-WHERE	seqrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.seqrelid);
- ctid | seqrelid 
-------+----------
-(0 rows)
-
-SELECT	ctid, seqtypid
-FROM	pg_catalog.pg_sequence fk
-WHERE	seqtypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.seqtypid);
- ctid | seqtypid 
-------+----------
-(0 rows)
-
-SELECT	ctid, refclassid
-FROM	pg_catalog.pg_shdepend fk
-WHERE	refclassid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.refclassid);
- ctid | refclassid 
-------+------------
-(0 rows)
-
-SELECT	ctid, classoid
-FROM	pg_catalog.pg_shdescription fk
-WHERE	classoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid);
- ctid | classoid 
-------+----------
-(0 rows)
-
-SELECT	ctid, starelid
-FROM	pg_catalog.pg_statistic fk
-WHERE	starelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.starelid);
- ctid | starelid 
-------+----------
-(0 rows)
-
-SELECT	ctid, staop1
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop1 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop1);
- ctid | staop1 
-------+--------
-(0 rows)
-
-SELECT	ctid, staop2
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop2 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop2);
- ctid | staop2 
-------+--------
-(0 rows)
-
-SELECT	ctid, staop3
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop3 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop3);
- ctid | staop3 
-------+--------
-(0 rows)
-
-SELECT	ctid, staop4
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop4 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop4);
- ctid | staop4 
-------+--------
-(0 rows)
-
-SELECT	ctid, staop5
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop5 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop5);
- ctid | staop5 
-------+--------
-(0 rows)
-
-SELECT	ctid, stacoll1
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll1 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll1);
- ctid | stacoll1 
-------+----------
-(0 rows)
-
-SELECT	ctid, stacoll2
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll2 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll2);
- ctid | stacoll2 
-------+----------
-(0 rows)
-
-SELECT	ctid, stacoll3
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll3 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll3);
- ctid | stacoll3 
-------+----------
-(0 rows)
-
-SELECT	ctid, stacoll4
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll4 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll4);
- ctid | stacoll4 
-------+----------
-(0 rows)
-
-SELECT	ctid, stacoll5
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll5 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll5);
- ctid | stacoll5 
-------+----------
-(0 rows)
-
-SELECT	ctid, stxrelid
-FROM	pg_catalog.pg_statistic_ext fk
-WHERE	stxrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.stxrelid);
- ctid | stxrelid 
-------+----------
-(0 rows)
-
-SELECT	ctid, stxnamespace
-FROM	pg_catalog.pg_statistic_ext fk
-WHERE	stxnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.stxnamespace);
- ctid | stxnamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, stxowner
-FROM	pg_catalog.pg_statistic_ext fk
-WHERE	stxowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.stxowner);
- ctid | stxowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, stxoid
-FROM	pg_catalog.pg_statistic_ext_data fk
-WHERE	stxoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_statistic_ext pk WHERE pk.oid = fk.stxoid);
- ctid | stxoid 
-------+--------
-(0 rows)
-
-SELECT	ctid, spcowner
-FROM	pg_catalog.pg_tablespace fk
-WHERE	spcowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.spcowner);
- ctid | spcowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, trftype
-FROM	pg_catalog.pg_transform fk
-WHERE	trftype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.trftype);
- ctid | trftype 
-------+---------
-(0 rows)
-
-SELECT	ctid, trflang
-FROM	pg_catalog.pg_transform fk
-WHERE	trflang != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_language pk WHERE pk.oid = fk.trflang);
- ctid | trflang 
-------+---------
-(0 rows)
-
-SELECT	ctid, trffromsql
-FROM	pg_catalog.pg_transform fk
-WHERE	trffromsql != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.trffromsql);
- ctid | trffromsql 
-------+------------
-(0 rows)
-
-SELECT	ctid, trftosql
-FROM	pg_catalog.pg_transform fk
-WHERE	trftosql != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.trftosql);
- ctid | trftosql 
-------+----------
-(0 rows)
-
-SELECT	ctid, tgrelid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.tgrelid);
- ctid | tgrelid 
-------+---------
-(0 rows)
-
-SELECT	ctid, tgparentid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgparentid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_trigger pk WHERE pk.oid = fk.tgparentid);
- ctid | tgparentid 
-------+------------
-(0 rows)
-
-SELECT	ctid, tgfoid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgfoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.tgfoid);
- ctid | tgfoid 
-------+--------
-(0 rows)
-
-SELECT	ctid, tgconstrrelid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgconstrrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.tgconstrrelid);
- ctid | tgconstrrelid 
-------+---------------
-(0 rows)
-
-SELECT	ctid, tgconstrindid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgconstrindid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.tgconstrindid);
- ctid | tgconstrindid 
-------+---------------
-(0 rows)
-
-SELECT	ctid, tgconstraint
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgconstraint != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_constraint pk WHERE pk.oid = fk.tgconstraint);
- ctid | tgconstraint 
-------+--------------
-(0 rows)
-
-SELECT	ctid, cfgnamespace
-FROM	pg_catalog.pg_ts_config fk
-WHERE	cfgnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.cfgnamespace);
- ctid | cfgnamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, cfgowner
-FROM	pg_catalog.pg_ts_config fk
-WHERE	cfgowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.cfgowner);
- ctid | cfgowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, cfgparser
-FROM	pg_catalog.pg_ts_config fk
-WHERE	cfgparser != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_parser pk WHERE pk.oid = fk.cfgparser);
- ctid | cfgparser 
-------+-----------
-(0 rows)
-
-SELECT	ctid, mapcfg
-FROM	pg_catalog.pg_ts_config_map fk
-WHERE	mapcfg != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_config pk WHERE pk.oid = fk.mapcfg);
- ctid | mapcfg 
-------+--------
-(0 rows)
-
-SELECT	ctid, mapdict
-FROM	pg_catalog.pg_ts_config_map fk
-WHERE	mapdict != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_dict pk WHERE pk.oid = fk.mapdict);
- ctid | mapdict 
-------+---------
-(0 rows)
-
-SELECT	ctid, dictnamespace
-FROM	pg_catalog.pg_ts_dict fk
-WHERE	dictnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.dictnamespace);
- ctid | dictnamespace 
-------+---------------
-(0 rows)
-
-SELECT	ctid, dictowner
-FROM	pg_catalog.pg_ts_dict fk
-WHERE	dictowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.dictowner);
- ctid | dictowner 
-------+-----------
-(0 rows)
-
-SELECT	ctid, dicttemplate
-FROM	pg_catalog.pg_ts_dict fk
-WHERE	dicttemplate != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_template pk WHERE pk.oid = fk.dicttemplate);
- ctid | dicttemplate 
-------+--------------
-(0 rows)
-
-SELECT	ctid, prsnamespace
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prsnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.prsnamespace);
- ctid | prsnamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, prsstart
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prsstart != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prsstart);
- ctid | prsstart 
-------+----------
-(0 rows)
-
-SELECT	ctid, prstoken
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prstoken != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prstoken);
- ctid | prstoken 
-------+----------
-(0 rows)
-
-SELECT	ctid, prsend
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prsend != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prsend);
- ctid | prsend 
-------+--------
-(0 rows)
-
-SELECT	ctid, prsheadline
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prsheadline != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prsheadline);
- ctid | prsheadline 
-------+-------------
-(0 rows)
-
-SELECT	ctid, prslextype
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prslextype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prslextype);
- ctid | prslextype 
-------+------------
-(0 rows)
-
-SELECT	ctid, tmplnamespace
-FROM	pg_catalog.pg_ts_template fk
-WHERE	tmplnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.tmplnamespace);
- ctid | tmplnamespace 
-------+---------------
-(0 rows)
-
-SELECT	ctid, tmplinit
-FROM	pg_catalog.pg_ts_template fk
-WHERE	tmplinit != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.tmplinit);
- ctid | tmplinit 
-------+----------
-(0 rows)
-
-SELECT	ctid, tmpllexize
-FROM	pg_catalog.pg_ts_template fk
-WHERE	tmpllexize != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.tmpllexize);
- ctid | tmpllexize 
-------+------------
-(0 rows)
-
-SELECT	ctid, typnamespace
-FROM	pg_catalog.pg_type fk
-WHERE	typnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.typnamespace);
- ctid | typnamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, typowner
-FROM	pg_catalog.pg_type fk
-WHERE	typowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.typowner);
- ctid | typowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, typrelid
-FROM	pg_catalog.pg_type fk
-WHERE	typrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.typrelid);
- ctid | typrelid 
-------+----------
-(0 rows)
-
-SELECT	ctid, typelem
-FROM	pg_catalog.pg_type fk
-WHERE	typelem != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typelem);
- ctid | typelem 
-------+---------
-(0 rows)
-
-SELECT	ctid, typarray
-FROM	pg_catalog.pg_type fk
-WHERE	typarray != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typarray);
- ctid | typarray 
-------+----------
-(0 rows)
-
-SELECT	ctid, typinput
-FROM	pg_catalog.pg_type fk
-WHERE	typinput != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typinput);
- ctid | typinput 
-------+----------
-(0 rows)
-
-SELECT	ctid, typoutput
-FROM	pg_catalog.pg_type fk
-WHERE	typoutput != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typoutput);
- ctid | typoutput 
-------+-----------
-(0 rows)
-
-SELECT	ctid, typreceive
-FROM	pg_catalog.pg_type fk
-WHERE	typreceive != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typreceive);
- ctid | typreceive 
-------+------------
-(0 rows)
-
-SELECT	ctid, typsend
-FROM	pg_catalog.pg_type fk
-WHERE	typsend != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typsend);
- ctid | typsend 
-------+---------
-(0 rows)
-
-SELECT	ctid, typmodin
-FROM	pg_catalog.pg_type fk
-WHERE	typmodin != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typmodin);
- ctid | typmodin 
-------+----------
-(0 rows)
-
-SELECT	ctid, typmodout
-FROM	pg_catalog.pg_type fk
-WHERE	typmodout != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typmodout);
- ctid | typmodout 
-------+-----------
-(0 rows)
-
-SELECT	ctid, typanalyze
-FROM	pg_catalog.pg_type fk
-WHERE	typanalyze != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typanalyze);
- ctid | typanalyze 
-------+------------
-(0 rows)
-
-SELECT	ctid, typbasetype
-FROM	pg_catalog.pg_type fk
-WHERE	typbasetype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typbasetype);
- ctid | typbasetype 
-------+-------------
-(0 rows)
-
-SELECT	ctid, typcollation
-FROM	pg_catalog.pg_type fk
-WHERE	typcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.typcollation);
- ctid | typcollation 
-------+--------------
-(0 rows)
-
-SELECT	ctid, conpfeqop
-FROM	(SELECT ctid, unnest(conpfeqop) AS conpfeqop FROM pg_catalog.pg_constraint) fk
-WHERE	conpfeqop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conpfeqop);
- ctid | conpfeqop 
-------+-----------
-(0 rows)
-
-SELECT	ctid, conppeqop
-FROM	(SELECT ctid, unnest(conppeqop) AS conppeqop FROM pg_catalog.pg_constraint) fk
-WHERE	conppeqop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conppeqop);
- ctid | conppeqop 
-------+-----------
-(0 rows)
-
-SELECT	ctid, conffeqop
-FROM	(SELECT ctid, unnest(conffeqop) AS conffeqop FROM pg_catalog.pg_constraint) fk
-WHERE	conffeqop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conffeqop);
- ctid | conffeqop 
-------+-----------
-(0 rows)
-
-SELECT	ctid, conexclop
-FROM	(SELECT ctid, unnest(conexclop) AS conexclop FROM pg_catalog.pg_constraint) fk
-WHERE	conexclop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conexclop);
- ctid | conexclop 
-------+-----------
-(0 rows)
-
-SELECT	ctid, indcollation
-FROM	(SELECT ctid, unnest(indcollation) AS indcollation FROM pg_catalog.pg_index) fk
-WHERE	indcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.indcollation);
- ctid | indcollation 
-------+--------------
-(0 rows)
-
-SELECT	ctid, indclass
-FROM	(SELECT ctid, unnest(indclass) AS indclass FROM pg_catalog.pg_index) fk
-WHERE	indclass != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.indclass);
- ctid | indclass 
-------+----------
-(0 rows)
-
-SELECT	ctid, partclass
-FROM	(SELECT ctid, unnest(partclass) AS partclass FROM pg_catalog.pg_partitioned_table) fk
-WHERE	partclass != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.partclass);
- ctid | partclass 
-------+-----------
-(0 rows)
-
-SELECT	ctid, partcollation
-FROM	(SELECT ctid, unnest(partcollation) AS partcollation FROM pg_catalog.pg_partitioned_table) fk
-WHERE	partcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.partcollation);
- ctid | partcollation 
-------+---------------
-(0 rows)
-
-SELECT	ctid, proargtypes
-FROM	(SELECT ctid, unnest(proargtypes) AS proargtypes FROM pg_catalog.pg_proc) fk
-WHERE	proargtypes != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.proargtypes);
- ctid | proargtypes 
-------+-------------
-(0 rows)
-
-SELECT	ctid, proallargtypes
-FROM	(SELECT ctid, unnest(proallargtypes) AS proallargtypes FROM pg_catalog.pg_proc) fk
-WHERE	proallargtypes != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.proallargtypes);
- ctid | proallargtypes 
-------+----------------
-(0 rows)
-
+DO $doblock$
+declare
+  fk record;
+  nkeys integer;
+  cmd text;
+  err record;
+begin
+  for fk in select * from pg_get_catalog_foreign_keys()
+  loop
+    raise notice 'checking % % => % %',
+      fk.fktable, fk.fkcols, fk.pktable, fk.pkcols;
+    nkeys := array_length(fk.fkcols, 1);
+    cmd := 'SELECT ctid';
+    for i in 1 .. nkeys loop
+      cmd := cmd || ', ' || quote_ident(fk.fkcols[i]);
+    end loop;
+    if fk.is_array then
+      cmd := cmd || ' FROM (SELECT ctid';
+      for i in 1 .. nkeys-1 loop
+        cmd := cmd || ', ' || quote_ident(fk.fkcols[i]);
+      end loop;
+      cmd := cmd || ', unnest(' || quote_ident(fk.fkcols[nkeys]);
+      cmd := cmd || ') as ' || quote_ident(fk.fkcols[nkeys]);
+      cmd := cmd || ' FROM ' || fk.fktable::text || ') fk';
+    else
+      cmd := cmd || ' FROM ' || fk.fktable::text || ' fk';
+    end if;
+    cmd := cmd || ' WHERE (' || quote_ident(fk.fkcols[1]) || ' != 0';
+    for i in 2 .. nkeys loop
+      cmd := cmd || ' OR ' || quote_ident(fk.fkcols[i]) || ' != 0';
+    end loop;
+    cmd := cmd || ') AND NOT EXISTS(SELECT 1 FROM ' || fk.pktable::text || ' pk WHERE ';
+    for i in 1 .. nkeys loop
+      if i > 1 then cmd := cmd || ' AND '; end if;
+      cmd := cmd || 'pk.' || quote_ident(fk.pkcols[i]);
+      cmd := cmd || ' = fk.' || quote_ident(fk.fkcols[i]);
+    end loop;
+    cmd := cmd || ')';
+    -- raise notice 'cmd = %', cmd;
+    for err in execute cmd loop
+      raise notice 'FK VIOLATION: %', err;
+    end loop;
+  end loop;
+end
+$doblock$;
+NOTICE:  checking pg_proc {pronamespace} => pg_namespace {oid}
+NOTICE:  checking pg_proc {proowner} => pg_authid {oid}
+NOTICE:  checking pg_proc {prolang} => pg_language {oid}
+NOTICE:  checking pg_proc {provariadic} => pg_type {oid}
+NOTICE:  checking pg_proc {prosupport} => pg_proc {oid}
+NOTICE:  checking pg_proc {prorettype} => pg_type {oid}
+NOTICE:  checking pg_proc {proargtypes} => pg_type {oid}
+NOTICE:  checking pg_proc {proallargtypes} => pg_type {oid}
+NOTICE:  checking pg_proc {protrftypes} => pg_type {oid}
+NOTICE:  checking pg_type {typnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_type {typowner} => pg_authid {oid}
+NOTICE:  checking pg_type {typrelid} => pg_class {oid}
+NOTICE:  checking pg_type {typsubscript} => pg_proc {oid}
+NOTICE:  checking pg_type {typelem} => pg_type {oid}
+NOTICE:  checking pg_type {typarray} => pg_type {oid}
+NOTICE:  checking pg_type {typinput} => pg_proc {oid}
+NOTICE:  checking pg_type {typoutput} => pg_proc {oid}
+NOTICE:  checking pg_type {typreceive} => pg_proc {oid}
+NOTICE:  checking pg_type {typsend} => pg_proc {oid}
+NOTICE:  checking pg_type {typmodin} => pg_proc {oid}
+NOTICE:  checking pg_type {typmodout} => pg_proc {oid}
+NOTICE:  checking pg_type {typanalyze} => pg_proc {oid}
+NOTICE:  checking pg_type {typbasetype} => pg_type {oid}
+NOTICE:  checking pg_type {typcollation} => pg_collation {oid}
+NOTICE:  checking pg_attribute {attrelid} => pg_class {oid}
+NOTICE:  checking pg_attribute {atttypid} => pg_type {oid}
+NOTICE:  checking pg_attribute {attcollation} => pg_collation {oid}
+NOTICE:  checking pg_class {relnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_class {reltype} => pg_type {oid}
+NOTICE:  checking pg_class {reloftype} => pg_type {oid}
+NOTICE:  checking pg_class {relowner} => pg_authid {oid}
+NOTICE:  checking pg_class {relam} => pg_am {oid}
+NOTICE:  checking pg_class {reltablespace} => pg_tablespace {oid}
+NOTICE:  checking pg_class {reltoastrelid} => pg_class {oid}
+NOTICE:  checking pg_class {relrewrite} => pg_class {oid}
+NOTICE:  checking pg_attrdef {adrelid} => pg_class {oid}
+NOTICE:  checking pg_attrdef {adrelid,adnum} => pg_attribute {attrelid,attnum}
+NOTICE:  checking pg_constraint {connamespace} => pg_namespace {oid}
+NOTICE:  checking pg_constraint {conrelid} => pg_class {oid}
+NOTICE:  checking pg_constraint {contypid} => pg_type {oid}
+NOTICE:  checking pg_constraint {conindid} => pg_class {oid}
+NOTICE:  checking pg_constraint {conparentid} => pg_constraint {oid}
+NOTICE:  checking pg_constraint {confrelid} => pg_class {oid}
+NOTICE:  checking pg_constraint {conpfeqop} => pg_operator {oid}
+NOTICE:  checking pg_constraint {conppeqop} => pg_operator {oid}
+NOTICE:  checking pg_constraint {conffeqop} => pg_operator {oid}
+NOTICE:  checking pg_constraint {conexclop} => pg_operator {oid}
+NOTICE:  checking pg_constraint {conrelid,conkey} => pg_attribute {attrelid,attnum}
+NOTICE:  checking pg_constraint {confrelid,confkey} => pg_attribute {attrelid,attnum}
+NOTICE:  checking pg_inherits {inhrelid} => pg_class {oid}
+NOTICE:  checking pg_inherits {inhparent} => pg_class {oid}
+NOTICE:  checking pg_index {indexrelid} => pg_class {oid}
+NOTICE:  checking pg_index {indrelid} => pg_class {oid}
+NOTICE:  checking pg_index {indcollation} => pg_collation {oid}
+NOTICE:  checking pg_index {indclass} => pg_opclass {oid}
+NOTICE:  checking pg_index {indrelid,indkey} => pg_attribute {attrelid,attnum}
+NOTICE:  checking pg_operator {oprnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_operator {oprowner} => pg_authid {oid}
+NOTICE:  checking pg_operator {oprleft} => pg_type {oid}
+NOTICE:  checking pg_operator {oprright} => pg_type {oid}
+NOTICE:  checking pg_operator {oprresult} => pg_type {oid}
+NOTICE:  checking pg_operator {oprcom} => pg_operator {oid}
+NOTICE:  checking pg_operator {oprnegate} => pg_operator {oid}
+NOTICE:  checking pg_operator {oprcode} => pg_proc {oid}
+NOTICE:  checking pg_operator {oprrest} => pg_proc {oid}
+NOTICE:  checking pg_operator {oprjoin} => pg_proc {oid}
+NOTICE:  checking pg_opfamily {opfmethod} => pg_am {oid}
+NOTICE:  checking pg_opfamily {opfnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_opfamily {opfowner} => pg_authid {oid}
+NOTICE:  checking pg_opclass {opcmethod} => pg_am {oid}
+NOTICE:  checking pg_opclass {opcnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_opclass {opcowner} => pg_authid {oid}
+NOTICE:  checking pg_opclass {opcfamily} => pg_opfamily {oid}
+NOTICE:  checking pg_opclass {opcintype} => pg_type {oid}
+NOTICE:  checking pg_opclass {opckeytype} => pg_type {oid}
+NOTICE:  checking pg_am {amhandler} => pg_proc {oid}
+NOTICE:  checking pg_amop {amopfamily} => pg_opfamily {oid}
+NOTICE:  checking pg_amop {amoplefttype} => pg_type {oid}
+NOTICE:  checking pg_amop {amoprighttype} => pg_type {oid}
+NOTICE:  checking pg_amop {amopopr} => pg_operator {oid}
+NOTICE:  checking pg_amop {amopmethod} => pg_am {oid}
+NOTICE:  checking pg_amop {amopsortfamily} => pg_opfamily {oid}
+NOTICE:  checking pg_amproc {amprocfamily} => pg_opfamily {oid}
+NOTICE:  checking pg_amproc {amproclefttype} => pg_type {oid}
+NOTICE:  checking pg_amproc {amprocrighttype} => pg_type {oid}
+NOTICE:  checking pg_amproc {amproc} => pg_proc {oid}
+NOTICE:  checking pg_language {lanowner} => pg_authid {oid}
+NOTICE:  checking pg_language {lanplcallfoid} => pg_proc {oid}
+NOTICE:  checking pg_language {laninline} => pg_proc {oid}
+NOTICE:  checking pg_language {lanvalidator} => pg_proc {oid}
+NOTICE:  checking pg_largeobject_metadata {lomowner} => pg_authid {oid}
+NOTICE:  checking pg_largeobject {loid} => pg_largeobject_metadata {oid}
+NOTICE:  checking pg_aggregate {aggfnoid} => pg_proc {oid}
+NOTICE:  checking pg_aggregate {aggtransfn} => pg_proc {oid}
+NOTICE:  checking pg_aggregate {aggfinalfn} => pg_proc {oid}
+NOTICE:  checking pg_aggregate {aggcombinefn} => pg_proc {oid}
+NOTICE:  checking pg_aggregate {aggserialfn} => pg_proc {oid}
+NOTICE:  checking pg_aggregate {aggdeserialfn} => pg_proc {oid}
+NOTICE:  checking pg_aggregate {aggmtransfn} => pg_proc {oid}
+NOTICE:  checking pg_aggregate {aggminvtransfn} => pg_proc {oid}
+NOTICE:  checking pg_aggregate {aggmfinalfn} => pg_proc {oid}
+NOTICE:  checking pg_aggregate {aggsortop} => pg_operator {oid}
+NOTICE:  checking pg_aggregate {aggtranstype} => pg_type {oid}
+NOTICE:  checking pg_aggregate {aggmtranstype} => pg_type {oid}
+NOTICE:  checking pg_statistic_ext {stxrelid} => pg_class {oid}
+NOTICE:  checking pg_statistic_ext {stxnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_statistic_ext {stxowner} => pg_authid {oid}
+NOTICE:  checking pg_statistic_ext {stxrelid,stxkeys} => pg_attribute {attrelid,attnum}
+NOTICE:  checking pg_statistic_ext_data {stxoid} => pg_statistic_ext {oid}
+NOTICE:  checking pg_statistic {starelid} => pg_class {oid}
+NOTICE:  checking pg_statistic {staop1} => pg_operator {oid}
+NOTICE:  checking pg_statistic {staop2} => pg_operator {oid}
+NOTICE:  checking pg_statistic {staop3} => pg_operator {oid}
+NOTICE:  checking pg_statistic {staop4} => pg_operator {oid}
+NOTICE:  checking pg_statistic {staop5} => pg_operator {oid}
+NOTICE:  checking pg_statistic {stacoll1} => pg_collation {oid}
+NOTICE:  checking pg_statistic {stacoll2} => pg_collation {oid}
+NOTICE:  checking pg_statistic {stacoll3} => pg_collation {oid}
+NOTICE:  checking pg_statistic {stacoll4} => pg_collation {oid}
+NOTICE:  checking pg_statistic {stacoll5} => pg_collation {oid}
+NOTICE:  checking pg_statistic {starelid,staattnum} => pg_attribute {attrelid,attnum}
+NOTICE:  checking pg_rewrite {ev_class} => pg_class {oid}
+NOTICE:  checking pg_trigger {tgrelid} => pg_class {oid}
+NOTICE:  checking pg_trigger {tgparentid} => pg_trigger {oid}
+NOTICE:  checking pg_trigger {tgfoid} => pg_proc {oid}
+NOTICE:  checking pg_trigger {tgconstrrelid} => pg_class {oid}
+NOTICE:  checking pg_trigger {tgconstrindid} => pg_class {oid}
+NOTICE:  checking pg_trigger {tgconstraint} => pg_constraint {oid}
+NOTICE:  checking pg_trigger {tgrelid,tgattr} => pg_attribute {attrelid,attnum}
+NOTICE:  checking pg_event_trigger {evtowner} => pg_authid {oid}
+NOTICE:  checking pg_event_trigger {evtfoid} => pg_proc {oid}
+NOTICE:  checking pg_description {classoid} => pg_class {oid}
+NOTICE:  checking pg_cast {castsource} => pg_type {oid}
+NOTICE:  checking pg_cast {casttarget} => pg_type {oid}
+NOTICE:  checking pg_cast {castfunc} => pg_proc {oid}
+NOTICE:  checking pg_enum {enumtypid} => pg_type {oid}
+NOTICE:  checking pg_namespace {nspowner} => pg_authid {oid}
+NOTICE:  checking pg_conversion {connamespace} => pg_namespace {oid}
+NOTICE:  checking pg_conversion {conowner} => pg_authid {oid}
+NOTICE:  checking pg_conversion {conproc} => pg_proc {oid}
+NOTICE:  checking pg_depend {classid} => pg_class {oid}
+NOTICE:  checking pg_depend {refclassid} => pg_class {oid}
+NOTICE:  checking pg_database {datdba} => pg_authid {oid}
+NOTICE:  checking pg_database {dattablespace} => pg_tablespace {oid}
+NOTICE:  checking pg_db_role_setting {setdatabase} => pg_database {oid}
+NOTICE:  checking pg_db_role_setting {setrole} => pg_authid {oid}
+NOTICE:  checking pg_tablespace {spcowner} => pg_authid {oid}
+NOTICE:  checking pg_auth_members {roleid} => pg_authid {oid}
+NOTICE:  checking pg_auth_members {member} => pg_authid {oid}
+NOTICE:  checking pg_auth_members {grantor} => pg_authid {oid}
+NOTICE:  checking pg_shdepend {dbid} => pg_database {oid}
+NOTICE:  checking pg_shdepend {classid} => pg_class {oid}
+NOTICE:  checking pg_shdepend {refclassid} => pg_class {oid}
+NOTICE:  checking pg_shdescription {classoid} => pg_class {oid}
+NOTICE:  checking pg_ts_config {cfgnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_ts_config {cfgowner} => pg_authid {oid}
+NOTICE:  checking pg_ts_config {cfgparser} => pg_ts_parser {oid}
+NOTICE:  checking pg_ts_config_map {mapcfg} => pg_ts_config {oid}
+NOTICE:  checking pg_ts_config_map {mapdict} => pg_ts_dict {oid}
+NOTICE:  checking pg_ts_dict {dictnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_ts_dict {dictowner} => pg_authid {oid}
+NOTICE:  checking pg_ts_dict {dicttemplate} => pg_ts_template {oid}
+NOTICE:  checking pg_ts_parser {prsnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_ts_parser {prsstart} => pg_proc {oid}
+NOTICE:  checking pg_ts_parser {prstoken} => pg_proc {oid}
+NOTICE:  checking pg_ts_parser {prsend} => pg_proc {oid}
+NOTICE:  checking pg_ts_parser {prsheadline} => pg_proc {oid}
+NOTICE:  checking pg_ts_parser {prslextype} => pg_proc {oid}
+NOTICE:  checking pg_ts_template {tmplnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_ts_template {tmplinit} => pg_proc {oid}
+NOTICE:  checking pg_ts_template {tmpllexize} => pg_proc {oid}
+NOTICE:  checking pg_extension {extowner} => pg_authid {oid}
+NOTICE:  checking pg_extension {extnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_extension {extconfig} => pg_class {oid}
+NOTICE:  checking pg_foreign_data_wrapper {fdwowner} => pg_authid {oid}
+NOTICE:  checking pg_foreign_data_wrapper {fdwhandler} => pg_proc {oid}
+NOTICE:  checking pg_foreign_data_wrapper {fdwvalidator} => pg_proc {oid}
+NOTICE:  checking pg_foreign_server {srvowner} => pg_authid {oid}
+NOTICE:  checking pg_foreign_server {srvfdw} => pg_foreign_data_wrapper {oid}
+NOTICE:  checking pg_user_mapping {umuser} => pg_authid {oid}
+NOTICE:  checking pg_user_mapping {umserver} => pg_foreign_server {oid}
+NOTICE:  checking pg_foreign_table {ftrelid} => pg_class {oid}
+NOTICE:  checking pg_foreign_table {ftserver} => pg_foreign_server {oid}
+NOTICE:  checking pg_policy {polrelid} => pg_class {oid}
+NOTICE:  checking pg_policy {polroles} => pg_authid {oid}
+NOTICE:  checking pg_default_acl {defaclrole} => pg_authid {oid}
+NOTICE:  checking pg_default_acl {defaclnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_init_privs {classoid} => pg_class {oid}
+NOTICE:  checking pg_seclabel {classoid} => pg_class {oid}
+NOTICE:  checking pg_shseclabel {classoid} => pg_class {oid}
+NOTICE:  checking pg_collation {collnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_collation {collowner} => pg_authid {oid}
+NOTICE:  checking pg_partitioned_table {partrelid} => pg_class {oid}
+NOTICE:  checking pg_partitioned_table {partdefid} => pg_class {oid}
+NOTICE:  checking pg_partitioned_table {partclass} => pg_opclass {oid}
+NOTICE:  checking pg_partitioned_table {partcollation} => pg_collation {oid}
+NOTICE:  checking pg_partitioned_table {partrelid,partattrs} => pg_attribute {attrelid,attnum}
+NOTICE:  checking pg_range {rngtypid} => pg_type {oid}
+NOTICE:  checking pg_range {rngsubtype} => pg_type {oid}
+NOTICE:  checking pg_range {rngmultitypid} => pg_type {oid}
+NOTICE:  checking pg_range {rngcollation} => pg_collation {oid}
+NOTICE:  checking pg_range {rngsubopc} => pg_opclass {oid}
+NOTICE:  checking pg_range {rngcanonical} => pg_proc {oid}
+NOTICE:  checking pg_range {rngsubdiff} => pg_proc {oid}
+NOTICE:  checking pg_transform {trftype} => pg_type {oid}
+NOTICE:  checking pg_transform {trflang} => pg_language {oid}
+NOTICE:  checking pg_transform {trffromsql} => pg_proc {oid}
+NOTICE:  checking pg_transform {trftosql} => pg_proc {oid}
+NOTICE:  checking pg_sequence {seqrelid} => pg_class {oid}
+NOTICE:  checking pg_sequence {seqtypid} => pg_type {oid}
+NOTICE:  checking pg_publication {pubowner} => pg_authid {oid}
+NOTICE:  checking pg_publication_rel {prpubid} => pg_publication {oid}
+NOTICE:  checking pg_publication_rel {prrelid} => pg_class {oid}
+NOTICE:  checking pg_subscription {subdbid} => pg_database {oid}
+NOTICE:  checking pg_subscription {subowner} => pg_authid {oid}
+NOTICE:  checking pg_subscription_rel {srsubid} => pg_subscription {oid}
+NOTICE:  checking pg_subscription_rel {srrelid} => pg_class {oid}
diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql
index f6d2d3c68c..df6d70bf11 100644
--- a/src/test/regress/sql/oidjoins.sql
+++ b/src/test/regress/sql/oidjoins.sql
@@ -1,727 +1,48 @@
 --
--- This is created by pgsql/src/tools/findoidjoins/make_oidjoins_check
+-- Verify system catalog foreign key relationships
 --
-SELECT	ctid, aggfnoid
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggfnoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggfnoid);
-SELECT	ctid, aggtransfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggtransfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggtransfn);
-SELECT	ctid, aggfinalfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggfinalfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggfinalfn);
-SELECT	ctid, aggcombinefn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggcombinefn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggcombinefn);
-SELECT	ctid, aggserialfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggserialfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggserialfn);
-SELECT	ctid, aggdeserialfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggdeserialfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggdeserialfn);
-SELECT	ctid, aggmtransfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggmtransfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggmtransfn);
-SELECT	ctid, aggminvtransfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggminvtransfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggminvtransfn);
-SELECT	ctid, aggmfinalfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggmfinalfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggmfinalfn);
-SELECT	ctid, aggsortop
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggsortop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.aggsortop);
-SELECT	ctid, aggtranstype
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggtranstype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggtranstype);
-SELECT	ctid, aggmtranstype
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggmtranstype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype);
-SELECT	ctid, amhandler
-FROM	pg_catalog.pg_am fk
-WHERE	amhandler != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amhandler);
-SELECT	ctid, amopfamily
-FROM	pg_catalog.pg_amop fk
-WHERE	amopfamily != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amopfamily);
-SELECT	ctid, amoplefttype
-FROM	pg_catalog.pg_amop fk
-WHERE	amoplefttype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amoplefttype);
-SELECT	ctid, amoprighttype
-FROM	pg_catalog.pg_amop fk
-WHERE	amoprighttype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amoprighttype);
-SELECT	ctid, amopopr
-FROM	pg_catalog.pg_amop fk
-WHERE	amopopr != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.amopopr);
-SELECT	ctid, amopmethod
-FROM	pg_catalog.pg_amop fk
-WHERE	amopmethod != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.amopmethod);
-SELECT	ctid, amopsortfamily
-FROM	pg_catalog.pg_amop fk
-WHERE	amopsortfamily != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amopsortfamily);
-SELECT	ctid, amprocfamily
-FROM	pg_catalog.pg_amproc fk
-WHERE	amprocfamily != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amprocfamily);
-SELECT	ctid, amproclefttype
-FROM	pg_catalog.pg_amproc fk
-WHERE	amproclefttype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amproclefttype);
-SELECT	ctid, amprocrighttype
-FROM	pg_catalog.pg_amproc fk
-WHERE	amprocrighttype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amprocrighttype);
-SELECT	ctid, amproc
-FROM	pg_catalog.pg_amproc fk
-WHERE	amproc != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amproc);
-SELECT	ctid, adrelid
-FROM	pg_catalog.pg_attrdef fk
-WHERE	adrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.adrelid);
-SELECT	ctid, attrelid
-FROM	pg_catalog.pg_attribute fk
-WHERE	attrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.attrelid);
-SELECT	ctid, atttypid
-FROM	pg_catalog.pg_attribute fk
-WHERE	atttypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.atttypid);
-SELECT	ctid, attcollation
-FROM	pg_catalog.pg_attribute fk
-WHERE	attcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.attcollation);
-SELECT	ctid, roleid
-FROM	pg_catalog.pg_auth_members fk
-WHERE	roleid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.roleid);
-SELECT	ctid, member
-FROM	pg_catalog.pg_auth_members fk
-WHERE	member != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.member);
-SELECT	ctid, grantor
-FROM	pg_catalog.pg_auth_members fk
-WHERE	grantor != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.grantor);
-SELECT	ctid, castsource
-FROM	pg_catalog.pg_cast fk
-WHERE	castsource != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.castsource);
-SELECT	ctid, casttarget
-FROM	pg_catalog.pg_cast fk
-WHERE	casttarget != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.casttarget);
-SELECT	ctid, castfunc
-FROM	pg_catalog.pg_cast fk
-WHERE	castfunc != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.castfunc);
-SELECT	ctid, relnamespace
-FROM	pg_catalog.pg_class fk
-WHERE	relnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.relnamespace);
-SELECT	ctid, reltype
-FROM	pg_catalog.pg_class fk
-WHERE	reltype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.reltype);
-SELECT	ctid, reloftype
-FROM	pg_catalog.pg_class fk
-WHERE	reloftype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.reloftype);
-SELECT	ctid, relowner
-FROM	pg_catalog.pg_class fk
-WHERE	relowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.relowner);
-SELECT	ctid, relam
-FROM	pg_catalog.pg_class fk
-WHERE	relam != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.relam);
-SELECT	ctid, reltablespace
-FROM	pg_catalog.pg_class fk
-WHERE	reltablespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_tablespace pk WHERE pk.oid = fk.reltablespace);
-SELECT	ctid, reltoastrelid
-FROM	pg_catalog.pg_class fk
-WHERE	reltoastrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.reltoastrelid);
-SELECT	ctid, collnamespace
-FROM	pg_catalog.pg_collation fk
-WHERE	collnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.collnamespace);
-SELECT	ctid, collowner
-FROM	pg_catalog.pg_collation fk
-WHERE	collowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.collowner);
-SELECT	ctid, connamespace
-FROM	pg_catalog.pg_constraint fk
-WHERE	connamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.connamespace);
-SELECT	ctid, conrelid
-FROM	pg_catalog.pg_constraint fk
-WHERE	conrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.conrelid);
-SELECT	ctid, contypid
-FROM	pg_catalog.pg_constraint fk
-WHERE	contypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.contypid);
-SELECT	ctid, conindid
-FROM	pg_catalog.pg_constraint fk
-WHERE	conindid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.conindid);
-SELECT	ctid, conparentid
-FROM	pg_catalog.pg_constraint fk
-WHERE	conparentid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_constraint pk WHERE pk.oid = fk.conparentid);
-SELECT	ctid, confrelid
-FROM	pg_catalog.pg_constraint fk
-WHERE	confrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.confrelid);
-SELECT	ctid, connamespace
-FROM	pg_catalog.pg_conversion fk
-WHERE	connamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.connamespace);
-SELECT	ctid, conowner
-FROM	pg_catalog.pg_conversion fk
-WHERE	conowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.conowner);
-SELECT	ctid, conproc
-FROM	pg_catalog.pg_conversion fk
-WHERE	conproc != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.conproc);
-SELECT	ctid, datdba
-FROM	pg_catalog.pg_database fk
-WHERE	datdba != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.datdba);
-SELECT	ctid, dattablespace
-FROM	pg_catalog.pg_database fk
-WHERE	dattablespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_tablespace pk WHERE pk.oid = fk.dattablespace);
-SELECT	ctid, setdatabase
-FROM	pg_catalog.pg_db_role_setting fk
-WHERE	setdatabase != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_database pk WHERE pk.oid = fk.setdatabase);
-SELECT	ctid, classid
-FROM	pg_catalog.pg_depend fk
-WHERE	classid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classid);
-SELECT	ctid, refclassid
-FROM	pg_catalog.pg_depend fk
-WHERE	refclassid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.refclassid);
-SELECT	ctid, classoid
-FROM	pg_catalog.pg_description fk
-WHERE	classoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid);
-SELECT	ctid, enumtypid
-FROM	pg_catalog.pg_enum fk
-WHERE	enumtypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.enumtypid);
-SELECT	ctid, extowner
-FROM	pg_catalog.pg_extension fk
-WHERE	extowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.extowner);
-SELECT	ctid, extnamespace
-FROM	pg_catalog.pg_extension fk
-WHERE	extnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.extnamespace);
-SELECT	ctid, fdwowner
-FROM	pg_catalog.pg_foreign_data_wrapper fk
-WHERE	fdwowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.fdwowner);
-SELECT	ctid, srvowner
-FROM	pg_catalog.pg_foreign_server fk
-WHERE	srvowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.srvowner);
-SELECT	ctid, srvfdw
-FROM	pg_catalog.pg_foreign_server fk
-WHERE	srvfdw != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_foreign_data_wrapper pk WHERE pk.oid = fk.srvfdw);
-SELECT	ctid, indexrelid
-FROM	pg_catalog.pg_index fk
-WHERE	indexrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.indexrelid);
-SELECT	ctid, indrelid
-FROM	pg_catalog.pg_index fk
-WHERE	indrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.indrelid);
-SELECT	ctid, inhrelid
-FROM	pg_catalog.pg_inherits fk
-WHERE	inhrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.inhrelid);
-SELECT	ctid, inhparent
-FROM	pg_catalog.pg_inherits fk
-WHERE	inhparent != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.inhparent);
-SELECT	ctid, classoid
-FROM	pg_catalog.pg_init_privs fk
-WHERE	classoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid);
-SELECT	ctid, lanowner
-FROM	pg_catalog.pg_language fk
-WHERE	lanowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.lanowner);
-SELECT	ctid, lanplcallfoid
-FROM	pg_catalog.pg_language fk
-WHERE	lanplcallfoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.lanplcallfoid);
-SELECT	ctid, laninline
-FROM	pg_catalog.pg_language fk
-WHERE	laninline != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.laninline);
-SELECT	ctid, lanvalidator
-FROM	pg_catalog.pg_language fk
-WHERE	lanvalidator != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.lanvalidator);
-SELECT	ctid, loid
-FROM	pg_catalog.pg_largeobject fk
-WHERE	loid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_largeobject_metadata pk WHERE pk.oid = fk.loid);
-SELECT	ctid, lomowner
-FROM	pg_catalog.pg_largeobject_metadata fk
-WHERE	lomowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.lomowner);
-SELECT	ctid, nspowner
-FROM	pg_catalog.pg_namespace fk
-WHERE	nspowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.nspowner);
-SELECT	ctid, opcmethod
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcmethod != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opcmethod);
-SELECT	ctid, opcnamespace
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.opcnamespace);
-SELECT	ctid, opcowner
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.opcowner);
-SELECT	ctid, opcfamily
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcfamily != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.opcfamily);
-SELECT	ctid, opcintype
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcintype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.opcintype);
-SELECT	ctid, opckeytype
-FROM	pg_catalog.pg_opclass fk
-WHERE	opckeytype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.opckeytype);
-SELECT	ctid, oprnamespace
-FROM	pg_catalog.pg_operator fk
-WHERE	oprnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.oprnamespace);
-SELECT	ctid, oprowner
-FROM	pg_catalog.pg_operator fk
-WHERE	oprowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.oprowner);
-SELECT	ctid, oprleft
-FROM	pg_catalog.pg_operator fk
-WHERE	oprleft != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.oprleft);
-SELECT	ctid, oprright
-FROM	pg_catalog.pg_operator fk
-WHERE	oprright != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.oprright);
-SELECT	ctid, oprresult
-FROM	pg_catalog.pg_operator fk
-WHERE	oprresult != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.oprresult);
-SELECT	ctid, oprcom
-FROM	pg_catalog.pg_operator fk
-WHERE	oprcom != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprcom);
-SELECT	ctid, oprnegate
-FROM	pg_catalog.pg_operator fk
-WHERE	oprnegate != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprnegate);
-SELECT	ctid, oprcode
-FROM	pg_catalog.pg_operator fk
-WHERE	oprcode != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprcode);
-SELECT	ctid, oprrest
-FROM	pg_catalog.pg_operator fk
-WHERE	oprrest != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprrest);
-SELECT	ctid, oprjoin
-FROM	pg_catalog.pg_operator fk
-WHERE	oprjoin != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprjoin);
-SELECT	ctid, opfmethod
-FROM	pg_catalog.pg_opfamily fk
-WHERE	opfmethod != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opfmethod);
-SELECT	ctid, opfnamespace
-FROM	pg_catalog.pg_opfamily fk
-WHERE	opfnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.opfnamespace);
-SELECT	ctid, opfowner
-FROM	pg_catalog.pg_opfamily fk
-WHERE	opfowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.opfowner);
-SELECT	ctid, partrelid
-FROM	pg_catalog.pg_partitioned_table fk
-WHERE	partrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.partrelid);
-SELECT	ctid, partdefid
-FROM	pg_catalog.pg_partitioned_table fk
-WHERE	partdefid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.partdefid);
-SELECT	ctid, polrelid
-FROM	pg_catalog.pg_policy fk
-WHERE	polrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.polrelid);
-SELECT	ctid, pronamespace
-FROM	pg_catalog.pg_proc fk
-WHERE	pronamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.pronamespace);
-SELECT	ctid, proowner
-FROM	pg_catalog.pg_proc fk
-WHERE	proowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.proowner);
-SELECT	ctid, prolang
-FROM	pg_catalog.pg_proc fk
-WHERE	prolang != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_language pk WHERE pk.oid = fk.prolang);
-SELECT	ctid, provariadic
-FROM	pg_catalog.pg_proc fk
-WHERE	provariadic != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.provariadic);
-SELECT	ctid, prosupport
-FROM	pg_catalog.pg_proc fk
-WHERE	prosupport != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prosupport);
-SELECT	ctid, prorettype
-FROM	pg_catalog.pg_proc fk
-WHERE	prorettype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.prorettype);
-SELECT	ctid, rngtypid
-FROM	pg_catalog.pg_range fk
-WHERE	rngtypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.rngtypid);
-SELECT	ctid, rngsubtype
-FROM	pg_catalog.pg_range fk
-WHERE	rngsubtype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.rngsubtype);
-SELECT	ctid, rngcollation
-FROM	pg_catalog.pg_range fk
-WHERE	rngcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.rngcollation);
-SELECT	ctid, rngsubopc
-FROM	pg_catalog.pg_range fk
-WHERE	rngsubopc != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.rngsubopc);
-SELECT	ctid, rngcanonical
-FROM	pg_catalog.pg_range fk
-WHERE	rngcanonical != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.rngcanonical);
-SELECT	ctid, rngsubdiff
-FROM	pg_catalog.pg_range fk
-WHERE	rngsubdiff != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.rngsubdiff);
-SELECT	ctid, ev_class
-FROM	pg_catalog.pg_rewrite fk
-WHERE	ev_class != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.ev_class);
-SELECT	ctid, seqrelid
-FROM	pg_catalog.pg_sequence fk
-WHERE	seqrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.seqrelid);
-SELECT	ctid, seqtypid
-FROM	pg_catalog.pg_sequence fk
-WHERE	seqtypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.seqtypid);
-SELECT	ctid, refclassid
-FROM	pg_catalog.pg_shdepend fk
-WHERE	refclassid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.refclassid);
-SELECT	ctid, classoid
-FROM	pg_catalog.pg_shdescription fk
-WHERE	classoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid);
-SELECT	ctid, starelid
-FROM	pg_catalog.pg_statistic fk
-WHERE	starelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.starelid);
-SELECT	ctid, staop1
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop1 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop1);
-SELECT	ctid, staop2
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop2 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop2);
-SELECT	ctid, staop3
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop3 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop3);
-SELECT	ctid, staop4
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop4 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop4);
-SELECT	ctid, staop5
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop5 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop5);
-SELECT	ctid, stacoll1
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll1 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll1);
-SELECT	ctid, stacoll2
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll2 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll2);
-SELECT	ctid, stacoll3
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll3 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll3);
-SELECT	ctid, stacoll4
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll4 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll4);
-SELECT	ctid, stacoll5
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll5 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll5);
-SELECT	ctid, stxrelid
-FROM	pg_catalog.pg_statistic_ext fk
-WHERE	stxrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.stxrelid);
-SELECT	ctid, stxnamespace
-FROM	pg_catalog.pg_statistic_ext fk
-WHERE	stxnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.stxnamespace);
-SELECT	ctid, stxowner
-FROM	pg_catalog.pg_statistic_ext fk
-WHERE	stxowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.stxowner);
-SELECT	ctid, stxoid
-FROM	pg_catalog.pg_statistic_ext_data fk
-WHERE	stxoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_statistic_ext pk WHERE pk.oid = fk.stxoid);
-SELECT	ctid, spcowner
-FROM	pg_catalog.pg_tablespace fk
-WHERE	spcowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.spcowner);
-SELECT	ctid, trftype
-FROM	pg_catalog.pg_transform fk
-WHERE	trftype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.trftype);
-SELECT	ctid, trflang
-FROM	pg_catalog.pg_transform fk
-WHERE	trflang != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_language pk WHERE pk.oid = fk.trflang);
-SELECT	ctid, trffromsql
-FROM	pg_catalog.pg_transform fk
-WHERE	trffromsql != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.trffromsql);
-SELECT	ctid, trftosql
-FROM	pg_catalog.pg_transform fk
-WHERE	trftosql != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.trftosql);
-SELECT	ctid, tgrelid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.tgrelid);
-SELECT	ctid, tgparentid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgparentid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_trigger pk WHERE pk.oid = fk.tgparentid);
-SELECT	ctid, tgfoid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgfoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.tgfoid);
-SELECT	ctid, tgconstrrelid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgconstrrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.tgconstrrelid);
-SELECT	ctid, tgconstrindid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgconstrindid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.tgconstrindid);
-SELECT	ctid, tgconstraint
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgconstraint != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_constraint pk WHERE pk.oid = fk.tgconstraint);
-SELECT	ctid, cfgnamespace
-FROM	pg_catalog.pg_ts_config fk
-WHERE	cfgnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.cfgnamespace);
-SELECT	ctid, cfgowner
-FROM	pg_catalog.pg_ts_config fk
-WHERE	cfgowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.cfgowner);
-SELECT	ctid, cfgparser
-FROM	pg_catalog.pg_ts_config fk
-WHERE	cfgparser != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_parser pk WHERE pk.oid = fk.cfgparser);
-SELECT	ctid, mapcfg
-FROM	pg_catalog.pg_ts_config_map fk
-WHERE	mapcfg != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_config pk WHERE pk.oid = fk.mapcfg);
-SELECT	ctid, mapdict
-FROM	pg_catalog.pg_ts_config_map fk
-WHERE	mapdict != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_dict pk WHERE pk.oid = fk.mapdict);
-SELECT	ctid, dictnamespace
-FROM	pg_catalog.pg_ts_dict fk
-WHERE	dictnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.dictnamespace);
-SELECT	ctid, dictowner
-FROM	pg_catalog.pg_ts_dict fk
-WHERE	dictowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.dictowner);
-SELECT	ctid, dicttemplate
-FROM	pg_catalog.pg_ts_dict fk
-WHERE	dicttemplate != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_template pk WHERE pk.oid = fk.dicttemplate);
-SELECT	ctid, prsnamespace
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prsnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.prsnamespace);
-SELECT	ctid, prsstart
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prsstart != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prsstart);
-SELECT	ctid, prstoken
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prstoken != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prstoken);
-SELECT	ctid, prsend
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prsend != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prsend);
-SELECT	ctid, prsheadline
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prsheadline != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prsheadline);
-SELECT	ctid, prslextype
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prslextype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prslextype);
-SELECT	ctid, tmplnamespace
-FROM	pg_catalog.pg_ts_template fk
-WHERE	tmplnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.tmplnamespace);
-SELECT	ctid, tmplinit
-FROM	pg_catalog.pg_ts_template fk
-WHERE	tmplinit != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.tmplinit);
-SELECT	ctid, tmpllexize
-FROM	pg_catalog.pg_ts_template fk
-WHERE	tmpllexize != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.tmpllexize);
-SELECT	ctid, typnamespace
-FROM	pg_catalog.pg_type fk
-WHERE	typnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.typnamespace);
-SELECT	ctid, typowner
-FROM	pg_catalog.pg_type fk
-WHERE	typowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.typowner);
-SELECT	ctid, typrelid
-FROM	pg_catalog.pg_type fk
-WHERE	typrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.typrelid);
-SELECT	ctid, typelem
-FROM	pg_catalog.pg_type fk
-WHERE	typelem != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typelem);
-SELECT	ctid, typarray
-FROM	pg_catalog.pg_type fk
-WHERE	typarray != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typarray);
-SELECT	ctid, typinput
-FROM	pg_catalog.pg_type fk
-WHERE	typinput != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typinput);
-SELECT	ctid, typoutput
-FROM	pg_catalog.pg_type fk
-WHERE	typoutput != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typoutput);
-SELECT	ctid, typreceive
-FROM	pg_catalog.pg_type fk
-WHERE	typreceive != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typreceive);
-SELECT	ctid, typsend
-FROM	pg_catalog.pg_type fk
-WHERE	typsend != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typsend);
-SELECT	ctid, typmodin
-FROM	pg_catalog.pg_type fk
-WHERE	typmodin != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typmodin);
-SELECT	ctid, typmodout
-FROM	pg_catalog.pg_type fk
-WHERE	typmodout != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typmodout);
-SELECT	ctid, typanalyze
-FROM	pg_catalog.pg_type fk
-WHERE	typanalyze != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typanalyze);
-SELECT	ctid, typbasetype
-FROM	pg_catalog.pg_type fk
-WHERE	typbasetype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typbasetype);
-SELECT	ctid, typcollation
-FROM	pg_catalog.pg_type fk
-WHERE	typcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.typcollation);
-SELECT	ctid, conpfeqop
-FROM	(SELECT ctid, unnest(conpfeqop) AS conpfeqop FROM pg_catalog.pg_constraint) fk
-WHERE	conpfeqop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conpfeqop);
-SELECT	ctid, conppeqop
-FROM	(SELECT ctid, unnest(conppeqop) AS conppeqop FROM pg_catalog.pg_constraint) fk
-WHERE	conppeqop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conppeqop);
-SELECT	ctid, conffeqop
-FROM	(SELECT ctid, unnest(conffeqop) AS conffeqop FROM pg_catalog.pg_constraint) fk
-WHERE	conffeqop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conffeqop);
-SELECT	ctid, conexclop
-FROM	(SELECT ctid, unnest(conexclop) AS conexclop FROM pg_catalog.pg_constraint) fk
-WHERE	conexclop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conexclop);
-SELECT	ctid, indcollation
-FROM	(SELECT ctid, unnest(indcollation) AS indcollation FROM pg_catalog.pg_index) fk
-WHERE	indcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.indcollation);
-SELECT	ctid, indclass
-FROM	(SELECT ctid, unnest(indclass) AS indclass FROM pg_catalog.pg_index) fk
-WHERE	indclass != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.indclass);
-SELECT	ctid, partclass
-FROM	(SELECT ctid, unnest(partclass) AS partclass FROM pg_catalog.pg_partitioned_table) fk
-WHERE	partclass != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.partclass);
-SELECT	ctid, partcollation
-FROM	(SELECT ctid, unnest(partcollation) AS partcollation FROM pg_catalog.pg_partitioned_table) fk
-WHERE	partcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.partcollation);
-SELECT	ctid, proargtypes
-FROM	(SELECT ctid, unnest(proargtypes) AS proargtypes FROM pg_catalog.pg_proc) fk
-WHERE	proargtypes != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.proargtypes);
-SELECT	ctid, proallargtypes
-FROM	(SELECT ctid, unnest(proallargtypes) AS proallargtypes FROM pg_catalog.pg_proc) fk
-WHERE	proallargtypes != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.proallargtypes);
+DO $doblock$
+declare
+  fk record;
+  nkeys integer;
+  cmd text;
+  err record;
+begin
+  for fk in select * from pg_get_catalog_foreign_keys()
+  loop
+    raise notice 'checking % % => % %',
+      fk.fktable, fk.fkcols, fk.pktable, fk.pkcols;
+    nkeys := array_length(fk.fkcols, 1);
+    cmd := 'SELECT ctid';
+    for i in 1 .. nkeys loop
+      cmd := cmd || ', ' || quote_ident(fk.fkcols[i]);
+    end loop;
+    if fk.is_array then
+      cmd := cmd || ' FROM (SELECT ctid';
+      for i in 1 .. nkeys-1 loop
+        cmd := cmd || ', ' || quote_ident(fk.fkcols[i]);
+      end loop;
+      cmd := cmd || ', unnest(' || quote_ident(fk.fkcols[nkeys]);
+      cmd := cmd || ') as ' || quote_ident(fk.fkcols[nkeys]);
+      cmd := cmd || ' FROM ' || fk.fktable::text || ') fk';
+    else
+      cmd := cmd || ' FROM ' || fk.fktable::text || ' fk';
+    end if;
+    cmd := cmd || ' WHERE (' || quote_ident(fk.fkcols[1]) || ' != 0';
+    for i in 2 .. nkeys loop
+      cmd := cmd || ' OR ' || quote_ident(fk.fkcols[i]) || ' != 0';
+    end loop;
+    cmd := cmd || ') AND NOT EXISTS(SELECT 1 FROM ' || fk.pktable::text || ' pk WHERE ';
+    for i in 1 .. nkeys loop
+      if i > 1 then cmd := cmd || ' AND '; end if;
+      cmd := cmd || 'pk.' || quote_ident(fk.pkcols[i]);
+      cmd := cmd || ' = fk.' || quote_ident(fk.fkcols[i]);
+    end loop;
+    cmd := cmd || ')';
+    -- raise notice 'cmd = %', cmd;
+    for err in execute cmd loop
+      raise notice 'FK VIOLATION: %', err;
+    end loop;
+  end loop;
+end
+$doblock$;
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index 2f28de0355..b1efca542f 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -818,6 +818,9 @@ EOF
 		copyFile(
 			'src/backend/catalog/schemapg.h',
 			'src/include/catalog/schemapg.h');
+		copyFile(
+			'src/backend/catalog/system_fk_info.h',
+			'src/include/catalog/system_fk_info.h');
 		open(my $chs, '>', 'src/include/catalog/header-stamp')
 		  || confess "Could not touch header-stamp";
 		close($chs);
diff --git a/src/tools/msvc/clean.bat b/src/tools/msvc/clean.bat
index 4575e3f95f..d0d79a0932 100755
--- a/src/tools/msvc/clean.bat
+++ b/src/tools/msvc/clean.bat
@@ -47,6 +47,7 @@ if exist src\include\utils\fmgrprotos.h del /q src\include\utils\fmgrprotos.h
 if exist src\include\storage\lwlocknames.h del /q src\include\storage\lwlocknames.h
 if exist src\include\utils\probes.h del /q src\include\utils\probes.h
 if exist src\include\catalog\schemapg.h del /q src\include\catalog\schemapg.h
+if exist src\include\catalog\system_fk_info.h del /q src\include\catalog\system_fk_info.h
 if exist src\include\catalog\pg_*_d.h del /q src\include\catalog\pg_*_d.h
 if exist src\include\catalog\header-stamp del /q src\include\catalog\header-stamp
 if exist doc\src\sgml\version.sgml del /q doc\src\sgml\version.sgml
@@ -73,6 +74,7 @@ if %DIST%==1 if exist src\interfaces\ecpg\preproc\preproc.y del /q src\interface
 if %DIST%==1 if exist src\backend\catalog\postgres.bki del /q src\backend\catalog\postgres.bki
 if %DIST%==1 if exist src\backend\catalog\system_constraints.sql del /q src\backend\catalog\system_constraints.sql
 if %DIST%==1 if exist src\backend\catalog\schemapg.h del /q src\backend\catalog\schemapg.h
+if %DIST%==1 if exist src\backend\catalog\system_fk_info.h del /q src\backend\catalog\system_fk_info.h
 if %DIST%==1 if exist src\backend\catalog\pg_*_d.h del /q src\backend\catalog\pg_*_d.h
 if %DIST%==1 if exist src\backend\catalog\bki-stamp del /q src\backend\catalog\bki-stamp
 if %DIST%==1 if exist src\backend\parser\scan.c del /q src\backend\parser\scan.c
#2Joel Jacobson
joel@compiler.org
In reply to: Tom Lane (#1)
Re: Recording foreign key relationships for the system catalogs

Very nice. Thanks to this patch, I can get rid of my own parse-catalogs.pl hack and use pg_get_catalog_foreign_keys() instead.

+1

I can with high confidence assert the correctness of pg_get_catalog_foreign_keys()'s output,
as it matches the lookup tables for the tool I'm hacking on precisely:

--
-- verify single column foreign keys
--
WITH
a AS (
SELECT
fktable::text,
fkcols[1]::text,
pktable::text,
pkcols[1]::text
FROM pg_get_catalog_foreign_keys()
WHERE cardinality(fkcols) = 1
),
b AS (
SELECT
table_name,
column_name,
ref_table_name,
ref_column_name
FROM pit.oid_joins
)
SELECT
(SELECT COUNT(*) FROM (SELECT * FROM a EXCEPT SELECT * FROM b) AS x) AS except_b,
(SELECT COUNT(*) FROM (SELECT * FROM b EXCEPT SELECT * FROM a) AS x) AS except_a,
(SELECT COUNT(*) FROM (SELECT * FROM b INTERSECT SELECT * FROM a) AS x) AS a_intersect_b
;

except_b | except_a | a_intersect_b
----------+----------+---------------
0 | 0 | 209
(1 row)

--
-- verify multi-column foreign keys
--
WITH
a AS (
SELECT
fktable::text,
fkcols,
pktable::text,
pkcols
FROM pg_get_catalog_foreign_keys()
WHERE cardinality(fkcols) > 1
),
b AS (
SELECT
table_name,
ARRAY[rel_column_name,attnum_column_name],
'pg_attribute',
'{attrelid,attnum}'::text[]
FROM pit.attnum_joins
)
SELECT
(SELECT COUNT(*) FROM (SELECT * FROM a EXCEPT SELECT * FROM b) AS x) AS except_b,
(SELECT COUNT(*) FROM (SELECT * FROM b EXCEPT SELECT * FROM a) AS x) AS except_a,
(SELECT COUNT(*) FROM (SELECT * FROM b INTERSECT SELECT * FROM a) AS x) AS a_intersect_b
;

except_b | except_a | a_intersect_b
----------+----------+---------------
0 | 0 | 8
(1 row)

/Joel

On Sun, Jan 31, 2021, at 22:39, Tom Lane wrote:

Now that dfb75e478 is in, I looked into whether we can have some
machine-readable representation of the catalogs' foreign key
relationships. As per the previous discussion [1], it's not
practical to have "real" SQL foreign key constraints, because
the semantics we use aren't quite right (i.e., using 0 instead
of NULL in rows with no reference). Nonetheless it would be
nice to have the knowledge available in some form, and we agreed
that a set-returning function returning the data would be useful.

The attached patch creates that function, and rewrites the oidjoins.sql
regression test to use it, in place of the very incomplete info that's
reverse-engineered by findoidjoins. It's mostly straightforward.

My original thought had been to add DECLARE_FOREIGN_KEY() macros
for all references, but I soon realized that in a large majority of
the cases, that's redundant with the BKI_LOOKUP() annotations we
already have. So I taught genbki.pl to extract FK data from
BKI_LOOKUP() as well as the explicit DECLARE macros. That didn't
remove the work entirely, because it turned out that we hadn't
bothered to apply BKI_LOOKUP() labels to most of the catalogs that
have no hand-made data. A big chunk of the patch consists in
adding those as needed. Also, I had to make the BKI_LOOKUP()
mechanism a little more complete, because it failed on pg_namespace
and pg_authid references. (It will still fail on some other
cases such as BKI_LOOKUP(pg_foreign_server), but I think there's
no need to fill that in until/unless we have some built-in data
that needs it.)

There are various loose ends yet to be cleaned up:

* I'm unsure whether it's better for the SRF to return the
column names as textual names, or as column numbers. Names was
a bit easier for all the parts of the current patch so I did
it that way, but maybe there's a case for the other way.
Actually the whole API for the SRF is just spur-of-the-moment,
so maybe a different API would be better.

* It would now be possible to remove the PGNSP and PGUID kluges
entirely in favor of plain BKI_LOOKUP references to pg_namespace
and pg_authid. The catalog header usage would get a little
more verbose: BKI_DEFAULT(PGNSP) becomes BKI_DEFAULT(pg_catalog)
and BKI_DEFAULT(PGUID) becomes BKI_DEFAULT(POSTGRES). I'm a bit
inclined to do it, simply to remove one bit of mechanism that has
to be documented; but it's material for a separate patch perhaps.

* src/tools/findoidjoins should be nuked entirely, AFAICS.
Again, that could be a follow-on patch.

* I've not touched the SGML docs. Certainly
pg_get_catalog_foreign_keys() should be documented, and some
adjustments in bki.sgml might be appropriate.

regards, tom lane

[1] /messages/by-id/dc5f44d9-5ec1-a596-0251-dadadcdede98@2ndquadrant.com

*Attachments:*
* add-catalog-foreign-key-info-1.patch

Kind regards,

Joel

#3Joel Jacobson
joel@compiler.org
In reply to: Tom Lane (#1)
Re: Recording foreign key relationships for the system catalogs

Could it be an idea to also add

OUT can_be_zero boolean

to pg_get_catalog_foreign_keys()'s out parameters?

This information is useful to know if one should be doing an INNER JOIN or a LEFT JOIN on the foreign keys.

The information is mostly available in the documentation already,
but not quite accurate, which I've proposed a patch [1]/messages/by-id/4ed9a372-7bf9-479a-926c-ae8e774717a8@www.fastmail.com to fix.

[1]: /messages/by-id/4ed9a372-7bf9-479a-926c-ae8e774717a8@www.fastmail.com

#4Joel Jacobson
joel@compiler.org
In reply to: Tom Lane (#1)
Re: Recording foreign key relationships for the system catalogs

Hi again,

After trying to use pg_get_catalog_foreign_keys() to replace what I had before,
I notice one ambiguity which I think is a serious problem in the machine-readable context.

The is_array OUT parameter doesn't say which of the possibly many fkcols that is the array column.

One example:

fktable | fkcols | pktable | pkcols | is_array
----------------------+-----------------------+--------------+-------------------+----------
pg_constraint | {conrelid,conkey} | pg_attribute | {attrelid,attnum} | t

Is the array "conrelid" or is it "conkey"? As a human, I know it's "conkey", but for a machine to figure out, one would need to join information_schema.columns and check the data_type or something similar.

Suggestions on how to fix:

* Make is_array an boolean[], and let each element represent the is_array value for each fkcols element.

* Change interface to be more like information_schema, and add a "ordinal_position" column, and return each column on a separate row.

I think I prefer the latter since it's more information_schema-conformant, but any works.

/Joel

#5Joel Jacobson
joel@compiler.org
In reply to: Joel Jacobson (#4)
Re: Recording foreign key relationships for the system catalogs

On Mon, Feb 1, 2021, at 20:33, Joel Jacobson wrote:

Suggestions on how to fix:

* Make is_array an boolean[], and let each element represent the is_array value for each fkcols element.

* Change interface to be more like information_schema, and add a "ordinal_position" column, and return each column on a separate row.

I think I prefer the latter since it's more information_schema-conformant, but any works.

Ops. I see a problem with just adding a "ordinal_position", since then one would also need enumerate the "foreing key" constraints or give them names like "constraint_name" in information_schema.table_constraints (since there can be multiple foreign keys per fktable, so there would be multiple e.g. ordinal_position=1 per fktable).

With this into consideration, I think the easiest and cleanest solution is to make is_array a boolean[].

I like the usage of arrays, it makes it much easier to understand the output,
as it's the visually easy to see what groups of columns that references what group of columns.

/Joel

#6Tom Lane
tgl@sss.pgh.pa.us
In reply to: Joel Jacobson (#4)
Re: Recording foreign key relationships for the system catalogs

"Joel Jacobson" <joel@compiler.org> writes:

The is_array OUT parameter doesn't say which of the possibly many fkcols that is the array column.

Yeah, I didn't write the sgml docs yet, but the comments explain that
the array is always the last fkcol. Maybe someday that won't be
general enough, but we can cross that bridge when we come to it.

regards, tom lane

#7Tom Lane
tgl@sss.pgh.pa.us
In reply to: Joel Jacobson (#3)
1 attachment(s)
Re: Recording foreign key relationships for the system catalogs

"Joel Jacobson" <joel@compiler.org> writes:

Could it be an idea to also add
OUT can_be_zero boolean
to pg_get_catalog_foreign_keys()'s out parameters?

I was initially feeling resistant to that idea, but warmed to it
once I realized that a majority of the FK referencing columns
actually should not contain zeroes. So we can get a useful
improvement in the strictness of the test coverage if we make this
distinction --- and we can enforce it in the initial catalog data,
too.

So here's a v2 that does that. In the interests of brevity,
I spelled the declaration macros that allow a zero as BKI_LOOKUP_OPT,
DECLARE_FOREIGN_KEY_OPT, etc; and thus the output column is
also is_opt. I'm not wedded to that term but I think we need
something pretty short.

This also moves the oidjoins regression test to run near the
end of the test suite. As I commented earlier, that test was
originally mainly meant to validate the handwritten initial
data; but nowadays it's hard to see what it would catch that
genbki.pl doesn't. So the usefulness is in looking at rows
that get added later, and therefore we ought to run it after
the regression tests have created stuff. I've tried here
to run it in parallel with event_triggers, which might be
foolish.

I also added some documentation. I feel like this might
be committable at this point.

regards, tom lane

Attachments:

add-catalog-foreign-key-info-2.patchtext/x-diff; charset=us-ascii; name=add-catalog-foreign-key-info-2.patchDownload
diff --git a/doc/src/sgml/bki.sgml b/doc/src/sgml/bki.sgml
index 036a72c81e..6d3c5be67f 100644
--- a/doc/src/sgml/bki.sgml
+++ b/doc/src/sgml/bki.sgml
@@ -474,10 +474,15 @@
 
     <listitem>
      <para>
-      In such a column, all entries must use the symbolic format except
-      when writing <literal>0</literal> for InvalidOid.  (If the column is
+      In some catalog columns, it's allowed for entries to be zero instead
+      of a valid reference.  If this is allowed, write
+      <literal>BKI_LOOKUP_OPT</literal> instead
+      of <literal>BKI_LOOKUP</literal>.  Then you can
+      write <literal>0</literal> for an entry.  (If the column is
       declared <type>regproc</type>, you can optionally
       write <literal>-</literal> instead of <literal>0</literal>.)
+      Except for this special case, all entries in
+      a <literal>BKI_LOOKUP</literal> column must be symbolic references.
       <filename>genbki.pl</filename> will warn about unrecognized names.
      </para>
     </listitem>
@@ -554,6 +559,22 @@
     therefore no need for the bootstrap backend to deal with symbolic
     references.
    </para>
+
+   <para>
+    It's desirable to mark OID reference columns
+    with <literal>BKI_LOOKUP</literal> or <literal>BKI_LOOKUP_OPT</literal>
+    even if the catalog has no initial data that requires lookup.  This
+    allows <filename>genbki.pl</filename> to record the foreign key
+    relationships that exist in the system catalogs.  That information is
+    used in the regression tests to check for incorrect entries.  See also
+    the macros <literal>DECLARE_FOREIGN_KEY</literal>,
+    <literal>DECLARE_FOREIGN_KEY_OPT</literal>,
+    <literal>DECLARE_ARRAY_FOREIGN_KEY</literal>,
+    and <literal>DECLARE_ARRAY_FOREIGN_KEY_OPT</literal>, which are
+    used to declare foreign key relationships that are too complex
+    for <literal>BKI_LOOKUP</literal> (typically, multi-column foreign
+    keys).
+   </para>
   </sect2>
 
   <sect2 id="system-catalog-auto-array-types">
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 865e826fb0..5da82a4846 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -5588,7 +5588,8 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
        (references <link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.<structfield>oid</structfield>)
       </para>
       <para>
-       The roles to which the policy is applied
+       The roles to which the policy is applied;
+       zero means <literal>PUBLIC</literal>
       </para></entry>
      </row>
 
@@ -7836,7 +7837,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
       <para>
        The OID of the function to use when converting the data type for input
        to the procedural language (e.g., function parameters).  Zero is stored
-       if this operation is not supported.
+       if the default behavior should be used.
       </para></entry>
      </row>
 
@@ -7848,7 +7849,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
       <para>
        The OID of the function to use when converting output from the
        procedural language (e.g., return values) to the data type.  Zero is
-       stored if this operation is not supported.
+       stored if the default behavior should be used.
       </para></entry>
      </row>
     </tbody>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 081f04ce1a..b7150510ab 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -22789,6 +22789,38 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
        </para></entry>
       </row>
 
+      <row>
+       <entry role="func_table_entry"><para role="func_signature">
+        <indexterm>
+         <primary>pg_get_catalog_foreign_keys</primary>
+        </indexterm>
+        <function>pg_get_catalog_foreign_keys</function> ()
+        <returnvalue>setof record</returnvalue>
+        ( <parameter>fktable</parameter> <type>regclass</type>,
+          <parameter>fkcols</parameter> <type>text[]</type>,
+          <parameter>pktable</parameter> <type>regclass</type>,
+          <parameter>pkcols</parameter> <type>text[]</type>,
+          <parameter>is_array</parameter> <type>boolean</type>,
+          <parameter>is_opt</parameter> <type>boolean</type> )
+       </para>
+       <para>
+        Returns a set of records describing the foreign key relationships
+        that exist within the <productname>PostgreSQL</productname> system
+        catalogs.
+        The <parameter>fktable</parameter> column contains the name of the
+        referencing catalog, and the <parameter>fkcols</parameter> column
+        contains the name(s) of the referencing column(s).  Similarly,
+        the <parameter>pktable</parameter> column contains the name of the
+        referenced catalog, and the <parameter>pkcols</parameter> column
+        contains the name(s) of the referenced column(s).
+        If <parameter>is_array</parameter> is true, the last referencing
+        column is an array, each of whose elements should match some entry
+        in the referenced catalog.
+        If <parameter>is_opt</parameter> is true, the referencing column(s)
+        are allowed to contain zeroes instead of a valid reference.
+       </para></entry>
+      </row>
+
       <row>
        <entry role="func_table_entry"><para role="func_signature">
         <indexterm>
diff --git a/src/backend/catalog/.gitignore b/src/backend/catalog/.gitignore
index 4bd3ee9d7f..237ff54165 100644
--- a/src/backend/catalog/.gitignore
+++ b/src/backend/catalog/.gitignore
@@ -1,5 +1,6 @@
 /postgres.bki
 /schemapg.h
+/system_fk_info.h
 /system_constraints.sql
 /pg_*_d.h
 /bki-stamp
diff --git a/src/backend/catalog/Catalog.pm b/src/backend/catalog/Catalog.pm
index 061f3d8c21..b44d568b54 100644
--- a/src/backend/catalog/Catalog.pm
+++ b/src/backend/catalog/Catalog.pm
@@ -105,6 +105,17 @@ sub ParseHeader
 				index_decl => $5
 			  };
 		}
+		elsif (/^DECLARE_(ARRAY_)?FOREIGN_KEY(_OPT)?\(\s*\(([^)]+)\),\s*(\w+),\s*\(([^)]+)\)\)/)
+		{
+			push @{ $catalog{foreign_keys} },
+			  {
+				is_array => $1 ? 1 : 0,
+				is_opt   => $2 ? 1 : 0,
+				fk_cols  => $3,
+				pk_table => $4,
+				pk_cols  => $5
+			  };
+		}
 		elsif (/^CATALOG\((\w+),(\d+),(\w+)\)/)
 		{
 			$catalog{catname}            = $1;
@@ -197,9 +208,22 @@ sub ParseHeader
 					{
 						$column{array_default} = $1;
 					}
-					elsif ($attopt =~ /BKI_LOOKUP\((\w+)\)/)
+					elsif ($attopt =~ /BKI_LOOKUP(_OPT)?\((\w+)\)/)
 					{
-						$column{lookup} = $1;
+						$column{lookup} = $2;
+						$column{lookup_opt} = $1 ? 1 : 0;
+						# BKI_LOOKUP implicitly makes an FK reference
+						push @{ $catalog{foreign_keys} },
+						  {
+							is_array =>
+							  ($atttype eq 'oidvector' || $atttype eq '_oid')
+							? 1
+							: 0,
+							is_opt   => $column{lookup_opt},
+							fk_cols  => $attname,
+							pk_table => $column{lookup},
+							pk_cols  => 'oid'
+						  };
 					}
 					else
 					{
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index 995ddf1285..70bc2123df 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -70,7 +70,7 @@ CATALOG_HEADERS := \
 	pg_sequence.h pg_publication.h pg_publication_rel.h pg_subscription.h \
 	pg_subscription_rel.h
 
-GENERATED_HEADERS := $(CATALOG_HEADERS:%.h=%_d.h) schemapg.h
+GENERATED_HEADERS := $(CATALOG_HEADERS:%.h=%_d.h) schemapg.h system_fk_info.h
 
 POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/, $(CATALOG_HEADERS))
 
diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl
index b68c1752c0..5bdc7adc44 100644
--- a/src/backend/catalog/genbki.pl
+++ b/src/backend/catalog/genbki.pl
@@ -213,6 +213,12 @@ foreach my $row (@{ $catalog_data{pg_am} })
 	$amoids{ $row->{amname} } = $row->{oid};
 }
 
+# There is only one authid at bootstrap time, and we handle it specially:
+# the usually-defaulted symbol PGUID becomes the bootstrap superuser's OID.
+# (We could drop this in favor of writing out BKI_DEFAULT(POSTGRES) ...)
+my %authidoids;
+$authidoids{'PGUID'} = $BOOTSTRAP_SUPERUSERID;
+
 # class (relation) OID lookup (note this only covers bootstrap catalogs!)
 my %classoids;
 foreach my $row (@{ $catalog_data{pg_class} })
@@ -234,6 +240,12 @@ foreach my $row (@{ $catalog_data{pg_language} })
 	$langoids{ $row->{lanname} } = $row->{oid};
 }
 
+# There is only one namespace at bootstrap time, and we handle it specially:
+# the usually-defaulted symbol PGNSP becomes the pg_catalog namespace's OID.
+# (We could drop this in favor of writing out BKI_DEFAULT(pg_catalog) ...)
+my %namespaceoids;
+$namespaceoids{'PGNSP'} = $PG_CATALOG_NAMESPACE;
+
 # opclass OID lookup
 my %opcoids;
 foreach my $row (@{ $catalog_data{pg_opclass} })
@@ -376,9 +388,11 @@ close $ef;
 # Map lookup name to the corresponding hash table.
 my %lookup_kind = (
 	pg_am          => \%amoids,
+	pg_authid      => \%authidoids,
 	pg_class       => \%classoids,
 	pg_collation   => \%collationoids,
 	pg_language    => \%langoids,
+	pg_namespace   => \%namespaceoids,
 	pg_opclass     => \%opcoids,
 	pg_operator    => \%operoids,
 	pg_opfamily    => \%opfoids,
@@ -400,6 +414,9 @@ open my $bki, '>', $bkifile . $tmpext
 my $schemafile = $output_path . 'schemapg.h';
 open my $schemapg, '>', $schemafile . $tmpext
   or die "can't open $schemafile$tmpext: $!";
+my $fk_info_file = $output_path . 'system_fk_info.h';
+open my $fk_info, '>', $fk_info_file . $tmpext
+  or die "can't open $fk_info_file$tmpext: $!";
 my $constraints_file = $output_path . 'system_constraints.sql';
 open my $constraints, '>', $constraints_file . $tmpext
   or die "can't open $constraints_file$tmpext: $!";
@@ -554,18 +571,14 @@ EOM
 				$GenbkiNextOid++;
 			}
 
-			# 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 OID synonyms with OIDs per the appropriate lookup rule.
 			#
 			# If the column type is oidvector or _oid, we have to replace
 			# each element of the array as per the lookup rule.
 			if ($column->{lookup})
 			{
-				my $lookup = $lookup_kind{ $column->{lookup} };
+				my $lookup     = $lookup_kind{ $column->{lookup} };
+				my $lookup_opt = $column->{lookup_opt};
 				my @lookupnames;
 				my @lookupoids;
 
@@ -575,8 +588,9 @@ EOM
 				if ($atttype eq 'oidvector')
 				{
 					@lookupnames = split /\s+/, $bki_values{$attname};
-					@lookupoids = lookup_oids($lookup, $catname, \%bki_values,
-						@lookupnames);
+					@lookupoids =
+					  lookup_oids($lookup, $catname, $attname, $lookup_opt,
+						\%bki_values, @lookupnames);
 					$bki_values{$attname} = join(' ', @lookupoids);
 				}
 				elsif ($atttype eq '_oid')
@@ -586,8 +600,8 @@ EOM
 						$bki_values{$attname} =~ s/[{}]//g;
 						@lookupnames = split /,/, $bki_values{$attname};
 						@lookupoids =
-						  lookup_oids($lookup, $catname, \%bki_values,
-							@lookupnames);
+						  lookup_oids($lookup, $catname, $attname,
+							$lookup_opt, \%bki_values, @lookupnames);
 						$bki_values{$attname} = sprintf "{%s}",
 						  join(',', @lookupoids);
 					}
@@ -595,8 +609,9 @@ EOM
 				else
 				{
 					$lookupnames[0] = $bki_values{$attname};
-					@lookupoids = lookup_oids($lookup, $catname, \%bki_values,
-						@lookupnames);
+					@lookupoids =
+					  lookup_oids($lookup, $catname, $attname, $lookup_opt,
+						\%bki_values, @lookupnames);
 					$bki_values{$attname} = $lookupoids[0];
 				}
 			}
@@ -706,14 +721,78 @@ foreach my $table_name (@tables_needing_macros)
 # Closing boilerplate for schemapg.h
 print $schemapg "\n#endif\t\t\t\t\t\t\t/* SCHEMAPG_H */\n";
 
+# Now generate system_fk_info.h
+
+# Opening boilerplate for system_fk_info.h
+print $fk_info <<EOM;
+/*-------------------------------------------------------------------------
+ *
+ * system_fk_info.h
+ *    Data about the foreign-key relationships in the system catalogs
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * NOTES
+ *  ******************************
+ *  *** DO NOT EDIT THIS FILE! ***
+ *  ******************************
+ *
+ *  It has been GENERATED by src/backend/catalog/genbki.pl
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef SYSTEM_FK_INFO_H
+#define SYSTEM_FK_INFO_H
+
+typedef struct SysFKRelationship
+{
+	Oid			fk_table;		/* referencing catalog */
+	Oid			pk_table;		/* referenced catalog */
+	const char *fk_columns;		/* referencing column name(s) */
+	const char *pk_columns;		/* referenced column name(s) */
+	bool		is_array;		/* if true, last fk_column is an array */
+	bool		is_opt;			/* if true, fk_column can be zero */
+} SysFKRelationship;
+
+static const SysFKRelationship sys_fk_relationships[] = {
+EOM
+
+# Emit system_fk_info data
+foreach my $catname (@catnames)
+{
+	my $catalog = $catalogs{$catname};
+	foreach my $fkinfo (@{ $catalog->{foreign_keys} })
+	{
+		my $pktabname = $fkinfo->{pk_table};
+
+		# We use BKI_LOOKUP for encodings, but there's no real catalog there
+		next if $pktabname eq 'encoding';
+
+		printf $fk_info
+		  "\t{ /* %s */ %s, /* %s */ %s, \"{%s}\", \"{%s}\", %s, %s},\n",
+		  $catname,   $catalog->{relation_oid},
+		  $pktabname, $catalogs{$pktabname}->{relation_oid},
+		  $fkinfo->{fk_cols},
+		  $fkinfo->{pk_cols},
+		  ($fkinfo->{is_array} ? "true" : "false"),
+		  ($fkinfo->{is_opt}   ? "true" : "false");
+	}
+}
+
+# Closing boilerplate for system_fk_info.h
+print $fk_info "};\n\n#endif\t\t\t\t\t\t\t/* SYSTEM_FK_INFO_H */\n";
+
 # We're done emitting data
 close $bki;
 close $schemapg;
+close $fk_info;
 close $constraints;
 
 # Finally, rename the completed files into place.
 Catalog::RenameTempFile($bkifile,    $tmpext);
 Catalog::RenameTempFile($schemafile, $tmpext);
+Catalog::RenameTempFile($fk_info_file, $tmpext);
 Catalog::RenameTempFile($constraints_file, $tmpext);
 
 exit 0;
@@ -948,7 +1027,8 @@ sub morph_row_for_schemapg
 # within this genbki.pl run.)
 sub lookup_oids
 {
-	my ($lookup, $catname, $bki_values, @lookupnames) = @_;
+	my ($lookup, $catname, $attname, $lookup_opt, $bki_values, @lookupnames)
+	  = @_;
 
 	my @lookupoids;
 	foreach my $lookupname (@lookupnames)
@@ -961,10 +1041,19 @@ sub lookup_oids
 		else
 		{
 			push @lookupoids, $lookupname;
-			warn sprintf
-			  "unresolved OID reference \"%s\" in %s.dat line %s\n",
-			  $lookupname, $catname, $bki_values->{line_number}
-			  if $lookupname ne '-' and $lookupname ne '0';
+			if ($lookupname eq '-' or $lookupname eq '0')
+			{
+				warn sprintf
+				  "invalid zero OID reference in %s.dat field %s line %s\n",
+				  $catname, $attname, $bki_values->{line_number}
+				  if !$lookup_opt;
+			}
+			else
+			{
+				warn sprintf
+				  "unresolved OID reference \"%s\" in %s.dat field %s line %s\n",
+				  $lookupname, $catname, $attname, $bki_values->{line_number};
+			}
 		}
 	}
 	return @lookupoids;
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 4096faff9a..634f574d7e 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -25,6 +25,7 @@
 #include "catalog/catalog.h"
 #include "catalog/pg_tablespace.h"
 #include "catalog/pg_type.h"
+#include "catalog/system_fk_info.h"
 #include "commands/dbcommands.h"
 #include "commands/tablespace.h"
 #include "common/keywords.h"
@@ -37,6 +38,7 @@
 #include "storage/fd.h"
 #include "tcop/tcopprot.h"
 #include "utils/builtins.h"
+#include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/ruleutils.h"
 #include "utils/timestamp.h"
@@ -489,6 +491,84 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 }
 
 
+/* Function to return the list of catalog foreign key relationships */
+Datum
+pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
+{
+	FuncCallContext *funcctx;
+	FmgrInfo   *arrayinp;
+
+	if (SRF_IS_FIRSTCALL())
+	{
+		MemoryContext oldcontext;
+		TupleDesc	tupdesc;
+
+		funcctx = SRF_FIRSTCALL_INIT();
+		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+		tupdesc = CreateTemplateTupleDesc(6);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "fktable",
+						   REGCLASSOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "fkcols",
+						   TEXTARRAYOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "pktable",
+						   REGCLASSOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pkcols",
+						   TEXTARRAYOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 5, "is_array",
+						   BOOLOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 6, "is_opt",
+						   BOOLOID, -1, 0);
+
+		funcctx->tuple_desc = BlessTupleDesc(tupdesc);
+
+		/*
+		 * We use array_in to convert the C strings in sys_fk_relationships[]
+		 * to text arrays.  But we cannot use DirectFunctionCallN to call
+		 * array_in, and it wouldn't be very efficient if we could.  Fill an
+		 * FmgrInfo to use for the call.
+		 */
+		arrayinp = (FmgrInfo *) palloc(sizeof(FmgrInfo));
+		fmgr_info(F_ARRAY_IN, arrayinp);
+		funcctx->user_fctx = arrayinp;
+
+		MemoryContextSwitchTo(oldcontext);
+	}
+
+	funcctx = SRF_PERCALL_SETUP();
+	arrayinp = (FmgrInfo *) funcctx->user_fctx;
+
+	if (funcctx->call_cntr < lengthof(sys_fk_relationships))
+	{
+		const SysFKRelationship *fkrel = &sys_fk_relationships[funcctx->call_cntr];
+		Datum		values[6];
+		bool		nulls[6];
+		HeapTuple	tuple;
+
+		memset(nulls, false, sizeof(nulls));
+
+		values[0] = ObjectIdGetDatum(fkrel->fk_table);
+		values[1] = FunctionCall3(arrayinp,
+								  CStringGetDatum(fkrel->fk_columns),
+								  ObjectIdGetDatum(TEXTOID),
+								  Int32GetDatum(-1));
+		values[2] = ObjectIdGetDatum(fkrel->pk_table);
+		values[3] = FunctionCall3(arrayinp,
+								  CStringGetDatum(fkrel->pk_columns),
+								  ObjectIdGetDatum(TEXTOID),
+								  Int32GetDatum(-1));
+		values[4] = BoolGetDatum(fkrel->is_array);
+		values[5] = BoolGetDatum(fkrel->is_opt);
+
+		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
+
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+	}
+
+	SRF_RETURN_DONE(funcctx);
+}
+
+
 /*
  * Return the type of the argument.
  */
diff --git a/src/include/Makefile b/src/include/Makefile
index c557375ae3..5f257a958c 100644
--- a/src/include/Makefile
+++ b/src/include/Makefile
@@ -54,7 +54,7 @@ install: all installdirs
 	  cp $(srcdir)/$$dir/*.h '$(DESTDIR)$(includedir_server)'/$$dir/ || exit; \
 	done
 ifeq ($(vpath_build),yes)
-	for file in catalog/schemapg.h catalog/pg_*_d.h parser/gram.h storage/lwlocknames.h utils/probes.h; do \
+	for file in catalog/schemapg.h catalog/system_fk_info.h catalog/pg_*_d.h parser/gram.h storage/lwlocknames.h utils/probes.h; do \
 	  cp $$file '$(DESTDIR)$(includedir_server)'/$$file || exit; \
 	done
 endif
@@ -79,7 +79,8 @@ uninstall:
 clean:
 	rm -f utils/fmgroids.h utils/fmgrprotos.h utils/errcodes.h utils/header-stamp
 	rm -f parser/gram.h storage/lwlocknames.h utils/probes.h
-	rm -f catalog/schemapg.h catalog/pg_*_d.h catalog/header-stamp
+	rm -f catalog/schemapg.h catalog/system_fk_info.h
+	rm -f catalog/pg_*_d.h catalog/header-stamp
 
 distclean maintainer-clean: clean
 	rm -f pg_config.h pg_config_ext.h pg_config_os.h stamp-h stamp-ext-h
diff --git a/src/include/catalog/.gitignore b/src/include/catalog/.gitignore
index 6c8da5401d..6b83d4c7e6 100644
--- a/src/include/catalog/.gitignore
+++ b/src/include/catalog/.gitignore
@@ -1,3 +1,4 @@
 /schemapg.h
+/system_fk_info.h
 /pg_*_d.h
 /header-stamp
diff --git a/src/include/catalog/genbki.h b/src/include/catalog/genbki.h
index 5d05fafb5d..b1fee54d3c 100644
--- a/src/include/catalog/genbki.h
+++ b/src/include/catalog/genbki.h
@@ -36,10 +36,15 @@
 /* Specifies a default value for auto-generated array types */
 #define BKI_ARRAY_DEFAULT(value)
 /*
- * Indicates how to perform name lookups, typically for an OID or
- * OID-array field
+ * Indicates that the attribute contains OIDs referencing the named catalog;
+ * can be applied to columns of oid, regproc, oid[], or oidvector type.
+ * genbki.pl uses this to know how to perform name lookups in the initial
+ * data (if any), and it also feeds into regression-test validity checks.
+ * The _OPT suffix indicates that values can be zero instead of
+ * a valid OID reference.
  */
 #define BKI_LOOKUP(catalog)
+#define BKI_LOOKUP_OPT(catalog)
 
 /*
  * These lines are processed by genbki.pl to create the statements
@@ -75,6 +80,33 @@
 #define DECLARE_UNIQUE_INDEX(name,oid,decl) extern int no_such_variable
 #define DECLARE_UNIQUE_INDEX_PKEY(name,oid,decl) extern int no_such_variable
 
+/*
+ * These lines are processed by genbki.pl to create a table for use
+ * by the pg_get_catalog_foreign_keys() function.  We do not have any
+ * mechanism that actually enforces foreign-key relationships in the
+ * system catalogs, but it is still useful to record the intended
+ * relationships in a machine-readable form.
+ *
+ * The keyword is DECLARE_FOREIGN_KEY[_OPT] or DECLARE_ARRAY_FOREIGN_KEY[_OPT].
+ * The first argument is a parenthesized list of the referencing columns;
+ * the second, the name of the referenced table; the third, a parenthesized
+ * list of the referenced columns.  Use of the ARRAY macros means that the
+ * last referencing column is an array, each of whose elements is supposed
+ * to match some entry in the last referenced column.  Use of the OPT suffix
+ * indicates that the referencing column(s) can be zero instead of a valid
+ * reference.
+ *
+ * Columns that are marked with a BKI_LOOKUP rule do not need an explicit
+ * DECLARE_FOREIGN_KEY macro, as genbki.pl can infer the FK relationship
+ * from that.  Thus, these macros are only needed in special cases.
+ *
+ * The macro definitions are just to keep the C compiler from spitting up.
+ */
+#define DECLARE_FOREIGN_KEY(cols,reftbl,refcols) extern int no_such_variable
+#define DECLARE_FOREIGN_KEY_OPT(cols,reftbl,refcols) extern int no_such_variable
+#define DECLARE_ARRAY_FOREIGN_KEY(cols,reftbl,refcols) extern int no_such_variable
+#define DECLARE_ARRAY_FOREIGN_KEY_OPT(cols,reftbl,refcols) extern int no_such_variable
+
 /* The following are never defined; they are here only for documentation. */
 
 /*
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 8b03cdeea2..25feb41678 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -44,25 +44,25 @@ CATALOG(pg_aggregate,2600,AggregateRelationId)
 	regproc		aggtransfn BKI_LOOKUP(pg_proc);
 
 	/* final function (0 if none) */
-	regproc		aggfinalfn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);
+	regproc		aggfinalfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
 
 	/* combine function (0 if none) */
-	regproc		aggcombinefn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);
+	regproc		aggcombinefn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
 
 	/* function to convert transtype to bytea (0 if none) */
-	regproc		aggserialfn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);
+	regproc		aggserialfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
 
 	/* function to convert bytea to transtype (0 if none) */
-	regproc		aggdeserialfn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);
+	regproc		aggdeserialfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
 
 	/* forward function for moving-aggregate mode (0 if none) */
-	regproc		aggmtransfn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);
+	regproc		aggmtransfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
 
 	/* inverse function for moving-aggregate mode (0 if none) */
-	regproc		aggminvtransfn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);
+	regproc		aggminvtransfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
 
 	/* final function for moving-aggregate mode (0 if none) */
-	regproc		aggmfinalfn BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);
+	regproc		aggmfinalfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
 
 	/* true to pass extra dummy arguments to aggfinalfn */
 	bool		aggfinalextra BKI_DEFAULT(f);
@@ -77,7 +77,7 @@ CATALOG(pg_aggregate,2600,AggregateRelationId)
 	char		aggmfinalmodify BKI_DEFAULT(r);
 
 	/* associated sort operator (0 if none) */
-	Oid			aggsortop BKI_DEFAULT(0) BKI_LOOKUP(pg_operator);
+	Oid			aggsortop BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_operator);
 
 	/* type of aggregate's transition (state) data */
 	Oid			aggtranstype BKI_LOOKUP(pg_type);
@@ -86,7 +86,7 @@ CATALOG(pg_aggregate,2600,AggregateRelationId)
 	int32		aggtransspace BKI_DEFAULT(0);
 
 	/* type of moving-aggregate state data (0 if none) */
-	Oid			aggmtranstype BKI_DEFAULT(0) BKI_LOOKUP(pg_type);
+	Oid			aggmtranstype BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type);
 
 	/* estimated size of moving-agg state (0 for default est) */
 	int32		aggmtransspace BKI_DEFAULT(0);
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index 554fc41497..e1cca35e31 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -77,7 +77,7 @@ CATALOG(pg_amop,2602,AccessMethodOperatorRelationId)
 	Oid			amopmethod BKI_LOOKUP(pg_am);
 
 	/* ordering opfamily OID, or 0 if search op */
-	Oid			amopsortfamily BKI_DEFAULT(0) BKI_LOOKUP(pg_opfamily);
+	Oid			amopsortfamily BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_opfamily);
 } FormData_pg_amop;
 
 /* ----------------
diff --git a/src/include/catalog/pg_attrdef.h b/src/include/catalog/pg_attrdef.h
index 03efaaded9..d689ca20c8 100644
--- a/src/include/catalog/pg_attrdef.h
+++ b/src/include/catalog/pg_attrdef.h
@@ -30,7 +30,8 @@ CATALOG(pg_attrdef,2604,AttrDefaultRelationId)
 {
 	Oid			oid;			/* oid */
 
-	Oid			adrelid;		/* OID of table containing attribute */
+	Oid			adrelid BKI_LOOKUP(pg_class);	/* OID of table containing
+												 * attribute */
 	int16		adnum;			/* attnum of attribute */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
@@ -53,4 +54,6 @@ DECLARE_UNIQUE_INDEX(pg_attrdef_adrelid_adnum_index, 2656, on pg_attrdef using b
 DECLARE_UNIQUE_INDEX_PKEY(pg_attrdef_oid_index, 2657, on pg_attrdef using btree(oid oid_ops));
 #define AttrDefaultOidIndexId  2657
 
+DECLARE_FOREIGN_KEY((adrelid, adnum), pg_attribute, (attrelid, attnum));
+
 #endif							/* PG_ATTRDEF_H */
diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h
index ba0efff08c..3db42abf08 100644
--- a/src/include/catalog/pg_attribute.h
+++ b/src/include/catalog/pg_attribute.h
@@ -36,7 +36,8 @@
  */
 CATALOG(pg_attribute,1249,AttributeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(75,AttributeRelation_Rowtype_Id) BKI_SCHEMA_MACRO
 {
-	Oid			attrelid;		/* OID of relation containing this attribute */
+	Oid			attrelid BKI_LOOKUP(pg_class);	/* OID of relation containing
+												 * this attribute */
 	NameData	attname;		/* name of attribute */
 
 	/*
@@ -44,9 +45,12 @@ CATALOG(pg_attribute,1249,AttributeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(75,
 	 * defines the data type of this attribute (e.g. int4).  Information in
 	 * that instance is redundant with the attlen, attbyval, and attalign
 	 * attributes of this instance, so they had better match or Postgres will
-	 * fail.
+	 * fail.  In an entry for a dropped column, this field is set to zero
+	 * since the pg_type entry may no longer exist; but we rely on attlen,
+	 * attbyval, and attalign to still tell us how large the values in the
+	 * table are.
 	 */
-	Oid			atttypid;
+	Oid			atttypid BKI_LOOKUP_OPT(pg_type);
 
 	/*
 	 * attstattarget is the target number of statistics datapoints to collect
@@ -153,8 +157,8 @@ CATALOG(pg_attribute,1249,AttributeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(75,
 	/* Number of times inherited from direct parent relation(s) */
 	int32		attinhcount BKI_DEFAULT(0);
 
-	/* attribute's collation */
-	Oid			attcollation;
+	/* attribute's collation, if any */
+	Oid			attcollation BKI_LOOKUP_OPT(pg_collation);
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	/* NOTE: The following fields are not present in tuple descriptors. */
diff --git a/src/include/catalog/pg_auth_members.h b/src/include/catalog/pg_auth_members.h
index e90c395640..76ab90c939 100644
--- a/src/include/catalog/pg_auth_members.h
+++ b/src/include/catalog/pg_auth_members.h
@@ -29,9 +29,9 @@
  */
 CATALOG(pg_auth_members,1261,AuthMemRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID(2843,AuthMemRelation_Rowtype_Id) BKI_SCHEMA_MACRO
 {
-	Oid			roleid;			/* ID of a role */
-	Oid			member;			/* ID of a member of that role */
-	Oid			grantor;		/* who granted the membership */
+	Oid			roleid BKI_LOOKUP(pg_authid);	/* ID of a role */
+	Oid			member BKI_LOOKUP(pg_authid);	/* ID of a member of that role */
+	Oid			grantor BKI_LOOKUP(pg_authid);	/* who granted the membership */
 	bool		admin_option;	/* granted with admin option? */
 } FormData_pg_auth_members;
 
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index 2d36628c20..f64a9df54c 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -40,7 +40,7 @@ CATALOG(pg_cast,2605,CastRelationId)
 	Oid			casttarget BKI_LOOKUP(pg_type);
 
 	/* cast function; 0 = binary coercible */
-	Oid			castfunc BKI_LOOKUP(pg_proc);
+	Oid			castfunc BKI_LOOKUP_OPT(pg_proc);
 
 	/* contexts in which cast can be used */
 	char		castcontext;
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index eca306ca98..bb6938caa2 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -38,26 +38,26 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat
 	NameData	relname;
 
 	/* OID of namespace containing this class */
-	Oid			relnamespace BKI_DEFAULT(PGNSP);
+	Oid			relnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
-	/* OID of entry in pg_type for table's implicit row type */
-	Oid			reltype BKI_LOOKUP(pg_type);
+	/* OID of entry in pg_type for relation's implicit row type, if any */
+	Oid			reltype BKI_LOOKUP_OPT(pg_type);
 
-	/* OID of entry in pg_type for underlying composite type */
-	Oid			reloftype BKI_DEFAULT(0) BKI_LOOKUP(pg_type);
+	/* OID of entry in pg_type for underlying composite type, if any */
+	Oid			reloftype BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type);
 
 	/* class owner */
-	Oid			relowner BKI_DEFAULT(PGUID);
+	Oid			relowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/* access method; 0 if not a table / index */
-	Oid			relam BKI_DEFAULT(heap) BKI_LOOKUP(pg_am);
+	Oid			relam BKI_DEFAULT(heap) BKI_LOOKUP_OPT(pg_am);
 
 	/* identifier of physical storage file */
 	/* relfilenode == 0 means it is a "mapped" relation, see relmapper.c */
 	Oid			relfilenode BKI_DEFAULT(0);
 
 	/* identifier of table space for relation (0 means default for database) */
-	Oid			reltablespace BKI_DEFAULT(0) BKI_LOOKUP(pg_tablespace);
+	Oid			reltablespace BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_tablespace);
 
 	/* # of blocks (not always up-to-date) */
 	int32		relpages BKI_DEFAULT(0);
@@ -69,7 +69,7 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat
 	int32		relallvisible BKI_DEFAULT(0);
 
 	/* OID of toast table; 0 if none */
-	Oid			reltoastrelid BKI_DEFAULT(0);
+	Oid			reltoastrelid BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_class);
 
 	/* T if has (or has had) any indexes */
 	bool		relhasindex BKI_DEFAULT(f);
@@ -119,8 +119,8 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat
 	/* is relation a partition? */
 	bool		relispartition BKI_DEFAULT(f);
 
-	/* heap for rewrite during DDL, link to original rel */
-	Oid			relrewrite BKI_DEFAULT(0);
+	/* link to original rel during table rewrite; otherwise 0 */
+	Oid			relrewrite BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_class);
 
 	/* all Xids < this are frozen in this rel */
 	TransactionId relfrozenxid BKI_DEFAULT(3);	/* FirstNormalTransactionId */
diff --git a/src/include/catalog/pg_collation.dat b/src/include/catalog/pg_collation.dat
index ad57b0fa6d..6e0ab1ab4b 100644
--- a/src/include/catalog/pg_collation.dat
+++ b/src/include/catalog/pg_collation.dat
@@ -14,18 +14,15 @@
 
 { oid => '100', oid_symbol => 'DEFAULT_COLLATION_OID',
   descr => 'database\'s default collation',
-  collname => 'default', collnamespace => 'PGNSP', collowner => 'PGUID',
-  collprovider => 'd', collencoding => '-1', collcollate => '',
-  collctype => '' },
+  collname => 'default', collprovider => 'd', collencoding => '-1',
+  collcollate => '', collctype => '' },
 { oid => '950', oid_symbol => 'C_COLLATION_OID',
   descr => 'standard C collation',
-  collname => 'C', collnamespace => 'PGNSP', collowner => 'PGUID',
-  collprovider => 'c', collencoding => '-1', collcollate => 'C',
-  collctype => 'C' },
+  collname => 'C', collprovider => 'c', collencoding => '-1',
+  collcollate => 'C', collctype => 'C' },
 { oid => '951', oid_symbol => 'POSIX_COLLATION_OID',
   descr => 'standard POSIX collation',
-  collname => 'POSIX', collnamespace => 'PGNSP', collowner => 'PGUID',
-  collprovider => 'c', collencoding => '-1', collcollate => 'POSIX',
-  collctype => 'POSIX' },
+  collname => 'POSIX', collprovider => 'c', collencoding => '-1',
+  collcollate => 'POSIX', collctype => 'POSIX' },
 
 ]
diff --git a/src/include/catalog/pg_collation.h b/src/include/catalog/pg_collation.h
index 3c496ea914..3bd7873c68 100644
--- a/src/include/catalog/pg_collation.h
+++ b/src/include/catalog/pg_collation.h
@@ -30,8 +30,9 @@ CATALOG(pg_collation,3456,CollationRelationId)
 {
 	Oid			oid;			/* oid */
 	NameData	collname;		/* collation name */
-	Oid			collnamespace;	/* OID of namespace containing collation */
-	Oid			collowner;		/* owner of collation */
+	Oid			collnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);	/* OID of namespace
+																			 * containing collation */
+	Oid			collowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); /* owner of collation */
 	char		collprovider;	/* see constants below */
 	bool		collisdeterministic BKI_DEFAULT(t);
 	int32		collencoding;	/* encoding for this collation; -1 = "all" */
diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h
index 6449937b35..63f0f8bf41 100644
--- a/src/include/catalog/pg_constraint.h
+++ b/src/include/catalog/pg_constraint.h
@@ -46,7 +46,8 @@ CATALOG(pg_constraint,2606,ConstraintRelationId)
 	 * conrelid + contypid + conname.
 	 */
 	NameData	conname;		/* name of this constraint */
-	Oid			connamespace;	/* OID of namespace containing constraint */
+	Oid			connamespace BKI_LOOKUP(pg_namespace);	/* OID of namespace
+														 * containing constraint */
 	char		contype;		/* constraint type; see codes below */
 	bool		condeferrable;	/* deferrable constraint? */
 	bool		condeferred;	/* deferred by default? */
@@ -57,7 +58,8 @@ CATALOG(pg_constraint,2606,ConstraintRelationId)
 	 * specific relation (this excludes domain constraints and assertions).
 	 * Otherwise conrelid is 0 and conkey is NULL.
 	 */
-	Oid			conrelid;		/* relation this constraint constrains */
+	Oid			conrelid BKI_LOOKUP_OPT(pg_class);	/* relation this
+													 * constraint constrains */
 
 	/*
 	 * contypid links to the pg_type row for a domain if this is a domain
@@ -66,7 +68,8 @@ CATALOG(pg_constraint,2606,ConstraintRelationId)
 	 * For SQL-style global ASSERTIONs, both conrelid and contypid would be
 	 * zero. This is not presently supported, however.
 	 */
-	Oid			contypid;		/* domain this constraint constrains */
+	Oid			contypid BKI_LOOKUP_OPT(pg_type);	/* domain this constraint
+													 * constrains */
 
 	/*
 	 * conindid links to the index supporting the constraint, if any;
@@ -76,19 +79,21 @@ CATALOG(pg_constraint,2606,ConstraintRelationId)
 	 * columns).  Notice that the index is on conrelid in the first case but
 	 * confrelid in the second.
 	 */
-	Oid			conindid;		/* index supporting this constraint */
+	Oid			conindid BKI_LOOKUP_OPT(pg_class);	/* index supporting this
+													 * constraint */
 
 	/*
 	 * If this constraint is on a partition inherited from a partitioned
 	 * table, this is the OID of the corresponding constraint in the parent.
 	 */
-	Oid			conparentid;
+	Oid			conparentid BKI_LOOKUP_OPT(pg_constraint);
 
 	/*
 	 * These fields, plus confkey, are only meaningful for a foreign-key
 	 * constraint.  Otherwise confrelid is 0 and the char fields are spaces.
 	 */
-	Oid			confrelid;		/* relation referenced by foreign key */
+	Oid			confrelid BKI_LOOKUP_OPT(pg_class); /* relation referenced by
+													 * foreign key */
 	char		confupdtype;	/* foreign key's ON UPDATE action */
 	char		confdeltype;	/* foreign key's ON DELETE action */
 	char		confmatchtype;	/* foreign key's match type */
@@ -119,25 +124,25 @@ CATALOG(pg_constraint,2606,ConstraintRelationId)
 	 * If a foreign key, the OIDs of the PK = FK equality operators for each
 	 * column of the constraint
 	 */
-	Oid			conpfeqop[1];
+	Oid			conpfeqop[1] BKI_LOOKUP(pg_operator);
 
 	/*
 	 * If a foreign key, the OIDs of the PK = PK equality operators for each
 	 * column of the constraint (i.e., equality for the referenced columns)
 	 */
-	Oid			conppeqop[1];
+	Oid			conppeqop[1] BKI_LOOKUP(pg_operator);
 
 	/*
 	 * If a foreign key, the OIDs of the FK = FK equality operators for each
 	 * column of the constraint (i.e., equality for the referencing columns)
 	 */
-	Oid			conffeqop[1];
+	Oid			conffeqop[1] BKI_LOOKUP(pg_operator);
 
 	/*
 	 * If an exclusion constraint, the OIDs of the exclusion operators for
 	 * each column of the constraint
 	 */
-	Oid			conexclop[1];
+	Oid			conexclop[1] BKI_LOOKUP(pg_operator);
 
 	/*
 	 * If a check constraint, nodeToString representation of expression
@@ -166,6 +171,10 @@ DECLARE_UNIQUE_INDEX_PKEY(pg_constraint_oid_index, 2667, on pg_constraint using
 DECLARE_INDEX(pg_constraint_conparentid_index, 2579, on pg_constraint using btree(conparentid oid_ops));
 #define ConstraintParentIndexId	2579
 
+/* conkey can contain zero (InvalidAttrNumber) if a whole-row Var is used */
+DECLARE_ARRAY_FOREIGN_KEY_OPT((conrelid, conkey), pg_attribute, (attrelid, attnum));
+DECLARE_ARRAY_FOREIGN_KEY((confrelid, confkey), pg_attribute, (attrelid, attnum));
+
 #ifdef EXPOSE_TO_CLIENT_CODE
 
 /* Valid values for contype */
diff --git a/src/include/catalog/pg_conversion.h b/src/include/catalog/pg_conversion.h
index b02dfe0c3f..96bb92f251 100644
--- a/src/include/catalog/pg_conversion.h
+++ b/src/include/catalog/pg_conversion.h
@@ -35,10 +35,10 @@ CATALOG(pg_conversion,2607,ConversionRelationId)
 	NameData	conname;
 
 	/* namespace that the conversion belongs to */
-	Oid			connamespace BKI_DEFAULT(PGNSP);
+	Oid			connamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* owner of the conversion */
-	Oid			conowner BKI_DEFAULT(PGUID);
+	Oid			conowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/* FOR encoding id */
 	int32		conforencoding BKI_LOOKUP(encoding);
diff --git a/src/include/catalog/pg_database.h b/src/include/catalog/pg_database.h
index b7a0b6a381..f0240c58cf 100644
--- a/src/include/catalog/pg_database.h
+++ b/src/include/catalog/pg_database.h
@@ -35,7 +35,7 @@ CATALOG(pg_database,1262,DatabaseRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID
 	NameData	datname;
 
 	/* owner of database */
-	Oid			datdba BKI_DEFAULT(PGUID);
+	Oid			datdba BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/* character encoding */
 	int32		encoding;
diff --git a/src/include/catalog/pg_db_role_setting.h b/src/include/catalog/pg_db_role_setting.h
index f18819d670..705f698ae7 100644
--- a/src/include/catalog/pg_db_role_setting.h
+++ b/src/include/catalog/pg_db_role_setting.h
@@ -33,8 +33,11 @@
  */
 CATALOG(pg_db_role_setting,2964,DbRoleSettingRelationId) BKI_SHARED_RELATION
 {
-	Oid			setdatabase;	/* database */
-	Oid			setrole;		/* role */
+	/* database, or 0 for a role-specific setting */
+	Oid			setdatabase BKI_LOOKUP_OPT(pg_database);
+
+	/* role, or 0 for a database-specific setting */
+	Oid			setrole BKI_LOOKUP_OPT(pg_authid);
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	text		setconfig[1];	/* GUC settings to apply at login */
diff --git a/src/include/catalog/pg_default_acl.h b/src/include/catalog/pg_default_acl.h
index bb7db32cd6..156fc0712d 100644
--- a/src/include/catalog/pg_default_acl.h
+++ b/src/include/catalog/pg_default_acl.h
@@ -30,8 +30,10 @@
 CATALOG(pg_default_acl,826,DefaultAclRelationId)
 {
 	Oid			oid;			/* oid */
-	Oid			defaclrole;		/* OID of role owning this ACL */
-	Oid			defaclnamespace;	/* OID of namespace, or 0 for all */
+	Oid			defaclrole BKI_LOOKUP(pg_authid);	/* OID of role owning this
+													 * ACL */
+	Oid			defaclnamespace BKI_LOOKUP_OPT(pg_namespace);	/* OID of namespace, or
+																 * 0 for all */
 	char		defaclobjtype;	/* see DEFACLOBJ_xxx constants below */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
diff --git a/src/include/catalog/pg_depend.h b/src/include/catalog/pg_depend.h
index b083790180..606a2a8e19 100644
--- a/src/include/catalog/pg_depend.h
+++ b/src/include/catalog/pg_depend.h
@@ -45,14 +45,16 @@ CATALOG(pg_depend,2608,DependRelationId)
 	 *
 	 * These fields are all zeroes for a DEPENDENCY_PIN entry.
 	 */
-	Oid			classid;		/* OID of table containing object */
+	Oid			classid BKI_LOOKUP_OPT(pg_class);	/* OID of table containing
+													 * object */
 	Oid			objid;			/* OID of object itself */
 	int32		objsubid;		/* column number, or 0 if not used */
 
 	/*
 	 * Identification of the independent (referenced) object.
 	 */
-	Oid			refclassid;		/* OID of table containing object */
+	Oid			refclassid BKI_LOOKUP(pg_class);	/* OID of table containing
+													 * object */
 	Oid			refobjid;		/* OID of object itself */
 	int32		refobjsubid;	/* column number, or 0 if not used */
 
diff --git a/src/include/catalog/pg_description.h b/src/include/catalog/pg_description.h
index ad9de5e0a0..adc06a854d 100644
--- a/src/include/catalog/pg_description.h
+++ b/src/include/catalog/pg_description.h
@@ -68,4 +68,7 @@ DECLARE_TOAST(pg_description, 2834, 2835);
 DECLARE_UNIQUE_INDEX_PKEY(pg_description_o_c_o_index, 2675, on pg_description using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops));
 #define DescriptionObjIndexId  2675
 
+/* We do not use BKI_LOOKUP here because it causes problems for genbki.pl */
+DECLARE_FOREIGN_KEY((classoid), pg_class, (oid));
+
 #endif							/* PG_DESCRIPTION_H */
diff --git a/src/include/catalog/pg_enum.h b/src/include/catalog/pg_enum.h
index 5eaf70772c..78a183b27d 100644
--- a/src/include/catalog/pg_enum.h
+++ b/src/include/catalog/pg_enum.h
@@ -31,7 +31,7 @@
 CATALOG(pg_enum,3501,EnumRelationId)
 {
 	Oid			oid;			/* oid */
-	Oid			enumtypid;		/* OID of owning enum type */
+	Oid			enumtypid BKI_LOOKUP(pg_type);	/* OID of owning enum type */
 	float4		enumsortorder;	/* sort position of this enum value */
 	NameData	enumlabel;		/* text representation of enum value */
 } FormData_pg_enum;
diff --git a/src/include/catalog/pg_event_trigger.h b/src/include/catalog/pg_event_trigger.h
index 6f0266ed0f..eeaa6be518 100644
--- a/src/include/catalog/pg_event_trigger.h
+++ b/src/include/catalog/pg_event_trigger.h
@@ -31,8 +31,9 @@ CATALOG(pg_event_trigger,3466,EventTriggerRelationId)
 	Oid			oid;			/* oid */
 	NameData	evtname;		/* trigger's name */
 	NameData	evtevent;		/* trigger's event */
-	Oid			evtowner;		/* trigger's owner */
-	Oid			evtfoid;		/* OID of function to be called */
+	Oid			evtowner BKI_LOOKUP(pg_authid); /* trigger's owner */
+	Oid			evtfoid BKI_LOOKUP(pg_proc);	/* OID of function to be
+												 * called */
 	char		evtenabled;		/* trigger's firing configuration WRT
 								 * session_replication_role */
 
diff --git a/src/include/catalog/pg_extension.h b/src/include/catalog/pg_extension.h
index af119bfea7..2d6ad9fa88 100644
--- a/src/include/catalog/pg_extension.h
+++ b/src/include/catalog/pg_extension.h
@@ -30,14 +30,16 @@ CATALOG(pg_extension,3079,ExtensionRelationId)
 {
 	Oid			oid;			/* oid */
 	NameData	extname;		/* extension name */
-	Oid			extowner;		/* extension owner */
-	Oid			extnamespace;	/* namespace of contained objects */
+	Oid			extowner BKI_LOOKUP(pg_authid); /* extension owner */
+	Oid			extnamespace BKI_LOOKUP(pg_namespace);	/* namespace of
+														 * contained objects */
 	bool		extrelocatable; /* if true, allow ALTER EXTENSION SET SCHEMA */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	/* extversion may never be null, but the others can be. */
 	text		extversion BKI_FORCE_NOT_NULL;	/* extension version name */
-	Oid			extconfig[1];	/* dumpable configuration tables */
+	Oid			extconfig[1] BKI_LOOKUP(pg_class);	/* dumpable configuration
+													 * tables */
 	text		extcondition[1];	/* WHERE clauses for config tables */
 #endif
 } FormData_pg_extension;
diff --git a/src/include/catalog/pg_foreign_data_wrapper.h b/src/include/catalog/pg_foreign_data_wrapper.h
index 0f523a26b9..f6240d9eb3 100644
--- a/src/include/catalog/pg_foreign_data_wrapper.h
+++ b/src/include/catalog/pg_foreign_data_wrapper.h
@@ -30,9 +30,12 @@ CATALOG(pg_foreign_data_wrapper,2328,ForeignDataWrapperRelationId)
 {
 	Oid			oid;			/* oid */
 	NameData	fdwname;		/* foreign-data wrapper name */
-	Oid			fdwowner;		/* FDW owner */
-	Oid			fdwhandler;		/* handler function, or 0 if none */
-	Oid			fdwvalidator;	/* option validation function, or 0 if none */
+	Oid			fdwowner BKI_LOOKUP(pg_authid); /* FDW owner */
+	Oid			fdwhandler BKI_LOOKUP_OPT(pg_proc); /* handler function, or 0
+													 * if none */
+	Oid			fdwvalidator BKI_LOOKUP_OPT(pg_proc);	/* option validation
+														 * function, or 0 if
+														 * none */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	aclitem		fdwacl[1];		/* access permissions */
diff --git a/src/include/catalog/pg_foreign_server.h b/src/include/catalog/pg_foreign_server.h
index 385b896e97..a173699aef 100644
--- a/src/include/catalog/pg_foreign_server.h
+++ b/src/include/catalog/pg_foreign_server.h
@@ -29,8 +29,8 @@ CATALOG(pg_foreign_server,1417,ForeignServerRelationId)
 {
 	Oid			oid;			/* oid */
 	NameData	srvname;		/* foreign server name */
-	Oid			srvowner;		/* server owner */
-	Oid			srvfdw;			/* server FDW */
+	Oid			srvowner BKI_LOOKUP(pg_authid); /* server owner */
+	Oid			srvfdw BKI_LOOKUP(pg_foreign_data_wrapper); /* server FDW */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	text		srvtype;
diff --git a/src/include/catalog/pg_foreign_table.h b/src/include/catalog/pg_foreign_table.h
index 24f7f2998e..3b6221b0e6 100644
--- a/src/include/catalog/pg_foreign_table.h
+++ b/src/include/catalog/pg_foreign_table.h
@@ -27,8 +27,8 @@
  */
 CATALOG(pg_foreign_table,3118,ForeignTableRelationId)
 {
-	Oid			ftrelid;		/* OID of foreign table */
-	Oid			ftserver;		/* OID of foreign server */
+	Oid			ftrelid BKI_LOOKUP(pg_class);	/* OID of foreign table */
+	Oid			ftserver BKI_LOOKUP(pg_foreign_server); /* OID of foreign server */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	text		ftoptions[1];	/* FDW-specific options */
diff --git a/src/include/catalog/pg_index.h b/src/include/catalog/pg_index.h
index 1a7aef18ce..00d0b439f5 100644
--- a/src/include/catalog/pg_index.h
+++ b/src/include/catalog/pg_index.h
@@ -28,8 +28,9 @@
  */
 CATALOG(pg_index,2610,IndexRelationId) BKI_SCHEMA_MACRO
 {
-	Oid			indexrelid;		/* OID of the index */
-	Oid			indrelid;		/* OID of the relation it indexes */
+	Oid			indexrelid BKI_LOOKUP(pg_class);	/* OID of the index */
+	Oid			indrelid BKI_LOOKUP(pg_class);	/* OID of the relation it
+												 * indexes */
 	int16		indnatts;		/* total number of columns in index */
 	int16		indnkeyatts;	/* number of key columns in index */
 	bool		indisunique;	/* is this a unique index? */
@@ -48,8 +49,8 @@ CATALOG(pg_index,2610,IndexRelationId) BKI_SCHEMA_MACRO
 											 * or 0 */
 
 #ifdef CATALOG_VARLEN
-	oidvector	indcollation BKI_FORCE_NOT_NULL;	/* collation identifiers */
-	oidvector	indclass BKI_FORCE_NOT_NULL;	/* opclass identifiers */
+	oidvector	indcollation BKI_LOOKUP_OPT(pg_collation) BKI_FORCE_NOT_NULL;	/* collation identifiers */
+	oidvector	indclass BKI_LOOKUP(pg_opclass) BKI_FORCE_NOT_NULL; /* opclass identifiers */
 	int2vector	indoption BKI_FORCE_NOT_NULL;	/* per-column flags
 												 * (AM-specific meanings) */
 	pg_node_tree indexprs;		/* expression trees for index attributes that
@@ -72,6 +73,9 @@ DECLARE_INDEX(pg_index_indrelid_index, 2678, on pg_index using btree(indrelid oi
 DECLARE_UNIQUE_INDEX_PKEY(pg_index_indexrelid_index, 2679, on pg_index using btree(indexrelid oid_ops));
 #define IndexRelidIndexId  2679
 
+/* indkey can contain zero (InvalidAttrNumber) to represent expressions */
+DECLARE_ARRAY_FOREIGN_KEY_OPT((indrelid, indkey), pg_attribute, (attrelid, attnum));
+
 #ifdef EXPOSE_TO_CLIENT_CODE
 
 /*
diff --git a/src/include/catalog/pg_inherits.h b/src/include/catalog/pg_inherits.h
index b8147796d8..2b71cad9a2 100644
--- a/src/include/catalog/pg_inherits.h
+++ b/src/include/catalog/pg_inherits.h
@@ -31,8 +31,8 @@
  */
 CATALOG(pg_inherits,2611,InheritsRelationId)
 {
-	Oid			inhrelid;
-	Oid			inhparent;
+	Oid			inhrelid BKI_LOOKUP(pg_class);
+	Oid			inhparent BKI_LOOKUP(pg_class);
 	int32		inhseqno;
 } FormData_pg_inherits;
 
diff --git a/src/include/catalog/pg_init_privs.h b/src/include/catalog/pg_init_privs.h
index 983b1857c0..4aafeb246d 100644
--- a/src/include/catalog/pg_init_privs.h
+++ b/src/include/catalog/pg_init_privs.h
@@ -46,7 +46,8 @@
 CATALOG(pg_init_privs,3394,InitPrivsRelationId)
 {
 	Oid			objoid;			/* OID of object itself */
-	Oid			classoid;		/* OID of table containing object */
+	Oid			classoid BKI_LOOKUP(pg_class);	/* OID of table containing
+												 * object */
 	int32		objsubid;		/* column number, or 0 if not used */
 	char		privtype;		/* from initdb or extension? */
 
diff --git a/src/include/catalog/pg_language.h b/src/include/catalog/pg_language.h
index b1dcd0a4f5..e9df9dac09 100644
--- a/src/include/catalog/pg_language.h
+++ b/src/include/catalog/pg_language.h
@@ -34,7 +34,7 @@ CATALOG(pg_language,2612,LanguageRelationId)
 	NameData	lanname;
 
 	/* Language's owner */
-	Oid			lanowner BKI_DEFAULT(PGUID);
+	Oid			lanowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/* Is a procedural language */
 	bool		lanispl BKI_DEFAULT(f);
@@ -43,13 +43,13 @@ CATALOG(pg_language,2612,LanguageRelationId)
 	bool		lanpltrusted BKI_DEFAULT(f);
 
 	/* Call handler, if it's a PL */
-	Oid			lanplcallfoid BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);
+	Oid			lanplcallfoid BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_proc);
 
 	/* Optional anonymous-block handler function */
-	Oid			laninline BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);
+	Oid			laninline BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_proc);
 
 	/* Optional validation function */
-	Oid			lanvalidator BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);
+	Oid			lanvalidator BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_proc);
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	/* Access privileges */
diff --git a/src/include/catalog/pg_largeobject.h b/src/include/catalog/pg_largeobject.h
index f453319322..32225f4de7 100644
--- a/src/include/catalog/pg_largeobject.h
+++ b/src/include/catalog/pg_largeobject.h
@@ -28,7 +28,8 @@
  */
 CATALOG(pg_largeobject,2613,LargeObjectRelationId)
 {
-	Oid			loid;			/* Identifier of large object */
+	Oid			loid BKI_LOOKUP(pg_largeobject_metadata);	/* Identifier of large
+															 * object */
 	int32		pageno;			/* Page number (starting from 0) */
 
 	/* data has variable length, but we allow direct access; see inv_api.c */
diff --git a/src/include/catalog/pg_largeobject_metadata.h b/src/include/catalog/pg_largeobject_metadata.h
index 220988b0ad..9b689bab84 100644
--- a/src/include/catalog/pg_largeobject_metadata.h
+++ b/src/include/catalog/pg_largeobject_metadata.h
@@ -31,7 +31,8 @@ CATALOG(pg_largeobject_metadata,2995,LargeObjectMetadataRelationId)
 {
 	Oid			oid;			/* oid */
 
-	Oid			lomowner;		/* OID of the largeobject owner */
+	Oid			lomowner BKI_LOOKUP(pg_authid); /* OID of the largeobject
+												 * owner */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	aclitem		lomacl[1];		/* access permissions */
diff --git a/src/include/catalog/pg_namespace.dat b/src/include/catalog/pg_namespace.dat
index 76257e98fc..2ed136b787 100644
--- a/src/include/catalog/pg_namespace.dat
+++ b/src/include/catalog/pg_namespace.dat
@@ -14,12 +14,12 @@
 
 { oid => '11', oid_symbol => 'PG_CATALOG_NAMESPACE',
   descr => 'system catalog schema',
-  nspname => 'pg_catalog', nspowner => 'PGUID', nspacl => '_null_' },
+  nspname => 'pg_catalog', nspacl => '_null_' },
 { oid => '99', oid_symbol => 'PG_TOAST_NAMESPACE',
   descr => 'reserved schema for TOAST tables',
-  nspname => 'pg_toast', nspowner => 'PGUID', nspacl => '_null_' },
+  nspname => 'pg_toast', nspacl => '_null_' },
 { oid => '2200', oid_symbol => 'PG_PUBLIC_NAMESPACE',
   descr => 'standard public schema',
-  nspname => 'public', nspowner => 'PGUID', nspacl => '_null_' },
+  nspname => 'public', nspacl => '_null_' },
 
 ]
diff --git a/src/include/catalog/pg_namespace.h b/src/include/catalog/pg_namespace.h
index 0a68958b1c..d920c6cfc6 100644
--- a/src/include/catalog/pg_namespace.h
+++ b/src/include/catalog/pg_namespace.h
@@ -37,7 +37,7 @@ CATALOG(pg_namespace,2615,NamespaceRelationId)
 	Oid			oid;			/* oid */
 
 	NameData	nspname;
-	Oid			nspowner;
+	Oid			nspowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	aclitem		nspacl[1];
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index d132df1f2f..9f321f2a85 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -57,10 +57,10 @@ CATALOG(pg_opclass,2616,OperatorClassRelationId)
 	NameData	opcname;
 
 	/* namespace of this opclass */
-	Oid			opcnamespace BKI_DEFAULT(PGNSP);
+	Oid			opcnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* opclass owner */
-	Oid			opcowner BKI_DEFAULT(PGUID);
+	Oid			opcowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/* containing operator family */
 	Oid			opcfamily BKI_LOOKUP(pg_opfamily);
@@ -71,8 +71,8 @@ CATALOG(pg_opclass,2616,OperatorClassRelationId)
 	/* T if opclass is default for opcintype */
 	bool		opcdefault BKI_DEFAULT(t);
 
-	/* type of data in index, or InvalidOid */
-	Oid			opckeytype BKI_DEFAULT(0) BKI_LOOKUP(pg_type);
+	/* type of data in index, or InvalidOid if same as input column type */
+	Oid			opckeytype BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type);
 } FormData_pg_opclass;
 
 /* ----------------
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 3ca57e7c1b..7f06abaeec 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -36,10 +36,10 @@ CATALOG(pg_operator,2617,OperatorRelationId)
 	NameData	oprname;
 
 	/* OID of namespace containing this oper */
-	Oid			oprnamespace BKI_DEFAULT(PGNSP);
+	Oid			oprnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* operator owner */
-	Oid			oprowner BKI_DEFAULT(PGUID);
+	Oid			oprowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/* 'l' for prefix or 'b' for infix */
 	char		oprkind BKI_DEFAULT(b);
@@ -51,28 +51,28 @@ CATALOG(pg_operator,2617,OperatorRelationId)
 	bool		oprcanhash BKI_DEFAULT(f);
 
 	/* left arg type, or 0 if prefix operator */
-	Oid			oprleft BKI_LOOKUP(pg_type);
+	Oid			oprleft BKI_LOOKUP_OPT(pg_type);
 
 	/* right arg type */
 	Oid			oprright BKI_LOOKUP(pg_type);
 
-	/* result datatype */
-	Oid			oprresult BKI_LOOKUP(pg_type);
+	/* result datatype; can be 0 in a "shell" operator */
+	Oid			oprresult BKI_LOOKUP_OPT(pg_type);
 
 	/* OID of commutator oper, or 0 if none */
-	Oid			oprcom BKI_DEFAULT(0) BKI_LOOKUP(pg_operator);
+	Oid			oprcom BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_operator);
 
 	/* OID of negator oper, or 0 if none */
-	Oid			oprnegate BKI_DEFAULT(0) BKI_LOOKUP(pg_operator);
+	Oid			oprnegate BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_operator);
 
-	/* OID of underlying function */
-	regproc		oprcode BKI_LOOKUP(pg_proc);
+	/* OID of underlying function; can be 0 in a "shell" operator */
+	regproc		oprcode BKI_LOOKUP_OPT(pg_proc);
 
 	/* OID of restriction estimator, or 0 */
-	regproc		oprrest BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);
+	regproc		oprrest BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
 
 	/* OID of join estimator, or 0 */
-	regproc		oprjoin BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);
+	regproc		oprjoin BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
 } FormData_pg_operator;
 
 /* ----------------
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index 18385a6fd6..1a723b76f6 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -37,10 +37,10 @@ CATALOG(pg_opfamily,2753,OperatorFamilyRelationId)
 	NameData	opfname;
 
 	/* namespace of this opfamily */
-	Oid			opfnamespace BKI_DEFAULT(PGNSP);
+	Oid			opfnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* opfamily owner */
-	Oid			opfowner BKI_DEFAULT(PGUID);
+	Oid			opfowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 } FormData_pg_opfamily;
 
 /* ----------------
diff --git a/src/include/catalog/pg_partitioned_table.h b/src/include/catalog/pg_partitioned_table.h
index 038730b005..48cbaf30ff 100644
--- a/src/include/catalog/pg_partitioned_table.h
+++ b/src/include/catalog/pg_partitioned_table.h
@@ -29,11 +29,11 @@
  */
 CATALOG(pg_partitioned_table,3350,PartitionedRelationId)
 {
-	Oid			partrelid;		/* partitioned table oid */
+	Oid			partrelid BKI_LOOKUP(pg_class); /* partitioned table oid */
 	char		partstrat;		/* partitioning strategy */
 	int16		partnatts;		/* number of partition key columns */
-	Oid			partdefid;		/* default partition oid; InvalidOid if there
-								 * isn't one */
+	Oid			partdefid BKI_LOOKUP_OPT(pg_class); /* default partition oid;
+													 * 0 if there isn't one */
 
 	/*
 	 * variable-length fields start here, but we allow direct access to
@@ -48,10 +48,10 @@ CATALOG(pg_partitioned_table,3350,PartitionedRelationId)
 												 * an expression */
 
 #ifdef CATALOG_VARLEN
-	oidvector	partclass BKI_FORCE_NOT_NULL;	/* operator class to compare
-												 * keys */
-	oidvector	partcollation BKI_FORCE_NOT_NULL;	/* user-specified
-													 * collation for keys */
+	oidvector	partclass BKI_LOOKUP(pg_opclass) BKI_FORCE_NOT_NULL;	/* operator class to
+																		 * compare keys */
+	oidvector	partcollation BKI_LOOKUP_OPT(pg_collation) BKI_FORCE_NOT_NULL;	/* user-specified
+																				 * collation for keys */
 	pg_node_tree partexprs;		/* list of expressions in the partition key;
 								 * one item for each zero entry in partattrs[] */
 #endif
@@ -69,4 +69,7 @@ DECLARE_TOAST(pg_partitioned_table, 4165, 4166);
 DECLARE_UNIQUE_INDEX_PKEY(pg_partitioned_table_partrelid_index, 3351, on pg_partitioned_table using btree(partrelid oid_ops));
 #define PartitionedRelidIndexId			 3351
 
+/* partattrs can contain zero (InvalidAttrNumber) to represent expressions */
+DECLARE_ARRAY_FOREIGN_KEY_OPT((partrelid, partattrs), pg_attribute, (attrelid, attnum));
+
 #endif							/* PG_PARTITIONED_TABLE_H */
diff --git a/src/include/catalog/pg_policy.h b/src/include/catalog/pg_policy.h
index 44197613e0..645b8fe498 100644
--- a/src/include/catalog/pg_policy.h
+++ b/src/include/catalog/pg_policy.h
@@ -30,13 +30,14 @@ CATALOG(pg_policy,3256,PolicyRelationId)
 {
 	Oid			oid;			/* oid */
 	NameData	polname;		/* Policy name. */
-	Oid			polrelid;		/* Oid of the relation with policy. */
+	Oid			polrelid BKI_LOOKUP(pg_class);	/* Oid of the relation with
+												 * policy. */
 	char		polcmd;			/* One of ACL_*_CHR, or '*' for all */
 	bool		polpermissive;	/* restrictive or permissive policy */
 
 #ifdef CATALOG_VARLEN
-	Oid			polroles[1] BKI_FORCE_NOT_NULL; /* Roles associated with
-												 * policy */
+	/* Roles to which the policy is applied; zero means PUBLIC */
+	Oid			polroles[1] BKI_LOOKUP_OPT(pg_authid) BKI_FORCE_NOT_NULL;
 	pg_node_tree polqual;		/* Policy quals. */
 	pg_node_tree polwithcheck;	/* WITH CHECK quals. */
 #endif
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index f8174061ef..4e0c9be58c 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -2405,7 +2405,7 @@
 { oid => '1215', descr => 'get description for object id and catalog name',
   proname => 'obj_description', prolang => 'sql', procost => '100',
   provolatile => 's', prorettype => 'text', proargtypes => 'oid name',
-  prosrc => 'select description from pg_catalog.pg_description where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = PGNSP) and objsubid = 0' },
+  prosrc => 'select description from pg_catalog.pg_description where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = \'pg_catalog\'::pg_catalog.regnamespace) and objsubid = 0' },
 { oid => '1216', descr => 'get description for table column',
   proname => 'col_description', prolang => 'sql', procost => '100',
   provolatile => 's', prorettype => 'text', proargtypes => 'oid int4',
@@ -2414,7 +2414,7 @@
   descr => 'get description for object id and shared catalog name',
   proname => 'shobj_description', prolang => 'sql', procost => '100',
   provolatile => 's', prorettype => 'text', proargtypes => 'oid name',
-  prosrc => 'select description from pg_catalog.pg_shdescription where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = PGNSP)' },
+  prosrc => 'select description from pg_catalog.pg_shdescription where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = \'pg_catalog\'::pg_catalog.regnamespace)' },
 
 { oid => '1217',
   descr => 'truncate timestamp with time zone to specified units',
@@ -3698,6 +3698,14 @@
   proargnames => '{word,catcode,barelabel,catdesc,baredesc}',
   prosrc => 'pg_get_keywords' },
 
+{ oid => '8103', descr => 'list of catalog foreign key relationships',
+  proname => 'pg_get_catalog_foreign_keys', procost => '10', prorows => '250',
+  proretset => 't', provolatile => 's', prorettype => 'record',
+  proargtypes => '', proallargtypes => '{regclass,_text,regclass,_text,bool,bool}',
+  proargmodes => '{o,o,o,o,o,o}',
+  proargnames => '{fktable,fkcols,pktable,pkcols,is_array,is_opt}',
+  prosrc => 'pg_get_catalog_foreign_keys' },
+
 { oid => '2289', descr => 'convert generic options array to name/value table',
   proname => 'pg_options_to_table', prorows => '3', proretset => 't',
   provolatile => 's', prorettype => 'record', proargtypes => '_text',
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 03c8bef422..2f54aa171e 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -35,10 +35,10 @@ CATALOG(pg_proc,1255,ProcedureRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81,Proce
 	NameData	proname;
 
 	/* OID of namespace containing this proc */
-	Oid			pronamespace BKI_DEFAULT(PGNSP);
+	Oid			pronamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* procedure owner */
-	Oid			proowner BKI_DEFAULT(PGUID);
+	Oid			proowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/* OID of pg_language entry */
 	Oid			prolang BKI_DEFAULT(internal) BKI_LOOKUP(pg_language);
@@ -49,11 +49,11 @@ CATALOG(pg_proc,1255,ProcedureRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81,Proce
 	/* estimated # of rows out (if proretset) */
 	float4		prorows BKI_DEFAULT(0);
 
-	/* element type of variadic array, or 0 */
-	Oid			provariadic BKI_DEFAULT(0) BKI_LOOKUP(pg_type);
+	/* element type of variadic array, or 0 if not variadic */
+	Oid			provariadic BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type);
 
 	/* planner support function for this function, or 0 if none */
-	regproc		prosupport BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);
+	regproc		prosupport BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_proc);
 
 	/* see PROKIND_ categories below */
 	char		prokind BKI_DEFAULT(f);
@@ -109,7 +109,7 @@ CATALOG(pg_proc,1255,ProcedureRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81,Proce
 	pg_node_tree proargdefaults BKI_DEFAULT(_null_);
 
 	/* types for which to apply transforms */
-	Oid			protrftypes[1] BKI_DEFAULT(_null_);
+	Oid			protrftypes[1] BKI_DEFAULT(_null_) BKI_LOOKUP(pg_type);
 
 	/* procedure source text */
 	text		prosrc BKI_FORCE_NOT_NULL;
diff --git a/src/include/catalog/pg_publication.h b/src/include/catalog/pg_publication.h
index 4127611f5a..1b31fee9e3 100644
--- a/src/include/catalog/pg_publication.h
+++ b/src/include/catalog/pg_publication.h
@@ -32,7 +32,7 @@ CATALOG(pg_publication,6104,PublicationRelationId)
 
 	NameData	pubname;		/* name of the publication */
 
-	Oid			pubowner;		/* publication owner */
+	Oid			pubowner BKI_LOOKUP(pg_authid); /* publication owner */
 
 	/*
 	 * indicates that this is special publication which should encompass all
diff --git a/src/include/catalog/pg_publication_rel.h b/src/include/catalog/pg_publication_rel.h
index c79b7fb487..aecf53b3b3 100644
--- a/src/include/catalog/pg_publication_rel.h
+++ b/src/include/catalog/pg_publication_rel.h
@@ -29,8 +29,8 @@
 CATALOG(pg_publication_rel,6106,PublicationRelRelationId)
 {
 	Oid			oid;			/* oid */
-	Oid			prpubid;		/* Oid of the publication */
-	Oid			prrelid;		/* Oid of the relation */
+	Oid			prpubid BKI_LOOKUP(pg_publication); /* Oid of the publication */
+	Oid			prrelid BKI_LOOKUP(pg_class);	/* Oid of the relation */
 } FormData_pg_publication_rel;
 
 /* ----------------
diff --git a/src/include/catalog/pg_range.h b/src/include/catalog/pg_range.h
index 2ec6a4b126..5dfa4eef8b 100644
--- a/src/include/catalog/pg_range.h
+++ b/src/include/catalog/pg_range.h
@@ -38,16 +38,16 @@ CATALOG(pg_range,3541,RangeRelationId)
 	Oid			rngmultitypid BKI_LOOKUP(pg_type);
 
 	/* collation for this range type, or 0 */
-	Oid			rngcollation BKI_DEFAULT(0);
+	Oid			rngcollation BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_collation);
 
 	/* subtype's btree opclass */
 	Oid			rngsubopc BKI_LOOKUP(pg_opclass);
 
 	/* canonicalize range, or 0 */
-	regproc		rngcanonical BKI_LOOKUP(pg_proc);
+	regproc		rngcanonical BKI_LOOKUP_OPT(pg_proc);
 
 	/* subtype difference as a float8, or 0 */
-	regproc		rngsubdiff BKI_LOOKUP(pg_proc);
+	regproc		rngsubdiff BKI_LOOKUP_OPT(pg_proc);
 } FormData_pg_range;
 
 /* ----------------
diff --git a/src/include/catalog/pg_rewrite.h b/src/include/catalog/pg_rewrite.h
index 36f92b1cf1..89c72545d0 100644
--- a/src/include/catalog/pg_rewrite.h
+++ b/src/include/catalog/pg_rewrite.h
@@ -33,7 +33,7 @@ CATALOG(pg_rewrite,2618,RewriteRelationId)
 {
 	Oid			oid;			/* oid */
 	NameData	rulename;
-	Oid			ev_class;
+	Oid			ev_class BKI_LOOKUP(pg_class);
 	char		ev_type;
 	char		ev_enabled;
 	bool		is_instead;
diff --git a/src/include/catalog/pg_seclabel.h b/src/include/catalog/pg_seclabel.h
index b14fd7febe..0a12225eb7 100644
--- a/src/include/catalog/pg_seclabel.h
+++ b/src/include/catalog/pg_seclabel.h
@@ -28,7 +28,8 @@
 CATALOG(pg_seclabel,3596,SecLabelRelationId)
 {
 	Oid			objoid;			/* OID of the object itself */
-	Oid			classoid;		/* OID of table containing the object */
+	Oid			classoid BKI_LOOKUP(pg_class);	/* OID of table containing the
+												 * object */
 	int32		objsubid;		/* column number, or 0 if not used */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
diff --git a/src/include/catalog/pg_sequence.h b/src/include/catalog/pg_sequence.h
index addf21abce..8d0a00baf6 100644
--- a/src/include/catalog/pg_sequence.h
+++ b/src/include/catalog/pg_sequence.h
@@ -22,8 +22,8 @@
 
 CATALOG(pg_sequence,2224,SequenceRelationId)
 {
-	Oid			seqrelid;
-	Oid			seqtypid;
+	Oid			seqrelid BKI_LOOKUP(pg_class);
+	Oid			seqtypid BKI_LOOKUP(pg_type);
 	int64		seqstart;
 	int64		seqincrement;
 	int64		seqmax;
diff --git a/src/include/catalog/pg_shdepend.h b/src/include/catalog/pg_shdepend.h
index f5863954e9..4faa95794d 100644
--- a/src/include/catalog/pg_shdepend.h
+++ b/src/include/catalog/pg_shdepend.h
@@ -42,8 +42,10 @@ CATALOG(pg_shdepend,1214,SharedDependRelationId) BKI_SHARED_RELATION
 	 * These fields are all zeroes for a DEPENDENCY_PIN entry.  Also, dbid can
 	 * be zero to denote a shared object.
 	 */
-	Oid			dbid;			/* OID of database containing object */
-	Oid			classid;		/* OID of table containing object */
+	Oid			dbid BKI_LOOKUP_OPT(pg_database);	/* OID of database
+													 * containing object */
+	Oid			classid BKI_LOOKUP_OPT(pg_class);	/* OID of table containing
+													 * object */
 	Oid			objid;			/* OID of object itself */
 	int32		objsubid;		/* column number, or 0 if not used */
 
@@ -52,7 +54,8 @@ CATALOG(pg_shdepend,1214,SharedDependRelationId) BKI_SHARED_RELATION
 	 * a shared object, so we need no database ID field.  We don't bother with
 	 * a sub-object ID either.
 	 */
-	Oid			refclassid;		/* OID of table containing object */
+	Oid			refclassid BKI_LOOKUP(pg_class);	/* OID of table containing
+													 * object */
 	Oid			refobjid;		/* OID of object itself */
 
 	/*
diff --git a/src/include/catalog/pg_shdescription.h b/src/include/catalog/pg_shdescription.h
index a37db4fa0b..543e216710 100644
--- a/src/include/catalog/pg_shdescription.h
+++ b/src/include/catalog/pg_shdescription.h
@@ -62,4 +62,7 @@ DECLARE_TOAST(pg_shdescription, 2846, 2847);
 DECLARE_UNIQUE_INDEX_PKEY(pg_shdescription_o_c_index, 2397, on pg_shdescription using btree(objoid oid_ops, classoid oid_ops));
 #define SharedDescriptionObjIndexId 2397
 
+/* We do not use BKI_LOOKUP here because it causes problems for genbki.pl */
+DECLARE_FOREIGN_KEY((classoid), pg_class, (oid));
+
 #endif							/* PG_SHDESCRIPTION_H */
diff --git a/src/include/catalog/pg_shseclabel.h b/src/include/catalog/pg_shseclabel.h
index 406f5328a7..5d6864cf8c 100644
--- a/src/include/catalog/pg_shseclabel.h
+++ b/src/include/catalog/pg_shseclabel.h
@@ -28,7 +28,8 @@
 CATALOG(pg_shseclabel,3592,SharedSecLabelRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID(4066,SharedSecLabelRelation_Rowtype_Id) BKI_SCHEMA_MACRO
 {
 	Oid			objoid;			/* OID of the shared object itself */
-	Oid			classoid;		/* OID of table containing the shared object */
+	Oid			classoid BKI_LOOKUP(pg_class);	/* OID of table containing the
+												 * shared object */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	text		provider BKI_FORCE_NOT_NULL;	/* name of label provider */
diff --git a/src/include/catalog/pg_statistic.h b/src/include/catalog/pg_statistic.h
index 4a66bda879..d1827858e2 100644
--- a/src/include/catalog/pg_statistic.h
+++ b/src/include/catalog/pg_statistic.h
@@ -29,7 +29,8 @@
 CATALOG(pg_statistic,2619,StatisticRelationId)
 {
 	/* These fields form the unique key for the entry: */
-	Oid			starelid;		/* relation containing attribute */
+	Oid			starelid BKI_LOOKUP(pg_class);	/* relation containing
+												 * attribute */
 	int16		staattnum;		/* attribute (column) stats are for */
 	bool		stainherit;		/* true if inheritance children are included */
 
@@ -90,17 +91,17 @@ CATALOG(pg_statistic,2619,StatisticRelationId)
 	int16		stakind4;
 	int16		stakind5;
 
-	Oid			staop1;
-	Oid			staop2;
-	Oid			staop3;
-	Oid			staop4;
-	Oid			staop5;
+	Oid			staop1 BKI_LOOKUP_OPT(pg_operator);
+	Oid			staop2 BKI_LOOKUP_OPT(pg_operator);
+	Oid			staop3 BKI_LOOKUP_OPT(pg_operator);
+	Oid			staop4 BKI_LOOKUP_OPT(pg_operator);
+	Oid			staop5 BKI_LOOKUP_OPT(pg_operator);
 
-	Oid			stacoll1;
-	Oid			stacoll2;
-	Oid			stacoll3;
-	Oid			stacoll4;
-	Oid			stacoll5;
+	Oid			stacoll1 BKI_LOOKUP_OPT(pg_collation);
+	Oid			stacoll2 BKI_LOOKUP_OPT(pg_collation);
+	Oid			stacoll3 BKI_LOOKUP_OPT(pg_collation);
+	Oid			stacoll4 BKI_LOOKUP_OPT(pg_collation);
+	Oid			stacoll5 BKI_LOOKUP_OPT(pg_collation);
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	float4		stanumbers1[1];
@@ -138,6 +139,8 @@ DECLARE_TOAST(pg_statistic, 2840, 2841);
 DECLARE_UNIQUE_INDEX_PKEY(pg_statistic_relid_att_inh_index, 2696, on pg_statistic using btree(starelid oid_ops, staattnum int2_ops, stainherit bool_ops));
 #define StatisticRelidAttnumInhIndexId	2696
 
+DECLARE_FOREIGN_KEY((starelid, staattnum), pg_attribute, (attrelid, attnum));
+
 #ifdef EXPOSE_TO_CLIENT_CODE
 
 /*
diff --git a/src/include/catalog/pg_statistic_ext.h b/src/include/catalog/pg_statistic_ext.h
index 10f52f912c..29649f5814 100644
--- a/src/include/catalog/pg_statistic_ext.h
+++ b/src/include/catalog/pg_statistic_ext.h
@@ -34,13 +34,15 @@ CATALOG(pg_statistic_ext,3381,StatisticExtRelationId)
 {
 	Oid			oid;			/* oid */
 
-	Oid			stxrelid;		/* relation containing attributes */
+	Oid			stxrelid BKI_LOOKUP(pg_class);	/* relation containing
+												 * attributes */
 
 	/* These two fields form the unique key for the entry: */
 	NameData	stxname;		/* statistics object name */
-	Oid			stxnamespace;	/* OID of statistics object's namespace */
+	Oid			stxnamespace BKI_LOOKUP(pg_namespace);	/* OID of statistics
+														 * object's namespace */
 
-	Oid			stxowner;		/* statistics object's owner */
+	Oid			stxowner BKI_LOOKUP(pg_authid); /* statistics object's owner */
 	int32		stxstattarget BKI_DEFAULT(-1);	/* statistics target */
 
 	/*
@@ -72,6 +74,8 @@ DECLARE_UNIQUE_INDEX(pg_statistic_ext_name_index, 3997, on pg_statistic_ext usin
 DECLARE_INDEX(pg_statistic_ext_relid_index, 3379, on pg_statistic_ext using btree(stxrelid oid_ops));
 #define StatisticExtRelidIndexId 3379
 
+DECLARE_ARRAY_FOREIGN_KEY((stxrelid, stxkeys), pg_attribute, (attrelid, attnum));
+
 #ifdef EXPOSE_TO_CLIENT_CODE
 
 #define STATS_EXT_NDISTINCT			'd'
diff --git a/src/include/catalog/pg_statistic_ext_data.h b/src/include/catalog/pg_statistic_ext_data.h
index 6f7a36c141..2f2577c218 100644
--- a/src/include/catalog/pg_statistic_ext_data.h
+++ b/src/include/catalog/pg_statistic_ext_data.h
@@ -30,7 +30,8 @@
  */
 CATALOG(pg_statistic_ext_data,3429,StatisticExtDataRelationId)
 {
-	Oid			stxoid;			/* statistics object this data is for */
+	Oid			stxoid BKI_LOOKUP(pg_statistic_ext);	/* statistics object
+														 * this data is for */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 
diff --git a/src/include/catalog/pg_subscription.h b/src/include/catalog/pg_subscription.h
index 4e44c29149..a5d6efdf20 100644
--- a/src/include/catalog/pg_subscription.h
+++ b/src/include/catalog/pg_subscription.h
@@ -40,10 +40,11 @@ CATALOG(pg_subscription,6100,SubscriptionRelationId) BKI_SHARED_RELATION BKI_ROW
 {
 	Oid			oid;			/* oid */
 
-	Oid			subdbid;		/* Database the subscription is in. */
+	Oid			subdbid BKI_LOOKUP(pg_database);	/* Database the
+													 * subscription is in. */
 	NameData	subname;		/* Name of the subscription */
 
-	Oid			subowner;		/* Owner of the subscription */
+	Oid			subowner BKI_LOOKUP(pg_authid); /* Owner of the subscription */
 
 	bool		subenabled;		/* True if the subscription is enabled (the
 								 * worker should be running) */
diff --git a/src/include/catalog/pg_subscription_rel.h b/src/include/catalog/pg_subscription_rel.h
index ab1202cf9b..2bea2c52aa 100644
--- a/src/include/catalog/pg_subscription_rel.h
+++ b/src/include/catalog/pg_subscription_rel.h
@@ -30,8 +30,8 @@
  */
 CATALOG(pg_subscription_rel,6102,SubscriptionRelRelationId)
 {
-	Oid			srsubid;		/* Oid of subscription */
-	Oid			srrelid;		/* Oid of relation */
+	Oid			srsubid BKI_LOOKUP(pg_subscription);	/* Oid of subscription */
+	Oid			srrelid BKI_LOOKUP(pg_class);	/* Oid of relation */
 	char		srsubstate;		/* state of the relation in subscription */
 
 	/*
diff --git a/src/include/catalog/pg_tablespace.dat b/src/include/catalog/pg_tablespace.dat
index 212a0ad07f..bf0d81d306 100644
--- a/src/include/catalog/pg_tablespace.dat
+++ b/src/include/catalog/pg_tablespace.dat
@@ -13,10 +13,8 @@
 [
 
 { oid => '1663', oid_symbol => 'DEFAULTTABLESPACE_OID',
-  spcname => 'pg_default', spcowner => 'PGUID', spcacl => '_null_',
-  spcoptions => '_null_' },
+  spcname => 'pg_default', spcacl => '_null_', spcoptions => '_null_' },
 { oid => '1664', oid_symbol => 'GLOBALTABLESPACE_OID',
-  spcname => 'pg_global', spcowner => 'PGUID', spcacl => '_null_',
-  spcoptions => '_null_' },
+  spcname => 'pg_global', spcacl => '_null_', spcoptions => '_null_' },
 
 ]
diff --git a/src/include/catalog/pg_tablespace.h b/src/include/catalog/pg_tablespace.h
index 6a6c66a61c..ed38e6950d 100644
--- a/src/include/catalog/pg_tablespace.h
+++ b/src/include/catalog/pg_tablespace.h
@@ -30,7 +30,7 @@ CATALOG(pg_tablespace,1213,TableSpaceRelationId) BKI_SHARED_RELATION
 {
 	Oid			oid;			/* oid */
 	NameData	spcname;		/* tablespace name */
-	Oid			spcowner;		/* owner of tablespace */
+	Oid			spcowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);	/* owner of tablespace */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	aclitem		spcacl[1];		/* access permissions */
diff --git a/src/include/catalog/pg_transform.h b/src/include/catalog/pg_transform.h
index ad25db1841..d603246138 100644
--- a/src/include/catalog/pg_transform.h
+++ b/src/include/catalog/pg_transform.h
@@ -29,10 +29,10 @@
 CATALOG(pg_transform,3576,TransformRelationId)
 {
 	Oid			oid;			/* oid */
-	Oid			trftype;
-	Oid			trflang;
-	regproc		trffromsql;
-	regproc		trftosql;
+	Oid			trftype BKI_LOOKUP(pg_type);
+	Oid			trflang BKI_LOOKUP(pg_language);
+	regproc		trffromsql BKI_LOOKUP_OPT(pg_proc);
+	regproc		trftosql BKI_LOOKUP_OPT(pg_proc);
 } FormData_pg_transform;
 
 /* ----------------
diff --git a/src/include/catalog/pg_trigger.h b/src/include/catalog/pg_trigger.h
index 55111ed864..2e3d233876 100644
--- a/src/include/catalog/pg_trigger.h
+++ b/src/include/catalog/pg_trigger.h
@@ -34,18 +34,25 @@
 CATALOG(pg_trigger,2620,TriggerRelationId)
 {
 	Oid			oid;			/* oid */
-	Oid			tgrelid;		/* relation trigger is attached to */
-	Oid			tgparentid;		/* OID of parent trigger, if any */
+	Oid			tgrelid BKI_LOOKUP(pg_class);	/* relation trigger is
+												 * attached to */
+	Oid			tgparentid BKI_LOOKUP_OPT(pg_trigger);	/* OID of parent
+														 * trigger, if any */
 	NameData	tgname;			/* trigger's name */
-	Oid			tgfoid;			/* OID of function to be called */
+	Oid			tgfoid BKI_LOOKUP(pg_proc); /* OID of function to be called */
 	int16		tgtype;			/* BEFORE/AFTER/INSTEAD, UPDATE/DELETE/INSERT,
 								 * ROW/STATEMENT; see below */
 	char		tgenabled;		/* trigger's firing configuration WRT
 								 * session_replication_role */
 	bool		tgisinternal;	/* trigger is system-generated */
-	Oid			tgconstrrelid;	/* constraint's FROM table, if any */
-	Oid			tgconstrindid;	/* constraint's supporting index, if any */
-	Oid			tgconstraint;	/* associated pg_constraint entry, if any */
+	Oid			tgconstrrelid BKI_LOOKUP_OPT(pg_class); /* constraint's FROM
+														 * table, if any */
+	Oid			tgconstrindid BKI_LOOKUP_OPT(pg_class); /* constraint's
+														 * supporting index, if
+														 * any */
+	Oid			tgconstraint BKI_LOOKUP_OPT(pg_constraint); /* associated
+															 * pg_constraint entry,
+															 * if any */
 	bool		tgdeferrable;	/* constraint trigger is deferrable */
 	bool		tginitdeferred; /* constraint trigger is deferred initially */
 	int16		tgnargs;		/* # of extra arguments in tgargs */
@@ -81,6 +88,8 @@ DECLARE_UNIQUE_INDEX(pg_trigger_tgrelid_tgname_index, 2701, on pg_trigger using
 DECLARE_UNIQUE_INDEX_PKEY(pg_trigger_oid_index, 2702, on pg_trigger using btree(oid oid_ops));
 #define TriggerOidIndexId  2702
 
+DECLARE_ARRAY_FOREIGN_KEY((tgrelid, tgattr), pg_attribute, (attrelid, attnum));
+
 #ifdef EXPOSE_TO_CLIENT_CODE
 
 /* Bits within tgtype */
diff --git a/src/include/catalog/pg_ts_config.h b/src/include/catalog/pg_ts_config.h
index 02ef1a1554..e705899b17 100644
--- a/src/include/catalog/pg_ts_config.h
+++ b/src/include/catalog/pg_ts_config.h
@@ -36,10 +36,10 @@ CATALOG(pg_ts_config,3602,TSConfigRelationId)
 	NameData	cfgname;
 
 	/* name space */
-	Oid			cfgnamespace BKI_DEFAULT(PGNSP);
+	Oid			cfgnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* owner */
-	Oid			cfgowner BKI_DEFAULT(PGUID);
+	Oid			cfgowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/* OID of parser */
 	Oid			cfgparser BKI_LOOKUP(pg_ts_parser);
diff --git a/src/include/catalog/pg_ts_dict.h b/src/include/catalog/pg_ts_dict.h
index bfe3378ff8..57f626e7b5 100644
--- a/src/include/catalog/pg_ts_dict.h
+++ b/src/include/catalog/pg_ts_dict.h
@@ -35,10 +35,10 @@ CATALOG(pg_ts_dict,3600,TSDictionaryRelationId)
 	NameData	dictname;
 
 	/* name space */
-	Oid			dictnamespace BKI_DEFAULT(PGNSP);
+	Oid			dictnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* owner */
-	Oid			dictowner BKI_DEFAULT(PGUID);
+	Oid			dictowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/* dictionary's template */
 	Oid			dicttemplate BKI_LOOKUP(pg_ts_template);
diff --git a/src/include/catalog/pg_ts_parser.h b/src/include/catalog/pg_ts_parser.h
index f9f22716fd..e0d705fd9a 100644
--- a/src/include/catalog/pg_ts_parser.h
+++ b/src/include/catalog/pg_ts_parser.h
@@ -34,7 +34,7 @@ CATALOG(pg_ts_parser,3601,TSParserRelationId)
 	NameData	prsname;
 
 	/* name space */
-	Oid			prsnamespace BKI_DEFAULT(PGNSP);
+	Oid			prsnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* init parsing session */
 	regproc		prsstart BKI_LOOKUP(pg_proc);
@@ -46,7 +46,7 @@ CATALOG(pg_ts_parser,3601,TSParserRelationId)
 	regproc		prsend BKI_LOOKUP(pg_proc);
 
 	/* return data for headline creation */
-	regproc		prsheadline BKI_LOOKUP(pg_proc);
+	regproc		prsheadline BKI_LOOKUP_OPT(pg_proc);
 
 	/* return descriptions of lexeme's types */
 	regproc		prslextype BKI_LOOKUP(pg_proc);
diff --git a/src/include/catalog/pg_ts_template.h b/src/include/catalog/pg_ts_template.h
index ae91922688..2ee1ae4e85 100644
--- a/src/include/catalog/pg_ts_template.h
+++ b/src/include/catalog/pg_ts_template.h
@@ -34,10 +34,10 @@ CATALOG(pg_ts_template,3764,TSTemplateRelationId)
 	NameData	tmplname;
 
 	/* name space */
-	Oid			tmplnamespace BKI_DEFAULT(PGNSP);
+	Oid			tmplnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* initialization method of dict (may be 0) */
-	regproc		tmplinit BKI_LOOKUP(pg_proc);
+	regproc		tmplinit BKI_LOOKUP_OPT(pg_proc);
 
 	/* base method of dictionary */
 	regproc		tmpllexize BKI_LOOKUP(pg_proc);
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 0d6981bc87..1ec8606703 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -41,10 +41,10 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati
 	NameData	typname;
 
 	/* OID of namespace containing this type */
-	Oid			typnamespace BKI_DEFAULT(PGNSP);
+	Oid			typnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
 
 	/* type owner */
-	Oid			typowner BKI_DEFAULT(PGUID);
+	Oid			typowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
 
 	/*
 	 * For a fixed-size type, typlen is the number of bytes we use to
@@ -98,7 +98,7 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati
 	char		typdelim BKI_DEFAULT(',');
 
 	/* associated pg_class OID if a composite type, else 0 */
-	Oid			typrelid BKI_DEFAULT(0) BKI_ARRAY_DEFAULT(0) BKI_LOOKUP(pg_class);
+	Oid			typrelid BKI_DEFAULT(0) BKI_ARRAY_DEFAULT(0) BKI_LOOKUP_OPT(pg_class);
 
 	/*
 	 * Type-specific subscripting handler.  If typsubscript is 0, it means
@@ -106,7 +106,7 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati
 	 * of the system deem types to be "true" array types only if their
 	 * typsubscript is array_subscript_handler.
 	 */
-	regproc		typsubscript BKI_DEFAULT(-) BKI_ARRAY_DEFAULT(array_subscript_handler) BKI_LOOKUP(pg_proc);
+	regproc		typsubscript BKI_DEFAULT(-) BKI_ARRAY_DEFAULT(array_subscript_handler) BKI_LOOKUP_OPT(pg_proc);
 
 	/*
 	 * If typelem is not 0 then it identifies another row in pg_type, defining
@@ -117,13 +117,13 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati
 	 * of the element type in this type; so DDL changes on the element type
 	 * might be restricted by the presence of this type.
 	 */
-	Oid			typelem BKI_DEFAULT(0) BKI_LOOKUP(pg_type);
+	Oid			typelem BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type);
 
 	/*
 	 * If there is a "true" array type having this type as element type,
 	 * typarray links to it.  Zero if no associated "true" array type.
 	 */
-	Oid			typarray BKI_DEFAULT(0) BKI_ARRAY_DEFAULT(0) BKI_LOOKUP(pg_type);
+	Oid			typarray BKI_DEFAULT(0) BKI_ARRAY_DEFAULT(0) BKI_LOOKUP_OPT(pg_type);
 
 	/*
 	 * I/O conversion procedures for the datatype.
@@ -134,19 +134,19 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati
 	regproc		typoutput BKI_ARRAY_DEFAULT(array_out) BKI_LOOKUP(pg_proc);
 
 	/* binary format (optional) */
-	regproc		typreceive BKI_ARRAY_DEFAULT(array_recv) BKI_LOOKUP(pg_proc);
-	regproc		typsend BKI_ARRAY_DEFAULT(array_send) BKI_LOOKUP(pg_proc);
+	regproc		typreceive BKI_ARRAY_DEFAULT(array_recv) BKI_LOOKUP_OPT(pg_proc);
+	regproc		typsend BKI_ARRAY_DEFAULT(array_send) BKI_LOOKUP_OPT(pg_proc);
 
 	/*
 	 * I/O functions for optional type modifiers.
 	 */
-	regproc		typmodin BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);
-	regproc		typmodout BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);
+	regproc		typmodin BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
+	regproc		typmodout BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
 
 	/*
 	 * Custom ANALYZE procedure for the datatype (0 selects the default).
 	 */
-	regproc		typanalyze BKI_DEFAULT(-) BKI_ARRAY_DEFAULT(array_typanalyze) BKI_LOOKUP(pg_proc);
+	regproc		typanalyze BKI_DEFAULT(-) BKI_ARRAY_DEFAULT(array_typanalyze) BKI_LOOKUP_OPT(pg_proc);
 
 	/* ----------------
 	 * typalign is the alignment required when storing a value of this
@@ -205,7 +205,7 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati
 	 * Domains use typbasetype to show the base (or domain) type that the
 	 * domain is based on.  Zero if the type is not a domain.
 	 */
-	Oid			typbasetype BKI_DEFAULT(0);
+	Oid			typbasetype BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type);
 
 	/*
 	 * Domains use typtypmod to record the typmod to be applied to their base
@@ -225,7 +225,7 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati
 	 * DEFAULT_COLLATION_OID) for collatable base types, possibly some other
 	 * OID for domains over collatable types
 	 */
-	Oid			typcollation BKI_DEFAULT(0) BKI_LOOKUP(pg_collation);
+	Oid			typcollation BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_collation);
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 
diff --git a/src/include/catalog/pg_user_mapping.h b/src/include/catalog/pg_user_mapping.h
index cabca048a9..d440c67da1 100644
--- a/src/include/catalog/pg_user_mapping.h
+++ b/src/include/catalog/pg_user_mapping.h
@@ -29,9 +29,11 @@ CATALOG(pg_user_mapping,1418,UserMappingRelationId)
 {
 	Oid			oid;			/* oid */
 
-	Oid			umuser;			/* Id of the user, InvalidOid if PUBLIC is
-								 * wanted */
-	Oid			umserver;		/* server of this mapping */
+	Oid			umuser BKI_LOOKUP_OPT(pg_authid);	/* Id of the user,
+													 * InvalidOid if PUBLIC is
+													 * wanted */
+	Oid			umserver BKI_LOOKUP(pg_foreign_server); /* server of this
+														 * mapping */
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	text		umoptions[1];	/* user mapping options */
diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out
index 4731dacfbf..bc24949616 100644
--- a/src/test/regress/expected/oidjoins.out
+++ b/src/test/regress/expected/oidjoins.out
@@ -1,1451 +1,266 @@
 --
--- This is created by pgsql/src/tools/findoidjoins/make_oidjoins_check
+-- Verify system catalog foreign key relationships
 --
-SELECT	ctid, aggfnoid
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggfnoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggfnoid);
- ctid | aggfnoid 
-------+----------
-(0 rows)
-
-SELECT	ctid, aggtransfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggtransfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggtransfn);
- ctid | aggtransfn 
-------+------------
-(0 rows)
-
-SELECT	ctid, aggfinalfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggfinalfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggfinalfn);
- ctid | aggfinalfn 
-------+------------
-(0 rows)
-
-SELECT	ctid, aggcombinefn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggcombinefn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggcombinefn);
- ctid | aggcombinefn 
-------+--------------
-(0 rows)
-
-SELECT	ctid, aggserialfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggserialfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggserialfn);
- ctid | aggserialfn 
-------+-------------
-(0 rows)
-
-SELECT	ctid, aggdeserialfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggdeserialfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggdeserialfn);
- ctid | aggdeserialfn 
-------+---------------
-(0 rows)
-
-SELECT	ctid, aggmtransfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggmtransfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggmtransfn);
- ctid | aggmtransfn 
-------+-------------
-(0 rows)
-
-SELECT	ctid, aggminvtransfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggminvtransfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggminvtransfn);
- ctid | aggminvtransfn 
-------+----------------
-(0 rows)
-
-SELECT	ctid, aggmfinalfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggmfinalfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggmfinalfn);
- ctid | aggmfinalfn 
-------+-------------
-(0 rows)
-
-SELECT	ctid, aggsortop
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggsortop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.aggsortop);
- ctid | aggsortop 
-------+-----------
-(0 rows)
-
-SELECT	ctid, aggtranstype
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggtranstype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggtranstype);
- ctid | aggtranstype 
-------+--------------
-(0 rows)
-
-SELECT	ctid, aggmtranstype
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggmtranstype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype);
- ctid | aggmtranstype 
-------+---------------
-(0 rows)
-
-SELECT	ctid, amhandler
-FROM	pg_catalog.pg_am fk
-WHERE	amhandler != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amhandler);
- ctid | amhandler 
-------+-----------
-(0 rows)
-
-SELECT	ctid, amopfamily
-FROM	pg_catalog.pg_amop fk
-WHERE	amopfamily != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amopfamily);
- ctid | amopfamily 
-------+------------
-(0 rows)
-
-SELECT	ctid, amoplefttype
-FROM	pg_catalog.pg_amop fk
-WHERE	amoplefttype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amoplefttype);
- ctid | amoplefttype 
-------+--------------
-(0 rows)
-
-SELECT	ctid, amoprighttype
-FROM	pg_catalog.pg_amop fk
-WHERE	amoprighttype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amoprighttype);
- ctid | amoprighttype 
-------+---------------
-(0 rows)
-
-SELECT	ctid, amopopr
-FROM	pg_catalog.pg_amop fk
-WHERE	amopopr != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.amopopr);
- ctid | amopopr 
-------+---------
-(0 rows)
-
-SELECT	ctid, amopmethod
-FROM	pg_catalog.pg_amop fk
-WHERE	amopmethod != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.amopmethod);
- ctid | amopmethod 
-------+------------
-(0 rows)
-
-SELECT	ctid, amopsortfamily
-FROM	pg_catalog.pg_amop fk
-WHERE	amopsortfamily != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amopsortfamily);
- ctid | amopsortfamily 
-------+----------------
-(0 rows)
-
-SELECT	ctid, amprocfamily
-FROM	pg_catalog.pg_amproc fk
-WHERE	amprocfamily != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amprocfamily);
- ctid | amprocfamily 
-------+--------------
-(0 rows)
-
-SELECT	ctid, amproclefttype
-FROM	pg_catalog.pg_amproc fk
-WHERE	amproclefttype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amproclefttype);
- ctid | amproclefttype 
-------+----------------
-(0 rows)
-
-SELECT	ctid, amprocrighttype
-FROM	pg_catalog.pg_amproc fk
-WHERE	amprocrighttype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amprocrighttype);
- ctid | amprocrighttype 
-------+-----------------
-(0 rows)
-
-SELECT	ctid, amproc
-FROM	pg_catalog.pg_amproc fk
-WHERE	amproc != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amproc);
- ctid | amproc 
-------+--------
-(0 rows)
-
-SELECT	ctid, adrelid
-FROM	pg_catalog.pg_attrdef fk
-WHERE	adrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.adrelid);
- ctid | adrelid 
-------+---------
-(0 rows)
-
-SELECT	ctid, attrelid
-FROM	pg_catalog.pg_attribute fk
-WHERE	attrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.attrelid);
- ctid | attrelid 
-------+----------
-(0 rows)
-
-SELECT	ctid, atttypid
-FROM	pg_catalog.pg_attribute fk
-WHERE	atttypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.atttypid);
- ctid | atttypid 
-------+----------
-(0 rows)
-
-SELECT	ctid, attcollation
-FROM	pg_catalog.pg_attribute fk
-WHERE	attcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.attcollation);
- ctid | attcollation 
-------+--------------
-(0 rows)
-
-SELECT	ctid, roleid
-FROM	pg_catalog.pg_auth_members fk
-WHERE	roleid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.roleid);
- ctid | roleid 
-------+--------
-(0 rows)
-
-SELECT	ctid, member
-FROM	pg_catalog.pg_auth_members fk
-WHERE	member != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.member);
- ctid | member 
-------+--------
-(0 rows)
-
-SELECT	ctid, grantor
-FROM	pg_catalog.pg_auth_members fk
-WHERE	grantor != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.grantor);
- ctid | grantor 
-------+---------
-(0 rows)
-
-SELECT	ctid, castsource
-FROM	pg_catalog.pg_cast fk
-WHERE	castsource != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.castsource);
- ctid | castsource 
-------+------------
-(0 rows)
-
-SELECT	ctid, casttarget
-FROM	pg_catalog.pg_cast fk
-WHERE	casttarget != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.casttarget);
- ctid | casttarget 
-------+------------
-(0 rows)
-
-SELECT	ctid, castfunc
-FROM	pg_catalog.pg_cast fk
-WHERE	castfunc != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.castfunc);
- ctid | castfunc 
-------+----------
-(0 rows)
-
-SELECT	ctid, relnamespace
-FROM	pg_catalog.pg_class fk
-WHERE	relnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.relnamespace);
- ctid | relnamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, reltype
-FROM	pg_catalog.pg_class fk
-WHERE	reltype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.reltype);
- ctid | reltype 
-------+---------
-(0 rows)
-
-SELECT	ctid, reloftype
-FROM	pg_catalog.pg_class fk
-WHERE	reloftype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.reloftype);
- ctid | reloftype 
-------+-----------
-(0 rows)
-
-SELECT	ctid, relowner
-FROM	pg_catalog.pg_class fk
-WHERE	relowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.relowner);
- ctid | relowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, relam
-FROM	pg_catalog.pg_class fk
-WHERE	relam != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.relam);
- ctid | relam 
-------+-------
-(0 rows)
-
-SELECT	ctid, reltablespace
-FROM	pg_catalog.pg_class fk
-WHERE	reltablespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_tablespace pk WHERE pk.oid = fk.reltablespace);
- ctid | reltablespace 
-------+---------------
-(0 rows)
-
-SELECT	ctid, reltoastrelid
-FROM	pg_catalog.pg_class fk
-WHERE	reltoastrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.reltoastrelid);
- ctid | reltoastrelid 
-------+---------------
-(0 rows)
-
-SELECT	ctid, collnamespace
-FROM	pg_catalog.pg_collation fk
-WHERE	collnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.collnamespace);
- ctid | collnamespace 
-------+---------------
-(0 rows)
-
-SELECT	ctid, collowner
-FROM	pg_catalog.pg_collation fk
-WHERE	collowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.collowner);
- ctid | collowner 
-------+-----------
-(0 rows)
-
-SELECT	ctid, connamespace
-FROM	pg_catalog.pg_constraint fk
-WHERE	connamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.connamespace);
- ctid | connamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, conrelid
-FROM	pg_catalog.pg_constraint fk
-WHERE	conrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.conrelid);
- ctid | conrelid 
-------+----------
-(0 rows)
-
-SELECT	ctid, contypid
-FROM	pg_catalog.pg_constraint fk
-WHERE	contypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.contypid);
- ctid | contypid 
-------+----------
-(0 rows)
-
-SELECT	ctid, conindid
-FROM	pg_catalog.pg_constraint fk
-WHERE	conindid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.conindid);
- ctid | conindid 
-------+----------
-(0 rows)
-
-SELECT	ctid, conparentid
-FROM	pg_catalog.pg_constraint fk
-WHERE	conparentid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_constraint pk WHERE pk.oid = fk.conparentid);
- ctid | conparentid 
-------+-------------
-(0 rows)
-
-SELECT	ctid, confrelid
-FROM	pg_catalog.pg_constraint fk
-WHERE	confrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.confrelid);
- ctid | confrelid 
-------+-----------
-(0 rows)
-
-SELECT	ctid, connamespace
-FROM	pg_catalog.pg_conversion fk
-WHERE	connamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.connamespace);
- ctid | connamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, conowner
-FROM	pg_catalog.pg_conversion fk
-WHERE	conowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.conowner);
- ctid | conowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, conproc
-FROM	pg_catalog.pg_conversion fk
-WHERE	conproc != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.conproc);
- ctid | conproc 
-------+---------
-(0 rows)
-
-SELECT	ctid, datdba
-FROM	pg_catalog.pg_database fk
-WHERE	datdba != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.datdba);
- ctid | datdba 
-------+--------
-(0 rows)
-
-SELECT	ctid, dattablespace
-FROM	pg_catalog.pg_database fk
-WHERE	dattablespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_tablespace pk WHERE pk.oid = fk.dattablespace);
- ctid | dattablespace 
-------+---------------
-(0 rows)
-
-SELECT	ctid, setdatabase
-FROM	pg_catalog.pg_db_role_setting fk
-WHERE	setdatabase != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_database pk WHERE pk.oid = fk.setdatabase);
- ctid | setdatabase 
-------+-------------
-(0 rows)
-
-SELECT	ctid, classid
-FROM	pg_catalog.pg_depend fk
-WHERE	classid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classid);
- ctid | classid 
-------+---------
-(0 rows)
-
-SELECT	ctid, refclassid
-FROM	pg_catalog.pg_depend fk
-WHERE	refclassid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.refclassid);
- ctid | refclassid 
-------+------------
-(0 rows)
-
-SELECT	ctid, classoid
-FROM	pg_catalog.pg_description fk
-WHERE	classoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid);
- ctid | classoid 
-------+----------
-(0 rows)
-
-SELECT	ctid, enumtypid
-FROM	pg_catalog.pg_enum fk
-WHERE	enumtypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.enumtypid);
- ctid | enumtypid 
-------+-----------
-(0 rows)
-
-SELECT	ctid, extowner
-FROM	pg_catalog.pg_extension fk
-WHERE	extowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.extowner);
- ctid | extowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, extnamespace
-FROM	pg_catalog.pg_extension fk
-WHERE	extnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.extnamespace);
- ctid | extnamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, fdwowner
-FROM	pg_catalog.pg_foreign_data_wrapper fk
-WHERE	fdwowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.fdwowner);
- ctid | fdwowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, srvowner
-FROM	pg_catalog.pg_foreign_server fk
-WHERE	srvowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.srvowner);
- ctid | srvowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, srvfdw
-FROM	pg_catalog.pg_foreign_server fk
-WHERE	srvfdw != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_foreign_data_wrapper pk WHERE pk.oid = fk.srvfdw);
- ctid | srvfdw 
-------+--------
-(0 rows)
-
-SELECT	ctid, indexrelid
-FROM	pg_catalog.pg_index fk
-WHERE	indexrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.indexrelid);
- ctid | indexrelid 
-------+------------
-(0 rows)
-
-SELECT	ctid, indrelid
-FROM	pg_catalog.pg_index fk
-WHERE	indrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.indrelid);
- ctid | indrelid 
-------+----------
-(0 rows)
-
-SELECT	ctid, inhrelid
-FROM	pg_catalog.pg_inherits fk
-WHERE	inhrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.inhrelid);
- ctid | inhrelid 
-------+----------
-(0 rows)
-
-SELECT	ctid, inhparent
-FROM	pg_catalog.pg_inherits fk
-WHERE	inhparent != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.inhparent);
- ctid | inhparent 
-------+-----------
-(0 rows)
-
-SELECT	ctid, classoid
-FROM	pg_catalog.pg_init_privs fk
-WHERE	classoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid);
- ctid | classoid 
-------+----------
-(0 rows)
-
-SELECT	ctid, lanowner
-FROM	pg_catalog.pg_language fk
-WHERE	lanowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.lanowner);
- ctid | lanowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, lanplcallfoid
-FROM	pg_catalog.pg_language fk
-WHERE	lanplcallfoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.lanplcallfoid);
- ctid | lanplcallfoid 
-------+---------------
-(0 rows)
-
-SELECT	ctid, laninline
-FROM	pg_catalog.pg_language fk
-WHERE	laninline != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.laninline);
- ctid | laninline 
-------+-----------
-(0 rows)
-
-SELECT	ctid, lanvalidator
-FROM	pg_catalog.pg_language fk
-WHERE	lanvalidator != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.lanvalidator);
- ctid | lanvalidator 
-------+--------------
-(0 rows)
-
-SELECT	ctid, loid
-FROM	pg_catalog.pg_largeobject fk
-WHERE	loid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_largeobject_metadata pk WHERE pk.oid = fk.loid);
- ctid | loid 
-------+------
-(0 rows)
-
-SELECT	ctid, lomowner
-FROM	pg_catalog.pg_largeobject_metadata fk
-WHERE	lomowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.lomowner);
- ctid | lomowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, nspowner
-FROM	pg_catalog.pg_namespace fk
-WHERE	nspowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.nspowner);
- ctid | nspowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, opcmethod
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcmethod != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opcmethod);
- ctid | opcmethod 
-------+-----------
-(0 rows)
-
-SELECT	ctid, opcnamespace
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.opcnamespace);
- ctid | opcnamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, opcowner
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.opcowner);
- ctid | opcowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, opcfamily
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcfamily != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.opcfamily);
- ctid | opcfamily 
-------+-----------
-(0 rows)
-
-SELECT	ctid, opcintype
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcintype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.opcintype);
- ctid | opcintype 
-------+-----------
-(0 rows)
-
-SELECT	ctid, opckeytype
-FROM	pg_catalog.pg_opclass fk
-WHERE	opckeytype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.opckeytype);
- ctid | opckeytype 
-------+------------
-(0 rows)
-
-SELECT	ctid, oprnamespace
-FROM	pg_catalog.pg_operator fk
-WHERE	oprnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.oprnamespace);
- ctid | oprnamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, oprowner
-FROM	pg_catalog.pg_operator fk
-WHERE	oprowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.oprowner);
- ctid | oprowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, oprleft
-FROM	pg_catalog.pg_operator fk
-WHERE	oprleft != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.oprleft);
- ctid | oprleft 
-------+---------
-(0 rows)
-
-SELECT	ctid, oprright
-FROM	pg_catalog.pg_operator fk
-WHERE	oprright != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.oprright);
- ctid | oprright 
-------+----------
-(0 rows)
-
-SELECT	ctid, oprresult
-FROM	pg_catalog.pg_operator fk
-WHERE	oprresult != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.oprresult);
- ctid | oprresult 
-------+-----------
-(0 rows)
-
-SELECT	ctid, oprcom
-FROM	pg_catalog.pg_operator fk
-WHERE	oprcom != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprcom);
- ctid | oprcom 
-------+--------
-(0 rows)
-
-SELECT	ctid, oprnegate
-FROM	pg_catalog.pg_operator fk
-WHERE	oprnegate != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprnegate);
- ctid | oprnegate 
-------+-----------
-(0 rows)
-
-SELECT	ctid, oprcode
-FROM	pg_catalog.pg_operator fk
-WHERE	oprcode != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprcode);
- ctid | oprcode 
-------+---------
-(0 rows)
-
-SELECT	ctid, oprrest
-FROM	pg_catalog.pg_operator fk
-WHERE	oprrest != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprrest);
- ctid | oprrest 
-------+---------
-(0 rows)
-
-SELECT	ctid, oprjoin
-FROM	pg_catalog.pg_operator fk
-WHERE	oprjoin != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprjoin);
- ctid | oprjoin 
-------+---------
-(0 rows)
-
-SELECT	ctid, opfmethod
-FROM	pg_catalog.pg_opfamily fk
-WHERE	opfmethod != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opfmethod);
- ctid | opfmethod 
-------+-----------
-(0 rows)
-
-SELECT	ctid, opfnamespace
-FROM	pg_catalog.pg_opfamily fk
-WHERE	opfnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.opfnamespace);
- ctid | opfnamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, opfowner
-FROM	pg_catalog.pg_opfamily fk
-WHERE	opfowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.opfowner);
- ctid | opfowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, partrelid
-FROM	pg_catalog.pg_partitioned_table fk
-WHERE	partrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.partrelid);
- ctid | partrelid 
-------+-----------
-(0 rows)
-
-SELECT	ctid, partdefid
-FROM	pg_catalog.pg_partitioned_table fk
-WHERE	partdefid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.partdefid);
- ctid | partdefid 
-------+-----------
-(0 rows)
-
-SELECT	ctid, polrelid
-FROM	pg_catalog.pg_policy fk
-WHERE	polrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.polrelid);
- ctid | polrelid 
-------+----------
-(0 rows)
-
-SELECT	ctid, pronamespace
-FROM	pg_catalog.pg_proc fk
-WHERE	pronamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.pronamespace);
- ctid | pronamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, proowner
-FROM	pg_catalog.pg_proc fk
-WHERE	proowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.proowner);
- ctid | proowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, prolang
-FROM	pg_catalog.pg_proc fk
-WHERE	prolang != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_language pk WHERE pk.oid = fk.prolang);
- ctid | prolang 
-------+---------
-(0 rows)
-
-SELECT	ctid, provariadic
-FROM	pg_catalog.pg_proc fk
-WHERE	provariadic != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.provariadic);
- ctid | provariadic 
-------+-------------
-(0 rows)
-
-SELECT	ctid, prosupport
-FROM	pg_catalog.pg_proc fk
-WHERE	prosupport != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prosupport);
- ctid | prosupport 
-------+------------
-(0 rows)
-
-SELECT	ctid, prorettype
-FROM	pg_catalog.pg_proc fk
-WHERE	prorettype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.prorettype);
- ctid | prorettype 
-------+------------
-(0 rows)
-
-SELECT	ctid, rngtypid
-FROM	pg_catalog.pg_range fk
-WHERE	rngtypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.rngtypid);
- ctid | rngtypid 
-------+----------
-(0 rows)
-
-SELECT	ctid, rngsubtype
-FROM	pg_catalog.pg_range fk
-WHERE	rngsubtype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.rngsubtype);
- ctid | rngsubtype 
-------+------------
-(0 rows)
-
-SELECT	ctid, rngcollation
-FROM	pg_catalog.pg_range fk
-WHERE	rngcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.rngcollation);
- ctid | rngcollation 
-------+--------------
-(0 rows)
-
-SELECT	ctid, rngsubopc
-FROM	pg_catalog.pg_range fk
-WHERE	rngsubopc != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.rngsubopc);
- ctid | rngsubopc 
-------+-----------
-(0 rows)
-
-SELECT	ctid, rngcanonical
-FROM	pg_catalog.pg_range fk
-WHERE	rngcanonical != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.rngcanonical);
- ctid | rngcanonical 
-------+--------------
-(0 rows)
-
-SELECT	ctid, rngsubdiff
-FROM	pg_catalog.pg_range fk
-WHERE	rngsubdiff != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.rngsubdiff);
- ctid | rngsubdiff 
-------+------------
-(0 rows)
-
-SELECT	ctid, ev_class
-FROM	pg_catalog.pg_rewrite fk
-WHERE	ev_class != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.ev_class);
- ctid | ev_class 
-------+----------
-(0 rows)
-
-SELECT	ctid, seqrelid
-FROM	pg_catalog.pg_sequence fk
-WHERE	seqrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.seqrelid);
- ctid | seqrelid 
-------+----------
-(0 rows)
-
-SELECT	ctid, seqtypid
-FROM	pg_catalog.pg_sequence fk
-WHERE	seqtypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.seqtypid);
- ctid | seqtypid 
-------+----------
-(0 rows)
-
-SELECT	ctid, refclassid
-FROM	pg_catalog.pg_shdepend fk
-WHERE	refclassid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.refclassid);
- ctid | refclassid 
-------+------------
-(0 rows)
-
-SELECT	ctid, classoid
-FROM	pg_catalog.pg_shdescription fk
-WHERE	classoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid);
- ctid | classoid 
-------+----------
-(0 rows)
-
-SELECT	ctid, starelid
-FROM	pg_catalog.pg_statistic fk
-WHERE	starelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.starelid);
- ctid | starelid 
-------+----------
-(0 rows)
-
-SELECT	ctid, staop1
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop1 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop1);
- ctid | staop1 
-------+--------
-(0 rows)
-
-SELECT	ctid, staop2
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop2 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop2);
- ctid | staop2 
-------+--------
-(0 rows)
-
-SELECT	ctid, staop3
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop3 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop3);
- ctid | staop3 
-------+--------
-(0 rows)
-
-SELECT	ctid, staop4
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop4 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop4);
- ctid | staop4 
-------+--------
-(0 rows)
-
-SELECT	ctid, staop5
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop5 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop5);
- ctid | staop5 
-------+--------
-(0 rows)
-
-SELECT	ctid, stacoll1
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll1 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll1);
- ctid | stacoll1 
-------+----------
-(0 rows)
-
-SELECT	ctid, stacoll2
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll2 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll2);
- ctid | stacoll2 
-------+----------
-(0 rows)
-
-SELECT	ctid, stacoll3
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll3 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll3);
- ctid | stacoll3 
-------+----------
-(0 rows)
-
-SELECT	ctid, stacoll4
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll4 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll4);
- ctid | stacoll4 
-------+----------
-(0 rows)
-
-SELECT	ctid, stacoll5
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll5 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll5);
- ctid | stacoll5 
-------+----------
-(0 rows)
-
-SELECT	ctid, stxrelid
-FROM	pg_catalog.pg_statistic_ext fk
-WHERE	stxrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.stxrelid);
- ctid | stxrelid 
-------+----------
-(0 rows)
-
-SELECT	ctid, stxnamespace
-FROM	pg_catalog.pg_statistic_ext fk
-WHERE	stxnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.stxnamespace);
- ctid | stxnamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, stxowner
-FROM	pg_catalog.pg_statistic_ext fk
-WHERE	stxowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.stxowner);
- ctid | stxowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, stxoid
-FROM	pg_catalog.pg_statistic_ext_data fk
-WHERE	stxoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_statistic_ext pk WHERE pk.oid = fk.stxoid);
- ctid | stxoid 
-------+--------
-(0 rows)
-
-SELECT	ctid, spcowner
-FROM	pg_catalog.pg_tablespace fk
-WHERE	spcowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.spcowner);
- ctid | spcowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, trftype
-FROM	pg_catalog.pg_transform fk
-WHERE	trftype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.trftype);
- ctid | trftype 
-------+---------
-(0 rows)
-
-SELECT	ctid, trflang
-FROM	pg_catalog.pg_transform fk
-WHERE	trflang != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_language pk WHERE pk.oid = fk.trflang);
- ctid | trflang 
-------+---------
-(0 rows)
-
-SELECT	ctid, trffromsql
-FROM	pg_catalog.pg_transform fk
-WHERE	trffromsql != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.trffromsql);
- ctid | trffromsql 
-------+------------
-(0 rows)
-
-SELECT	ctid, trftosql
-FROM	pg_catalog.pg_transform fk
-WHERE	trftosql != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.trftosql);
- ctid | trftosql 
-------+----------
-(0 rows)
-
-SELECT	ctid, tgrelid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.tgrelid);
- ctid | tgrelid 
-------+---------
-(0 rows)
-
-SELECT	ctid, tgparentid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgparentid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_trigger pk WHERE pk.oid = fk.tgparentid);
- ctid | tgparentid 
-------+------------
-(0 rows)
-
-SELECT	ctid, tgfoid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgfoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.tgfoid);
- ctid | tgfoid 
-------+--------
-(0 rows)
-
-SELECT	ctid, tgconstrrelid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgconstrrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.tgconstrrelid);
- ctid | tgconstrrelid 
-------+---------------
-(0 rows)
-
-SELECT	ctid, tgconstrindid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgconstrindid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.tgconstrindid);
- ctid | tgconstrindid 
-------+---------------
-(0 rows)
-
-SELECT	ctid, tgconstraint
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgconstraint != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_constraint pk WHERE pk.oid = fk.tgconstraint);
- ctid | tgconstraint 
-------+--------------
-(0 rows)
-
-SELECT	ctid, cfgnamespace
-FROM	pg_catalog.pg_ts_config fk
-WHERE	cfgnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.cfgnamespace);
- ctid | cfgnamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, cfgowner
-FROM	pg_catalog.pg_ts_config fk
-WHERE	cfgowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.cfgowner);
- ctid | cfgowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, cfgparser
-FROM	pg_catalog.pg_ts_config fk
-WHERE	cfgparser != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_parser pk WHERE pk.oid = fk.cfgparser);
- ctid | cfgparser 
-------+-----------
-(0 rows)
-
-SELECT	ctid, mapcfg
-FROM	pg_catalog.pg_ts_config_map fk
-WHERE	mapcfg != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_config pk WHERE pk.oid = fk.mapcfg);
- ctid | mapcfg 
-------+--------
-(0 rows)
-
-SELECT	ctid, mapdict
-FROM	pg_catalog.pg_ts_config_map fk
-WHERE	mapdict != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_dict pk WHERE pk.oid = fk.mapdict);
- ctid | mapdict 
-------+---------
-(0 rows)
-
-SELECT	ctid, dictnamespace
-FROM	pg_catalog.pg_ts_dict fk
-WHERE	dictnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.dictnamespace);
- ctid | dictnamespace 
-------+---------------
-(0 rows)
-
-SELECT	ctid, dictowner
-FROM	pg_catalog.pg_ts_dict fk
-WHERE	dictowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.dictowner);
- ctid | dictowner 
-------+-----------
-(0 rows)
-
-SELECT	ctid, dicttemplate
-FROM	pg_catalog.pg_ts_dict fk
-WHERE	dicttemplate != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_template pk WHERE pk.oid = fk.dicttemplate);
- ctid | dicttemplate 
-------+--------------
-(0 rows)
-
-SELECT	ctid, prsnamespace
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prsnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.prsnamespace);
- ctid | prsnamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, prsstart
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prsstart != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prsstart);
- ctid | prsstart 
-------+----------
-(0 rows)
-
-SELECT	ctid, prstoken
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prstoken != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prstoken);
- ctid | prstoken 
-------+----------
-(0 rows)
-
-SELECT	ctid, prsend
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prsend != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prsend);
- ctid | prsend 
-------+--------
-(0 rows)
-
-SELECT	ctid, prsheadline
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prsheadline != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prsheadline);
- ctid | prsheadline 
-------+-------------
-(0 rows)
-
-SELECT	ctid, prslextype
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prslextype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prslextype);
- ctid | prslextype 
-------+------------
-(0 rows)
-
-SELECT	ctid, tmplnamespace
-FROM	pg_catalog.pg_ts_template fk
-WHERE	tmplnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.tmplnamespace);
- ctid | tmplnamespace 
-------+---------------
-(0 rows)
-
-SELECT	ctid, tmplinit
-FROM	pg_catalog.pg_ts_template fk
-WHERE	tmplinit != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.tmplinit);
- ctid | tmplinit 
-------+----------
-(0 rows)
-
-SELECT	ctid, tmpllexize
-FROM	pg_catalog.pg_ts_template fk
-WHERE	tmpllexize != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.tmpllexize);
- ctid | tmpllexize 
-------+------------
-(0 rows)
-
-SELECT	ctid, typnamespace
-FROM	pg_catalog.pg_type fk
-WHERE	typnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.typnamespace);
- ctid | typnamespace 
-------+--------------
-(0 rows)
-
-SELECT	ctid, typowner
-FROM	pg_catalog.pg_type fk
-WHERE	typowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.typowner);
- ctid | typowner 
-------+----------
-(0 rows)
-
-SELECT	ctid, typrelid
-FROM	pg_catalog.pg_type fk
-WHERE	typrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.typrelid);
- ctid | typrelid 
-------+----------
-(0 rows)
-
-SELECT	ctid, typelem
-FROM	pg_catalog.pg_type fk
-WHERE	typelem != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typelem);
- ctid | typelem 
-------+---------
-(0 rows)
-
-SELECT	ctid, typarray
-FROM	pg_catalog.pg_type fk
-WHERE	typarray != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typarray);
- ctid | typarray 
-------+----------
-(0 rows)
-
-SELECT	ctid, typinput
-FROM	pg_catalog.pg_type fk
-WHERE	typinput != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typinput);
- ctid | typinput 
-------+----------
-(0 rows)
-
-SELECT	ctid, typoutput
-FROM	pg_catalog.pg_type fk
-WHERE	typoutput != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typoutput);
- ctid | typoutput 
-------+-----------
-(0 rows)
-
-SELECT	ctid, typreceive
-FROM	pg_catalog.pg_type fk
-WHERE	typreceive != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typreceive);
- ctid | typreceive 
-------+------------
-(0 rows)
-
-SELECT	ctid, typsend
-FROM	pg_catalog.pg_type fk
-WHERE	typsend != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typsend);
- ctid | typsend 
-------+---------
-(0 rows)
-
-SELECT	ctid, typmodin
-FROM	pg_catalog.pg_type fk
-WHERE	typmodin != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typmodin);
- ctid | typmodin 
-------+----------
-(0 rows)
-
-SELECT	ctid, typmodout
-FROM	pg_catalog.pg_type fk
-WHERE	typmodout != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typmodout);
- ctid | typmodout 
-------+-----------
-(0 rows)
-
-SELECT	ctid, typanalyze
-FROM	pg_catalog.pg_type fk
-WHERE	typanalyze != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typanalyze);
- ctid | typanalyze 
-------+------------
-(0 rows)
-
-SELECT	ctid, typbasetype
-FROM	pg_catalog.pg_type fk
-WHERE	typbasetype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typbasetype);
- ctid | typbasetype 
-------+-------------
-(0 rows)
-
-SELECT	ctid, typcollation
-FROM	pg_catalog.pg_type fk
-WHERE	typcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.typcollation);
- ctid | typcollation 
-------+--------------
-(0 rows)
-
-SELECT	ctid, conpfeqop
-FROM	(SELECT ctid, unnest(conpfeqop) AS conpfeqop FROM pg_catalog.pg_constraint) fk
-WHERE	conpfeqop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conpfeqop);
- ctid | conpfeqop 
-------+-----------
-(0 rows)
-
-SELECT	ctid, conppeqop
-FROM	(SELECT ctid, unnest(conppeqop) AS conppeqop FROM pg_catalog.pg_constraint) fk
-WHERE	conppeqop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conppeqop);
- ctid | conppeqop 
-------+-----------
-(0 rows)
-
-SELECT	ctid, conffeqop
-FROM	(SELECT ctid, unnest(conffeqop) AS conffeqop FROM pg_catalog.pg_constraint) fk
-WHERE	conffeqop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conffeqop);
- ctid | conffeqop 
-------+-----------
-(0 rows)
-
-SELECT	ctid, conexclop
-FROM	(SELECT ctid, unnest(conexclop) AS conexclop FROM pg_catalog.pg_constraint) fk
-WHERE	conexclop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conexclop);
- ctid | conexclop 
-------+-----------
-(0 rows)
-
-SELECT	ctid, indcollation
-FROM	(SELECT ctid, unnest(indcollation) AS indcollation FROM pg_catalog.pg_index) fk
-WHERE	indcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.indcollation);
- ctid | indcollation 
-------+--------------
-(0 rows)
-
-SELECT	ctid, indclass
-FROM	(SELECT ctid, unnest(indclass) AS indclass FROM pg_catalog.pg_index) fk
-WHERE	indclass != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.indclass);
- ctid | indclass 
-------+----------
-(0 rows)
-
-SELECT	ctid, partclass
-FROM	(SELECT ctid, unnest(partclass) AS partclass FROM pg_catalog.pg_partitioned_table) fk
-WHERE	partclass != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.partclass);
- ctid | partclass 
-------+-----------
-(0 rows)
-
-SELECT	ctid, partcollation
-FROM	(SELECT ctid, unnest(partcollation) AS partcollation FROM pg_catalog.pg_partitioned_table) fk
-WHERE	partcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.partcollation);
- ctid | partcollation 
-------+---------------
-(0 rows)
-
-SELECT	ctid, proargtypes
-FROM	(SELECT ctid, unnest(proargtypes) AS proargtypes FROM pg_catalog.pg_proc) fk
-WHERE	proargtypes != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.proargtypes);
- ctid | proargtypes 
-------+-------------
-(0 rows)
-
-SELECT	ctid, proallargtypes
-FROM	(SELECT ctid, unnest(proallargtypes) AS proallargtypes FROM pg_catalog.pg_proc) fk
-WHERE	proallargtypes != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.proallargtypes);
- ctid | proallargtypes 
-------+----------------
-(0 rows)
-
+DO $doblock$
+declare
+  fk record;
+  nkeys integer;
+  cmd text;
+  err record;
+begin
+  for fk in select * from pg_get_catalog_foreign_keys()
+  loop
+    raise notice 'checking % % => % %',
+      fk.fktable, fk.fkcols, fk.pktable, fk.pkcols;
+    nkeys := array_length(fk.fkcols, 1);
+    cmd := 'SELECT ctid';
+    for i in 1 .. nkeys loop
+      cmd := cmd || ', ' || quote_ident(fk.fkcols[i]);
+    end loop;
+    if fk.is_array then
+      cmd := cmd || ' FROM (SELECT ctid';
+      for i in 1 .. nkeys-1 loop
+        cmd := cmd || ', ' || quote_ident(fk.fkcols[i]);
+      end loop;
+      cmd := cmd || ', unnest(' || quote_ident(fk.fkcols[nkeys]);
+      cmd := cmd || ') as ' || quote_ident(fk.fkcols[nkeys]);
+      cmd := cmd || ' FROM ' || fk.fktable::text || ') fk WHERE ';
+    else
+      cmd := cmd || ' FROM ' || fk.fktable::text || ' fk WHERE ';
+    end if;
+    if fk.is_opt then
+      for i in 1 .. nkeys loop
+        cmd := cmd || quote_ident(fk.fkcols[i]) || ' != 0 AND ';
+      end loop;
+    end if;
+    cmd := cmd || 'NOT EXISTS(SELECT 1 FROM ' || fk.pktable::text || ' pk WHERE ';
+    for i in 1 .. nkeys loop
+      if i > 1 then cmd := cmd || ' AND '; end if;
+      cmd := cmd || 'pk.' || quote_ident(fk.pkcols[i]);
+      cmd := cmd || ' = fk.' || quote_ident(fk.fkcols[i]);
+    end loop;
+    cmd := cmd || ')';
+    -- raise notice 'cmd = %', cmd;
+    for err in execute cmd loop
+      raise notice 'FK VIOLATION IN %(%): %', fk.fktable, fk.fkcols, err;
+    end loop;
+  end loop;
+end
+$doblock$;
+NOTICE:  checking pg_proc {pronamespace} => pg_namespace {oid}
+NOTICE:  checking pg_proc {proowner} => pg_authid {oid}
+NOTICE:  checking pg_proc {prolang} => pg_language {oid}
+NOTICE:  checking pg_proc {provariadic} => pg_type {oid}
+NOTICE:  checking pg_proc {prosupport} => pg_proc {oid}
+NOTICE:  checking pg_proc {prorettype} => pg_type {oid}
+NOTICE:  checking pg_proc {proargtypes} => pg_type {oid}
+NOTICE:  checking pg_proc {proallargtypes} => pg_type {oid}
+NOTICE:  checking pg_proc {protrftypes} => pg_type {oid}
+NOTICE:  checking pg_type {typnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_type {typowner} => pg_authid {oid}
+NOTICE:  checking pg_type {typrelid} => pg_class {oid}
+NOTICE:  checking pg_type {typsubscript} => pg_proc {oid}
+NOTICE:  checking pg_type {typelem} => pg_type {oid}
+NOTICE:  checking pg_type {typarray} => pg_type {oid}
+NOTICE:  checking pg_type {typinput} => pg_proc {oid}
+NOTICE:  checking pg_type {typoutput} => pg_proc {oid}
+NOTICE:  checking pg_type {typreceive} => pg_proc {oid}
+NOTICE:  checking pg_type {typsend} => pg_proc {oid}
+NOTICE:  checking pg_type {typmodin} => pg_proc {oid}
+NOTICE:  checking pg_type {typmodout} => pg_proc {oid}
+NOTICE:  checking pg_type {typanalyze} => pg_proc {oid}
+NOTICE:  checking pg_type {typbasetype} => pg_type {oid}
+NOTICE:  checking pg_type {typcollation} => pg_collation {oid}
+NOTICE:  checking pg_attribute {attrelid} => pg_class {oid}
+NOTICE:  checking pg_attribute {atttypid} => pg_type {oid}
+NOTICE:  checking pg_attribute {attcollation} => pg_collation {oid}
+NOTICE:  checking pg_class {relnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_class {reltype} => pg_type {oid}
+NOTICE:  checking pg_class {reloftype} => pg_type {oid}
+NOTICE:  checking pg_class {relowner} => pg_authid {oid}
+NOTICE:  checking pg_class {relam} => pg_am {oid}
+NOTICE:  checking pg_class {reltablespace} => pg_tablespace {oid}
+NOTICE:  checking pg_class {reltoastrelid} => pg_class {oid}
+NOTICE:  checking pg_class {relrewrite} => pg_class {oid}
+NOTICE:  checking pg_attrdef {adrelid} => pg_class {oid}
+NOTICE:  checking pg_attrdef {adrelid,adnum} => pg_attribute {attrelid,attnum}
+NOTICE:  checking pg_constraint {connamespace} => pg_namespace {oid}
+NOTICE:  checking pg_constraint {conrelid} => pg_class {oid}
+NOTICE:  checking pg_constraint {contypid} => pg_type {oid}
+NOTICE:  checking pg_constraint {conindid} => pg_class {oid}
+NOTICE:  checking pg_constraint {conparentid} => pg_constraint {oid}
+NOTICE:  checking pg_constraint {confrelid} => pg_class {oid}
+NOTICE:  checking pg_constraint {conpfeqop} => pg_operator {oid}
+NOTICE:  checking pg_constraint {conppeqop} => pg_operator {oid}
+NOTICE:  checking pg_constraint {conffeqop} => pg_operator {oid}
+NOTICE:  checking pg_constraint {conexclop} => pg_operator {oid}
+NOTICE:  checking pg_constraint {conrelid,conkey} => pg_attribute {attrelid,attnum}
+NOTICE:  checking pg_constraint {confrelid,confkey} => pg_attribute {attrelid,attnum}
+NOTICE:  checking pg_inherits {inhrelid} => pg_class {oid}
+NOTICE:  checking pg_inherits {inhparent} => pg_class {oid}
+NOTICE:  checking pg_index {indexrelid} => pg_class {oid}
+NOTICE:  checking pg_index {indrelid} => pg_class {oid}
+NOTICE:  checking pg_index {indcollation} => pg_collation {oid}
+NOTICE:  checking pg_index {indclass} => pg_opclass {oid}
+NOTICE:  checking pg_index {indrelid,indkey} => pg_attribute {attrelid,attnum}
+NOTICE:  checking pg_operator {oprnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_operator {oprowner} => pg_authid {oid}
+NOTICE:  checking pg_operator {oprleft} => pg_type {oid}
+NOTICE:  checking pg_operator {oprright} => pg_type {oid}
+NOTICE:  checking pg_operator {oprresult} => pg_type {oid}
+NOTICE:  checking pg_operator {oprcom} => pg_operator {oid}
+NOTICE:  checking pg_operator {oprnegate} => pg_operator {oid}
+NOTICE:  checking pg_operator {oprcode} => pg_proc {oid}
+NOTICE:  checking pg_operator {oprrest} => pg_proc {oid}
+NOTICE:  checking pg_operator {oprjoin} => pg_proc {oid}
+NOTICE:  checking pg_opfamily {opfmethod} => pg_am {oid}
+NOTICE:  checking pg_opfamily {opfnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_opfamily {opfowner} => pg_authid {oid}
+NOTICE:  checking pg_opclass {opcmethod} => pg_am {oid}
+NOTICE:  checking pg_opclass {opcnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_opclass {opcowner} => pg_authid {oid}
+NOTICE:  checking pg_opclass {opcfamily} => pg_opfamily {oid}
+NOTICE:  checking pg_opclass {opcintype} => pg_type {oid}
+NOTICE:  checking pg_opclass {opckeytype} => pg_type {oid}
+NOTICE:  checking pg_am {amhandler} => pg_proc {oid}
+NOTICE:  checking pg_amop {amopfamily} => pg_opfamily {oid}
+NOTICE:  checking pg_amop {amoplefttype} => pg_type {oid}
+NOTICE:  checking pg_amop {amoprighttype} => pg_type {oid}
+NOTICE:  checking pg_amop {amopopr} => pg_operator {oid}
+NOTICE:  checking pg_amop {amopmethod} => pg_am {oid}
+NOTICE:  checking pg_amop {amopsortfamily} => pg_opfamily {oid}
+NOTICE:  checking pg_amproc {amprocfamily} => pg_opfamily {oid}
+NOTICE:  checking pg_amproc {amproclefttype} => pg_type {oid}
+NOTICE:  checking pg_amproc {amprocrighttype} => pg_type {oid}
+NOTICE:  checking pg_amproc {amproc} => pg_proc {oid}
+NOTICE:  checking pg_language {lanowner} => pg_authid {oid}
+NOTICE:  checking pg_language {lanplcallfoid} => pg_proc {oid}
+NOTICE:  checking pg_language {laninline} => pg_proc {oid}
+NOTICE:  checking pg_language {lanvalidator} => pg_proc {oid}
+NOTICE:  checking pg_largeobject_metadata {lomowner} => pg_authid {oid}
+NOTICE:  checking pg_largeobject {loid} => pg_largeobject_metadata {oid}
+NOTICE:  checking pg_aggregate {aggfnoid} => pg_proc {oid}
+NOTICE:  checking pg_aggregate {aggtransfn} => pg_proc {oid}
+NOTICE:  checking pg_aggregate {aggfinalfn} => pg_proc {oid}
+NOTICE:  checking pg_aggregate {aggcombinefn} => pg_proc {oid}
+NOTICE:  checking pg_aggregate {aggserialfn} => pg_proc {oid}
+NOTICE:  checking pg_aggregate {aggdeserialfn} => pg_proc {oid}
+NOTICE:  checking pg_aggregate {aggmtransfn} => pg_proc {oid}
+NOTICE:  checking pg_aggregate {aggminvtransfn} => pg_proc {oid}
+NOTICE:  checking pg_aggregate {aggmfinalfn} => pg_proc {oid}
+NOTICE:  checking pg_aggregate {aggsortop} => pg_operator {oid}
+NOTICE:  checking pg_aggregate {aggtranstype} => pg_type {oid}
+NOTICE:  checking pg_aggregate {aggmtranstype} => pg_type {oid}
+NOTICE:  checking pg_statistic_ext {stxrelid} => pg_class {oid}
+NOTICE:  checking pg_statistic_ext {stxnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_statistic_ext {stxowner} => pg_authid {oid}
+NOTICE:  checking pg_statistic_ext {stxrelid,stxkeys} => pg_attribute {attrelid,attnum}
+NOTICE:  checking pg_statistic_ext_data {stxoid} => pg_statistic_ext {oid}
+NOTICE:  checking pg_statistic {starelid} => pg_class {oid}
+NOTICE:  checking pg_statistic {staop1} => pg_operator {oid}
+NOTICE:  checking pg_statistic {staop2} => pg_operator {oid}
+NOTICE:  checking pg_statistic {staop3} => pg_operator {oid}
+NOTICE:  checking pg_statistic {staop4} => pg_operator {oid}
+NOTICE:  checking pg_statistic {staop5} => pg_operator {oid}
+NOTICE:  checking pg_statistic {stacoll1} => pg_collation {oid}
+NOTICE:  checking pg_statistic {stacoll2} => pg_collation {oid}
+NOTICE:  checking pg_statistic {stacoll3} => pg_collation {oid}
+NOTICE:  checking pg_statistic {stacoll4} => pg_collation {oid}
+NOTICE:  checking pg_statistic {stacoll5} => pg_collation {oid}
+NOTICE:  checking pg_statistic {starelid,staattnum} => pg_attribute {attrelid,attnum}
+NOTICE:  checking pg_rewrite {ev_class} => pg_class {oid}
+NOTICE:  checking pg_trigger {tgrelid} => pg_class {oid}
+NOTICE:  checking pg_trigger {tgparentid} => pg_trigger {oid}
+NOTICE:  checking pg_trigger {tgfoid} => pg_proc {oid}
+NOTICE:  checking pg_trigger {tgconstrrelid} => pg_class {oid}
+NOTICE:  checking pg_trigger {tgconstrindid} => pg_class {oid}
+NOTICE:  checking pg_trigger {tgconstraint} => pg_constraint {oid}
+NOTICE:  checking pg_trigger {tgrelid,tgattr} => pg_attribute {attrelid,attnum}
+NOTICE:  checking pg_event_trigger {evtowner} => pg_authid {oid}
+NOTICE:  checking pg_event_trigger {evtfoid} => pg_proc {oid}
+NOTICE:  checking pg_description {classoid} => pg_class {oid}
+NOTICE:  checking pg_cast {castsource} => pg_type {oid}
+NOTICE:  checking pg_cast {casttarget} => pg_type {oid}
+NOTICE:  checking pg_cast {castfunc} => pg_proc {oid}
+NOTICE:  checking pg_enum {enumtypid} => pg_type {oid}
+NOTICE:  checking pg_namespace {nspowner} => pg_authid {oid}
+NOTICE:  checking pg_conversion {connamespace} => pg_namespace {oid}
+NOTICE:  checking pg_conversion {conowner} => pg_authid {oid}
+NOTICE:  checking pg_conversion {conproc} => pg_proc {oid}
+NOTICE:  checking pg_depend {classid} => pg_class {oid}
+NOTICE:  checking pg_depend {refclassid} => pg_class {oid}
+NOTICE:  checking pg_database {datdba} => pg_authid {oid}
+NOTICE:  checking pg_database {dattablespace} => pg_tablespace {oid}
+NOTICE:  checking pg_db_role_setting {setdatabase} => pg_database {oid}
+NOTICE:  checking pg_db_role_setting {setrole} => pg_authid {oid}
+NOTICE:  checking pg_tablespace {spcowner} => pg_authid {oid}
+NOTICE:  checking pg_auth_members {roleid} => pg_authid {oid}
+NOTICE:  checking pg_auth_members {member} => pg_authid {oid}
+NOTICE:  checking pg_auth_members {grantor} => pg_authid {oid}
+NOTICE:  checking pg_shdepend {dbid} => pg_database {oid}
+NOTICE:  checking pg_shdepend {classid} => pg_class {oid}
+NOTICE:  checking pg_shdepend {refclassid} => pg_class {oid}
+NOTICE:  checking pg_shdescription {classoid} => pg_class {oid}
+NOTICE:  checking pg_ts_config {cfgnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_ts_config {cfgowner} => pg_authid {oid}
+NOTICE:  checking pg_ts_config {cfgparser} => pg_ts_parser {oid}
+NOTICE:  checking pg_ts_config_map {mapcfg} => pg_ts_config {oid}
+NOTICE:  checking pg_ts_config_map {mapdict} => pg_ts_dict {oid}
+NOTICE:  checking pg_ts_dict {dictnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_ts_dict {dictowner} => pg_authid {oid}
+NOTICE:  checking pg_ts_dict {dicttemplate} => pg_ts_template {oid}
+NOTICE:  checking pg_ts_parser {prsnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_ts_parser {prsstart} => pg_proc {oid}
+NOTICE:  checking pg_ts_parser {prstoken} => pg_proc {oid}
+NOTICE:  checking pg_ts_parser {prsend} => pg_proc {oid}
+NOTICE:  checking pg_ts_parser {prsheadline} => pg_proc {oid}
+NOTICE:  checking pg_ts_parser {prslextype} => pg_proc {oid}
+NOTICE:  checking pg_ts_template {tmplnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_ts_template {tmplinit} => pg_proc {oid}
+NOTICE:  checking pg_ts_template {tmpllexize} => pg_proc {oid}
+NOTICE:  checking pg_extension {extowner} => pg_authid {oid}
+NOTICE:  checking pg_extension {extnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_extension {extconfig} => pg_class {oid}
+NOTICE:  checking pg_foreign_data_wrapper {fdwowner} => pg_authid {oid}
+NOTICE:  checking pg_foreign_data_wrapper {fdwhandler} => pg_proc {oid}
+NOTICE:  checking pg_foreign_data_wrapper {fdwvalidator} => pg_proc {oid}
+NOTICE:  checking pg_foreign_server {srvowner} => pg_authid {oid}
+NOTICE:  checking pg_foreign_server {srvfdw} => pg_foreign_data_wrapper {oid}
+NOTICE:  checking pg_user_mapping {umuser} => pg_authid {oid}
+NOTICE:  checking pg_user_mapping {umserver} => pg_foreign_server {oid}
+NOTICE:  checking pg_foreign_table {ftrelid} => pg_class {oid}
+NOTICE:  checking pg_foreign_table {ftserver} => pg_foreign_server {oid}
+NOTICE:  checking pg_policy {polrelid} => pg_class {oid}
+NOTICE:  checking pg_policy {polroles} => pg_authid {oid}
+NOTICE:  checking pg_default_acl {defaclrole} => pg_authid {oid}
+NOTICE:  checking pg_default_acl {defaclnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_init_privs {classoid} => pg_class {oid}
+NOTICE:  checking pg_seclabel {classoid} => pg_class {oid}
+NOTICE:  checking pg_shseclabel {classoid} => pg_class {oid}
+NOTICE:  checking pg_collation {collnamespace} => pg_namespace {oid}
+NOTICE:  checking pg_collation {collowner} => pg_authid {oid}
+NOTICE:  checking pg_partitioned_table {partrelid} => pg_class {oid}
+NOTICE:  checking pg_partitioned_table {partdefid} => pg_class {oid}
+NOTICE:  checking pg_partitioned_table {partclass} => pg_opclass {oid}
+NOTICE:  checking pg_partitioned_table {partcollation} => pg_collation {oid}
+NOTICE:  checking pg_partitioned_table {partrelid,partattrs} => pg_attribute {attrelid,attnum}
+NOTICE:  checking pg_range {rngtypid} => pg_type {oid}
+NOTICE:  checking pg_range {rngsubtype} => pg_type {oid}
+NOTICE:  checking pg_range {rngmultitypid} => pg_type {oid}
+NOTICE:  checking pg_range {rngcollation} => pg_collation {oid}
+NOTICE:  checking pg_range {rngsubopc} => pg_opclass {oid}
+NOTICE:  checking pg_range {rngcanonical} => pg_proc {oid}
+NOTICE:  checking pg_range {rngsubdiff} => pg_proc {oid}
+NOTICE:  checking pg_transform {trftype} => pg_type {oid}
+NOTICE:  checking pg_transform {trflang} => pg_language {oid}
+NOTICE:  checking pg_transform {trffromsql} => pg_proc {oid}
+NOTICE:  checking pg_transform {trftosql} => pg_proc {oid}
+NOTICE:  checking pg_sequence {seqrelid} => pg_class {oid}
+NOTICE:  checking pg_sequence {seqtypid} => pg_type {oid}
+NOTICE:  checking pg_publication {pubowner} => pg_authid {oid}
+NOTICE:  checking pg_publication_rel {prpubid} => pg_publication {oid}
+NOTICE:  checking pg_publication_rel {prrelid} => pg_class {oid}
+NOTICE:  checking pg_subscription {subdbid} => pg_database {oid}
+NOTICE:  checking pg_subscription {subowner} => pg_authid {oid}
+NOTICE:  checking pg_subscription_rel {srsubid} => pg_subscription {oid}
+NOTICE:  checking pg_subscription_rel {srrelid} => pg_class {oid}
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index e0e1ef71dd..12bb67e491 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -29,7 +29,7 @@ test: strings numerology point lseg line box path polygon circle date time timet
 # geometry depends on point, lseg, box, path, polygon and circle
 # horology depends on interval, timetz, timestamp, timestamptz
 # ----------
-test: geometry horology regex oidjoins type_sanity opr_sanity misc_sanity comments expressions unicode xid
+test: geometry horology regex type_sanity opr_sanity misc_sanity comments expressions unicode xid
 
 # ----------
 # These four each depend on the previous one
@@ -117,7 +117,8 @@ test: plancache limit plpgsql copy2 temp domain rangefuncs prepare conversion tr
 test: partition_join partition_prune reloptions hash_part indexing partition_aggregate partition_info tuplesort explain
 
 # event triggers cannot run concurrently with any test that runs DDL
-test: event_trigger
+# oidjoins is read-only, though, and should run late for best coverage
+test: event_trigger oidjoins
 # this test also uses event triggers, so likewise run it by itself
 test: fast_default
 
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 081fce32e7..59b416fd80 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -45,7 +45,6 @@ test: tstypes
 test: geometry
 test: horology
 test: regex
-test: oidjoins
 test: type_sanity
 test: opr_sanity
 test: misc_sanity
@@ -201,5 +200,6 @@ test: partition_info
 test: tuplesort
 test: explain
 test: event_trigger
+test: oidjoins
 test: fast_default
 test: stats
diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql
index f6d2d3c68c..07a9a74190 100644
--- a/src/test/regress/sql/oidjoins.sql
+++ b/src/test/regress/sql/oidjoins.sql
@@ -1,727 +1,49 @@
 --
--- This is created by pgsql/src/tools/findoidjoins/make_oidjoins_check
+-- Verify system catalog foreign key relationships
 --
-SELECT	ctid, aggfnoid
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggfnoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggfnoid);
-SELECT	ctid, aggtransfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggtransfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggtransfn);
-SELECT	ctid, aggfinalfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggfinalfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggfinalfn);
-SELECT	ctid, aggcombinefn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggcombinefn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggcombinefn);
-SELECT	ctid, aggserialfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggserialfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggserialfn);
-SELECT	ctid, aggdeserialfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggdeserialfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggdeserialfn);
-SELECT	ctid, aggmtransfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggmtransfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggmtransfn);
-SELECT	ctid, aggminvtransfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggminvtransfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggminvtransfn);
-SELECT	ctid, aggmfinalfn
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggmfinalfn != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggmfinalfn);
-SELECT	ctid, aggsortop
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggsortop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.aggsortop);
-SELECT	ctid, aggtranstype
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggtranstype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggtranstype);
-SELECT	ctid, aggmtranstype
-FROM	pg_catalog.pg_aggregate fk
-WHERE	aggmtranstype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype);
-SELECT	ctid, amhandler
-FROM	pg_catalog.pg_am fk
-WHERE	amhandler != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amhandler);
-SELECT	ctid, amopfamily
-FROM	pg_catalog.pg_amop fk
-WHERE	amopfamily != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amopfamily);
-SELECT	ctid, amoplefttype
-FROM	pg_catalog.pg_amop fk
-WHERE	amoplefttype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amoplefttype);
-SELECT	ctid, amoprighttype
-FROM	pg_catalog.pg_amop fk
-WHERE	amoprighttype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amoprighttype);
-SELECT	ctid, amopopr
-FROM	pg_catalog.pg_amop fk
-WHERE	amopopr != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.amopopr);
-SELECT	ctid, amopmethod
-FROM	pg_catalog.pg_amop fk
-WHERE	amopmethod != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.amopmethod);
-SELECT	ctid, amopsortfamily
-FROM	pg_catalog.pg_amop fk
-WHERE	amopsortfamily != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amopsortfamily);
-SELECT	ctid, amprocfamily
-FROM	pg_catalog.pg_amproc fk
-WHERE	amprocfamily != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amprocfamily);
-SELECT	ctid, amproclefttype
-FROM	pg_catalog.pg_amproc fk
-WHERE	amproclefttype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amproclefttype);
-SELECT	ctid, amprocrighttype
-FROM	pg_catalog.pg_amproc fk
-WHERE	amprocrighttype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amprocrighttype);
-SELECT	ctid, amproc
-FROM	pg_catalog.pg_amproc fk
-WHERE	amproc != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amproc);
-SELECT	ctid, adrelid
-FROM	pg_catalog.pg_attrdef fk
-WHERE	adrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.adrelid);
-SELECT	ctid, attrelid
-FROM	pg_catalog.pg_attribute fk
-WHERE	attrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.attrelid);
-SELECT	ctid, atttypid
-FROM	pg_catalog.pg_attribute fk
-WHERE	atttypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.atttypid);
-SELECT	ctid, attcollation
-FROM	pg_catalog.pg_attribute fk
-WHERE	attcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.attcollation);
-SELECT	ctid, roleid
-FROM	pg_catalog.pg_auth_members fk
-WHERE	roleid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.roleid);
-SELECT	ctid, member
-FROM	pg_catalog.pg_auth_members fk
-WHERE	member != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.member);
-SELECT	ctid, grantor
-FROM	pg_catalog.pg_auth_members fk
-WHERE	grantor != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.grantor);
-SELECT	ctid, castsource
-FROM	pg_catalog.pg_cast fk
-WHERE	castsource != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.castsource);
-SELECT	ctid, casttarget
-FROM	pg_catalog.pg_cast fk
-WHERE	casttarget != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.casttarget);
-SELECT	ctid, castfunc
-FROM	pg_catalog.pg_cast fk
-WHERE	castfunc != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.castfunc);
-SELECT	ctid, relnamespace
-FROM	pg_catalog.pg_class fk
-WHERE	relnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.relnamespace);
-SELECT	ctid, reltype
-FROM	pg_catalog.pg_class fk
-WHERE	reltype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.reltype);
-SELECT	ctid, reloftype
-FROM	pg_catalog.pg_class fk
-WHERE	reloftype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.reloftype);
-SELECT	ctid, relowner
-FROM	pg_catalog.pg_class fk
-WHERE	relowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.relowner);
-SELECT	ctid, relam
-FROM	pg_catalog.pg_class fk
-WHERE	relam != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.relam);
-SELECT	ctid, reltablespace
-FROM	pg_catalog.pg_class fk
-WHERE	reltablespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_tablespace pk WHERE pk.oid = fk.reltablespace);
-SELECT	ctid, reltoastrelid
-FROM	pg_catalog.pg_class fk
-WHERE	reltoastrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.reltoastrelid);
-SELECT	ctid, collnamespace
-FROM	pg_catalog.pg_collation fk
-WHERE	collnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.collnamespace);
-SELECT	ctid, collowner
-FROM	pg_catalog.pg_collation fk
-WHERE	collowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.collowner);
-SELECT	ctid, connamespace
-FROM	pg_catalog.pg_constraint fk
-WHERE	connamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.connamespace);
-SELECT	ctid, conrelid
-FROM	pg_catalog.pg_constraint fk
-WHERE	conrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.conrelid);
-SELECT	ctid, contypid
-FROM	pg_catalog.pg_constraint fk
-WHERE	contypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.contypid);
-SELECT	ctid, conindid
-FROM	pg_catalog.pg_constraint fk
-WHERE	conindid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.conindid);
-SELECT	ctid, conparentid
-FROM	pg_catalog.pg_constraint fk
-WHERE	conparentid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_constraint pk WHERE pk.oid = fk.conparentid);
-SELECT	ctid, confrelid
-FROM	pg_catalog.pg_constraint fk
-WHERE	confrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.confrelid);
-SELECT	ctid, connamespace
-FROM	pg_catalog.pg_conversion fk
-WHERE	connamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.connamespace);
-SELECT	ctid, conowner
-FROM	pg_catalog.pg_conversion fk
-WHERE	conowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.conowner);
-SELECT	ctid, conproc
-FROM	pg_catalog.pg_conversion fk
-WHERE	conproc != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.conproc);
-SELECT	ctid, datdba
-FROM	pg_catalog.pg_database fk
-WHERE	datdba != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.datdba);
-SELECT	ctid, dattablespace
-FROM	pg_catalog.pg_database fk
-WHERE	dattablespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_tablespace pk WHERE pk.oid = fk.dattablespace);
-SELECT	ctid, setdatabase
-FROM	pg_catalog.pg_db_role_setting fk
-WHERE	setdatabase != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_database pk WHERE pk.oid = fk.setdatabase);
-SELECT	ctid, classid
-FROM	pg_catalog.pg_depend fk
-WHERE	classid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classid);
-SELECT	ctid, refclassid
-FROM	pg_catalog.pg_depend fk
-WHERE	refclassid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.refclassid);
-SELECT	ctid, classoid
-FROM	pg_catalog.pg_description fk
-WHERE	classoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid);
-SELECT	ctid, enumtypid
-FROM	pg_catalog.pg_enum fk
-WHERE	enumtypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.enumtypid);
-SELECT	ctid, extowner
-FROM	pg_catalog.pg_extension fk
-WHERE	extowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.extowner);
-SELECT	ctid, extnamespace
-FROM	pg_catalog.pg_extension fk
-WHERE	extnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.extnamespace);
-SELECT	ctid, fdwowner
-FROM	pg_catalog.pg_foreign_data_wrapper fk
-WHERE	fdwowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.fdwowner);
-SELECT	ctid, srvowner
-FROM	pg_catalog.pg_foreign_server fk
-WHERE	srvowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.srvowner);
-SELECT	ctid, srvfdw
-FROM	pg_catalog.pg_foreign_server fk
-WHERE	srvfdw != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_foreign_data_wrapper pk WHERE pk.oid = fk.srvfdw);
-SELECT	ctid, indexrelid
-FROM	pg_catalog.pg_index fk
-WHERE	indexrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.indexrelid);
-SELECT	ctid, indrelid
-FROM	pg_catalog.pg_index fk
-WHERE	indrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.indrelid);
-SELECT	ctid, inhrelid
-FROM	pg_catalog.pg_inherits fk
-WHERE	inhrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.inhrelid);
-SELECT	ctid, inhparent
-FROM	pg_catalog.pg_inherits fk
-WHERE	inhparent != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.inhparent);
-SELECT	ctid, classoid
-FROM	pg_catalog.pg_init_privs fk
-WHERE	classoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid);
-SELECT	ctid, lanowner
-FROM	pg_catalog.pg_language fk
-WHERE	lanowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.lanowner);
-SELECT	ctid, lanplcallfoid
-FROM	pg_catalog.pg_language fk
-WHERE	lanplcallfoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.lanplcallfoid);
-SELECT	ctid, laninline
-FROM	pg_catalog.pg_language fk
-WHERE	laninline != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.laninline);
-SELECT	ctid, lanvalidator
-FROM	pg_catalog.pg_language fk
-WHERE	lanvalidator != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.lanvalidator);
-SELECT	ctid, loid
-FROM	pg_catalog.pg_largeobject fk
-WHERE	loid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_largeobject_metadata pk WHERE pk.oid = fk.loid);
-SELECT	ctid, lomowner
-FROM	pg_catalog.pg_largeobject_metadata fk
-WHERE	lomowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.lomowner);
-SELECT	ctid, nspowner
-FROM	pg_catalog.pg_namespace fk
-WHERE	nspowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.nspowner);
-SELECT	ctid, opcmethod
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcmethod != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opcmethod);
-SELECT	ctid, opcnamespace
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.opcnamespace);
-SELECT	ctid, opcowner
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.opcowner);
-SELECT	ctid, opcfamily
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcfamily != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.opcfamily);
-SELECT	ctid, opcintype
-FROM	pg_catalog.pg_opclass fk
-WHERE	opcintype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.opcintype);
-SELECT	ctid, opckeytype
-FROM	pg_catalog.pg_opclass fk
-WHERE	opckeytype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.opckeytype);
-SELECT	ctid, oprnamespace
-FROM	pg_catalog.pg_operator fk
-WHERE	oprnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.oprnamespace);
-SELECT	ctid, oprowner
-FROM	pg_catalog.pg_operator fk
-WHERE	oprowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.oprowner);
-SELECT	ctid, oprleft
-FROM	pg_catalog.pg_operator fk
-WHERE	oprleft != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.oprleft);
-SELECT	ctid, oprright
-FROM	pg_catalog.pg_operator fk
-WHERE	oprright != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.oprright);
-SELECT	ctid, oprresult
-FROM	pg_catalog.pg_operator fk
-WHERE	oprresult != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.oprresult);
-SELECT	ctid, oprcom
-FROM	pg_catalog.pg_operator fk
-WHERE	oprcom != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprcom);
-SELECT	ctid, oprnegate
-FROM	pg_catalog.pg_operator fk
-WHERE	oprnegate != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprnegate);
-SELECT	ctid, oprcode
-FROM	pg_catalog.pg_operator fk
-WHERE	oprcode != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprcode);
-SELECT	ctid, oprrest
-FROM	pg_catalog.pg_operator fk
-WHERE	oprrest != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprrest);
-SELECT	ctid, oprjoin
-FROM	pg_catalog.pg_operator fk
-WHERE	oprjoin != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprjoin);
-SELECT	ctid, opfmethod
-FROM	pg_catalog.pg_opfamily fk
-WHERE	opfmethod != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opfmethod);
-SELECT	ctid, opfnamespace
-FROM	pg_catalog.pg_opfamily fk
-WHERE	opfnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.opfnamespace);
-SELECT	ctid, opfowner
-FROM	pg_catalog.pg_opfamily fk
-WHERE	opfowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.opfowner);
-SELECT	ctid, partrelid
-FROM	pg_catalog.pg_partitioned_table fk
-WHERE	partrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.partrelid);
-SELECT	ctid, partdefid
-FROM	pg_catalog.pg_partitioned_table fk
-WHERE	partdefid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.partdefid);
-SELECT	ctid, polrelid
-FROM	pg_catalog.pg_policy fk
-WHERE	polrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.polrelid);
-SELECT	ctid, pronamespace
-FROM	pg_catalog.pg_proc fk
-WHERE	pronamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.pronamespace);
-SELECT	ctid, proowner
-FROM	pg_catalog.pg_proc fk
-WHERE	proowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.proowner);
-SELECT	ctid, prolang
-FROM	pg_catalog.pg_proc fk
-WHERE	prolang != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_language pk WHERE pk.oid = fk.prolang);
-SELECT	ctid, provariadic
-FROM	pg_catalog.pg_proc fk
-WHERE	provariadic != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.provariadic);
-SELECT	ctid, prosupport
-FROM	pg_catalog.pg_proc fk
-WHERE	prosupport != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prosupport);
-SELECT	ctid, prorettype
-FROM	pg_catalog.pg_proc fk
-WHERE	prorettype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.prorettype);
-SELECT	ctid, rngtypid
-FROM	pg_catalog.pg_range fk
-WHERE	rngtypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.rngtypid);
-SELECT	ctid, rngsubtype
-FROM	pg_catalog.pg_range fk
-WHERE	rngsubtype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.rngsubtype);
-SELECT	ctid, rngcollation
-FROM	pg_catalog.pg_range fk
-WHERE	rngcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.rngcollation);
-SELECT	ctid, rngsubopc
-FROM	pg_catalog.pg_range fk
-WHERE	rngsubopc != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.rngsubopc);
-SELECT	ctid, rngcanonical
-FROM	pg_catalog.pg_range fk
-WHERE	rngcanonical != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.rngcanonical);
-SELECT	ctid, rngsubdiff
-FROM	pg_catalog.pg_range fk
-WHERE	rngsubdiff != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.rngsubdiff);
-SELECT	ctid, ev_class
-FROM	pg_catalog.pg_rewrite fk
-WHERE	ev_class != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.ev_class);
-SELECT	ctid, seqrelid
-FROM	pg_catalog.pg_sequence fk
-WHERE	seqrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.seqrelid);
-SELECT	ctid, seqtypid
-FROM	pg_catalog.pg_sequence fk
-WHERE	seqtypid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.seqtypid);
-SELECT	ctid, refclassid
-FROM	pg_catalog.pg_shdepend fk
-WHERE	refclassid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.refclassid);
-SELECT	ctid, classoid
-FROM	pg_catalog.pg_shdescription fk
-WHERE	classoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid);
-SELECT	ctid, starelid
-FROM	pg_catalog.pg_statistic fk
-WHERE	starelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.starelid);
-SELECT	ctid, staop1
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop1 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop1);
-SELECT	ctid, staop2
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop2 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop2);
-SELECT	ctid, staop3
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop3 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop3);
-SELECT	ctid, staop4
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop4 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop4);
-SELECT	ctid, staop5
-FROM	pg_catalog.pg_statistic fk
-WHERE	staop5 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop5);
-SELECT	ctid, stacoll1
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll1 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll1);
-SELECT	ctid, stacoll2
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll2 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll2);
-SELECT	ctid, stacoll3
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll3 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll3);
-SELECT	ctid, stacoll4
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll4 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll4);
-SELECT	ctid, stacoll5
-FROM	pg_catalog.pg_statistic fk
-WHERE	stacoll5 != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.stacoll5);
-SELECT	ctid, stxrelid
-FROM	pg_catalog.pg_statistic_ext fk
-WHERE	stxrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.stxrelid);
-SELECT	ctid, stxnamespace
-FROM	pg_catalog.pg_statistic_ext fk
-WHERE	stxnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.stxnamespace);
-SELECT	ctid, stxowner
-FROM	pg_catalog.pg_statistic_ext fk
-WHERE	stxowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.stxowner);
-SELECT	ctid, stxoid
-FROM	pg_catalog.pg_statistic_ext_data fk
-WHERE	stxoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_statistic_ext pk WHERE pk.oid = fk.stxoid);
-SELECT	ctid, spcowner
-FROM	pg_catalog.pg_tablespace fk
-WHERE	spcowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.spcowner);
-SELECT	ctid, trftype
-FROM	pg_catalog.pg_transform fk
-WHERE	trftype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.trftype);
-SELECT	ctid, trflang
-FROM	pg_catalog.pg_transform fk
-WHERE	trflang != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_language pk WHERE pk.oid = fk.trflang);
-SELECT	ctid, trffromsql
-FROM	pg_catalog.pg_transform fk
-WHERE	trffromsql != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.trffromsql);
-SELECT	ctid, trftosql
-FROM	pg_catalog.pg_transform fk
-WHERE	trftosql != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.trftosql);
-SELECT	ctid, tgrelid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.tgrelid);
-SELECT	ctid, tgparentid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgparentid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_trigger pk WHERE pk.oid = fk.tgparentid);
-SELECT	ctid, tgfoid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgfoid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.tgfoid);
-SELECT	ctid, tgconstrrelid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgconstrrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.tgconstrrelid);
-SELECT	ctid, tgconstrindid
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgconstrindid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.tgconstrindid);
-SELECT	ctid, tgconstraint
-FROM	pg_catalog.pg_trigger fk
-WHERE	tgconstraint != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_constraint pk WHERE pk.oid = fk.tgconstraint);
-SELECT	ctid, cfgnamespace
-FROM	pg_catalog.pg_ts_config fk
-WHERE	cfgnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.cfgnamespace);
-SELECT	ctid, cfgowner
-FROM	pg_catalog.pg_ts_config fk
-WHERE	cfgowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.cfgowner);
-SELECT	ctid, cfgparser
-FROM	pg_catalog.pg_ts_config fk
-WHERE	cfgparser != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_parser pk WHERE pk.oid = fk.cfgparser);
-SELECT	ctid, mapcfg
-FROM	pg_catalog.pg_ts_config_map fk
-WHERE	mapcfg != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_config pk WHERE pk.oid = fk.mapcfg);
-SELECT	ctid, mapdict
-FROM	pg_catalog.pg_ts_config_map fk
-WHERE	mapdict != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_dict pk WHERE pk.oid = fk.mapdict);
-SELECT	ctid, dictnamespace
-FROM	pg_catalog.pg_ts_dict fk
-WHERE	dictnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.dictnamespace);
-SELECT	ctid, dictowner
-FROM	pg_catalog.pg_ts_dict fk
-WHERE	dictowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.dictowner);
-SELECT	ctid, dicttemplate
-FROM	pg_catalog.pg_ts_dict fk
-WHERE	dicttemplate != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_ts_template pk WHERE pk.oid = fk.dicttemplate);
-SELECT	ctid, prsnamespace
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prsnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.prsnamespace);
-SELECT	ctid, prsstart
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prsstart != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prsstart);
-SELECT	ctid, prstoken
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prstoken != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prstoken);
-SELECT	ctid, prsend
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prsend != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prsend);
-SELECT	ctid, prsheadline
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prsheadline != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prsheadline);
-SELECT	ctid, prslextype
-FROM	pg_catalog.pg_ts_parser fk
-WHERE	prslextype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prslextype);
-SELECT	ctid, tmplnamespace
-FROM	pg_catalog.pg_ts_template fk
-WHERE	tmplnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.tmplnamespace);
-SELECT	ctid, tmplinit
-FROM	pg_catalog.pg_ts_template fk
-WHERE	tmplinit != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.tmplinit);
-SELECT	ctid, tmpllexize
-FROM	pg_catalog.pg_ts_template fk
-WHERE	tmpllexize != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.tmpllexize);
-SELECT	ctid, typnamespace
-FROM	pg_catalog.pg_type fk
-WHERE	typnamespace != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.typnamespace);
-SELECT	ctid, typowner
-FROM	pg_catalog.pg_type fk
-WHERE	typowner != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.typowner);
-SELECT	ctid, typrelid
-FROM	pg_catalog.pg_type fk
-WHERE	typrelid != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.typrelid);
-SELECT	ctid, typelem
-FROM	pg_catalog.pg_type fk
-WHERE	typelem != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typelem);
-SELECT	ctid, typarray
-FROM	pg_catalog.pg_type fk
-WHERE	typarray != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typarray);
-SELECT	ctid, typinput
-FROM	pg_catalog.pg_type fk
-WHERE	typinput != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typinput);
-SELECT	ctid, typoutput
-FROM	pg_catalog.pg_type fk
-WHERE	typoutput != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typoutput);
-SELECT	ctid, typreceive
-FROM	pg_catalog.pg_type fk
-WHERE	typreceive != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typreceive);
-SELECT	ctid, typsend
-FROM	pg_catalog.pg_type fk
-WHERE	typsend != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typsend);
-SELECT	ctid, typmodin
-FROM	pg_catalog.pg_type fk
-WHERE	typmodin != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typmodin);
-SELECT	ctid, typmodout
-FROM	pg_catalog.pg_type fk
-WHERE	typmodout != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typmodout);
-SELECT	ctid, typanalyze
-FROM	pg_catalog.pg_type fk
-WHERE	typanalyze != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typanalyze);
-SELECT	ctid, typbasetype
-FROM	pg_catalog.pg_type fk
-WHERE	typbasetype != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.typbasetype);
-SELECT	ctid, typcollation
-FROM	pg_catalog.pg_type fk
-WHERE	typcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.typcollation);
-SELECT	ctid, conpfeqop
-FROM	(SELECT ctid, unnest(conpfeqop) AS conpfeqop FROM pg_catalog.pg_constraint) fk
-WHERE	conpfeqop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conpfeqop);
-SELECT	ctid, conppeqop
-FROM	(SELECT ctid, unnest(conppeqop) AS conppeqop FROM pg_catalog.pg_constraint) fk
-WHERE	conppeqop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conppeqop);
-SELECT	ctid, conffeqop
-FROM	(SELECT ctid, unnest(conffeqop) AS conffeqop FROM pg_catalog.pg_constraint) fk
-WHERE	conffeqop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conffeqop);
-SELECT	ctid, conexclop
-FROM	(SELECT ctid, unnest(conexclop) AS conexclop FROM pg_catalog.pg_constraint) fk
-WHERE	conexclop != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.conexclop);
-SELECT	ctid, indcollation
-FROM	(SELECT ctid, unnest(indcollation) AS indcollation FROM pg_catalog.pg_index) fk
-WHERE	indcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.indcollation);
-SELECT	ctid, indclass
-FROM	(SELECT ctid, unnest(indclass) AS indclass FROM pg_catalog.pg_index) fk
-WHERE	indclass != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.indclass);
-SELECT	ctid, partclass
-FROM	(SELECT ctid, unnest(partclass) AS partclass FROM pg_catalog.pg_partitioned_table) fk
-WHERE	partclass != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.partclass);
-SELECT	ctid, partcollation
-FROM	(SELECT ctid, unnest(partcollation) AS partcollation FROM pg_catalog.pg_partitioned_table) fk
-WHERE	partcollation != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_collation pk WHERE pk.oid = fk.partcollation);
-SELECT	ctid, proargtypes
-FROM	(SELECT ctid, unnest(proargtypes) AS proargtypes FROM pg_catalog.pg_proc) fk
-WHERE	proargtypes != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.proargtypes);
-SELECT	ctid, proallargtypes
-FROM	(SELECT ctid, unnest(proallargtypes) AS proallargtypes FROM pg_catalog.pg_proc) fk
-WHERE	proallargtypes != 0 AND
-	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.proallargtypes);
+DO $doblock$
+declare
+  fk record;
+  nkeys integer;
+  cmd text;
+  err record;
+begin
+  for fk in select * from pg_get_catalog_foreign_keys()
+  loop
+    raise notice 'checking % % => % %',
+      fk.fktable, fk.fkcols, fk.pktable, fk.pkcols;
+    nkeys := array_length(fk.fkcols, 1);
+    cmd := 'SELECT ctid';
+    for i in 1 .. nkeys loop
+      cmd := cmd || ', ' || quote_ident(fk.fkcols[i]);
+    end loop;
+    if fk.is_array then
+      cmd := cmd || ' FROM (SELECT ctid';
+      for i in 1 .. nkeys-1 loop
+        cmd := cmd || ', ' || quote_ident(fk.fkcols[i]);
+      end loop;
+      cmd := cmd || ', unnest(' || quote_ident(fk.fkcols[nkeys]);
+      cmd := cmd || ') as ' || quote_ident(fk.fkcols[nkeys]);
+      cmd := cmd || ' FROM ' || fk.fktable::text || ') fk WHERE ';
+    else
+      cmd := cmd || ' FROM ' || fk.fktable::text || ' fk WHERE ';
+    end if;
+    if fk.is_opt then
+      for i in 1 .. nkeys loop
+        cmd := cmd || quote_ident(fk.fkcols[i]) || ' != 0 AND ';
+      end loop;
+    end if;
+    cmd := cmd || 'NOT EXISTS(SELECT 1 FROM ' || fk.pktable::text || ' pk WHERE ';
+    for i in 1 .. nkeys loop
+      if i > 1 then cmd := cmd || ' AND '; end if;
+      cmd := cmd || 'pk.' || quote_ident(fk.pkcols[i]);
+      cmd := cmd || ' = fk.' || quote_ident(fk.fkcols[i]);
+    end loop;
+    cmd := cmd || ')';
+    -- raise notice 'cmd = %', cmd;
+    for err in execute cmd loop
+      raise notice 'FK VIOLATION IN %(%): %', fk.fktable, fk.fkcols, err;
+    end loop;
+  end loop;
+end
+$doblock$;
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index 1c0c92fcd2..2aa062b2c9 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -818,6 +818,9 @@ EOF
 		copyFile(
 			'src/backend/catalog/schemapg.h',
 			'src/include/catalog/schemapg.h');
+		copyFile(
+			'src/backend/catalog/system_fk_info.h',
+			'src/include/catalog/system_fk_info.h');
 		open(my $chs, '>', 'src/include/catalog/header-stamp')
 		  || confess "Could not touch header-stamp";
 		close($chs);
diff --git a/src/tools/msvc/clean.bat b/src/tools/msvc/clean.bat
index 4575e3f95f..d0d79a0932 100755
--- a/src/tools/msvc/clean.bat
+++ b/src/tools/msvc/clean.bat
@@ -47,6 +47,7 @@ if exist src\include\utils\fmgrprotos.h del /q src\include\utils\fmgrprotos.h
 if exist src\include\storage\lwlocknames.h del /q src\include\storage\lwlocknames.h
 if exist src\include\utils\probes.h del /q src\include\utils\probes.h
 if exist src\include\catalog\schemapg.h del /q src\include\catalog\schemapg.h
+if exist src\include\catalog\system_fk_info.h del /q src\include\catalog\system_fk_info.h
 if exist src\include\catalog\pg_*_d.h del /q src\include\catalog\pg_*_d.h
 if exist src\include\catalog\header-stamp del /q src\include\catalog\header-stamp
 if exist doc\src\sgml\version.sgml del /q doc\src\sgml\version.sgml
@@ -73,6 +74,7 @@ if %DIST%==1 if exist src\interfaces\ecpg\preproc\preproc.y del /q src\interface
 if %DIST%==1 if exist src\backend\catalog\postgres.bki del /q src\backend\catalog\postgres.bki
 if %DIST%==1 if exist src\backend\catalog\system_constraints.sql del /q src\backend\catalog\system_constraints.sql
 if %DIST%==1 if exist src\backend\catalog\schemapg.h del /q src\backend\catalog\schemapg.h
+if %DIST%==1 if exist src\backend\catalog\system_fk_info.h del /q src\backend\catalog\system_fk_info.h
 if %DIST%==1 if exist src\backend\catalog\pg_*_d.h del /q src\backend\catalog\pg_*_d.h
 if %DIST%==1 if exist src\backend\catalog\bki-stamp del /q src\backend\catalog\bki-stamp
 if %DIST%==1 if exist src\backend\parser\scan.c del /q src\backend\parser\scan.c
#8Joel Jacobson
joel@compiler.org
In reply to: Tom Lane (#7)
Re: Recording foreign key relationships for the system catalogs

On Tue, Feb 2, 2021, at 04:27, Tom Lane wrote:

Attachments:
add-catalog-foreign-key-info-2.patch

Very nice.

I could only find one minor error,
found by running the regression-tests,
and then using the query below to compare "is_opt"
with my own "zero_values" in my tool
that derives its value from pg_catalog content.

--
-- Are there any observed oid columns with zero values
-- that are also marked as NOT is_opt by pg_get_catalog_foreign_keys()?
--
regression=# SELECT
table_name,
column_name
FROM pit.oid_columns
WHERE zero_values
INTERSECT
SELECT
fktable::text,
unnest(fkcols)
FROM pg_get_catalog_foreign_keys()
WHERE NOT is_opt;

Expected to return no rows but:

table_name | column_name
---------------+-------------
pg_constraint | confrelid
(1 row)

regression=# SELECT * FROM pg_get_catalog_foreign_keys() WHERE 'confrelid' = ANY(fkcols);
fktable | fkcols | pktable | pkcols | is_array | is_opt
---------------+---------------------+--------------+-------------------+----------+--------
pg_constraint | {confrelid} | pg_class | {oid} | f | t
pg_constraint | {confrelid,confkey} | pg_attribute | {attrelid,attnum} | t | f
(2 rows)

Reading the new documentation, I interpret "is_opt=false" to be a negation of

"the referencing column(s) are allowed to contain zeroes instead of a valid reference"

i.e. that none of the referencing columns (fkcols) are allowed to contain zeroes,
but since "confrelid" apparently can contain zeroes:

regression=# select * from pg_constraint where confrelid = 0 limit 1;
-[ RECORD 1 ]-+------------------
oid | 12111
conname | pg_proc_oid_index
connamespace | 11
contype | p
condeferrable | f
condeferred | f
convalidated | t
conrelid | 1255
contypid | 0
conindid | 2690
conparentid | 0
confrelid | 0
confupdtype |
confdeltype |
confmatchtype |
conislocal | t
coninhcount | 0
connoinherit | t
conkey | {1}
confkey |
confreftype |
conpfeqop |
conppeqop |
conffeqop |
conexclop |
conbin |

I therefore think is_opt should be changed to true for this row:
fktable | fkcols | pktable | pkcols | is_array | is_opt
---------------+---------------------+--------------+-------------------+----------+--------
pg_constraint | {confrelid,confkey} | pg_attribute | {attrelid,attnum} | t | f

If this is fixed, I also agree this is ready to be committed.

/Joel

#9Tom Lane
tgl@sss.pgh.pa.us
In reply to: Joel Jacobson (#8)
Re: Recording foreign key relationships for the system catalogs

"Joel Jacobson" <joel@compiler.org> writes:

I could only find one minor error,
found by running the regression-tests,
and then using the query below to compare "is_opt"
with my own "zero_values" in my tool
that derives its value from pg_catalog content.
...
I therefore think is_opt should be changed to true for this row:
fktable | fkcols | pktable | pkcols | is_array | is_opt
---------------+---------------------+--------------+-------------------+----------+--------
pg_constraint | {confrelid,confkey} | pg_attribute | {attrelid,attnum} | t | f

No, I think it's correct as-is (and this is one reason that I chose to
have two separate FK entries for cases like this). confrelid can be
zero in rows that are not FK constraints. However, such a row must
also have empty confkey. The above entry states that for each element
of confkey, the pair (confrelid,confkey[i]) must be nonzero and have
a match in pg_attribute. It creates no constraint if confkey is empty.

If this is fixed, I also agree this is ready to be committed.

Appreciate the review! Please confirm if you agree with above
analysis.

regards, tom lane

#10Joel Jacobson
joel@compiler.org
In reply to: Tom Lane (#9)
Re: Recording foreign key relationships for the system catalogs

On Tue, Feb 2, 2021, at 17:00, Tom Lane wrote:

No, I think it's correct as-is (and this is one reason that I chose to
have two separate FK entries for cases like this). confrelid can be
zero in rows that are not FK constraints. However, such a row must
also have empty confkey. The above entry states that for each element
of confkey, the pair (confrelid,confkey[i]) must be nonzero and have
a match in pg_attribute. It creates no constraint if confkey is empty.

Thanks for explaining, I get it now.

Appreciate the review! Please confirm if you agree with above
analysis.

Yes, I agree with the analysis.

/Joel

#11Tom Lane
tgl@sss.pgh.pa.us
In reply to: Joel Jacobson (#10)
Re: Recording foreign key relationships for the system catalogs

"Joel Jacobson" <joel@compiler.org> writes:

On Tue, Feb 2, 2021, at 17:00, Tom Lane wrote:

Appreciate the review! Please confirm if you agree with above
analysis.

Yes, I agree with the analysis.

Cool, thanks. I've pushed it now.

regards, tom lane

#12Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tom Lane (#1)
1 attachment(s)
Re: Recording foreign key relationships for the system catalogs

I wrote:

* It would now be possible to remove the PGNSP and PGUID kluges
entirely in favor of plain BKI_LOOKUP references to pg_namespace
and pg_authid. The catalog header usage would get a little
more verbose: BKI_DEFAULT(PGNSP) becomes BKI_DEFAULT(pg_catalog)
and BKI_DEFAULT(PGUID) becomes BKI_DEFAULT(POSTGRES). I'm a bit
inclined to do it, simply to remove one bit of mechanism that has
to be documented; but it's material for a separate patch perhaps.

Here's a patch for that part. I think this is probably a good
idea not only because it removes magic, but because now that we
have various predefined roles it's becoming more and more likely
that some of those will need to be cross-referenced in other
catalogs' initial data. With this change, nothing special
will be needed for that. Multiple built-in schemas also become
more feasible than they were.

regards, tom lane

Attachments:

retire-PGNSP-and-PGUID-symbols.patchtext/x-diff; charset=us-ascii; name=retire-PGNSP-and-PGUID-symbols.patchDownload
diff --git a/doc/src/sgml/bki.sgml b/doc/src/sgml/bki.sgml
index 6d3c5be67f..db1b3d5e9a 100644
--- a/doc/src/sgml/bki.sgml
+++ b/doc/src/sgml/bki.sgml
@@ -540,17 +540,6 @@
       expected to be in the <literal>pg_catalog</literal> schema.
      </para>
     </listitem>
-
-    <listitem>
-     <para>
-      In addition to the generic lookup mechanisms, there is a special
-      convention that <literal>PGNSP</literal> is replaced by the OID of
-      the <literal>pg_catalog</literal> schema,
-      and <literal>PGUID</literal> is replaced by the OID of the bootstrap
-      superuser role.  These usages are somewhat historical but so far
-      there hasn't been a need to generalize them.
-     </para>
-    </listitem>
    </itemizedlist>
 
    <para>
diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl
index 5bdc7adc44..b159958112 100644
--- a/src/backend/catalog/genbki.pl
+++ b/src/backend/catalog/genbki.pl
@@ -184,15 +184,9 @@ my $GenbkiNextOid = $FirstGenbkiObjectId;
 # within a given Postgres release, such as fixed OIDs.  Do not substitute
 # anything that could depend on platform or configuration.  (The right place
 # to handle those sorts of things is in initdb.c's bootstrap_template1().)
-my $BOOTSTRAP_SUPERUSERID =
-  Catalog::FindDefinedSymbolFromData($catalog_data{pg_authid},
-	'BOOTSTRAP_SUPERUSERID');
 my $C_COLLATION_OID =
   Catalog::FindDefinedSymbolFromData($catalog_data{pg_collation},
 	'C_COLLATION_OID');
-my $PG_CATALOG_NAMESPACE =
-  Catalog::FindDefinedSymbolFromData($catalog_data{pg_namespace},
-	'PG_CATALOG_NAMESPACE');
 
 
 # Fill in pg_class.relnatts by looking at the referenced catalog's schema.
@@ -213,11 +207,12 @@ foreach my $row (@{ $catalog_data{pg_am} })
 	$amoids{ $row->{amname} } = $row->{oid};
 }
 
-# There is only one authid at bootstrap time, and we handle it specially:
-# the usually-defaulted symbol PGUID becomes the bootstrap superuser's OID.
-# (We could drop this in favor of writing out BKI_DEFAULT(POSTGRES) ...)
+# role OID lookup
 my %authidoids;
-$authidoids{'PGUID'} = $BOOTSTRAP_SUPERUSERID;
+foreach my $row (@{ $catalog_data{pg_authid} })
+{
+	$authidoids{ $row->{rolname} } = $row->{oid};
+}
 
 # class (relation) OID lookup (note this only covers bootstrap catalogs!)
 my %classoids;
@@ -240,11 +235,12 @@ foreach my $row (@{ $catalog_data{pg_language} })
 	$langoids{ $row->{lanname} } = $row->{oid};
 }
 
-# There is only one namespace at bootstrap time, and we handle it specially:
-# the usually-defaulted symbol PGNSP becomes the pg_catalog namespace's OID.
-# (We could drop this in favor of writing out BKI_DEFAULT(pg_catalog) ...)
+# namespace (schema) OID lookup
 my %namespaceoids;
-$namespaceoids{'PGNSP'} = $PG_CATALOG_NAMESPACE;
+foreach my $row (@{ $catalog_data{pg_namespace} })
+{
+	$namespaceoids{ $row->{nspname} } = $row->{oid};
+}
 
 # opclass OID lookup
 my %opcoids;
diff --git a/src/include/catalog/pg_authid.dat b/src/include/catalog/pg_authid.dat
index a643a09588..87d917ffc3 100644
--- a/src/include/catalog/pg_authid.dat
+++ b/src/include/catalog/pg_authid.dat
@@ -15,6 +15,10 @@
 # The C code typically refers to these roles using the #define symbols,
 # so make sure every entry has an oid_symbol value.
 
+# The bootstrap superuser is named POSTGRES according to this data and
+# according to BKI_DEFAULT entries in other catalogs.  However, initdb
+# will replace that at database initialization time.
+
 { oid => '10', oid_symbol => 'BOOTSTRAP_SUPERUSERID',
   rolname => 'POSTGRES', rolsuper => 't', rolinherit => 't',
   rolcreaterole => 't', rolcreatedb => 't', rolcanlogin => 't',
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index bb6938caa2..3e37729436 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -38,7 +38,7 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat
 	NameData	relname;
 
 	/* OID of namespace containing this class */
-	Oid			relnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
+	Oid			relnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace);
 
 	/* OID of entry in pg_type for relation's implicit row type, if any */
 	Oid			reltype BKI_LOOKUP_OPT(pg_type);
@@ -47,7 +47,7 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat
 	Oid			reloftype BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type);
 
 	/* class owner */
-	Oid			relowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
+	Oid			relowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid);
 
 	/* access method; 0 if not a table / index */
 	Oid			relam BKI_DEFAULT(heap) BKI_LOOKUP_OPT(pg_am);
diff --git a/src/include/catalog/pg_collation.h b/src/include/catalog/pg_collation.h
index 3bd7873c68..c6394ca222 100644
--- a/src/include/catalog/pg_collation.h
+++ b/src/include/catalog/pg_collation.h
@@ -30,9 +30,12 @@ CATALOG(pg_collation,3456,CollationRelationId)
 {
 	Oid			oid;			/* oid */
 	NameData	collname;		/* collation name */
-	Oid			collnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);	/* OID of namespace
-																			 * containing collation */
-	Oid			collowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid); /* owner of collation */
+
+	/* OID of namespace containing this collation */
+	Oid			collnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace);
+
+	/* owner of collation */
+	Oid			collowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid);
 	char		collprovider;	/* see constants below */
 	bool		collisdeterministic BKI_DEFAULT(t);
 	int32		collencoding;	/* encoding for this collation; -1 = "all" */
diff --git a/src/include/catalog/pg_conversion.h b/src/include/catalog/pg_conversion.h
index 96bb92f251..ca556f6030 100644
--- a/src/include/catalog/pg_conversion.h
+++ b/src/include/catalog/pg_conversion.h
@@ -35,10 +35,10 @@ CATALOG(pg_conversion,2607,ConversionRelationId)
 	NameData	conname;
 
 	/* namespace that the conversion belongs to */
-	Oid			connamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
+	Oid			connamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace);
 
 	/* owner of the conversion */
-	Oid			conowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
+	Oid			conowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid);
 
 	/* FOR encoding id */
 	int32		conforencoding BKI_LOOKUP(encoding);
diff --git a/src/include/catalog/pg_database.h b/src/include/catalog/pg_database.h
index f0240c58cf..d3de45821c 100644
--- a/src/include/catalog/pg_database.h
+++ b/src/include/catalog/pg_database.h
@@ -35,7 +35,7 @@ CATALOG(pg_database,1262,DatabaseRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID
 	NameData	datname;
 
 	/* owner of database */
-	Oid			datdba BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
+	Oid			datdba BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid);
 
 	/* character encoding */
 	int32		encoding;
diff --git a/src/include/catalog/pg_language.h b/src/include/catalog/pg_language.h
index e9df9dac09..3e56597ece 100644
--- a/src/include/catalog/pg_language.h
+++ b/src/include/catalog/pg_language.h
@@ -34,7 +34,7 @@ CATALOG(pg_language,2612,LanguageRelationId)
 	NameData	lanname;
 
 	/* Language's owner */
-	Oid			lanowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
+	Oid			lanowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid);
 
 	/* Is a procedural language */
 	bool		lanispl BKI_DEFAULT(f);
diff --git a/src/include/catalog/pg_namespace.h b/src/include/catalog/pg_namespace.h
index d920c6cfc6..fe87a947ee 100644
--- a/src/include/catalog/pg_namespace.h
+++ b/src/include/catalog/pg_namespace.h
@@ -37,7 +37,7 @@ CATALOG(pg_namespace,2615,NamespaceRelationId)
 	Oid			oid;			/* oid */
 
 	NameData	nspname;
-	Oid			nspowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
+	Oid			nspowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid);
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	aclitem		nspacl[1];
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index 9f321f2a85..7b2cf25920 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -57,10 +57,10 @@ CATALOG(pg_opclass,2616,OperatorClassRelationId)
 	NameData	opcname;
 
 	/* namespace of this opclass */
-	Oid			opcnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
+	Oid			opcnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace);
 
 	/* opclass owner */
-	Oid			opcowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
+	Oid			opcowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid);
 
 	/* containing operator family */
 	Oid			opcfamily BKI_LOOKUP(pg_opfamily);
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 7f06abaeec..d32fcdc64e 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -36,10 +36,10 @@ CATALOG(pg_operator,2617,OperatorRelationId)
 	NameData	oprname;
 
 	/* OID of namespace containing this oper */
-	Oid			oprnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
+	Oid			oprnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace);
 
 	/* operator owner */
-	Oid			oprowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
+	Oid			oprowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid);
 
 	/* 'l' for prefix or 'b' for infix */
 	char		oprkind BKI_DEFAULT(b);
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index 1a723b76f6..129102b576 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -37,10 +37,10 @@ CATALOG(pg_opfamily,2753,OperatorFamilyRelationId)
 	NameData	opfname;
 
 	/* namespace of this opfamily */
-	Oid			opfnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
+	Oid			opfnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace);
 
 	/* opfamily owner */
-	Oid			opfowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
+	Oid			opfowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid);
 } FormData_pg_opfamily;
 
 /* ----------------
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 2f54aa171e..78f230894b 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -35,10 +35,10 @@ CATALOG(pg_proc,1255,ProcedureRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81,Proce
 	NameData	proname;
 
 	/* OID of namespace containing this proc */
-	Oid			pronamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
+	Oid			pronamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace);
 
 	/* procedure owner */
-	Oid			proowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
+	Oid			proowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid);
 
 	/* OID of pg_language entry */
 	Oid			prolang BKI_DEFAULT(internal) BKI_LOOKUP(pg_language);
diff --git a/src/include/catalog/pg_tablespace.h b/src/include/catalog/pg_tablespace.h
index ed38e6950d..58bb1087a3 100644
--- a/src/include/catalog/pg_tablespace.h
+++ b/src/include/catalog/pg_tablespace.h
@@ -30,7 +30,9 @@ CATALOG(pg_tablespace,1213,TableSpaceRelationId) BKI_SHARED_RELATION
 {
 	Oid			oid;			/* oid */
 	NameData	spcname;		/* tablespace name */
-	Oid			spcowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);	/* owner of tablespace */
+
+	/* owner of tablespace */
+	Oid			spcowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid);
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	aclitem		spcacl[1];		/* access permissions */
diff --git a/src/include/catalog/pg_ts_config.h b/src/include/catalog/pg_ts_config.h
index e705899b17..2e0263962d 100644
--- a/src/include/catalog/pg_ts_config.h
+++ b/src/include/catalog/pg_ts_config.h
@@ -36,10 +36,10 @@ CATALOG(pg_ts_config,3602,TSConfigRelationId)
 	NameData	cfgname;
 
 	/* name space */
-	Oid			cfgnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
+	Oid			cfgnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace);
 
 	/* owner */
-	Oid			cfgowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
+	Oid			cfgowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid);
 
 	/* OID of parser */
 	Oid			cfgparser BKI_LOOKUP(pg_ts_parser);
diff --git a/src/include/catalog/pg_ts_dict.h b/src/include/catalog/pg_ts_dict.h
index 57f626e7b5..e53eead829 100644
--- a/src/include/catalog/pg_ts_dict.h
+++ b/src/include/catalog/pg_ts_dict.h
@@ -35,10 +35,10 @@ CATALOG(pg_ts_dict,3600,TSDictionaryRelationId)
 	NameData	dictname;
 
 	/* name space */
-	Oid			dictnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
+	Oid			dictnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace);
 
 	/* owner */
-	Oid			dictowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
+	Oid			dictowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid);
 
 	/* dictionary's template */
 	Oid			dicttemplate BKI_LOOKUP(pg_ts_template);
diff --git a/src/include/catalog/pg_ts_parser.h b/src/include/catalog/pg_ts_parser.h
index e0d705fd9a..0231051cee 100644
--- a/src/include/catalog/pg_ts_parser.h
+++ b/src/include/catalog/pg_ts_parser.h
@@ -34,7 +34,7 @@ CATALOG(pg_ts_parser,3601,TSParserRelationId)
 	NameData	prsname;
 
 	/* name space */
-	Oid			prsnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
+	Oid			prsnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace);
 
 	/* init parsing session */
 	regproc		prsstart BKI_LOOKUP(pg_proc);
diff --git a/src/include/catalog/pg_ts_template.h b/src/include/catalog/pg_ts_template.h
index 2ee1ae4e85..194b921136 100644
--- a/src/include/catalog/pg_ts_template.h
+++ b/src/include/catalog/pg_ts_template.h
@@ -34,7 +34,7 @@ CATALOG(pg_ts_template,3764,TSTemplateRelationId)
 	NameData	tmplname;
 
 	/* name space */
-	Oid			tmplnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
+	Oid			tmplnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace);
 
 	/* initialization method of dict (may be 0) */
 	regproc		tmplinit BKI_LOOKUP_OPT(pg_proc);
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 1ec8606703..8ee5fa0507 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -41,10 +41,10 @@ CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelati
 	NameData	typname;
 
 	/* OID of namespace containing this type */
-	Oid			typnamespace BKI_DEFAULT(PGNSP) BKI_LOOKUP(pg_namespace);
+	Oid			typnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace);
 
 	/* type owner */
-	Oid			typowner BKI_DEFAULT(PGUID) BKI_LOOKUP(pg_authid);
+	Oid			typowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid);
 
 	/*
 	 * For a fixed-size type, typlen is the number of bytes we use to
#13Joel Jacobson
joel@compiler.org
In reply to: Tom Lane (#6)
Re: Recording foreign key relationships for the system catalogs

On Mon, Feb 1, 2021, at 21:03, Tom Lane wrote:

"Joel Jacobson" <joel@compiler.org> writes:

The is_array OUT parameter doesn't say which of the possibly many fkcols that is the array column.

Yeah, I didn't write the sgml docs yet, but the comments explain that
the array is always the last fkcol. Maybe someday that won't be
general enough, but we can cross that bridge when we come to it.

I've now fully migrated to using pg_get_catalog_foreign_keys()
instead of my own lookup tables, and have some additional hands-on experiences
to share with you.

I struggle to come up with a clean way to make use of is_array,
without being forced to introduce some CASE logic to figure out
if the fkcol is an array or not.

The alternative to join information_schema.columns and check data_type='ARRAY' is almost simpler,
but that seems wrong, since we now have is_array, and using it should be simpler than
joining information_schema.columns.

The best approach I've come up with so far is the CASE logic below:

WITH
foreign_keys AS
(
SELECT
fktable::text AS table_name,
unnest(fkcols) AS column_name,
pktable::text AS ref_table_name,
unnest(pkcols) AS ref_column_name,
--
-- is_array refers to the last fkcols column
--
unnest
(
CASE cardinality(fkcols)
WHEN 1 THEN ARRAY[is_array]
WHEN 2 THEN ARRAY[FALSE,is_array]
END
) AS is_array
FROM pg_get_catalog_foreign_keys()
)

If is_array would instead have been an boolean[], the query could have been written:

WITH
foreign_keys AS
(
SELECT
fktable::text AS table_name,
unnest(fkcols) AS column_name,
pktable::text AS ref_table_name,
unnest(pkcols) AS ref_column_name,
unnest(is_array) AS is_array
FROM pg_get_catalog_foreign_keys()
)

Maybe this can be written in a simpler way already.

Otherwise I think it would be more natural to change both is_array and is_opt
to boolean[] with the same cardinality as fkcols and pkcols,
to allow unnest()ing of them as well.

This would also be a more future proof solution,
and wouldn't require a code change to code using pg_get_catalog_foreign_keys(),
if we would ever add more complex cases in the future.

But even without increased future complexity,
I think the example above demonstrates a problem already today.

Maybe there is a simpler way to achieve what I'm trying to do,
i.e. to figure out if a specific fkcol is an array or not,
using some other simpler clever trick than the CASE variant above?

/Joel

#14Joel Jacobson
joel@compiler.org
In reply to: Joel Jacobson (#13)
Re: Recording foreign key relationships for the system catalogs

On Wed, Feb 3, 2021, at 21:41, Joel Jacobson wrote:

Otherwise I think it would be more natural to change both is_array and is_opt
to boolean[] with the same cardinality as fkcols and pkcols,
to allow unnest()ing of them as well.

Another option would perhaps be to add a new
system view in src/backend/catalog/system_views.sql

I see there are other cases with a slightly more complex view
using a function with a similar name, such as
the pg_stat_activity using pg_stat_get_activity().

Similar to this, maybe we could add a pg_catalog_foreign_keys view
using the output from pg_get_catalog_foreign_keys():

Example usage:

SELECT * FROM pg_catalog_foreign_keys
WHERE fktable = 'pg_constraint'::regclass
AND pktable = 'pg_attribute'::regclass;

fkid | fktable | fkcol | pktable | pkcol | is_array | is_opt | ordinal_position
------+---------------+-----------+--------------+----------+----------+--------+------------------
48 | pg_constraint | conkey | pg_attribute | attnum | t | t | 1
48 | pg_constraint | conrelid | pg_attribute | attrelid | f | f | 2
49 | pg_constraint | confkey | pg_attribute | attnum | t | f | 1
49 | pg_constraint | confrelid | pg_attribute | attrelid | f | f | 2
(4 rows)

The point of this would be to avoid unnecessary increase of data model complexity,
which I agree is not needed, since we only need single booleans as of today,
but to provide a more information_schema-like system view,
i.e. with columns on separate rows, with ordinal_position.

Since we don't have any "constraint_name" for these,
we need to enumerate the fks first, to let ordinal_position
be the position within each such fkid.

Here is my proposal on how to implement:

CREATE VIEW pg_catalog_foreign_keys AS
WITH
enumerate_fks AS (
SELECT
*,
ROW_NUMBER() OVER () AS fkid
FROM pg_catalog.pg_get_catalog_foreign_keys()
),
unnest_cols AS (
SELECT
C.fkid,
C.fktable,
unnest(C.fkcols) AS fkcol,
C.pktable,
unnest(C.pkcols) AS pkcol,
unnest(
CASE cardinality(fkcols)
WHEN 1 THEN ARRAY[C.is_array]
WHEN 2 THEN ARRAY[FALSE,C.is_array]
END
) AS is_array,
unnest(
CASE cardinality(fkcols)
WHEN 1 THEN ARRAY[C.is_opt]
WHEN 2 THEN ARRAY[FALSE,C.is_opt]
END
) AS is_opt
FROM enumerate_fks AS C
)
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY U.fkid
ORDER BY U.fkcol, U.pkcol
) AS ordinal_position
FROM unnest_cols AS U;

I think both the pg_get_catalog_foreign_keys() function
and this view are useful in different ways,
so it's good to provide both.

Only providing pg_get_catalog_foreign_keys() will
arguably mean some users of the function will need to implement
something like the same as above on their own, if they need the is_array and is_opt
value for a specific fkcol.

/Joel