}
};
+/*
+ * This struct maps the string object types as returned by
+ * getObjectTypeDescription into ObjType enum values. Note that some enum
+ * values can be obtained by different names, and that some string object types
+ * do not have corresponding values in the output enum. The user of this map
+ * must be careful to test for invalid values being returned.
+ *
+ * To ease maintenance, this follows the order of getObjectTypeDescription.
+ */
+static const struct object_type_map
+{
+ const char *tm_name;
+ ObjectType tm_type;
+}
+ObjectTypeMap[] =
+{
+ /* OCLASS_CLASS, all kinds of relations */
+ { "table", OBJECT_TABLE },
+ { "index", OBJECT_INDEX },
+ { "sequence", OBJECT_SEQUENCE },
+ { "toast table", -1 }, /* unmapped */
+ { "view", OBJECT_VIEW },
+ { "materialized view", OBJECT_MATVIEW },
+ { "composite type", -1 }, /* unmapped */
+ { "foreign table", OBJECT_FOREIGN_TABLE },
+ { "table column", OBJECT_COLUMN },
+ { "index column", -1 }, /* unmapped */
+ { "sequence column", -1 }, /* unmapped */
+ { "toast table column", -1 }, /* unmapped */
+ { "view column", -1 }, /* unmapped */
+ { "materialized view column", -1 }, /* unmapped */
+ { "composite type column", -1 }, /* unmapped */
+ { "foreign table column", OBJECT_COLUMN },
+ /* OCLASS_PROC */
+ { "aggregate", OBJECT_AGGREGATE },
+ { "function", OBJECT_FUNCTION },
+ /* OCLASS_TYPE */
+ { "type", OBJECT_TYPE },
+ /* OCLASS_CAST */
+ { "cast", OBJECT_CAST },
+ /* OCLASS_COLLATION */
+ { "collation", OBJECT_COLLATION },
+ /* OCLASS_CONSTRAINT */
+ { "table constraint", OBJECT_TABCONSTRAINT },
+ { "domain constraint", OBJECT_DOMCONSTRAINT },
+ /* OCLASS_CONVERSION */
+ { "conversion", OBJECT_CONVERSION },
+ /* OCLASS_DEFAULT */
+ { "default value", OBJECT_DEFAULT },
+ /* OCLASS_LANGUAGE */
+ { "language", OBJECT_LANGUAGE },
+ /* OCLASS_LARGEOBJECT */
+ { "large object", OBJECT_LARGEOBJECT },
+ /* OCLASS_OPERATOR */
+ { "operator", OBJECT_OPERATOR },
+ /* OCLASS_OPCLASS */
+ { "operator class", OBJECT_OPCLASS },
+ /* OCLASS_OPFAMILY */
+ { "operator family", OBJECT_OPFAMILY },
+ /* OCLASS_AMOP */
+ { "operator of access method", -1 }, /* unmapped */
+ /* OCLASS_AMPROC */
+ { "function of access method", -1 }, /* unmapped */
+ /* OCLASS_REWRITE */
+ { "rule", OBJECT_RULE },
+ /* OCLASS_TRIGGER */
+ { "trigger", OBJECT_TRIGGER },
+ /* OCLASS_SCHEMA */
+ { "schema", OBJECT_SCHEMA },
+ /* OCLASS_TSPARSER */
+ { "text search parser", OBJECT_TSPARSER },
+ /* OCLASS_TSDICT */
+ { "text search dictionary", OBJECT_TSDICTIONARY },
+ /* OCLASS_TSTEMPLATE */
+ { "text search template", OBJECT_TSTEMPLATE },
+ /* OCLASS_TSCONFIG */
+ { "text search configuration", OBJECT_TSCONFIGURATION },
+ /* OCLASS_ROLE */
+ { "role", OBJECT_ROLE },
+ /* OCLASS_DATABASE */
+ { "database", OBJECT_DATABASE },
+ /* OCLASS_TBLSPACE */
+ { "tablespace", OBJECT_TABLESPACE },
+ /* OCLASS_FDW */
+ { "foreign-data wrapper", OBJECT_FDW },
+ /* OCLASS_FOREIGN_SERVER */
+ { "server", OBJECT_FOREIGN_SERVER },
+ /* OCLASS_USER_MAPPING */
+ { "user mapping", -1 }, /* unmapped */
+ /* OCLASS_DEFACL */
+ { "default acl", -1 }, /* unmapped */
+ /* OCLASS_EXTENSION */
+ { "extension", OBJECT_EXTENSION },
+ /* OCLASS_EVENT_TRIGGER */
+ { "event trigger", OBJECT_EVENT_TRIGGER },
+ /* OCLASS_POLICY */
+ { "policy", OBJECT_POLICY }
+};
+
+
static ObjectAddress get_object_address_unqualified(ObjectType objtype,
List *qualname, bool missing_ok);
static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
static ObjectAddress get_object_address_attribute(ObjectType objtype,
List *objname, Relation *relp,
LOCKMODE lockmode, bool missing_ok);
+static ObjectAddress get_object_address_attrdef(ObjectType objtype,
+ List *objname, Relation *relp, LOCKMODE lockmode,
+ bool missing_ok);
static ObjectAddress get_object_address_type(ObjectType objtype,
List *objname, bool missing_ok);
static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname,
&relation, lockmode,
missing_ok);
break;
+ case OBJECT_DEFAULT:
+ address =
+ get_object_address_attrdef(objtype, objname,
+ &relation, lockmode,
+ missing_ok);
+ break;
case OBJECT_RULE:
case OBJECT_TRIGGER:
case OBJECT_TABCONSTRAINT:
return address;
}
+/*
+ * Find the ObjectAddress for an attribute's default value.
+ */
+static ObjectAddress
+get_object_address_attrdef(ObjectType objtype, List *objname,
+ Relation *relp, LOCKMODE lockmode,
+ bool missing_ok)
+{
+ ObjectAddress address;
+ List *relname;
+ Oid reloid;
+ Relation relation;
+ const char *attname;
+ AttrNumber attnum;
+ TupleDesc tupdesc;
+ Oid defoid;
+
+ /* Extract relation name and open relation. */
+ if (list_length(objname) < 2)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("column name must be qualified")));
+ attname = strVal(llast(objname));
+ relname = list_truncate(list_copy(objname), list_length(objname) - 1);
+ /* XXX no missing_ok support here */
+ relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
+ reloid = RelationGetRelid(relation);
+
+ tupdesc = RelationGetDescr(relation);
+
+ /* Look up attribute number and scan pg_attrdef to find its tuple */
+ attnum = get_attnum(reloid, attname);
+ defoid = InvalidOid;
+ if (attnum != InvalidAttrNumber && tupdesc->constr != NULL)
+ {
+ Relation attrdef;
+ ScanKeyData keys[2];
+ SysScanDesc scan;
+ HeapTuple tup;
+
+ attrdef = relation_open(AttrDefaultRelationId, AccessShareLock);
+ ScanKeyInit(&keys[0],
+ Anum_pg_attrdef_adrelid,
+ BTEqualStrategyNumber,
+ F_OIDEQ,
+ ObjectIdGetDatum(reloid));
+ ScanKeyInit(&keys[1],
+ Anum_pg_attrdef_adnum,
+ BTEqualStrategyNumber,
+ F_INT2EQ,
+ Int16GetDatum(attnum));
+ scan = systable_beginscan(attrdef, AttrDefaultIndexId, true,
+ NULL, 2, keys);
+ if (HeapTupleIsValid(tup = systable_getnext(scan)))
+ defoid = HeapTupleGetOid(tup);
+
+ systable_endscan(scan);
+ relation_close(attrdef, AccessShareLock);
+ }
+ if (!OidIsValid(defoid))
+ {
+ if (!missing_ok)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
+ errmsg("default value for column \"%s\" of relation \"%s\" does not exist",
+ attname, NameListToString(relname))));
+
+ address.classId = AttrDefaultRelationId;
+ address.objectId = InvalidOid;
+ address.objectSubId = InvalidAttrNumber;
+ relation_close(relation, lockmode);
+ return address;
+ }
+
+ address.classId = AttrDefaultRelationId;
+ address.objectId = defoid;
+ address.objectSubId = 0;
+
+ *relp = relation;
+ return address;
+}
+
/*
* Find the ObjectAddress for a type or domain
*/
return address;
}
+/*
+ * Convert an array of TEXT into a List of string Values, as emitted by the
+ * parser, which is what get_object_address uses as input.
+ */
+static List *
+textarray_to_strvaluelist(ArrayType *arr)
+{
+ Datum *elems;
+ bool *nulls;
+ int nelems;
+ List *list = NIL;
+ int i;
+
+ deconstruct_array(arr, TEXTOID, -1, false, 'i',
+ &elems, &nulls, &nelems);
+
+ for (i = 0; i < nelems; i++)
+ {
+ if (nulls[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("name or argument lists may not contain nulls")));
+ list = lappend(list, makeString(TextDatumGetCString(elems[i])));
+ }
+
+ return list;
+}
+
+/*
+ * SQL-callable version of get_object_address
+ */
+Datum
+pg_get_object_address(PG_FUNCTION_ARGS)
+{
+ char *ttype = TextDatumGetCString(PG_GETARG_TEXT_P(0));
+ ArrayType *namearr = PG_GETARG_ARRAYTYPE_P(1);
+ ArrayType *argsarr = PG_GETARG_ARRAYTYPE_P(2);
+ int itype;
+ ObjectType type;
+ List *name;
+ List *args;
+ ObjectAddress addr;
+ TupleDesc tupdesc;
+ Datum values[3];
+ bool nulls[3];
+ HeapTuple htup;
+ Relation relation;
+
+ /* Decode object type, raise error if unknown */
+ ttype = TextDatumGetCString(PG_GETARG_TEXT_P(0));
+ itype = read_objtype_from_string(ttype);
+ if (itype < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unsupported object type \"%s\"", ttype)));
+ type = (ObjectType) itype;
+
+ /*
+ * Convert the text array to the representation appropriate for the
+ * given object type. Most use a simple string Values list, but there
+ * are some exceptions.
+ */
+ if (type == OBJECT_TYPE || type == OBJECT_DOMAIN)
+ {
+ Datum *elems;
+ bool *nulls;
+ int nelems;
+ TypeName *typname;
+
+ deconstruct_array(namearr, TEXTOID, -1, false, 'i',
+ &elems, &nulls, &nelems);
+ if (nelems != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("name list length must be exactly %d", 1)));
+ if (nulls[0])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("name or argument lists may not contain nulls")));
+ typname = typeStringToTypeName(TextDatumGetCString(elems[0]));
+ name = typname->names;
+ }
+ else if (type == OBJECT_CAST)
+ {
+ Datum *elems;
+ bool *nulls;
+ int nelems;
+
+ deconstruct_array(namearr, TEXTOID, -1, false, 'i',
+ &elems, &nulls, &nelems);
+ if (nelems != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("name list length must be exactly %d", 1)));
+ if (nulls[0])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("name or argument lists may not contain nulls")));
+ name = list_make1(typeStringToTypeName(TextDatumGetCString(elems[0])));
+ }
+ else if (type == OBJECT_LARGEOBJECT)
+ {
+ Datum *elems;
+ bool *nulls;
+ int nelems;
+
+ deconstruct_array(namearr, TEXTOID, -1, false, 'i',
+ &elems, &nulls, &nelems);
+ if (nelems != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("name list length must be exactly %d", 1)));
+ if (nulls[0])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("large object OID may not be null")));
+ name = list_make1(makeFloat(TextDatumGetCString(elems[0])));
+ }
+ else
+ {
+ name = textarray_to_strvaluelist(namearr);
+ if (list_length(name) < 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("name list must be of length at least %d", 1)));
+ }
+
+ /*
+ * If args are given, decode them according to the object type.
+ */
+ if (type == OBJECT_AGGREGATE ||
+ type == OBJECT_FUNCTION ||
+ type == OBJECT_OPERATOR ||
+ type == OBJECT_CAST)
+ {
+ /* in these cases, the args list must be of TypeName */
+ Datum *elems;
+ bool *nulls;
+ int nelems;
+ int i;
+
+ deconstruct_array(argsarr, TEXTOID, -1, false, 'i',
+ &elems, &nulls, &nelems);
+
+ args = NIL;
+ for (i = 0; i < nelems; i++)
+ {
+ if (nulls[i])
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("name or argument lists may not contain nulls")));
+ args = lappend(args,
+ typeStringToTypeName(TextDatumGetCString(elems[i])));
+ }
+ }
+ else
+ {
+ /* For all other object types, use string Values */
+ args = textarray_to_strvaluelist(argsarr);
+ }
+
+ /*
+ * get_object_name is pretty sensitive to the length its input lists;
+ * check that they're what it wants.
+ */
+ switch (type)
+ {
+ case OBJECT_LARGEOBJECT:
+ if (list_length(name) != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("name list length must be %d", 1)));
+ break;
+ case OBJECT_OPCLASS:
+ case OBJECT_OPFAMILY:
+ case OBJECT_CAST:
+ if (list_length(args) != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("argument list length must be exactly %d", 1)));
+ break;
+ case OBJECT_OPERATOR:
+ if (list_length(args) != 2)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("argument list length must be exactly %d", 2)));
+ break;
+ default:
+ break;
+ }
+
+ addr = get_object_address(type, name, args,
+ &relation, AccessShareLock, false);
+
+ /* We don't need the relcache entry, thank you very much */
+ if (relation)
+ relation_close(relation, AccessShareLock);
+
+ tupdesc = CreateTemplateTupleDesc(3, false);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "classid",
+ OIDOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "objid",
+ OIDOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "objsubid",
+ INT4OID, -1, 0);
+ tupdesc = BlessTupleDesc(tupdesc);
+
+ values[0] = ObjectIdGetDatum(addr.classId);
+ values[1] = ObjectIdGetDatum(addr.objectId);
+ values[2] = Int32GetDatum(addr.objectSubId);
+ nulls[0] = false;
+ nulls[1] = false;
+ nulls[2] = false;
+
+ htup = heap_form_tuple(tupdesc, values, nulls);
+
+ PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+}
+
/*
* Check ownership of an object previously identified by get_object_address.
*/
return oid;
}
+/*
+ * Return ObjectType for the given object type as given by
+ * getObjectTypeDescription; if no valid ObjectType code exists, but it's a
+ * possible output type from getObjectTypeDescription, return -1.
+ * Otherwise, an error is thrown.
+ */
+int
+read_objtype_from_string(const char *objtype)
+{
+ ObjectType type;
+ int i;
+
+ for (i = 0; i < lengthof(ObjectTypeMap); i++)
+ {
+ if (strcmp(ObjectTypeMap[i].tm_name, objtype) == 0)
+ {
+ type = ObjectTypeMap[i].tm_type;
+ break;
+ }
+ }
+ if (i >= lengthof(ObjectTypeMap))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unrecognized object type \"%s\"", objtype)));
+
+ return type;
+}
+
/*
* Interfaces to reference fields of ObjectPropertyType
*/
/*
* Return a palloc'ed string that describes the type of object that the
* passed address is for.
+ *
+ * Keep ObjectTypeMap in sync with this.
*/
char *
getObjectTypeDescription(const ObjectAddress *object)
--- /dev/null
+--
+-- Test for pg_get_object_address
+--
+-- Clean up in case a prior regression run failed
+SET client_min_messages TO 'warning';
+DROP ROLE IF EXISTS regtest_addr_user;
+CREATE USER regtest_addr_user;
+-- Test generic object addressing/identification functions
+CREATE SCHEMA addr_nsp;
+SET search_path TO 'addr_nsp';
+CREATE FOREIGN DATA WRAPPER addr_fdw;
+CREATE SERVER addr_fserv FOREIGN DATA WRAPPER addr_fdw;
+CREATE TEXT SEARCH DICTIONARY addr_ts_dict (template=simple);
+CREATE TEXT SEARCH CONFIGURATION addr_ts_conf (copy=english);
+CREATE TEXT SEARCH TEMPLATE addr_ts_temp (lexize=dsimple_lexize);
+CREATE TEXT SEARCH PARSER addr_ts_prs
+ (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TABLE addr_nsp.gentable (
+ a serial primary key CONSTRAINT a_chk CHECK (a > 0),
+ b text DEFAULT 'hello');
+CREATE VIEW addr_nsp.genview AS SELECT * from addr_nsp.gentable;
+CREATE MATERIALIZED VIEW addr_nsp.genmatview AS SELECT * FROM addr_nsp.gentable;
+CREATE TYPE addr_nsp.gencomptype AS (a int);
+CREATE TYPE addr_nsp.genenum AS ENUM ('one', 'two');
+CREATE FOREIGN TABLE addr_nsp.genftable (a int) SERVER addr_fserv;
+CREATE AGGREGATE addr_nsp.genaggr(int4) (sfunc = int4pl, stype = int4);
+CREATE DOMAIN addr_nsp.gendomain AS int4 CONSTRAINT domconstr CHECK (value > 0);
+CREATE FUNCTION addr_nsp.trig() RETURNS TRIGGER LANGUAGE plpgsql AS $$ BEGIN END; $$;
+CREATE TRIGGER t BEFORE INSERT ON addr_nsp.gentable FOR EACH ROW EXECUTE PROCEDURE addr_nsp.trig();
+CREATE POLICY genpol ON addr_nsp.gentable;
+CREATE FUNCTION addr_nsp.etrig() RETURNS EVENT_TRIGGER LANGUAGE plpgsql AS $$ BEGIN END; $$;
+CREATE EVENT TRIGGER evttrig ON ddl_command_end EXECUTE PROCEDURE addr_nsp.etrig();
+-- test some error cases
+SELECT pg_get_object_address('stone', '{}', '{}');
+ERROR: unrecognized object type "stone"
+SELECT pg_get_object_address('table', '{}', '{}');
+ERROR: name list must be of length at least 1
+SELECT pg_get_object_address('table', '{NULL}', '{}');
+ERROR: name or argument lists may not contain nulls
+-- unrecognized object types
+DO $$
+DECLARE
+ objtype text;
+BEGIN
+ FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
+ ('toast table column'), ('view column'), ('materialized view column'),
+ ('operator of access method'), ('function of access method'),
+ ('user mapping')
+ LOOP
+ BEGIN
+ PERFORM pg_get_object_address(objtype, '{one}', '{}');
+ EXCEPTION WHEN invalid_parameter_value THEN
+ RAISE WARNING 'error for %: %', objtype, sqlerrm;
+ END;
+ END LOOP;
+END;
+$$;
+WARNING: error for toast table: unsupported object type "toast table"
+WARNING: error for index column: unsupported object type "index column"
+WARNING: error for sequence column: unsupported object type "sequence column"
+WARNING: error for toast table column: unsupported object type "toast table column"
+WARNING: error for view column: unsupported object type "view column"
+WARNING: error for materialized view column: unsupported object type "materialized view column"
+WARNING: error for operator of access method: unsupported object type "operator of access method"
+WARNING: error for function of access method: unsupported object type "function of access method"
+WARNING: error for user mapping: unsupported object type "user mapping"
+DO $$
+DECLARE
+ objtype text;
+ names text[];
+ args text[];
+BEGIN
+ FOR objtype IN VALUES
+ ('table'), ('index'), ('sequence'), ('view'),
+ ('materialized view'), ('foreign table'),
+ ('table column'), ('foreign table column'),
+ ('aggregate'), ('function'), ('type'), ('cast'),
+ ('collation'),
+ ('table constraint'), ('domain constraint'), ('conversion'), ('default value'),
+ ('operator'), ('operator class'), ('operator family'), ('rule'), ('trigger'),
+ ('text search parser'), ('text search dictionary'),
+ ('text search template'), ('text search configuration'),
+ ('policy')
+ LOOP
+ FOR names IN VALUES ('{eins}'), ('{addr_nsp, zwei}'), ('{eins, zwei, drei}')
+ LOOP
+ FOR args IN VALUES ('{}'), ('{integer}')
+ LOOP
+ BEGIN
+ PERFORM pg_get_object_address(objtype, names, args);
+ EXCEPTION WHEN OTHERS THEN
+ RAISE WARNING 'error for %,%,%: %', objtype, names, args, sqlerrm;
+ END;
+ END LOOP;
+ END LOOP;
+ END LOOP;
+END;
+$$;
+WARNING: error for table,{eins},{}: relation "eins" does not exist
+WARNING: error for table,{eins},{integer}: relation "eins" does not exist
+WARNING: error for table,{addr_nsp,zwei},{}: relation "addr_nsp.zwei" does not exist
+WARNING: error for table,{addr_nsp,zwei},{integer}: relation "addr_nsp.zwei" does not exist
+WARNING: error for table,{eins,zwei,drei},{}: cross-database references are not implemented: "eins.zwei.drei"
+WARNING: error for table,{eins,zwei,drei},{integer}: cross-database references are not implemented: "eins.zwei.drei"
+WARNING: error for index,{eins},{}: relation "eins" does not exist
+WARNING: error for index,{eins},{integer}: relation "eins" does not exist
+WARNING: error for index,{addr_nsp,zwei},{}: relation "addr_nsp.zwei" does not exist
+WARNING: error for index,{addr_nsp,zwei},{integer}: relation "addr_nsp.zwei" does not exist
+WARNING: error for index,{eins,zwei,drei},{}: cross-database references are not implemented: "eins.zwei.drei"
+WARNING: error for index,{eins,zwei,drei},{integer}: cross-database references are not implemented: "eins.zwei.drei"
+WARNING: error for sequence,{eins},{}: relation "eins" does not exist
+WARNING: error for sequence,{eins},{integer}: relation "eins" does not exist
+WARNING: error for sequence,{addr_nsp,zwei},{}: relation "addr_nsp.zwei" does not exist
+WARNING: error for sequence,{addr_nsp,zwei},{integer}: relation "addr_nsp.zwei" does not exist
+WARNING: error for sequence,{eins,zwei,drei},{}: cross-database references are not implemented: "eins.zwei.drei"
+WARNING: error for sequence,{eins,zwei,drei},{integer}: cross-database references are not implemented: "eins.zwei.drei"
+WARNING: error for view,{eins},{}: relation "eins" does not exist
+WARNING: error for view,{eins},{integer}: relation "eins" does not exist
+WARNING: error for view,{addr_nsp,zwei},{}: relation "addr_nsp.zwei" does not exist
+WARNING: error for view,{addr_nsp,zwei},{integer}: relation "addr_nsp.zwei" does not exist
+WARNING: error for view,{eins,zwei,drei},{}: cross-database references are not implemented: "eins.zwei.drei"
+WARNING: error for view,{eins,zwei,drei},{integer}: cross-database references are not implemented: "eins.zwei.drei"
+WARNING: error for materialized view,{eins},{}: relation "eins" does not exist
+WARNING: error for materialized view,{eins},{integer}: relation "eins" does not exist
+WARNING: error for materialized view,{addr_nsp,zwei},{}: relation "addr_nsp.zwei" does not exist
+WARNING: error for materialized view,{addr_nsp,zwei},{integer}: relation "addr_nsp.zwei" does not exist
+WARNING: error for materialized view,{eins,zwei,drei},{}: cross-database references are not implemented: "eins.zwei.drei"
+WARNING: error for materialized view,{eins,zwei,drei},{integer}: cross-database references are not implemented: "eins.zwei.drei"
+WARNING: error for foreign table,{eins},{}: relation "eins" does not exist
+WARNING: error for foreign table,{eins},{integer}: relation "eins" does not exist
+WARNING: error for foreign table,{addr_nsp,zwei},{}: relation "addr_nsp.zwei" does not exist
+WARNING: error for foreign table,{addr_nsp,zwei},{integer}: relation "addr_nsp.zwei" does not exist
+WARNING: error for foreign table,{eins,zwei,drei},{}: cross-database references are not implemented: "eins.zwei.drei"
+WARNING: error for foreign table,{eins,zwei,drei},{integer}: cross-database references are not implemented: "eins.zwei.drei"
+WARNING: error for table column,{eins},{}: column name must be qualified
+WARNING: error for table column,{eins},{integer}: column name must be qualified
+WARNING: error for table column,{addr_nsp,zwei},{}: relation "addr_nsp" does not exist
+WARNING: error for table column,{addr_nsp,zwei},{integer}: relation "addr_nsp" does not exist
+WARNING: error for table column,{eins,zwei,drei},{}: schema "eins" does not exist
+WARNING: error for table column,{eins,zwei,drei},{integer}: schema "eins" does not exist
+WARNING: error for foreign table column,{eins},{}: column name must be qualified
+WARNING: error for foreign table column,{eins},{integer}: column name must be qualified
+WARNING: error for foreign table column,{addr_nsp,zwei},{}: relation "addr_nsp" does not exist
+WARNING: error for foreign table column,{addr_nsp,zwei},{integer}: relation "addr_nsp" does not exist
+WARNING: error for foreign table column,{eins,zwei,drei},{}: schema "eins" does not exist
+WARNING: error for foreign table column,{eins,zwei,drei},{integer}: schema "eins" does not exist
+WARNING: error for aggregate,{eins},{}: aggregate eins(*) does not exist
+WARNING: error for aggregate,{eins},{integer}: aggregate eins(integer) does not exist
+WARNING: error for aggregate,{addr_nsp,zwei},{}: aggregate addr_nsp.zwei(*) does not exist
+WARNING: error for aggregate,{addr_nsp,zwei},{integer}: aggregate addr_nsp.zwei(integer) does not exist
+WARNING: error for aggregate,{eins,zwei,drei},{}: cross-database references are not implemented: eins.zwei.drei
+WARNING: error for aggregate,{eins,zwei,drei},{integer}: cross-database references are not implemented: eins.zwei.drei
+WARNING: error for function,{eins},{}: function eins() does not exist
+WARNING: error for function,{eins},{integer}: function eins(integer) does not exist
+WARNING: error for function,{addr_nsp,zwei},{}: function addr_nsp.zwei() does not exist
+WARNING: error for function,{addr_nsp,zwei},{integer}: function addr_nsp.zwei(integer) does not exist
+WARNING: error for function,{eins,zwei,drei},{}: cross-database references are not implemented: eins.zwei.drei
+WARNING: error for function,{eins,zwei,drei},{integer}: cross-database references are not implemented: eins.zwei.drei
+WARNING: error for type,{eins},{}: type "eins" does not exist
+WARNING: error for type,{eins},{integer}: type "eins" does not exist
+WARNING: error for type,{addr_nsp,zwei},{}: name list length must be exactly 1
+WARNING: error for type,{addr_nsp,zwei},{integer}: name list length must be exactly 1
+WARNING: error for type,{eins,zwei,drei},{}: name list length must be exactly 1
+WARNING: error for type,{eins,zwei,drei},{integer}: name list length must be exactly 1
+WARNING: error for cast,{eins},{}: argument list length must be exactly 1
+WARNING: error for cast,{eins},{integer}: type "eins" does not exist
+WARNING: error for cast,{addr_nsp,zwei},{}: name list length must be exactly 1
+WARNING: error for cast,{addr_nsp,zwei},{integer}: name list length must be exactly 1
+WARNING: error for cast,{eins,zwei,drei},{}: name list length must be exactly 1
+WARNING: error for cast,{eins,zwei,drei},{integer}: name list length must be exactly 1
+WARNING: error for collation,{eins},{}: collation "eins" for encoding "UTF8" does not exist
+WARNING: error for collation,{eins},{integer}: collation "eins" for encoding "UTF8" does not exist
+WARNING: error for collation,{addr_nsp,zwei},{}: collation "addr_nsp.zwei" for encoding "UTF8" does not exist
+WARNING: error for collation,{addr_nsp,zwei},{integer}: collation "addr_nsp.zwei" for encoding "UTF8" does not exist
+WARNING: error for collation,{eins,zwei,drei},{}: cross-database references are not implemented: eins.zwei.drei
+WARNING: error for collation,{eins,zwei,drei},{integer}: cross-database references are not implemented: eins.zwei.drei
+WARNING: error for table constraint,{eins},{}: must specify relation and object name
+WARNING: error for table constraint,{eins},{integer}: must specify relation and object name
+WARNING: error for table constraint,{addr_nsp,zwei},{}: relation "addr_nsp" does not exist
+WARNING: error for table constraint,{addr_nsp,zwei},{integer}: relation "addr_nsp" does not exist
+WARNING: error for table constraint,{eins,zwei,drei},{}: schema "eins" does not exist
+WARNING: error for table constraint,{eins,zwei,drei},{integer}: schema "eins" does not exist
+WARNING: error for domain constraint,{eins},{}: cache lookup failed for type 0
+WARNING: error for domain constraint,{eins},{integer}: cache lookup failed for type 0
+WARNING: error for domain constraint,{addr_nsp,zwei},{}: type "addr_nsp" does not exist
+WARNING: error for domain constraint,{addr_nsp,zwei},{integer}: type "addr_nsp" does not exist
+WARNING: error for domain constraint,{eins,zwei,drei},{}: schema "eins" does not exist
+WARNING: error for domain constraint,{eins,zwei,drei},{integer}: schema "eins" does not exist
+WARNING: error for conversion,{eins},{}: conversion "eins" does not exist
+WARNING: error for conversion,{eins},{integer}: conversion "eins" does not exist
+WARNING: error for conversion,{addr_nsp,zwei},{}: conversion "addr_nsp.zwei" does not exist
+WARNING: error for conversion,{addr_nsp,zwei},{integer}: conversion "addr_nsp.zwei" does not exist
+WARNING: error for conversion,{eins,zwei,drei},{}: cross-database references are not implemented: eins.zwei.drei
+WARNING: error for conversion,{eins,zwei,drei},{integer}: cross-database references are not implemented: eins.zwei.drei
+WARNING: error for default value,{eins},{}: column name must be qualified
+WARNING: error for default value,{eins},{integer}: column name must be qualified
+WARNING: error for default value,{addr_nsp,zwei},{}: relation "addr_nsp" does not exist
+WARNING: error for default value,{addr_nsp,zwei},{integer}: relation "addr_nsp" does not exist
+WARNING: error for default value,{eins,zwei,drei},{}: schema "eins" does not exist
+WARNING: error for default value,{eins,zwei,drei},{integer}: schema "eins" does not exist
+WARNING: error for operator,{eins},{}: argument list length must be exactly 2
+WARNING: error for operator,{eins},{integer}: argument list length must be exactly 2
+WARNING: error for operator,{addr_nsp,zwei},{}: argument list length must be exactly 2
+WARNING: error for operator,{addr_nsp,zwei},{integer}: argument list length must be exactly 2
+WARNING: error for operator,{eins,zwei,drei},{}: argument list length must be exactly 2
+WARNING: error for operator,{eins,zwei,drei},{integer}: argument list length must be exactly 2
+WARNING: error for operator class,{eins},{}: argument list length must be exactly 1
+WARNING: error for operator class,{eins},{integer}: access method "integer" does not exist
+WARNING: error for operator class,{addr_nsp,zwei},{}: argument list length must be exactly 1
+WARNING: error for operator class,{addr_nsp,zwei},{integer}: access method "integer" does not exist
+WARNING: error for operator class,{eins,zwei,drei},{}: argument list length must be exactly 1
+WARNING: error for operator class,{eins,zwei,drei},{integer}: access method "integer" does not exist
+WARNING: error for operator family,{eins},{}: argument list length must be exactly 1
+WARNING: error for operator family,{eins},{integer}: access method "integer" does not exist
+WARNING: error for operator family,{addr_nsp,zwei},{}: argument list length must be exactly 1
+WARNING: error for operator family,{addr_nsp,zwei},{integer}: access method "integer" does not exist
+WARNING: error for operator family,{eins,zwei,drei},{}: argument list length must be exactly 1
+WARNING: error for operator family,{eins,zwei,drei},{integer}: access method "integer" does not exist
+WARNING: error for rule,{eins},{}: rule "eins" does not exist
+WARNING: error for rule,{eins},{integer}: rule "eins" does not exist
+WARNING: error for rule,{addr_nsp,zwei},{}: relation "addr_nsp" does not exist
+WARNING: error for rule,{addr_nsp,zwei},{integer}: relation "addr_nsp" does not exist
+WARNING: error for rule,{eins,zwei,drei},{}: schema "eins" does not exist
+WARNING: error for rule,{eins,zwei,drei},{integer}: schema "eins" does not exist
+WARNING: error for trigger,{eins},{}: must specify relation and object name
+WARNING: error for trigger,{eins},{integer}: must specify relation and object name
+WARNING: error for trigger,{addr_nsp,zwei},{}: relation "addr_nsp" does not exist
+WARNING: error for trigger,{addr_nsp,zwei},{integer}: relation "addr_nsp" does not exist
+WARNING: error for trigger,{eins,zwei,drei},{}: schema "eins" does not exist
+WARNING: error for trigger,{eins,zwei,drei},{integer}: schema "eins" does not exist
+WARNING: error for text search parser,{eins},{}: text search parser "eins" does not exist
+WARNING: error for text search parser,{eins},{integer}: text search parser "eins" does not exist
+WARNING: error for text search parser,{addr_nsp,zwei},{}: text search parser "addr_nsp.zwei" does not exist
+WARNING: error for text search parser,{addr_nsp,zwei},{integer}: text search parser "addr_nsp.zwei" does not exist
+WARNING: error for text search parser,{eins,zwei,drei},{}: cross-database references are not implemented: eins.zwei.drei
+WARNING: error for text search parser,{eins,zwei,drei},{integer}: cross-database references are not implemented: eins.zwei.drei
+WARNING: error for text search dictionary,{eins},{}: text search dictionary "eins" does not exist
+WARNING: error for text search dictionary,{eins},{integer}: text search dictionary "eins" does not exist
+WARNING: error for text search dictionary,{addr_nsp,zwei},{}: text search dictionary "addr_nsp.zwei" does not exist
+WARNING: error for text search dictionary,{addr_nsp,zwei},{integer}: text search dictionary "addr_nsp.zwei" does not exist
+WARNING: error for text search dictionary,{eins,zwei,drei},{}: cross-database references are not implemented: eins.zwei.drei
+WARNING: error for text search dictionary,{eins,zwei,drei},{integer}: cross-database references are not implemented: eins.zwei.drei
+WARNING: error for text search template,{eins},{}: text search template "eins" does not exist
+WARNING: error for text search template,{eins},{integer}: text search template "eins" does not exist
+WARNING: error for text search template,{addr_nsp,zwei},{}: text search template "addr_nsp.zwei" does not exist
+WARNING: error for text search template,{addr_nsp,zwei},{integer}: text search template "addr_nsp.zwei" does not exist
+WARNING: error for text search template,{eins,zwei,drei},{}: cross-database references are not implemented: eins.zwei.drei
+WARNING: error for text search template,{eins,zwei,drei},{integer}: cross-database references are not implemented: eins.zwei.drei
+WARNING: error for text search configuration,{eins},{}: text search configuration "eins" does not exist
+WARNING: error for text search configuration,{eins},{integer}: text search configuration "eins" does not exist
+WARNING: error for text search configuration,{addr_nsp,zwei},{}: text search configuration "addr_nsp.zwei" does not exist
+WARNING: error for text search configuration,{addr_nsp,zwei},{integer}: text search configuration "addr_nsp.zwei" does not exist
+WARNING: error for text search configuration,{eins,zwei,drei},{}: cross-database references are not implemented: eins.zwei.drei
+WARNING: error for text search configuration,{eins,zwei,drei},{integer}: cross-database references are not implemented: eins.zwei.drei
+WARNING: error for policy,{eins},{}: must specify relation and object name
+WARNING: error for policy,{eins},{integer}: must specify relation and object name
+WARNING: error for policy,{addr_nsp,zwei},{}: relation "addr_nsp" does not exist
+WARNING: error for policy,{addr_nsp,zwei},{integer}: relation "addr_nsp" does not exist
+WARNING: error for policy,{eins,zwei,drei},{}: schema "eins" does not exist
+WARNING: error for policy,{eins,zwei,drei},{integer}: schema "eins" does not exist
+-- these object types cannot be qualified names
+SELECT pg_get_object_address('language', '{one}', '{}');
+ERROR: language "one" does not exist
+SELECT pg_get_object_address('language', '{one,two}', '{}');
+ERROR: language name cannot be qualified
+SELECT pg_get_object_address('large object', '{123}', '{}');
+ERROR: large object 123 does not exist
+SELECT pg_get_object_address('large object', '{123,456}', '{}');
+ERROR: name list length must be exactly 1
+SELECT pg_get_object_address('large object', '{blargh}', '{}');
+ERROR: invalid input syntax for type oid: "blargh"
+SELECT pg_get_object_address('schema', '{one}', '{}');
+ERROR: schema "one" does not exist
+SELECT pg_get_object_address('schema', '{one,two}', '{}');
+ERROR: schema name cannot be qualified
+SELECT pg_get_object_address('role', '{one}', '{}');
+ERROR: role "one" does not exist
+SELECT pg_get_object_address('role', '{one,two}', '{}');
+ERROR: role name cannot be qualified
+SELECT pg_get_object_address('database', '{one}', '{}');
+ERROR: database "one" does not exist
+SELECT pg_get_object_address('database', '{one,two}', '{}');
+ERROR: database name cannot be qualified
+SELECT pg_get_object_address('tablespace', '{one}', '{}');
+ERROR: tablespace "one" does not exist
+SELECT pg_get_object_address('tablespace', '{one,two}', '{}');
+ERROR: tablespace name cannot be qualified
+SELECT pg_get_object_address('foreign-data wrapper', '{one}', '{}');
+ERROR: foreign-data wrapper "one" does not exist
+SELECT pg_get_object_address('foreign-data wrapper', '{one,two}', '{}');
+ERROR: foreign-data wrapper name cannot be qualified
+SELECT pg_get_object_address('server', '{one}', '{}');
+ERROR: server "one" does not exist
+SELECT pg_get_object_address('server', '{one,two}', '{}');
+ERROR: server name cannot be qualified
+SELECT pg_get_object_address('extension', '{one}', '{}');
+ERROR: extension "one" does not exist
+SELECT pg_get_object_address('extension', '{one,two}', '{}');
+ERROR: extension name cannot be qualified
+SELECT pg_get_object_address('event trigger', '{one}', '{}');
+ERROR: event trigger "one" does not exist
+SELECT pg_get_object_address('event trigger', '{one,two}', '{}');
+ERROR: event trigger name cannot be qualified
+-- test successful cases
+WITH objects (type, name, args) AS (VALUES
+ ('table', '{addr_nsp, gentable}'::text[], '{}'::text[]),
+ ('index', '{addr_nsp, gentable_pkey}', '{}'),
+ ('sequence', '{addr_nsp, gentable_a_seq}', '{}'),
+ -- toast table
+ ('view', '{addr_nsp, genview}', '{}'),
+ ('materialized view', '{addr_nsp, genmatview}', '{}'),
+ ('foreign table', '{addr_nsp, genftable}', '{}'),
+ ('table column', '{addr_nsp, gentable, b}', '{}'),
+ ('foreign table column', '{addr_nsp, genftable, a}', '{}'),
+ ('aggregate', '{addr_nsp, genaggr}', '{int4}'),
+ ('function', '{pg_catalog, pg_identify_object}', '{pg_catalog.oid, pg_catalog.oid, int4}'),
+ ('type', '{pg_catalog._int4}', '{}'),
+ ('type', '{addr_nsp.gendomain}', '{}'),
+ ('type', '{addr_nsp.gencomptype}', '{}'),
+ ('type', '{addr_nsp.genenum}', '{}'),
+ ('cast', '{int8}', '{int4}'),
+ ('collation', '{default}', '{}'),
+ ('table constraint', '{addr_nsp, gentable, a_chk}', '{}'),
+ ('domain constraint', '{addr_nsp, gendomain, domconstr}', '{}'),
+ ('conversion', '{pg_catalog, ascii_to_mic}', '{}'),
+ ('default value', '{addr_nsp, gentable, b}', '{}'),
+ ('language', '{plpgsql}', '{}'),
+ -- large object
+ ('operator', '{+}', '{int4, int4}'),
+ ('operator class', '{int4_ops}', '{btree}'),
+ ('operator family', '{integer_ops}', '{btree}'),
+ -- operator of access method
+ -- function of access method
+ ('rule', '{addr_nsp, genview, _RETURN}', '{}'),
+ ('trigger', '{addr_nsp, gentable, t}', '{}'),
+ ('schema', '{addr_nsp}', '{}'),
+ ('text search parser', '{addr_ts_prs}', '{}'),
+ ('text search dictionary', '{addr_ts_dict}', '{}'),
+ ('text search template', '{addr_ts_temp}', '{}'),
+ ('text search configuration', '{addr_ts_conf}', '{}'),
+ ('role', '{regtest_addr_user}', '{}'),
+ -- database
+ -- tablespace
+ ('foreign-data wrapper', '{addr_fdw}', '{}'),
+ ('server', '{addr_fserv}', '{}'),
+ -- user mapping
+ -- extension
+ ('event trigger', '{evttrig}', '{}'),
+ ('policy', '{addr_nsp, gentable, genpol}', '{}')
+ )
+SELECT (pg_identify_object(classid, objid, subobjid)).*
+ FROM objects, pg_get_object_address(type, name, args)
+ORDER BY classid, objid;
+ type | schema | name | identity
+---------------------------+------------+-------------------+----------------------------------------------------------------------
+ type | pg_catalog | _int4 | integer[]
+ type | addr_nsp | gencomptype | addr_nsp.gencomptype
+ type | addr_nsp | genenum | addr_nsp.genenum
+ type | addr_nsp | gendomain | addr_nsp.gendomain
+ function | pg_catalog | | pg_catalog.pg_identify_object(pg_catalog.oid,pg_catalog.oid,integer)
+ aggregate | addr_nsp | | addr_nsp.genaggr(integer)
+ sequence | addr_nsp | gentable_a_seq | addr_nsp.gentable_a_seq
+ table | addr_nsp | gentable | addr_nsp.gentable
+ table column | addr_nsp | gentable | addr_nsp.gentable.b
+ index | addr_nsp | gentable_pkey | addr_nsp.gentable_pkey
+ view | addr_nsp | genview | addr_nsp.genview
+ materialized view | addr_nsp | genmatview | addr_nsp.genmatview
+ foreign table column | addr_nsp | genftable | addr_nsp.genftable.a
+ foreign table | addr_nsp | genftable | addr_nsp.genftable
+ role | | regtest_addr_user | regtest_addr_user
+ server | | addr_fserv | addr_fserv
+ foreign-data wrapper | | addr_fdw | addr_fdw
+ default value | | | for addr_nsp.gentable.b
+ cast | | | (bigint AS integer)
+ table constraint | addr_nsp | | a_chk on addr_nsp.gentable
+ domain constraint | addr_nsp | | domconstr on addr_nsp.gendomain
+ conversion | pg_catalog | ascii_to_mic | ascii_to_mic
+ language | | plpgsql | plpgsql
+ schema | | addr_nsp | addr_nsp
+ operator class | pg_catalog | int4_ops | pg_catalog.int4_ops for btree
+ operator | pg_catalog | | pg_catalog.+(integer,integer)
+ rule | | | "_RETURN" on addr_nsp.genview
+ trigger | | | t on addr_nsp.gentable
+ operator family | pg_catalog | integer_ops | pg_catalog.integer_ops for btree
+ policy | | | genpol on addr_nsp.gentable
+ collation | pg_catalog | "default" | pg_catalog."default"
+ event trigger | | evttrig | evttrig
+ text search dictionary | addr_nsp | addr_ts_dict | addr_nsp.addr_ts_dict
+ text search parser | addr_nsp | addr_ts_prs | addr_nsp.addr_ts_prs
+ text search configuration | addr_nsp | addr_ts_conf | addr_nsp.addr_ts_conf
+ text search template | addr_nsp | addr_ts_temp | addr_nsp.addr_ts_temp
+(36 rows)
+
+---
+--- Cleanup resources
+---
+DROP FOREIGN DATA WRAPPER addr_fdw CASCADE;
+DROP SCHEMA addr_nsp CASCADE;
+DROP USER regtest_addr_user;
--- /dev/null
+--
+-- Test for pg_get_object_address
+--
+
+-- Clean up in case a prior regression run failed
+SET client_min_messages TO 'warning';
+
+DROP ROLE IF EXISTS regtest_addr_user;
+
+CREATE USER regtest_addr_user;
+
+-- Test generic object addressing/identification functions
+CREATE SCHEMA addr_nsp;
+SET search_path TO 'addr_nsp';
+CREATE FOREIGN DATA WRAPPER addr_fdw;
+CREATE SERVER addr_fserv FOREIGN DATA WRAPPER addr_fdw;
+CREATE TEXT SEARCH DICTIONARY addr_ts_dict (template=simple);
+CREATE TEXT SEARCH CONFIGURATION addr_ts_conf (copy=english);
+CREATE TEXT SEARCH TEMPLATE addr_ts_temp (lexize=dsimple_lexize);
+CREATE TEXT SEARCH PARSER addr_ts_prs
+ (start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+CREATE TABLE addr_nsp.gentable (
+ a serial primary key CONSTRAINT a_chk CHECK (a > 0),
+ b text DEFAULT 'hello');
+CREATE VIEW addr_nsp.genview AS SELECT * from addr_nsp.gentable;
+CREATE MATERIALIZED VIEW addr_nsp.genmatview AS SELECT * FROM addr_nsp.gentable;
+CREATE TYPE addr_nsp.gencomptype AS (a int);
+CREATE TYPE addr_nsp.genenum AS ENUM ('one', 'two');
+CREATE FOREIGN TABLE addr_nsp.genftable (a int) SERVER addr_fserv;
+CREATE AGGREGATE addr_nsp.genaggr(int4) (sfunc = int4pl, stype = int4);
+CREATE DOMAIN addr_nsp.gendomain AS int4 CONSTRAINT domconstr CHECK (value > 0);
+CREATE FUNCTION addr_nsp.trig() RETURNS TRIGGER LANGUAGE plpgsql AS $$ BEGIN END; $$;
+CREATE TRIGGER t BEFORE INSERT ON addr_nsp.gentable FOR EACH ROW EXECUTE PROCEDURE addr_nsp.trig();
+CREATE POLICY genpol ON addr_nsp.gentable;
+
+CREATE FUNCTION addr_nsp.etrig() RETURNS EVENT_TRIGGER LANGUAGE plpgsql AS $$ BEGIN END; $$;
+CREATE EVENT TRIGGER evttrig ON ddl_command_end EXECUTE PROCEDURE addr_nsp.etrig();
+
+-- test some error cases
+SELECT pg_get_object_address('stone', '{}', '{}');
+SELECT pg_get_object_address('table', '{}', '{}');
+SELECT pg_get_object_address('table', '{NULL}', '{}');
+
+-- unrecognized object types
+DO $$
+DECLARE
+ objtype text;
+BEGIN
+ FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
+ ('toast table column'), ('view column'), ('materialized view column'),
+ ('operator of access method'), ('function of access method'),
+ ('user mapping')
+ LOOP
+ BEGIN
+ PERFORM pg_get_object_address(objtype, '{one}', '{}');
+ EXCEPTION WHEN invalid_parameter_value THEN
+ RAISE WARNING 'error for %: %', objtype, sqlerrm;
+ END;
+ END LOOP;
+END;
+$$;
+
+DO $$
+DECLARE
+ objtype text;
+ names text[];
+ args text[];
+BEGIN
+ FOR objtype IN VALUES
+ ('table'), ('index'), ('sequence'), ('view'),
+ ('materialized view'), ('foreign table'),
+ ('table column'), ('foreign table column'),
+ ('aggregate'), ('function'), ('type'), ('cast'),
+ ('collation'),
+ ('table constraint'), ('domain constraint'), ('conversion'), ('default value'),
+ ('operator'), ('operator class'), ('operator family'), ('rule'), ('trigger'),
+ ('text search parser'), ('text search dictionary'),
+ ('text search template'), ('text search configuration'),
+ ('policy')
+ LOOP
+ FOR names IN VALUES ('{eins}'), ('{addr_nsp, zwei}'), ('{eins, zwei, drei}')
+ LOOP
+ FOR args IN VALUES ('{}'), ('{integer}')
+ LOOP
+ BEGIN
+ PERFORM pg_get_object_address(objtype, names, args);
+ EXCEPTION WHEN OTHERS THEN
+ RAISE WARNING 'error for %,%,%: %', objtype, names, args, sqlerrm;
+ END;
+ END LOOP;
+ END LOOP;
+ END LOOP;
+END;
+$$;
+
+-- these object types cannot be qualified names
+SELECT pg_get_object_address('language', '{one}', '{}');
+SELECT pg_get_object_address('language', '{one,two}', '{}');
+SELECT pg_get_object_address('large object', '{123}', '{}');
+SELECT pg_get_object_address('large object', '{123,456}', '{}');
+SELECT pg_get_object_address('large object', '{blargh}', '{}');
+SELECT pg_get_object_address('schema', '{one}', '{}');
+SELECT pg_get_object_address('schema', '{one,two}', '{}');
+SELECT pg_get_object_address('role', '{one}', '{}');
+SELECT pg_get_object_address('role', '{one,two}', '{}');
+SELECT pg_get_object_address('database', '{one}', '{}');
+SELECT pg_get_object_address('database', '{one,two}', '{}');
+SELECT pg_get_object_address('tablespace', '{one}', '{}');
+SELECT pg_get_object_address('tablespace', '{one,two}', '{}');
+SELECT pg_get_object_address('foreign-data wrapper', '{one}', '{}');
+SELECT pg_get_object_address('foreign-data wrapper', '{one,two}', '{}');
+SELECT pg_get_object_address('server', '{one}', '{}');
+SELECT pg_get_object_address('server', '{one,two}', '{}');
+SELECT pg_get_object_address('extension', '{one}', '{}');
+SELECT pg_get_object_address('extension', '{one,two}', '{}');
+SELECT pg_get_object_address('event trigger', '{one}', '{}');
+SELECT pg_get_object_address('event trigger', '{one,two}', '{}');
+
+-- test successful cases
+WITH objects (type, name, args) AS (VALUES
+ ('table', '{addr_nsp, gentable}'::text[], '{}'::text[]),
+ ('index', '{addr_nsp, gentable_pkey}', '{}'),
+ ('sequence', '{addr_nsp, gentable_a_seq}', '{}'),
+ -- toast table
+ ('view', '{addr_nsp, genview}', '{}'),
+ ('materialized view', '{addr_nsp, genmatview}', '{}'),
+ ('foreign table', '{addr_nsp, genftable}', '{}'),
+ ('table column', '{addr_nsp, gentable, b}', '{}'),
+ ('foreign table column', '{addr_nsp, genftable, a}', '{}'),
+ ('aggregate', '{addr_nsp, genaggr}', '{int4}'),
+ ('function', '{pg_catalog, pg_identify_object}', '{pg_catalog.oid, pg_catalog.oid, int4}'),
+ ('type', '{pg_catalog._int4}', '{}'),
+ ('type', '{addr_nsp.gendomain}', '{}'),
+ ('type', '{addr_nsp.gencomptype}', '{}'),
+ ('type', '{addr_nsp.genenum}', '{}'),
+ ('cast', '{int8}', '{int4}'),
+ ('collation', '{default}', '{}'),
+ ('table constraint', '{addr_nsp, gentable, a_chk}', '{}'),
+ ('domain constraint', '{addr_nsp, gendomain, domconstr}', '{}'),
+ ('conversion', '{pg_catalog, ascii_to_mic}', '{}'),
+ ('default value', '{addr_nsp, gentable, b}', '{}'),
+ ('language', '{plpgsql}', '{}'),
+ -- large object
+ ('operator', '{+}', '{int4, int4}'),
+ ('operator class', '{int4_ops}', '{btree}'),
+ ('operator family', '{integer_ops}', '{btree}'),
+ -- operator of access method
+ -- function of access method
+ ('rule', '{addr_nsp, genview, _RETURN}', '{}'),
+ ('trigger', '{addr_nsp, gentable, t}', '{}'),
+ ('schema', '{addr_nsp}', '{}'),
+ ('text search parser', '{addr_ts_prs}', '{}'),
+ ('text search dictionary', '{addr_ts_dict}', '{}'),
+ ('text search template', '{addr_ts_temp}', '{}'),
+ ('text search configuration', '{addr_ts_conf}', '{}'),
+ ('role', '{regtest_addr_user}', '{}'),
+ -- database
+ -- tablespace
+ ('foreign-data wrapper', '{addr_fdw}', '{}'),
+ ('server', '{addr_fserv}', '{}'),
+ -- user mapping
+ -- extension
+ ('event trigger', '{evttrig}', '{}'),
+ ('policy', '{addr_nsp, gentable, genpol}', '{}')
+ )
+SELECT (pg_identify_object(classid, objid, subobjid)).*
+ FROM objects, pg_get_object_address(type, name, args)
+ORDER BY classid, objid;
+
+---
+--- Cleanup resources
+---
+DROP FOREIGN DATA WRAPPER addr_fdw CASCADE;
+
+DROP SCHEMA addr_nsp CASCADE;
+
+DROP USER regtest_addr_user;