From f4891dd383c56b886297c954a062d0a0040bdbbf Mon Sep 17 00:00:00 2001
From: John Naylor <jcnaylor@gmail.com>
Date: Thu, 14 Dec 2017 16:52:12 +0700
Subject: [PATCH 10/10] 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 oids when writing DDL.
---
 src/backend/catalog/genbki.pl     | 140 +++++++++++++++++++++++++++++++++++---
 src/include/catalog/genbki.h      |  10 +++
 src/include/catalog/pg_amop.h     |  10 +--
 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 |   6 +-
 src/include/catalog/pg_opfamily.h |   2 +-
 src/include/catalog/pg_range.h    |   4 +-
 9 files changed, 161 insertions(+), 29 deletions(-)

diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl
index 973ffc2..9de95cb 100644
--- a/src/backend/catalog/genbki.pl
+++ b/src/backend/catalog/genbki.pl
@@ -114,6 +114,57 @@ my $catalog_data = Catalog::ParseData(@datfiles);
 # tables here. However, if we need default values for a catalog, we
 # need to wait until the full tuples have been built.
 
+# vars to hold lookups built later
+my %regprocoids;
+my @types;
+
+# 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.
+	# Note: assumes that we're only interested in binary operators.
+	if (defined $row->{oprleft} and defined $row->{oprright})
+	{
+		my $key = "$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.
+	$regopfoids{$row->{opfmethod} . '/' . $row->{opfname}} = $row->{oid};
+}
+
+# type OID lookup
+# Note: We can't just use the same type lookup that pg_attribute uses,
+# because pg_proc has type names and comes before pg_type in the input list.
+my %regtypeoids;
+foreach my $row (@{ $catalog_data->{pg_type} })
+{
+	$regtypeoids{$row->{typname}} = $row->{oid};
+}
+
+# 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
@@ -122,8 +173,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;
 
 # Produce output, one catalog at a time.
 foreach my $catname (@{ $catalogs->{names} })
@@ -145,9 +194,12 @@ foreach my $catname (@{ $catalogs->{names} })
 	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";
@@ -201,21 +253,49 @@ foreach my $catname (@{ $catalogs->{names} })
 				$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')
 				{
 					my $procoid = $regprocoids{ $bki_values{$attname} };
+
+					# If we don't have a unique value to substitute,
+					# just do nothing (regprocin will complain).
 					$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!
 			if ($catname eq 'pg_proc')
 			{
+				# Save pg_proc oids for use in later regproc substitutions.
+				# We build this lookup after the forming the full tuple,
+				# since otherwise the script will break if the abbreviation
+				# for 'proname' is changed. This is fine since pg_proc
+				# comes first in the input list.
 				if (defined($regprocoids{ $bki_values{proname} }))
 				{
 					$regprocoids{ $bki_values{proname} } = 'MULTIPLE';
@@ -224,9 +304,51 @@ foreach my $catname (@{ $catalogs->{names} })
 				{
 					$regprocoids{ $bki_values{proname} } = $bki_values{oid};
 				}
+
+				# We can't do type lookups in a general way for pg_proc,
+				# so do special handling here.
+
+				# prorettype
+				# Note: We could handle this automatically by using the
+				# 'regtype' alias, but then we would have to teach
+				# emit_pgattr_row() to change it 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})
+				{
+					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);
+				}
+
+				# proallargtypes
+				if ($bki_values{proallargtypes} ne '_null_')
+				{
+					$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
+			# Save pg_type info for pg_attribute processing below.
+			# We need to build this lookup after the forming the full tuple.
 			if ($catname eq 'pg_type')
 			{
 				my %type = %bki_values;
diff --git a/src/include/catalog/genbki.h b/src/include/catalog/genbki.h
index c3ffa29..39e9b59 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(abb)
 
+/* ----------------
+ *	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 5724e3f..3d9e9e7 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,10 +71,10 @@ 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);
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 e0e4f62..472511c 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -50,7 +50,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 */
@@ -59,14 +59,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 fe6b660..8ca7621 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -50,13 +50,13 @@ CATALOG(pg_operator,2617)
 	bool		oprcanhash BKI_DEFAULT(f);
 
 	/* left arg type, or 0 if 'l' oprkind */
-	Oid			oprleft;
+	regtype		oprleft BKI_DEFAULT(0);
 
 	/* right arg type, or 0 if 'r' oprkind */
-	Oid			oprright;
+	regtype		oprright BKI_DEFAULT(0);
 
 	/* result datatype */
-	Oid			oprresult;
+	regtype		oprresult;
 
 	/* OID of commutator oper, or 0 if none */
 	Oid			oprcom BKI_DEFAULT(0);
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index b683770..2f410b4 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -30,7 +30,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

