From ba814e507b384cad94bb603dbab036405a24c09f Mon Sep 17 00:00:00 2001
From: John Naylor <jcnaylor@gmail.com>
Date: Wed, 27 Dec 2017 18:23:57 +0700
Subject: [PATCH v5 11/13] Type aliases for OID lookups

Introduce dummy type aliases for OIDs referring to index access methods,
operators, opfamilies, and types. Teach genbki.pl to do the necessary OID
lookups, and to turn the aliases back into 'oid' when writing DDL. Since
all the lookup tables are now built before we start writing the data to
BKI files, we can be less stringent about the order the catalogs are
processed.
---
 src/backend/catalog/README        |   1 -
 src/backend/catalog/genbki.pl     | 151 ++++++++++++++++++++++++++++++++------
 src/include/catalog/genbki.h      |  10 +++
 src/include/catalog/pg_amop.h     |  12 +--
 src/include/catalog/pg_amproc.h   |   6 +-
 src/include/catalog/pg_cast.h     |   4 +-
 src/include/catalog/pg_opclass.h  |   8 +-
 src/include/catalog/pg_operator.h |  10 +--
 src/include/catalog/pg_opfamily.h |   2 +-
 src/include/catalog/pg_range.h    |   4 +-
 10 files changed, 163 insertions(+), 45 deletions(-)

diff --git a/src/backend/catalog/README b/src/backend/catalog/README
index 3b2cef6..72aad06 100644
--- a/src/backend/catalog/README
+++ b/src/backend/catalog/README
@@ -137,7 +137,6 @@ POSTGRES_BKI_SRCS variable, as these cannot be created through the standard
 heap_create_with_catalog process, because it needs these tables to exist
 already.  The list of files this currently includes is:
 	pg_proc.h pg_type.h pg_attribute.h pg_class.h
-Within this list, pg_type.h must come before pg_attribute.h.
 Also, indexing.h must be last, since the indexes can't be created until all
 the tables are in place, and toasting.h should probably be next-to-last
 (or at least after all the tables that need toast tables).  There are
diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl
index bc52bc6..c15ed20 100644
--- a/src/backend/catalog/genbki.pl
+++ b/src/backend/catalog/genbki.pl
@@ -124,6 +124,69 @@ my $BOOTSTRAP_SUPERUSERID =
 my $PG_CATALOG_NAMESPACE =
   Catalog::FindDefinedSymbolFromData($catalog_data{pg_namespace}, 'PG_CATALOG_NAMESPACE');
 
+# Build lookup tables for reg* substitutions and for pg_attribute
+# copies of pg_type values.
+
+# procedure OID lookup
+my %regprocoids;
+foreach my $row (@{ $catalog_data{pg_proc} })
+{
+	if (defined($regprocoids{ $row->{proname} }))
+	{
+		$regprocoids{ $row->{proname} } = 'MULTIPLE';
+	}
+	else
+	{
+		$regprocoids{ $row->{proname} } = $row->{oid};
+	}
+}
+
+# index access method OID lookup
+my %regamoids;
+foreach my $row (@{ $catalog_data{pg_am} })
+{
+	$regamoids{$row->{amname}} = $row->{oid};
+}
+
+# operator OID lookup
+my %regoperoids;
+foreach my $row (@{ $catalog_data{pg_operator} })
+{
+	# There is no unique name, so we need to invent one that contains
+	# the relevant type names.
+	my $key = sprintf "%s(%s,%s)",
+	  $row->{oprname}, $row->{oprleft}, $row->{oprright};
+	$regoperoids{$key} = $row->{oid};
+}
+
+# opfamily OID lookup
+my %regopfoids;
+foreach my $row (@{ $catalog_data{pg_opfamily} })
+{
+	# There is no unique name, so we need to combine access method
+	# and opfamily name.
+	my $key = sprintf "%s/%s",
+	  $row->{opfmethod}, $row->{opfname};
+	$regopfoids{$key} = $row->{oid};
+}
+
+# type lookups
+my %regtypeoids;
+my @types;
+foreach my $row (@{ $catalog_data{pg_type} })
+{
+	$regtypeoids{$row->{typname}} = $row->{oid};
+	push @types, $row;
+}
+
+# We use OID aliases to indicate when to do OID lookups, so column names
+# have to be turned back into 'oid' before writing the CREATE command.
+my %RENAME_REGOID = (
+	regam => 'oid',
+	regoper => 'oid',
+	regopf => 'oid',
+	regtype => 'oid');
+
 # Generate postgres.bki, postgres.description, and postgres.shdescription
 
 # version marker for .bki file
@@ -132,8 +195,6 @@ print $bki "# PostgreSQL $major_version\n";
 # vars to hold data needed for schemapg.h
 my %schemapg_entries;
 my @tables_needing_macros;
-my %regprocoids;
-my @types;
 
 # var to hold data for oid_symbols.h
 my %oid_symbols;
@@ -159,9 +220,12 @@ foreach my $catname (@catnames)
 	foreach my $column (@$schema)
 	{
 		my $attname = $column->{name};
-		my $atttype = $column->{type};
 		push @attnames, $attname;
 
+		my $atttype = $column->{type};
+		$atttype = $RENAME_REGOID{$atttype}
+		  if exists $RENAME_REGOID{$atttype};
+
 		if (!$first)
 		{
 			print $bki " ,\n";
@@ -207,38 +271,85 @@ foreach my $catname (@catnames)
 				$bki_values{$attname} =~ s/\bPGUID\b/$BOOTSTRAP_SUPERUSERID/g;
 				$bki_values{$attname} =~ s/\bPGNSP\b/$PG_CATALOG_NAMESPACE/g;
 
-				# Replace regproc columns' values with OIDs.
-				# If we don't have a unique value to substitute,
-				# just do nothing (regprocin will complain).
+				# Replace reg* columns' values with OIDs.
 				if ($atttype eq 'regproc')
 				{
+					# If we don't have a unique value to substitute,
+					# just do nothing (regprocin will complain).
 					my $procoid = $regprocoids{ $bki_values{$attname} };
 					$bki_values{$attname} = $procoid
 					  if defined($procoid) && $procoid ne 'MULTIPLE';
 				}
+				elsif ($atttype eq 'regam')
+				{
+					my $amoid = $regamoids{ $bki_values{$attname} };
+					$bki_values{$attname} = $amoid
+					  if defined($amoid);
+				}
+				elsif ($atttype eq 'regopf')
+				{
+					my $opfoid = $regopfoids{ $bki_values{$attname} };
+					$bki_values{$attname} = $opfoid
+					  if defined($opfoid);
+				}
+				elsif ($atttype eq 'regoper')
+				{
+					my $operoid = $regoperoids{ $bki_values{$attname} };
+					$bki_values{$attname} = $operoid
+					  if defined($operoid);
+				}
+				elsif ($atttype eq 'regtype')
+				{
+					my $typeoid = $regtypeoids{ $bki_values{$attname} };
+					$bki_values{$attname} = $typeoid
+					  if defined($typeoid);
+				}
 			}
 
-			# Save pg_proc oids for use in later regproc substitutions.
-			# This relies on the order we process the files in!
+			# We can't do regtype lookups in a general way for
+			# pg_proc, so do special handling here.
 			if ($catname eq 'pg_proc')
 			{
-				if (defined($regprocoids{ $bki_values{proname} }))
+
+				# prorettype
+				# Note: We could handle this automatically by using the
+				# 'regtype' alias, but then we would have to teach
+				# emit_pgattr_row() to change the attribute type back to
+				# oid. Since we have to treat pg_proc differently anyway,
+				# just do the type lookup manually here.
+				my $rettypeoid = $regtypeoids{ $bki_values{prorettype}};
+				$bki_values{prorettype} = $rettypeoid
+				  if defined($rettypeoid);
+
+				# proargtypes
+				if ($bki_values{proargtypes})
 				{
-					$regprocoids{ $bki_values{proname} } = 'MULTIPLE';
+					my @argtypenames = split /\s+/, $bki_values{proargtypes};
+					my @argtypeoids;
+					foreach my $argtypename (@argtypenames)
+					{
+						my $argtypeoid  = $regtypeoids{$argtypename};
+						push @argtypeoids, $argtypeoid;
+					}
+					$bki_values{proargtypes} = join(' ', @argtypeoids);
 				}
-				else
+
+				# proallargtypes
+				if ($bki_values{proallargtypes} ne '_null_')
 				{
-					$regprocoids{ $bki_values{proname} } = $bki_values{oid};
+					$bki_values{proallargtypes} =~ s/[{}]//g;
+					my @argtypenames = split /,/, $bki_values{proallargtypes};
+					my @argtypeoids;
+					foreach my $argtypename (@argtypenames)
+					{
+						my $argtypeoid  = $regtypeoids{$argtypename};
+						push @argtypeoids, $argtypeoid;
+					}
+					$bki_values{proallargtypes} =
+						'{' . join(',', @argtypeoids) . '}';
 				}
 			}
 
-			# Save pg_type info for pg_attribute processing below
-			if ($catname eq 'pg_type')
-			{
-				my %type = %bki_values;
-				push @types, \%type;
-			}
-
 			# Store OID symbols for later.
 			if (exists $bki_values{oid_symbol})
 			{
@@ -278,8 +389,6 @@ foreach my $catname (@catnames)
 	{
 
 		# For pg_attribute.h, we generate data entries ourselves.
-		# NB: pg_type.h must come before pg_attribute.h in the input list
-		# of catalog names, since we use info from pg_type.h here.
 		foreach my $table_name (@catnames)
 		{
 			my $table = $catalogs{$table_name};
diff --git a/src/include/catalog/genbki.h b/src/include/catalog/genbki.h
index 5537b61..70d2761 100644
--- a/src/include/catalog/genbki.h
+++ b/src/include/catalog/genbki.h
@@ -37,6 +37,16 @@
 /* Specifies an abbreviated label for a column name */
 #define BKI_ABBREV(abbrev)
 
+/* ----------------
+ *	Some columns of type Oid have human-readable entries that are
+ *	resolved when creating postgres.bki.
+ * ----------------
+ */
+#define regam Oid
+#define regoper Oid
+#define regopf Oid
+#define regtype Oid
+
 /*
  * This is never defined; it's here only for documentation.
  *
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index c73f24b..247f067 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -56,13 +56,13 @@
 CATALOG(pg_amop,2602)
 {
 	/* the index opfamily this entry is for */
-	Oid			amopfamily BKI_ABBREV(opf);
+	regopf		amopfamily BKI_ABBREV(opf);
 
 	/* operator's left input data type */
-	Oid			amoplefttype BKI_ABBREV(lt);
+	regtype		amoplefttype BKI_ABBREV(lt);
 
 	/* operator's right input data type */
-	Oid			amoprighttype BKI_ABBREV(rt);
+	regtype		amoprighttype BKI_ABBREV(rt);
 
 	/* operator strategy number */
 	int16		amopstrategy BKI_ABBREV(str);
@@ -71,13 +71,13 @@ CATALOG(pg_amop,2602)
 	char		amoppurpose BKI_ABBREV(pur) BKI_DEFAULT(s);
 
 	/* the operator's pg_operator OID */
-	Oid			amopopr BKI_ABBREV(oper);
+	regoper		amopopr BKI_ABBREV(oper);
 
 	/* the index access method this entry is for */
-	Oid			amopmethod BKI_ABBREV(am);
+	regam		amopmethod BKI_ABBREV(am);
 
 	/* ordering opfamily OID, or 0 if search op */
-	Oid			amopsortfamily BKI_DEFAULT(0);
+	regopf		amopsortfamily BKI_DEFAULT(0);
 } FormData_pg_amop;
 
 /* allowed values of amoppurpose: */
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index afdfeb1..17ed0e2 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -45,13 +45,13 @@
 CATALOG(pg_amproc,2603)
 {
 	/* the index opfamily this entry is for */
-	Oid			amprocfamily BKI_ABBREV(opf);
+	regopf		amprocfamily BKI_ABBREV(opf);
 
 	/* procedure's left input data type */
-	Oid			amproclefttype BKI_ABBREV(lt);
+	regtype		amproclefttype BKI_ABBREV(lt);
 
 	/* procedure's right input data type */
-	Oid			amprocrighttype BKI_ABBREV(rt);
+	regtype		amprocrighttype BKI_ABBREV(rt);
 
 	/* support procedure index */
 	int16		amprocnum BKI_ABBREV(num);
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index 93e7b56..fbe9949 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -32,8 +32,8 @@
 
 CATALOG(pg_cast,2605)
 {
-	Oid			castsource;		/* source datatype for cast */
-	Oid			casttarget;		/* destination datatype for cast */
+	regtype		castsource;		/* source datatype for cast */
+	regtype		casttarget;		/* destination datatype for cast */
 	Oid			castfunc;		/* cast function; 0 = binary coercible */
 	char		castcontext;	/* contexts in which cast can be used */
 	char		castmethod;		/* cast method */
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index f44a0aa..c9ed806 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -51,7 +51,7 @@
 
 CATALOG(pg_opclass,2616)
 {
-	Oid			opcmethod;		/* index access method opclass is for */
+	regam		opcmethod;		/* index access method opclass is for */
 	NameData	opcname;		/* name of this opclass */
 
 	/* namespace of this opclass */
@@ -60,14 +60,14 @@ CATALOG(pg_opclass,2616)
 	/* opclass owner */
 	Oid			opcowner BKI_DEFAULT(PGUID);
 
-	Oid			opcfamily;		/* containing operator family */
-	Oid			opcintype;		/* type of data indexed by opclass */
+	regopf		opcfamily;		/* containing operator family */
+	regtype		opcintype;		/* type of data indexed by opclass */
 
 	/* T if opclass is default for opcintype */
 	bool		opcdefault BKI_DEFAULT(t);
 
 	/* type of data in index, or InvalidOid */
-	Oid			opckeytype BKI_DEFAULT(0);
+	regtype		opckeytype BKI_DEFAULT(0);
 } FormData_pg_opclass;
 
 /* ----------------
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index cd6e227..a099c9f 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -51,19 +51,19 @@ CATALOG(pg_operator,2617)
 	bool		oprcanhash BKI_DEFAULT(f);
 
 	/* left arg type, or 0 if 'l' oprkind */
-	Oid			oprleft;
+	regtype		oprleft;
 
 	/* right arg type, or 0 if 'r' oprkind */
-	Oid			oprright;
+	regtype		oprright;
 
 	/* result datatype */
-	Oid			oprresult;
+	regtype		oprresult;
 
 	/* OID of commutator oper, or 0 if none */
-	Oid			oprcom BKI_DEFAULT(0);
+	regoper		oprcom BKI_DEFAULT(0);
 
 	/* OID of negator oper, or 0 if none */
-	Oid			oprnegate BKI_DEFAULT(0);
+	regoper		oprnegate BKI_DEFAULT(0);
 
 	/* OID of underlying function */
 	regproc		oprcode;
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index a9be48f..ce3b07e 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -31,7 +31,7 @@
 
 CATALOG(pg_opfamily,2753)
 {
-	Oid			opfmethod;		/* index access method opfamily is for */
+	regam		opfmethod;		/* index access method opfamily is for */
 	NameData	opfname;		/* name of this opfamily */
 
 	/* namespace of this opfamily */
diff --git a/src/include/catalog/pg_range.h b/src/include/catalog/pg_range.h
index fa57096..e0bf704 100644
--- a/src/include/catalog/pg_range.h
+++ b/src/include/catalog/pg_range.h
@@ -30,8 +30,8 @@
 
 CATALOG(pg_range,3541) BKI_WITHOUT_OIDS
 {
-	Oid			rngtypid;		/* OID of owning range type */
-	Oid			rngsubtype;		/* OID of range's element type (subtype) */
+	regtype		rngtypid;		/* OID of owning range type */
+	regtype		rngsubtype;		/* OID of range's element type (subtype) */
 	Oid			rngcollation;	/* collation for this range type, or 0 */
 	Oid			rngsubopc;		/* subtype's btree opclass */
 	regproc		rngcanonical;	/* canonicalize range, or 0 */
-- 
2.7.4

