On Wed, 4 Mar 2020 at 15:28, vignesh C <vignes...@gmail.com> wrote: > > On Wed, Mar 4, 2020 at 9:02 AM Masahiko Sawada > <masahiko.saw...@2ndquadrant.com> wrote: > > > > On Tue, 3 Mar 2020 at 23:33, vignesh C <vignes...@gmail.com> wrote: > > > > > > Should we add some check if object exists or not here: > > > +Datum > > > +pg_is_user_object(PG_FUNCTION_ARGS) > > > +{ > > > + Oid oid = PG_GETARG_OID(0); > > > + > > > + PG_RETURN_BOOL(ObjectIsUserObject(oid)); > > > +} > > > > > > I was trying some scenarios where we pass an object which does not exist: > > > postgres=# SELECT pg_is_user_object(0); > > > pg_is_user_object > > > ------------------- > > > f > > > (1 row) > > > postgres=# SELECT pg_is_user_object(222222); > > > pg_is_user_object > > > ------------------- > > > t > > > (1 row) > > > SELECT pg_is_user_object('pg_class1'::regclass); > > > ERROR: relation "pg_class1" does not exist > > > LINE 1: SELECT pg_is_user_object('pg_class1'::regclass); > > > ^ > > > I felt these behavior seems to be slightly inconsistent. > > > Thoughts? > > > > > > > Hmm I'm not sure we should existing check in that function. Main use > > case would be passing an oid of a tuple of a system catalog to that > > function to check if the given object was created while multi-user > > mode. So I think this function can assume that the given object id > > exists. And if we want to do that check, we will end up with checking > > if the object having that oid in all system catalogs, which is very > > high cost I think. > > > > I suspect perhaps the function name pg_is_user_object led that > > confusion. That name looks like it checks if the given 'object' is > > created while multi-user mode. So maybe we can improve it either by > > renaming to pg_is_user_object_id (or pg_is_user_oid?) or leaving the > > name but describing in the doc (based on Amit's suggestion in previous > > mail): > > I liked pg_is_user_oid over pg_is_user_object_id but this liking may > vary from person to person, so I'm still ok if you don't change the > name. I'm fine about adding the information in the document unless > someone else feels that this check is required in this function. >
Attached updated patch that incorporated comments from Amit and Vignesh. Regards, -- Masahiko Sawada http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 323366feb6..3a2c7fa6a6 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -18752,6 +18752,10 @@ SELECT collation for ('foo' COLLATE "de_DE"); <primary>pg_get_object_address</primary> </indexterm> + <indexterm> + <primary>pg_is_user_object</primary> + </indexterm> + <para> <xref linkend="functions-info-object-table"/> lists functions related to database object identification and addressing. @@ -18785,6 +18789,14 @@ SELECT collation for ('foo' COLLATE "de_DE"); <entry><parameter>classid</parameter> <type>oid</type>, <parameter>objid</parameter> <type>oid</type>, <parameter>objsubid</parameter> <type>integer</type></entry> <entry>get address of a database object from its external representation</entry> </row> + <row> + <entry><literal><function>pg_is_user_object(<parameter>oid</parameter>)</function></literal></entry> + <entry><type>bool</type></entry> + <entry> + true for OIDs assigned while database is operating in normal multi-user + mode, as opposed to single-user mode (see <xref linkend="app-postgres"/>). + </entry> + </row> </tbody> </tgroup> </table> diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c index c5eea7af3f..7888e00d03 100644 --- a/src/backend/catalog/pg_publication.c +++ b/src/backend/catalog/pg_publication.c @@ -106,7 +106,7 @@ is_publishable_class(Oid relid, Form_pg_class reltuple) return reltuple->relkind == RELKIND_RELATION && !IsCatalogRelationOid(relid) && reltuple->relpersistence == RELPERSISTENCE_PERMANENT && - relid >= FirstNormalObjectId; + ObjectIsUserObject(relid); } /* diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c index 567eab1e01..e4f00fc309 100644 --- a/src/backend/utils/adt/json.c +++ b/src/backend/utils/adt/json.c @@ -204,7 +204,7 @@ json_categorize_type(Oid typoid, /* It's probably the general case ... */ *tcategory = JSONTYPE_OTHER; /* but let's look for a cast to json, if it's not built-in */ - if (typoid >= FirstNormalObjectId) + if (ObjectIsUserObject(typoid)) { Oid castfunc; CoercionPathType ctype; diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c index fea4335951..6869ea9954 100644 --- a/src/backend/utils/adt/jsonb.c +++ b/src/backend/utils/adt/jsonb.c @@ -690,7 +690,7 @@ jsonb_categorize_type(Oid typoid, * but first let's look for a cast to json (note: not to * jsonb) if it's not built-in. */ - if (typoid >= FirstNormalObjectId) + if (ObjectIsUserObject(typoid)) { Oid castfunc; CoercionPathType ctype; diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 158784474d..15b1ad13eb 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -3202,6 +3202,16 @@ pg_get_function_arg_default(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(string_to_text(str)); } +/* + * Return true if the given oid is normal user object + */ +Datum +pg_is_user_object(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + + PG_RETURN_BOOL(ObjectIsUserObject(oid)); +} /* * deparse_expression - General utility for deparsing expressions diff --git a/src/include/access/transam.h b/src/include/access/transam.h index 6a947b958b..ba79098ed6 100644 --- a/src/include/access/transam.h +++ b/src/include/access/transam.h @@ -140,6 +140,9 @@ FullTransactionIdAdvance(FullTransactionId *dest) #define FirstBootstrapObjectId 12000 #define FirstNormalObjectId 16384 +/* Return true if the oid is assigned during normal multiuser operation */ +#define ObjectIsUserObject(oid) (((Oid) oid) >= FirstNormalObjectId) + /* * VariableCache is a data structure in shared memory that is used to track * OID and XID assignment state. For largely historical reasons, there is diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 07a86c7b7b..d2f4480c96 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -3640,6 +3640,10 @@ proname => 'pg_get_function_arg_default', provolatile => 's', prorettype => 'text', proargtypes => 'oid int4', prosrc => 'pg_get_function_arg_default' }, +{ oid => '4192', descr => 'identify normal user object', + proname => 'pg_is_user_object', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid', + prosrc => 'pg_is_user_object' }, { oid => '1686', descr => 'list of SQL keywords', proname => 'pg_get_keywords', procost => '10', prorows => '400', diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index d6d1470156..c9f117ac38 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -492,6 +492,19 @@ SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.objsubid)).*, publication relation | | | addr_nsp.gentable in publication addr_pub | t (49 rows) +-- identity if the object is built-in or user-defined +SELECT pg_is_user_object('pg_class'::regclass); + pg_is_user_object +------------------- + f +(1 row) + +SELECT pg_is_user_object('trig'::regproc); + pg_is_user_object +------------------- + t +(1 row) + --- --- Cleanup resources --- diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 8e06248eb5..3b8f0316fe 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -210,6 +210,10 @@ SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.objsubid)).*, pg_get_object_address(typ, nms, ioa.args) as addr2 ORDER BY addr1.classid, addr1.objid, addr1.objsubid; +-- identity if the object is built-in or user-defined +SELECT pg_is_user_object('pg_class'::regclass); +SELECT pg_is_user_object('trig'::regproc); + --- --- Cleanup resources ---