From 3ef5874b4e3b65b81199dbf878f53d820940be96 Mon Sep 17 00:00:00 2001
From: vignesh <vignesh21@gmail.com>
Date: Wed, 19 May 2021 10:53:29 +0530
Subject: [PATCH v1 1/2] Implement type regpublication

It will help in casting publication information and it's also just generally
useful, like the other reg* types.
---
 doc/src/sgml/datatype.sgml            |  11 +++
 doc/src/sgml/func.sgml                |  18 ++++
 doc/src/sgml/ref/pgupgrade.sgml       |   1 +
 src/backend/utils/adt/regproc.c       | 126 ++++++++++++++++++++++++++
 src/bin/pg_upgrade/check.c            |   3 +-
 src/include/catalog/pg_cast.dat       |  14 +++
 src/include/catalog/pg_proc.dat       |  15 +++
 src/include/catalog/pg_type.dat       |   4 +
 src/test/regress/expected/regproc.out |  55 +++++++++++
 src/test/regress/sql/regproc.sql      |  16 ++++
 10 files changed, 262 insertions(+), 1 deletion(-)

diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 0e8ef958a9..dd578f3535 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -4603,6 +4603,10 @@ INSERT INTO mytable VALUES(-1);  -- fails
     <primary>regprocedure</primary>
    </indexterm>
 
+   <indexterm zone="datatype-oid">
+    <primary>regpublication</primary>
+   </indexterm>
+
    <indexterm zone="datatype-oid">
     <primary>regrole</primary>
    </indexterm>
@@ -4763,6 +4767,13 @@ SELECT * FROM pg_attribute
         <entry><literal>sum(int4)</literal></entry>
        </row>
 
+       <row>
+        <entry><type>regpublication</type></entry>
+        <entry><structname>pg_publication</structname></entry>
+        <entry>publication name</entry>
+        <entry><literal>testpub</literal></entry>
+       </row>
+
        <row>
         <entry><type>regrole</type></entry>
         <entry><structname>pg_authid</structname></entry>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 08b07f561e..50da778b06 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -23596,6 +23596,24 @@ SELECT collation for ('foo' COLLATE "de_DE");
        </para></entry>
       </row>
 
+      <row>
+       <entry role="func_table_entry"><para role="func_signature">
+        <indexterm>
+         <primary>to_regpublication</primary>
+        </indexterm>
+        <function>to_regpublication</function> ( <type>text</type> )
+        <returnvalue>regpublication</returnvalue>
+       </para>
+       <para>
+        Translates a textual publication name to its OID.  A similar result is
+        obtained by casting the string to type <type>regpublication</type> (see
+        <xref linkend="datatype-oid"/>); however, this function will return
+        <literal>NULL</literal> rather than throwing an error if the name is
+        not found.  Also unlike the cast, this does not accept
+        a numeric OID as input.
+       </para></entry>
+      </row>
+
       <row>
        <entry role="func_table_entry"><para role="func_signature">
         <indexterm>
diff --git a/doc/src/sgml/ref/pgupgrade.sgml b/doc/src/sgml/ref/pgupgrade.sgml
index a83c63cd98..bb2d908da6 100644
--- a/doc/src/sgml/ref/pgupgrade.sgml
+++ b/doc/src/sgml/ref/pgupgrade.sgml
@@ -785,6 +785,7 @@ psql --username=postgres --file=script.sql postgres
     <member><type>regoperator</type></member>
     <member><type>regproc</type></member>
     <member><type>regprocedure</type></member>
+    <member><type>regpublication</type></member>
    </simplelist>
    (<type>regclass</type>, <type>regrole</type>, and <type>regtype</type> can be upgraded.)
   </para>
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index f998fe2076..dfa826f1c2 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -27,6 +27,7 @@
 #include "catalog/pg_collation.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
+#include "catalog/pg_publication.h"
 #include "catalog/pg_ts_config.h"
 #include "catalog/pg_ts_dict.h"
 #include "catalog/pg_type.h"
@@ -1231,6 +1232,131 @@ regcollationsend(PG_FUNCTION_ARGS)
 	return oidsend(fcinfo);
 }
 
+/*
+ * regpublicationin		- converts "publicationname" to publication 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_publication entry.
+ */
+Datum
+regpublicationin(PG_FUNCTION_ARGS)
+{
+	char	   *publication_name_or_oid = PG_GETARG_CSTRING(0);
+	Oid			result = InvalidOid;
+	List	   *names;
+
+	/* '-' ? */
+	if (strcmp(publication_name_or_oid, "-") == 0)
+		PG_RETURN_OID(InvalidOid);
+
+	/* Numeric OID? */
+	if (publication_name_or_oid[0] >= '0' &&
+		publication_name_or_oid[0] <= '9' &&
+		strspn(publication_name_or_oid, "0123456789") == strlen(publication_name_or_oid))
+	{
+		result = DatumGetObjectId(DirectFunctionCall1(oidin,
+													  CStringGetDatum(publication_name_or_oid)));
+		PG_RETURN_OID(result);
+	}
+
+	/* The rest of this wouldn't work in bootstrap mode */
+	if (IsBootstrapProcessingMode())
+		elog(ERROR, "regpublication values must be OIDs in bootstrap mode");
+
+	/*
+	 * Normal case: parse the name into components and see if it matches any
+	 * pg_publication entries in the current search path.
+	 */
+	names = stringToQualifiedNameList(publication_name_or_oid);
+	if (list_length(names) != 1)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_NAME),
+				 errmsg("invalid name syntax")));
+
+	result = get_publication_oid(strVal(linitial(names)), false);
+
+	PG_RETURN_OID(result);
+}
+
+/*
+ * to_regpublication		- converts "publicationname" to publication OID
+ *
+ * If the name is not found, we return NULL.
+ */
+Datum
+to_regpublication(PG_FUNCTION_ARGS)
+{
+	char	   *publication_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
+	Oid			result;
+	List	   *names;
+
+	names = stringToQualifiedNameList(publication_name);
+	if (list_length(names) != 1)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_NAME),
+				 errmsg("invalid name syntax")));
+
+	result = get_publication_oid(strVal(linitial(names)), true);
+
+	if (OidIsValid(result))
+		PG_RETURN_OID(result);
+	else
+		PG_RETURN_NULL();
+}
+
+/*
+ * regpublicationout		- converts publication OID to "publication_name"
+ */
+Datum
+regpublicationout(PG_FUNCTION_ARGS)
+{
+	Oid			publicationid = PG_GETARG_OID(0);
+	char	   *result;
+
+	if (publicationid == InvalidOid)
+	{
+		result = pstrdup("-");
+		PG_RETURN_CSTRING(result);
+	}
+
+	result = get_publication_name(publicationid, true);
+	if (result)
+	{
+		/* pstrdup is not really necessary, but it avoids a compiler warning */
+		result = pstrdup(quote_identifier(result));
+	}
+	else
+	{
+		/* If OID doesn't match any publication, return it numerically */
+		result = (char *) palloc(NAMEDATALEN);
+		snprintf(result, NAMEDATALEN, "%u", publicationid);
+	}
+
+	PG_RETURN_CSTRING(result);
+}
+
+/*
+ *		regpublicationrecv			- converts external binary format to regpublication
+ */
+Datum
+regpublicationrecv(PG_FUNCTION_ARGS)
+{
+	/* Exactly the same as oidrecv, so share code */
+	return oidrecv(fcinfo);
+}
+
+/*
+ *		regpublicationsend			- converts regpublication to binary format
+ */
+Datum
+regpublicationsend(PG_FUNCTION_ARGS)
+{
+	/* Exactly the same as oidsend, so share code */
+	return oidsend(fcinfo);
+}
+
 
 /*
  * regtypein		- converts "typename" to type OID
diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c
index 0c47a6b8cc..8037874af5 100644
--- a/src/bin/pg_upgrade/check.c
+++ b/src/bin/pg_upgrade/check.c
@@ -1141,7 +1141,8 @@ check_for_reg_data_type_usage(ClusterInfo *cluster)
 									   "           'regoper', "
 									   "           'regoperator', "
 									   "           'regproc', "
-									   "           'regprocedure' "
+									   "           'regprocedure', "
+									   "		   'regpublication' "
 	/* pg_authid.oid is preserved, so 'regrole' is OK */
 	/* pg_type.oid is (mostly) preserved, so 'regtype' is OK */
 									   "         )",
diff --git a/src/include/catalog/pg_cast.dat b/src/include/catalog/pg_cast.dat
index 67f73cb6fb..63007d6527 100644
--- a/src/include/catalog/pg_cast.dat
+++ b/src/include/catalog/pg_cast.dat
@@ -207,6 +207,20 @@
   castcontext => 'a', castmethod => 'f' },
 { castsource => 'regcollation', casttarget => 'int4', castfunc => '0',
   castcontext => 'a', castmethod => 'b' },
+{ castsource => 'oid', casttarget => 'regpublication', castfunc => '0',
+  castcontext => 'i', castmethod => 'b' },
+{ castsource => 'regpublication', casttarget => 'oid', castfunc => '0',
+  castcontext => 'i', castmethod => 'b' },
+{ castsource => 'int8', casttarget => 'regpublication', castfunc => 'oid',
+  castcontext => 'i', castmethod => 'f' },
+{ castsource => 'int2', casttarget => 'regpublication', castfunc => 'int4(int2)',
+  castcontext => 'i', castmethod => 'f' },
+{ castsource => 'int4', casttarget => 'regpublication', castfunc => '0',
+  castcontext => 'i', castmethod => 'b' },
+{ castsource => 'regpublication', casttarget => 'int8', castfunc => 'int8(oid)',
+  castcontext => 'a', castmethod => 'f' },
+{ castsource => 'regpublication', 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 acbcae4607..11c6967348 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6882,6 +6882,15 @@
   proname => 'to_regcollation', provolatile => 's',
   prorettype => 'regcollation', proargtypes => 'text',
   prosrc => 'to_regcollation' },
+{ oid => '4544', descr => 'I/O',
+  proname => 'regpublicationin', provolatile => 's', prorettype => 'regpublication',
+  proargtypes => 'cstring', prosrc => 'regpublicationin' },
+{ oid => '4545', descr => 'I/O',
+  proname => 'regpublicationout', provolatile => 's', prorettype => 'cstring',
+  proargtypes => 'regpublication', prosrc => 'regpublicationout' },
+{ oid => '4546', descr => 'convert classname to regpublication',
+  proname => 'to_regpublication', provolatile => 's', prorettype => 'regpublication',
+  proargtypes => 'text', prosrc => 'to_regpublication' },
 { oid => '2220', descr => 'I/O',
   proname => 'regtypein', provolatile => 's', prorettype => 'regtype',
   proargtypes => 'cstring', prosrc => 'regtypein' },
@@ -7715,6 +7724,12 @@
 { oid => '4197', descr => 'I/O',
   proname => 'regcollationsend', prorettype => 'bytea',
   proargtypes => 'regcollation', prosrc => 'regcollationsend' },
+{ oid => '4547', descr => 'I/O',
+  proname => 'regpublicationrecv', prorettype => 'regpublication',
+  proargtypes => 'internal', prosrc => 'regpublicationrecv' },
+{ oid => '4548', descr => 'I/O',
+  proname => 'regpublicationsend', prorettype => 'bytea',
+  proargtypes => 'regpublication', prosrc => 'regpublicationsend' },
 { 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 41074c994b..cf2b7d1890 100644
--- a/src/include/catalog/pg_type.dat
+++ b/src/include/catalog/pg_type.dat
@@ -385,6 +385,10 @@
   typinput => 'regcollationin', typoutput => 'regcollationout',
   typreceive => 'regcollationrecv', typsend => 'regcollationsend',
   typalign => 'i' },
+{ oid => '4549', array_type_oid => '4550', descr => 'registered publication',
+  typname => 'regpublication', typlen => '4', typbyval => 't', typcategory => 'N',
+  typinput => 'regpublicationin', typoutput => 'regpublicationout',
+  typreceive => 'regpublicationrecv', typsend => 'regpublicationsend', typalign => 'i' },
 { oid => '2206', array_type_oid => '2211', descr => 'registered type',
   typname => 'regtype', typlen => '4', typbyval => 't', typcategory => 'N',
   typinput => 'regtypein', typoutput => 'regtypeout',
diff --git a/src/test/regress/expected/regproc.out b/src/test/regress/expected/regproc.out
index e45ff5483f..2801751718 100644
--- a/src/test/regress/expected/regproc.out
+++ b/src/test/regress/expected/regproc.out
@@ -3,6 +3,10 @@
 --
 /* If objects exist, return oids */
 CREATE ROLE regress_regrole_test;
+-- suppress warning that depends on wal_level
+SET client_min_messages = 'ERROR';
+CREATE PUBLICATION regress_testpub;
+RESET client_min_messages;
 -- without schemaname
 SELECT regoper('||/');
  regoper 
@@ -192,6 +196,18 @@ SELECT regnamespace('"pg_catalog"');
  pg_catalog
 (1 row)
 
+SELECT regpublication('regress_testpub');
+ regpublication  
+-----------------
+ regress_testpub
+(1 row)
+
+SELECT regpublication('"regress_testpub"');
+ regpublication  
+-----------------
+ regress_testpub
+(1 row)
+
 SELECT to_regrole('regress_regrole_test');
       to_regrole      
 ----------------------
@@ -216,8 +232,21 @@ SELECT to_regnamespace('"pg_catalog"');
  pg_catalog
 (1 row)
 
+SELECT to_regpublication('regress_testpub');
+ to_regpublication 
+-------------------
+ regress_testpub
+(1 row)
+
+SELECT to_regpublication('"regress_testpub"');
+ to_regpublication 
+-------------------
+ regress_testpub
+(1 row)
+
 /* If objects don't exist, raise errors. */
 DROP ROLE regress_regrole_test;
+DROP PUBLICATION regress_testpub;
 -- without schemaname
 SELECT regoper('||//');
 ERROR:  operator does not exist: ||//
@@ -305,6 +334,18 @@ SELECT regnamespace('foo.bar');
 ERROR:  invalid name syntax
 LINE 1: SELECT regnamespace('foo.bar');
                             ^
+SELECT regpublication('Nonexistent');
+ERROR:  publication "nonexistent" does not exist
+LINE 1: SELECT regpublication('Nonexistent');
+                              ^
+SELECT regpublication('"Nonexistent"');
+ERROR:  publication "Nonexistent" does not exist
+LINE 1: SELECT regpublication('"Nonexistent"');
+                              ^
+SELECT regpublication('foo.bar');
+ERROR:  invalid name syntax
+LINE 1: SELECT regpublication('foo.bar');
+                              ^
 /* If objects don't exist, return NULL with no error. */
 -- without schemaname
 SELECT to_regoper('||//');
@@ -435,3 +476,17 @@ SELECT to_regnamespace('"Nonexistent"');
 
 SELECT to_regnamespace('foo.bar');
 ERROR:  invalid name syntax
+SELECT to_regpublication('Nonexistent');
+ to_regpublication 
+-------------------
+ 
+(1 row)
+
+SELECT to_regpublication('"Nonexistent"');
+ to_regpublication 
+-------------------
+ 
+(1 row)
+
+SELECT to_regpublication('foo.bar');
+ERROR:  invalid name syntax
diff --git a/src/test/regress/sql/regproc.sql b/src/test/regress/sql/regproc.sql
index faab0c15ce..df29cfd3e8 100644
--- a/src/test/regress/sql/regproc.sql
+++ b/src/test/regress/sql/regproc.sql
@@ -6,6 +6,11 @@
 
 CREATE ROLE regress_regrole_test;
 
+-- suppress warning that depends on wal_level
+SET client_min_messages = 'ERROR';
+CREATE PUBLICATION regress_testpub;
+RESET client_min_messages;
+
 -- without schemaname
 
 SELECT regoper('||/');
@@ -47,15 +52,20 @@ SELECT regrole('regress_regrole_test');
 SELECT regrole('"regress_regrole_test"');
 SELECT regnamespace('pg_catalog');
 SELECT regnamespace('"pg_catalog"');
+SELECT regpublication('regress_testpub');
+SELECT regpublication('"regress_testpub"');
 
 SELECT to_regrole('regress_regrole_test');
 SELECT to_regrole('"regress_regrole_test"');
 SELECT to_regnamespace('pg_catalog');
 SELECT to_regnamespace('"pg_catalog"');
+SELECT to_regpublication('regress_testpub');
+SELECT to_regpublication('"regress_testpub"');
 
 /* If objects don't exist, raise errors. */
 
 DROP ROLE regress_regrole_test;
+DROP PUBLICATION regress_testpub;
 
 -- without schemaname
 
@@ -86,6 +96,9 @@ SELECT regrole('foo.bar');
 SELECT regnamespace('Nonexistent');
 SELECT regnamespace('"Nonexistent"');
 SELECT regnamespace('foo.bar');
+SELECT regpublication('Nonexistent');
+SELECT regpublication('"Nonexistent"');
+SELECT regpublication('foo.bar');
 
 /* If objects don't exist, return NULL with no error. */
 
@@ -120,3 +133,6 @@ SELECT to_regrole('foo.bar');
 SELECT to_regnamespace('Nonexistent');
 SELECT to_regnamespace('"Nonexistent"');
 SELECT to_regnamespace('foo.bar');
+SELECT to_regpublication('Nonexistent');
+SELECT to_regpublication('"Nonexistent"');
+SELECT to_regpublication('foo.bar');
-- 
2.25.1

