diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index ceda48e0fc..321d9c1fb1 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -18740,6 +18740,10 @@ SELECT collation for ('foo' COLLATE "de_DE");
pg_get_object_address
+
+ pg_is_user_object
+
+
lists functions related to
database object identification and addressing.
@@ -18768,6 +18772,14 @@ SELECT collation for ('foo' COLLATE "de_DE");
type text, object_names text[], object_args text[]
get external representation of a database object's address
+
+ pg_is_user_object(oid)
+ bool
+
+ true if oid is the object which is created during
+ normal multi-user database operation.
+
+
pg_get_object_address(type text, object_names text[], object_args text[])
classid oid, objid oid, objsubid integer
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..afc3c24978 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 eb3c1a88d1..5c83f5f80f 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -3637,6 +3637,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
---