Hi, I felt inclusion of alias types regpublication and regsubscription will help the logical replication users. This will also help in [1]. The alias types allow simplified lookup of publication oid values for objects. For example, to examine the pg_publication_rel rows, one could write: SELECT prpubid::regpublication, prrelid::regclass FROM pg_publication_rel;
rather than: SELECT p.pubname, prrelid::regclass FROM pg_publication_rel pr, pg_publication p WHERE pr.prpubid = p.oid; Similarly in case of subscription: For example, to examine the pg_subscription_rel rows, one could write: SELECT srsubid::regsubscription, srrelid::regclass FROM pg_subscription_rel; rather than: SELECT s.subname,srsubid::regclass FROM pg_subscription_rel sr, pg_subscription s where sr.srsubid = s.oid; Attached patch has the changes for the same. Thoughts? [1] - https://www.postgresql.org/message-id/flat/CALDaNm0OANxuJ6RXqwZsM1MSY4s19nuH3734j4a72etDwvBETQ%40mail.gmail.com Regards, Vignesh
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
From 9affe916f84e8ea3bd46bc793773e1281980502f Mon Sep 17 00:00:00 2001 From: vignesh <vignesh21@gmail.com> Date: Wed, 19 May 2021 12:18:00 +0530 Subject: [PATCH v1 2/2] Implement type regsubscription It will help in casting subscription 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 | 125 ++++++++++++++++++++++++++ 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 | 53 +++++++++++ src/test/regress/sql/regproc.sql | 13 +++ 10 files changed, 256 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index dd578f3535..67fbce1a7f 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -4607,6 +4607,10 @@ INSERT INTO mytable VALUES(-1); -- fails <primary>regpublication</primary> </indexterm> + <indexterm zone="datatype-oid"> + <primary>regsubscription</primary> + </indexterm> + <indexterm zone="datatype-oid"> <primary>regrole</primary> </indexterm> @@ -4774,6 +4778,13 @@ SELECT * FROM pg_attribute <entry><literal>testpub</literal></entry> </row> + <row> + <entry><type>regsubscription</type></entry> + <entry><structname>pg_subscription</structname></entry> + <entry>subscription name</entry> + <entry><literal>testsub</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 50da778b06..e487a02064 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -23614,6 +23614,24 @@ SELECT collation for ('foo' COLLATE "de_DE"); </para></entry> </row> + <row> + <entry role="func_table_entry"><para role="func_signature"> + <indexterm> + <primary>to_regsubscription</primary> + </indexterm> + <function>to_regsubscription</function> ( <type>text</type> ) + <returnvalue>regsubscritpion</returnvalue> + </para> + <para> + Translates a textual subscription name to its OID. A similar result is + obtained by casting the string to type <type>regsubscription</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 bb2d908da6..5616bd28b8 100644 --- a/doc/src/sgml/ref/pgupgrade.sgml +++ b/doc/src/sgml/ref/pgupgrade.sgml @@ -786,6 +786,7 @@ psql --username=postgres --file=script.sql postgres <member><type>regproc</type></member> <member><type>regprocedure</type></member> <member><type>regpublication</type></member> + <member><type>regsubscription</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 dfa826f1c2..e8e3c6ce9a 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -28,6 +28,7 @@ #include "catalog/pg_operator.h" #include "catalog/pg_proc.h" #include "catalog/pg_publication.h" +#include "catalog/pg_subscription.h" #include "catalog/pg_ts_config.h" #include "catalog/pg_ts_dict.h" #include "catalog/pg_type.h" @@ -1357,6 +1358,130 @@ regpublicationsend(PG_FUNCTION_ARGS) return oidsend(fcinfo); } +/* + * regsubscriptionin - converts "subscriptionname" to subscription 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_subscription entry. + */ +Datum +regsubscriptionin(PG_FUNCTION_ARGS) +{ + char *subscription_name_or_oid = PG_GETARG_CSTRING(0); + Oid result = InvalidOid; + List *names; + + /* '-' ? */ + if (strcmp(subscription_name_or_oid, "-") == 0) + PG_RETURN_OID(InvalidOid); + + /* Numeric OID? */ + if (subscription_name_or_oid[0] >= '0' && + subscription_name_or_oid[0] <= '9' && + strspn(subscription_name_or_oid, "0123456789") == strlen(subscription_name_or_oid)) + { + result = DatumGetObjectId(DirectFunctionCall1(oidin, + CStringGetDatum(subscription_name_or_oid))); + PG_RETURN_OID(result); + } + + /* The rest of this wouldn't work in bootstrap mode */ + if (IsBootstrapProcessingMode()) + elog(ERROR, "regsubscription values must be OIDs in bootstrap mode"); + + /* + * Normal case: parse the name into components and see if it matches any + * pg_subscription entries in the current search path. + */ + names = stringToQualifiedNameList(subscription_name_or_oid); + if (list_length(names) != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid name syntax"))); + + result = get_subscription_oid(strVal(linitial(names)), false); + + PG_RETURN_OID(result); +} + +/* + * to_regsubscription - converts "subscriptionname" to subscription OID + * + * If the name is not found, we return NULL. + */ +Datum +to_regsubscription(PG_FUNCTION_ARGS) +{ + char *subscription_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + Oid result; + List *names; + + names = stringToQualifiedNameList(subscription_name); + if (list_length(names) != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid name syntax"))); + + result = get_subscription_oid(strVal(linitial(names)), true); + + if (OidIsValid(result)) + PG_RETURN_OID(result); + else + PG_RETURN_NULL(); +} + +/* + * regsubscriptionout - converts subscription OID to "subscription_name" + */ +Datum +regsubscriptionout(PG_FUNCTION_ARGS) +{ + Oid subscriptionid = PG_GETARG_OID(0); + char *result; + + if (subscriptionid == InvalidOid) + { + result = pstrdup("-"); + PG_RETURN_CSTRING(result); + } + + result = get_subscription_name(subscriptionid, 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 subscription, return it numerically */ + result = (char *) palloc(NAMEDATALEN); + snprintf(result, NAMEDATALEN, "%u", subscriptionid); + } + + PG_RETURN_CSTRING(result); +} + +/* + * regsubscriptionrecv - converts external binary format to regsubscription + */ +Datum +regsubscriptionrecv(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidrecv, so share code */ + return oidrecv(fcinfo); +} + +/* + * regsubscriptionsend - converts regsubscription to binary format + */ +Datum +regsubscriptionsend(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 8037874af5..ad2a6fd275 100644 --- a/src/bin/pg_upgrade/check.c +++ b/src/bin/pg_upgrade/check.c @@ -1142,7 +1142,8 @@ check_for_reg_data_type_usage(ClusterInfo *cluster) " 'regoperator', " " 'regproc', " " 'regprocedure', " - " 'regpublication' " + " 'regpublication', " + " 'regsubscription' " /* 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 63007d6527..a6871f6b33 100644 --- a/src/include/catalog/pg_cast.dat +++ b/src/include/catalog/pg_cast.dat @@ -221,6 +221,20 @@ castcontext => 'a', castmethod => 'f' }, { castsource => 'regpublication', casttarget => 'int4', castfunc => '0', castcontext => 'a', castmethod => 'b' }, +{ castsource => 'oid', casttarget => 'regsubscription', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regsubscription', casttarget => 'oid', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'int8', casttarget => 'regsubscription', castfunc => 'oid', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'regsubscription', castfunc => 'int4(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'regsubscription', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regsubscription', casttarget => 'int8', castfunc => 'int8(oid)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'regsubscription', 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 11c6967348..9d68f2dd56 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -6891,6 +6891,15 @@ { oid => '4546', descr => 'convert classname to regpublication', proname => 'to_regpublication', provolatile => 's', prorettype => 'regpublication', proargtypes => 'text', prosrc => 'to_regpublication' }, +{ oid => '4551', descr => 'I/O', + proname => 'regsubscriptionin', provolatile => 's', prorettype => 'regsubscription', + proargtypes => 'cstring', prosrc => 'regsubscriptionin' }, +{ oid => '4552', descr => 'I/O', + proname => 'regsubscriptionout', provolatile => 's', prorettype => 'cstring', + proargtypes => 'regsubscription', prosrc => 'regsubscriptionout' }, +{ oid => '4553', descr => 'convert classname to regsubscription', + proname => 'to_regsubscription', provolatile => 's', prorettype => 'regsubscription', + proargtypes => 'text', prosrc => 'to_regsubscription' }, { oid => '2220', descr => 'I/O', proname => 'regtypein', provolatile => 's', prorettype => 'regtype', proargtypes => 'cstring', prosrc => 'regtypein' }, @@ -7730,6 +7739,12 @@ { oid => '4548', descr => 'I/O', proname => 'regpublicationsend', prorettype => 'bytea', proargtypes => 'regpublication', prosrc => 'regpublicationsend' }, +{ oid => '4554', descr => 'I/O', + proname => 'regsubscriptionrecv', prorettype => 'regsubscription', + proargtypes => 'internal', prosrc => 'regsubscriptionrecv' }, +{ oid => '4555', descr => 'I/O', + proname => 'regsubscriptionsend', prorettype => 'bytea', + proargtypes => 'regsubscription', prosrc => 'regsubscriptionsend' }, { 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 cf2b7d1890..61a965510f 100644 --- a/src/include/catalog/pg_type.dat +++ b/src/include/catalog/pg_type.dat @@ -389,6 +389,10 @@ typname => 'regpublication', typlen => '4', typbyval => 't', typcategory => 'N', typinput => 'regpublicationin', typoutput => 'regpublicationout', typreceive => 'regpublicationrecv', typsend => 'regpublicationsend', typalign => 'i' }, +{ oid => '4556', array_type_oid => '4557', descr => 'registered subscription', + typname => 'regsubscription', typlen => '4', typbyval => 't', typcategory => 'N', + typinput => 'regsubscriptionin', typoutput => 'regsubscriptionout', + typreceive => 'regsubscriptionrecv', typsend => 'regsubscriptionsend', 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 2801751718..49fda6444a 100644 --- a/src/test/regress/expected/regproc.out +++ b/src/test/regress/expected/regproc.out @@ -6,6 +6,7 @@ CREATE ROLE regress_regrole_test; -- suppress warning that depends on wal_level SET client_min_messages = 'ERROR'; CREATE PUBLICATION regress_testpub; +CREATE SUBSCRIPTION regress_testsub CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (connect = false); RESET client_min_messages; -- without schemaname SELECT regoper('||/'); @@ -208,6 +209,18 @@ SELECT regpublication('"regress_testpub"'); regress_testpub (1 row) +SELECT regsubscription('regress_testsub'); + regsubscription +----------------- + regress_testsub +(1 row) + +SELECT regsubscription('"regress_testsub"'); + regsubscription +----------------- + regress_testsub +(1 row) + SELECT to_regrole('regress_regrole_test'); to_regrole ---------------------- @@ -244,9 +257,23 @@ SELECT to_regpublication('"regress_testpub"'); regress_testpub (1 row) +SELECT to_regsubscription('regress_testsub'); + to_regsubscription +-------------------- + regress_testsub +(1 row) + +SELECT to_regsubscription('"regress_testsub"'); + to_regsubscription +-------------------- + regress_testsub +(1 row) + /* If objects don't exist, raise errors. */ DROP ROLE regress_regrole_test; DROP PUBLICATION regress_testpub; +ALTER SUBSCRIPTION regress_testsub SET (slot_name = NONE); +DROP SUBSCRIPTION regress_testsub; -- without schemaname SELECT regoper('||//'); ERROR: operator does not exist: ||// @@ -346,6 +373,18 @@ SELECT regpublication('foo.bar'); ERROR: invalid name syntax LINE 1: SELECT regpublication('foo.bar'); ^ +SELECT regsubscription('Nonexistent'); +ERROR: subscription "nonexistent" does not exist +LINE 1: SELECT regsubscription('Nonexistent'); + ^ +SELECT regsubscription('"Nonexistent"'); +ERROR: subscription "Nonexistent" does not exist +LINE 1: SELECT regsubscription('"Nonexistent"'); + ^ +SELECT regsubscription('foo.bar'); +ERROR: invalid name syntax +LINE 1: SELECT regsubscription('foo.bar'); + ^ /* If objects don't exist, return NULL with no error. */ -- without schemaname SELECT to_regoper('||//'); @@ -490,3 +529,17 @@ SELECT to_regpublication('"Nonexistent"'); SELECT to_regpublication('foo.bar'); ERROR: invalid name syntax +SELECT to_regsubscription('Nonexistent'); + to_regsubscription +-------------------- + +(1 row) + +SELECT to_regsubscription('"Nonexistent"'); + to_regsubscription +-------------------- + +(1 row) + +SELECT to_regsubscription('foo.bar'); +ERROR: invalid name syntax diff --git a/src/test/regress/sql/regproc.sql b/src/test/regress/sql/regproc.sql index df29cfd3e8..19a17b946a 100644 --- a/src/test/regress/sql/regproc.sql +++ b/src/test/regress/sql/regproc.sql @@ -9,6 +9,7 @@ CREATE ROLE regress_regrole_test; -- suppress warning that depends on wal_level SET client_min_messages = 'ERROR'; CREATE PUBLICATION regress_testpub; +CREATE SUBSCRIPTION regress_testsub CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (connect = false); RESET client_min_messages; -- without schemaname @@ -54,6 +55,8 @@ SELECT regnamespace('pg_catalog'); SELECT regnamespace('"pg_catalog"'); SELECT regpublication('regress_testpub'); SELECT regpublication('"regress_testpub"'); +SELECT regsubscription('regress_testsub'); +SELECT regsubscription('"regress_testsub"'); SELECT to_regrole('regress_regrole_test'); SELECT to_regrole('"regress_regrole_test"'); @@ -61,11 +64,15 @@ SELECT to_regnamespace('pg_catalog'); SELECT to_regnamespace('"pg_catalog"'); SELECT to_regpublication('regress_testpub'); SELECT to_regpublication('"regress_testpub"'); +SELECT to_regsubscription('regress_testsub'); +SELECT to_regsubscription('"regress_testsub"'); /* If objects don't exist, raise errors. */ DROP ROLE regress_regrole_test; DROP PUBLICATION regress_testpub; +ALTER SUBSCRIPTION regress_testsub SET (slot_name = NONE); +DROP SUBSCRIPTION regress_testsub; -- without schemaname @@ -99,6 +106,9 @@ SELECT regnamespace('foo.bar'); SELECT regpublication('Nonexistent'); SELECT regpublication('"Nonexistent"'); SELECT regpublication('foo.bar'); +SELECT regsubscription('Nonexistent'); +SELECT regsubscription('"Nonexistent"'); +SELECT regsubscription('foo.bar'); /* If objects don't exist, return NULL with no error. */ @@ -136,3 +146,6 @@ SELECT to_regnamespace('foo.bar'); SELECT to_regpublication('Nonexistent'); SELECT to_regpublication('"Nonexistent"'); SELECT to_regpublication('foo.bar'); +SELECT to_regsubscription('Nonexistent'); +SELECT to_regsubscription('"Nonexistent"'); +SELECT to_regsubscription('foo.bar'); -- 2.25.1