From fa922804d1facffa6a74662120dd13f3f46f7d65 Mon Sep 17 00:00:00 2001
From: Julien Rouhaud <julien.rouhaud@free.fr>
Date: Thu, 5 Dec 2019 18:59:28 +0100
Subject: [PATCH 3/6] Implement type regcollation.

This will be helpful for a following commit.

Author: Julien Rouhaud
Reviewed-by:
Discussion: https://postgr.es/m/CAEepm%3D0uEQCpfq_%2BLYFBdArCe4Ot98t1aR4eYiYTe%3DyavQygiQ%40mail.gmail.com
---
 src/backend/utils/adt/regproc.c | 152 ++++++++++++++++++++++++++++++++
 src/include/catalog/pg_cast.dat |  14 +++
 src/include/catalog/pg_proc.dat |  15 ++++
 src/include/catalog/pg_type.dat |   4 +
 4 files changed, 185 insertions(+)

diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index f0fa52bc27..da8cc0cf6b 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -24,6 +24,7 @@
 #include "access/htup_details.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_class.h"
+#include "catalog/pg_collation.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_ts_config.h"
@@ -1043,6 +1044,157 @@ regclasssend(PG_FUNCTION_ARGS)
 }
 
 
+/*
+ * regcollationin		- converts "collationname" to collation OID
+ *
+ * We also accept a numeric OID, for symmetry with the output routine.
+ *
+ * '-' signifies unknown (OID 0).  In all other cases, the input must
+ * match an existing pg_collation entry.
+ */
+Datum
+regcollationin(PG_FUNCTION_ARGS)
+{
+	char	   *collation_name_or_oid = PG_GETARG_CSTRING(0);
+	Oid			result = InvalidOid;
+	List	   *names;
+
+	/* '-' ? */
+	if (strcmp(collation_name_or_oid, "-") == 0)
+		PG_RETURN_OID(InvalidOid);
+
+	/* Numeric OID? */
+	if (collation_name_or_oid[0] >= '0' &&
+		collation_name_or_oid[0] <= '9' &&
+		strspn(collation_name_or_oid, "0123456789") == strlen(collation_name_or_oid))
+	{
+		result = DatumGetObjectId(DirectFunctionCall1(oidin,
+													  CStringGetDatum(collation_name_or_oid)));
+		PG_RETURN_OID(result);
+	}
+
+	/* Else it's a name, possibly schema-qualified */
+
+	/* The rest of this wouldn't work in bootstrap mode */
+	if (IsBootstrapProcessingMode())
+		elog(ERROR, "regcollation values must be OIDs in bootstrap mode");
+
+	/*
+	 * Normal case: parse the name into components and see if it matches any
+	 * pg_collation entries in the current search path.
+	 */
+	names = stringToQualifiedNameList(collation_name_or_oid);
+
+	result = get_collation_oid(names, false);
+
+	PG_RETURN_OID(result);
+}
+
+/*
+ * to_regcollation		- converts "collationname" to collation OID
+ *
+ * If the name is not found, we return NULL.
+ */
+Datum
+to_regcollation(PG_FUNCTION_ARGS)
+{
+	char	   *collation_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
+	Oid			result;
+	List	   *names;
+
+	/*
+	 * Parse the name into components and see if it matches any pg_collation
+	 * entries in the current search path.
+	 */
+	names = stringToQualifiedNameList(collation_name);
+
+	/* We might not even have permissions on this relation; don't lock it. */
+	result = get_collation_oid(names, true);
+
+	if (OidIsValid(result))
+		PG_RETURN_OID(result);
+	else
+		PG_RETURN_NULL();
+}
+
+/*
+ * regcollationout		- converts collation OID to "collation_name"
+ */
+Datum
+regcollationout(PG_FUNCTION_ARGS)
+{
+	Oid			collationid = PG_GETARG_OID(0);
+	char	   *result;
+	HeapTuple	collationtup;
+
+	if (collationid == InvalidOid)
+	{
+		result = pstrdup("-");
+		PG_RETURN_CSTRING(result);
+	}
+
+	collationtup = SearchSysCache1(COLLOID, ObjectIdGetDatum(collationid));
+
+	if (HeapTupleIsValid(collationtup))
+	{
+		Form_pg_collation collationform = (Form_pg_collation) GETSTRUCT(collationtup);
+		char	   *collationname = NameStr(collationform->collname);
+
+		/*
+		 * In bootstrap mode, skip the fancy namespace stuff and just return
+		 * the collation name.  (This path is only needed for debugging output
+		 * anyway.)
+		 */
+		if (IsBootstrapProcessingMode())
+			result = pstrdup(collationname);
+		else
+		{
+			char	   *nspname;
+
+			/*
+			 * Would this collation be found by regcollationin? If not, qualify it.
+			 */
+			if (CollationIsVisible(collationid))
+				nspname = NULL;
+			else
+				nspname = get_namespace_name(collationform->collnamespace);
+
+			result = quote_qualified_identifier(nspname, collationname);
+		}
+
+		ReleaseSysCache(collationtup);
+	}
+	else
+	{
+		/* If OID doesn't match any pg_collation entry, return it numerically */
+		result = (char *) palloc(NAMEDATALEN);
+		snprintf(result, NAMEDATALEN, "%u", collationid);
+	}
+
+	PG_RETURN_CSTRING(result);
+}
+
+/*
+ *		regcollationrecv			- converts external binary format to regcollation
+ */
+Datum
+regcollationrecv(PG_FUNCTION_ARGS)
+{
+	/* Exactly the same as oidrecv, so share code */
+	return oidrecv(fcinfo);
+}
+
+/*
+ *		regcollationsend			- converts regcollation to binary format
+ */
+Datum
+regcollationsend(PG_FUNCTION_ARGS)
+{
+	/* Exactly the same as oidsend, so share code */
+	return oidsend(fcinfo);
+}
+
+
 /*
  * regtypein		- converts "typename" to type OID
  *
diff --git a/src/include/catalog/pg_cast.dat b/src/include/catalog/pg_cast.dat
index 6ef8b8a4e7..01c5328ddd 100644
--- a/src/include/catalog/pg_cast.dat
+++ b/src/include/catalog/pg_cast.dat
@@ -189,6 +189,20 @@
   castcontext => 'a', castmethod => 'f' },
 { castsource => 'regclass', casttarget => 'int4', castfunc => '0',
   castcontext => 'a', castmethod => 'b' },
+{ castsource => 'oid', casttarget => 'regcollation', castfunc => '0',
+  castcontext => 'i', castmethod => 'b' },
+{ castsource => 'regcollation', casttarget => 'oid', castfunc => '0',
+  castcontext => 'i', castmethod => 'b' },
+{ castsource => 'int8', casttarget => 'regcollation', castfunc => 'oid',
+  castcontext => 'i', castmethod => 'f' },
+{ castsource => 'int2', casttarget => 'regcollation', castfunc => 'int4(int2)',
+  castcontext => 'i', castmethod => 'f' },
+{ castsource => 'int4', casttarget => 'regcollation', castfunc => '0',
+  castcontext => 'i', castmethod => 'b' },
+{ castsource => 'regcollation', casttarget => 'int8', castfunc => 'int8(oid)',
+  castcontext => 'a', castmethod => 'f' },
+{ castsource => 'regcollation', casttarget => 'int4', castfunc => '0',
+  castcontext => 'a', castmethod => 'b' },
 { castsource => 'oid', casttarget => 'regtype', castfunc => '0',
   castcontext => 'i', castmethod => 'b' },
 { castsource => 'regtype', casttarget => 'oid', castfunc => '0',
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 07a86c7b7b..f8fb62c623 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6666,6 +6666,15 @@
 { oid => '3495', descr => 'convert classname to regclass',
   proname => 'to_regclass', provolatile => 's', prorettype => 'regclass',
   proargtypes => 'text', prosrc => 'to_regclass' },
+{ oid => '9508', descr => 'I/O',
+  proname => 'regcollationin', provolatile => 's', prorettype => 'regcollation',
+  proargtypes => 'cstring', prosrc => 'regcollationin' },
+{ oid => '9509', descr => 'I/O',
+  proname => 'regcollationout', provolatile => 's', prorettype => 'cstring',
+  proargtypes => 'regcollation', prosrc => 'regcollationout' },
+{ oid => '9510', descr => 'convert classname to regcollation',
+  proname => 'to_regcollation', provolatile => 's', prorettype => 'regcollation',
+  proargtypes => 'text', prosrc => 'to_regcollation' },
 { oid => '2220', descr => 'I/O',
   proname => 'regtypein', provolatile => 's', prorettype => 'regtype',
   proargtypes => 'cstring', prosrc => 'regtypein' },
@@ -7452,6 +7461,12 @@
 { oid => '2453', descr => 'I/O',
   proname => 'regclasssend', prorettype => 'bytea', proargtypes => 'regclass',
   prosrc => 'regclasssend' },
+{ oid => '9511', descr => 'I/O',
+  proname => 'regcollationrecv', prorettype => 'regcollation',
+  proargtypes => 'internal', prosrc => 'regcollationrecv' },
+{ oid => '9512', descr => 'I/O',
+  proname => 'regcollationsend', prorettype => 'bytea', proargtypes => 'regcollation',
+  prosrc => 'regcollationsend' },
 { oid => '2454', descr => 'I/O',
   proname => 'regtyperecv', prorettype => 'regtype', proargtypes => 'internal',
   prosrc => 'regtyperecv' },
diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat
index 4cf2b9df7b..e4d9406730 100644
--- a/src/include/catalog/pg_type.dat
+++ b/src/include/catalog/pg_type.dat
@@ -379,6 +379,10 @@
   typname => 'regclass', typlen => '4', typbyval => 't', typcategory => 'N',
   typinput => 'regclassin', typoutput => 'regclassout',
   typreceive => 'regclassrecv', typsend => 'regclasssend', typalign => 'i' },
+{ oid => '9506', array_type_oid => '9507', descr => 'registered collation',
+  typname => 'regcollation', typlen => '4', typbyval => 't', typcategory => 'N',
+  typinput => 'regcollationin', typoutput => 'regcollationout',
+  typreceive => 'regcollationrecv', typsend => 'regcollationsend', typalign => 'i' },
 { oid => '2206', array_type_oid => '2211', descr => 'registered type',
   typname => 'regtype', typlen => '4', typbyval => 't', typcategory => 'N',
   typinput => 'regtypein', typoutput => 'regtypeout',
-- 
2.25.1

