1 /*-------------------------------------------------------------------------
4 * functions for working with ObjectAddresses
6 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/catalog/objectaddress.c
13 *-------------------------------------------------------------------------
18 #include "access/heapam.h"
19 #include "access/sysattr.h"
20 #include "catalog/catalog.h"
21 #include "catalog/dependency.h"
22 #include "catalog/indexing.h"
23 #include "catalog/namespace.h"
24 #include "catalog/objectaddress.h"
25 #include "catalog/pg_authid.h"
26 #include "catalog/pg_cast.h"
27 #include "catalog/pg_class.h"
28 #include "catalog/pg_constraint.h"
29 #include "catalog/pg_conversion.h"
30 #include "catalog/pg_database.h"
31 #include "catalog/pg_extension.h"
32 #include "catalog/pg_language.h"
33 #include "catalog/pg_largeobject.h"
34 #include "catalog/pg_largeobject_metadata.h"
35 #include "catalog/pg_namespace.h"
36 #include "catalog/pg_opclass.h"
37 #include "catalog/pg_opfamily.h"
38 #include "catalog/pg_operator.h"
39 #include "catalog/pg_proc.h"
40 #include "catalog/pg_rewrite.h"
41 #include "catalog/pg_tablespace.h"
42 #include "catalog/pg_trigger.h"
43 #include "catalog/pg_ts_config.h"
44 #include "catalog/pg_ts_dict.h"
45 #include "catalog/pg_ts_parser.h"
46 #include "catalog/pg_ts_template.h"
47 #include "catalog/pg_type.h"
48 #include "commands/dbcommands.h"
49 #include "commands/defrem.h"
50 #include "commands/extension.h"
51 #include "commands/proclang.h"
52 #include "commands/tablespace.h"
53 #include "commands/trigger.h"
54 #include "nodes/makefuncs.h"
55 #include "parser/parse_func.h"
56 #include "parser/parse_oper.h"
57 #include "parser/parse_type.h"
58 #include "rewrite/rewriteSupport.h"
59 #include "storage/lmgr.h"
60 #include "utils/acl.h"
61 #include "utils/builtins.h"
62 #include "utils/fmgroids.h"
63 #include "utils/lsyscache.h"
64 #include "utils/syscache.h"
65 #include "utils/rel.h"
66 #include "utils/tqual.h"
68 static ObjectAddress get_object_address_unqualified(ObjectType objtype,
70 static Relation get_relation_by_qualified_name(ObjectType objtype,
71 List *objname, LOCKMODE lockmode);
72 static ObjectAddress get_object_address_relobject(ObjectType objtype,
73 List *objname, Relation *relp);
74 static ObjectAddress get_object_address_attribute(ObjectType objtype,
75 List *objname, Relation *relp, LOCKMODE lockmode);
76 static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname,
78 static bool object_exists(ObjectAddress address);
81 * Translate an object name and arguments (as passed by the parser) to an
84 * The returned object will be locked using the specified lockmode. If a
85 * sub-object is looked up, the parent object will be locked instead.
87 * If the object is a relation or a child object of a relation (e.g. an
88 * attribute or contraint), the relation is also opened and *relp receives
89 * the open relcache entry pointer; otherwise, *relp is set to NULL. This
90 * is a bit grotty but it makes life simpler, since the caller will
91 * typically need the relcache entry too. Caller must close the relcache
92 * entry when done with it. The relation is locked with the specified lockmode
93 * if the target object is the relation itself or an attribute, but for other
94 * child objects, only AccessShareLock is acquired on the relation.
96 * We don't currently provide a function to release the locks acquired here;
97 * typically, the lock must be held until commit to guard against a concurrent
101 get_object_address(ObjectType objtype, List *objname, List *objargs,
102 Relation *relp, LOCKMODE lockmode)
104 ObjectAddress address;
105 Relation relation = NULL;
107 /* Some kind of lock must be taken. */
108 Assert(lockmode != NoLock);
113 case OBJECT_SEQUENCE:
116 case OBJECT_FOREIGN_TABLE:
118 get_relation_by_qualified_name(objtype, objname, lockmode);
119 address.classId = RelationRelationId;
120 address.objectId = RelationGetRelid(relation);
121 address.objectSubId = 0;
125 get_object_address_attribute(objtype, objname, &relation,
130 case OBJECT_CONSTRAINT:
131 address = get_object_address_relobject(objtype, objname, &relation);
133 case OBJECT_DATABASE:
134 case OBJECT_EXTENSION:
135 case OBJECT_TABLESPACE:
138 case OBJECT_LANGUAGE:
139 address = get_object_address_unqualified(objtype, objname);
142 address.classId = TypeRelationId;
144 typenameTypeId(NULL, makeTypeNameFromNameList(objname));
145 address.objectSubId = 0;
147 case OBJECT_AGGREGATE:
148 address.classId = ProcedureRelationId;
149 address.objectId = LookupAggNameTypeNames(objname, objargs, false);
150 address.objectSubId = 0;
152 case OBJECT_FUNCTION:
153 address.classId = ProcedureRelationId;
154 address.objectId = LookupFuncNameTypeNames(objname, objargs, false);
155 address.objectSubId = 0;
157 case OBJECT_OPERATOR:
158 Assert(list_length(objargs) == 2);
159 address.classId = OperatorRelationId;
161 LookupOperNameTypeNames(NULL, objname,
162 (TypeName *) linitial(objargs),
163 (TypeName *) lsecond(objargs),
165 address.objectSubId = 0;
167 case OBJECT_CONVERSION:
168 address.classId = ConversionRelationId;
169 address.objectId = get_conversion_oid(objname, false);
170 address.objectSubId = 0;
173 case OBJECT_OPFAMILY:
174 address = get_object_address_opcf(objtype, objname, objargs);
176 case OBJECT_LARGEOBJECT:
177 Assert(list_length(objname) == 1);
178 address.classId = LargeObjectRelationId;
179 address.objectId = oidparse(linitial(objname));
180 address.objectSubId = 0;
181 if (!LargeObjectExists(address.objectId))
183 (errcode(ERRCODE_UNDEFINED_OBJECT),
184 errmsg("large object %u does not exist",
189 TypeName *sourcetype = (TypeName *) linitial(objname);
190 TypeName *targettype = (TypeName *) linitial(objargs);
191 Oid sourcetypeid = typenameTypeId(NULL, sourcetype);
192 Oid targettypeid = typenameTypeId(NULL, targettype);
194 address.classId = CastRelationId;
196 get_cast_oid(sourcetypeid, targettypeid, false);
197 address.objectSubId = 0;
200 case OBJECT_TSPARSER:
201 address.classId = TSParserRelationId;
202 address.objectId = get_ts_parser_oid(objname, false);
203 address.objectSubId = 0;
205 case OBJECT_TSDICTIONARY:
206 address.classId = TSDictionaryRelationId;
207 address.objectId = get_ts_dict_oid(objname, false);
208 address.objectSubId = 0;
210 case OBJECT_TSTEMPLATE:
211 address.classId = TSTemplateRelationId;
212 address.objectId = get_ts_template_oid(objname, false);
213 address.objectSubId = 0;
215 case OBJECT_TSCONFIGURATION:
216 address.classId = TSConfigRelationId;
217 address.objectId = get_ts_config_oid(objname, false);
218 address.objectSubId = 0;
221 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
222 /* placate compiler, in case it thinks elog might return */
223 address.classId = InvalidOid;
224 address.objectId = InvalidOid;
225 address.objectSubId = 0;
229 * If we're dealing with a relation or attribute, then the relation is
230 * already locked. If we're dealing with any other type of object, we need
231 * to lock it and then verify that it still exists.
233 if (address.classId != RelationRelationId)
235 if (IsSharedRelation(address.classId))
236 LockSharedObject(address.classId, address.objectId, 0, lockmode);
238 LockDatabaseObject(address.classId, address.objectId, 0, lockmode);
239 /* Did it go away while we were waiting for the lock? */
240 if (!object_exists(address))
241 elog(ERROR, "cache lookup failed for class %u object %u subobj %d",
242 address.classId, address.objectId, address.objectSubId);
245 /* Return the object address and the relation. */
251 * Find an ObjectAddress for a type of object that is identified by an
255 get_object_address_unqualified(ObjectType objtype, List *qualname)
258 ObjectAddress address;
261 * The types of names handled by this function are not permitted to be
262 * schema-qualified or catalog-qualified.
264 if (list_length(qualname) != 1)
270 case OBJECT_DATABASE:
271 msg = gettext_noop("database name cannot be qualified");
273 case OBJECT_EXTENSION:
274 msg = gettext_noop("extension name cannot be qualified");
276 case OBJECT_TABLESPACE:
277 msg = gettext_noop("tablespace name cannot be qualified");
280 msg = gettext_noop("role name cannot be qualified");
283 msg = gettext_noop("schema name cannot be qualified");
285 case OBJECT_LANGUAGE:
286 msg = gettext_noop("language name cannot be qualified");
289 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
290 msg = NULL; /* placate compiler */
293 (errcode(ERRCODE_SYNTAX_ERROR),
294 errmsg("%s", _(msg))));
297 /* Format is valid, extract the actual name. */
298 name = strVal(linitial(qualname));
300 /* Translate name to OID. */
303 case OBJECT_DATABASE:
304 address.classId = DatabaseRelationId;
305 address.objectId = get_database_oid(name, false);
306 address.objectSubId = 0;
308 case OBJECT_EXTENSION:
309 address.classId = ExtensionRelationId;
310 address.objectId = get_extension_oid(name, false);
311 address.objectSubId = 0;
313 case OBJECT_TABLESPACE:
314 address.classId = TableSpaceRelationId;
315 address.objectId = get_tablespace_oid(name, false);
316 address.objectSubId = 0;
319 address.classId = AuthIdRelationId;
320 address.objectId = get_role_oid(name, false);
321 address.objectSubId = 0;
324 address.classId = NamespaceRelationId;
325 address.objectId = get_namespace_oid(name, false);
326 address.objectSubId = 0;
328 case OBJECT_LANGUAGE:
329 address.classId = LanguageRelationId;
330 address.objectId = get_language_oid(name, false);
331 address.objectSubId = 0;
334 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
335 /* placate compiler, which doesn't know elog won't return */
336 address.classId = InvalidOid;
337 address.objectId = InvalidOid;
338 address.objectSubId = 0;
345 * Locate a relation by qualified name.
348 get_relation_by_qualified_name(ObjectType objtype, List *objname,
353 relation = relation_openrv(makeRangeVarFromNameList(objname), lockmode);
357 if (relation->rd_rel->relkind != RELKIND_INDEX)
359 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
360 errmsg("\"%s\" is not an index",
361 RelationGetRelationName(relation))));
363 case OBJECT_SEQUENCE:
364 if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
366 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
367 errmsg("\"%s\" is not a sequence",
368 RelationGetRelationName(relation))));
371 if (relation->rd_rel->relkind != RELKIND_RELATION)
373 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
374 errmsg("\"%s\" is not a table",
375 RelationGetRelationName(relation))));
378 if (relation->rd_rel->relkind != RELKIND_VIEW)
380 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
381 errmsg("\"%s\" is not a view",
382 RelationGetRelationName(relation))));
384 case OBJECT_FOREIGN_TABLE:
385 if (relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
387 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
388 errmsg("\"%s\" is not a foreign table",
389 RelationGetRelationName(relation))));
392 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
400 * Find object address for an object that is attached to a relation.
402 * Note that we take only an AccessShareLock on the relation. We need not
403 * pass down the LOCKMODE from get_object_address(), because that is the lock
404 * mode for the object itself, not the relation to which it is attached.
407 get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
409 ObjectAddress address;
410 Relation relation = NULL;
414 /* Extract name of dependent object. */
415 depname = strVal(lfirst(list_tail(objname)));
417 /* Separate relation name from dependent object name. */
418 nnames = list_length(objname);
424 * For compatibility with very old releases, we sometimes allow users
425 * to attempt to specify a rule without mentioning the relation name.
426 * If there's only rule by that name in the entire database, this will
427 * work. But objects other than rules don't get this special
430 if (objtype != OBJECT_RULE)
431 elog(ERROR, "must specify relation and object name");
432 address.classId = RewriteRelationId;
433 address.objectId = get_rewrite_oid_without_relid(depname, &reloid);
434 address.objectSubId = 0;
435 relation = heap_open(reloid, AccessShareLock);
442 /* Extract relation name and open relation. */
443 relname = list_truncate(list_copy(objname), nnames - 1);
444 relation = heap_openrv(makeRangeVarFromNameList(relname),
446 reloid = RelationGetRelid(relation);
451 address.classId = RewriteRelationId;
452 address.objectId = get_rewrite_oid(reloid, depname, false);
453 address.objectSubId = 0;
456 address.classId = TriggerRelationId;
457 address.objectId = get_trigger_oid(reloid, depname, false);
458 address.objectSubId = 0;
460 case OBJECT_CONSTRAINT:
461 address.classId = ConstraintRelationId;
462 address.objectId = get_constraint_oid(reloid, depname, false);
463 address.objectSubId = 0;
466 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
467 /* placate compiler, which doesn't know elog won't return */
468 address.classId = InvalidOid;
469 address.objectId = InvalidOid;
470 address.objectSubId = 0;
480 * Find the ObjectAddress for an attribute.
483 get_object_address_attribute(ObjectType objtype, List *objname,
484 Relation *relp, LOCKMODE lockmode)
486 ObjectAddress address;
492 /* Extract relation name and open relation. */
493 attname = strVal(lfirst(list_tail(objname)));
494 relname = list_truncate(list_copy(objname), list_length(objname) - 1);
495 relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
496 reloid = RelationGetRelid(relation);
498 /* Look up attribute and construct return value. */
499 address.classId = RelationRelationId;
500 address.objectId = reloid;
501 address.objectSubId = get_attnum(reloid, attname);
502 if (address.objectSubId == InvalidAttrNumber)
504 (errcode(ERRCODE_UNDEFINED_COLUMN),
505 errmsg("column \"%s\" of relation \"%s\" does not exist",
506 attname, RelationGetRelationName(relation))));
513 * Find the ObjectAddress for an opclass or opfamily.
516 get_object_address_opcf(ObjectType objtype, List *objname, List *objargs)
519 ObjectAddress address;
521 Assert(list_length(objargs) == 1);
522 amoid = get_am_oid(strVal(linitial(objargs)), false);
527 address.classId = OperatorClassRelationId;
528 address.objectId = get_opclass_oid(amoid, objname, false);
529 address.objectSubId = 0;
531 case OBJECT_OPFAMILY:
532 address.classId = OperatorFamilyRelationId;
533 address.objectId = get_opfamily_oid(amoid, objname, false);
534 address.objectSubId = 0;
537 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
538 /* placate compiler, which doesn't know elog won't return */
539 address.classId = InvalidOid;
540 address.objectId = InvalidOid;
541 address.objectSubId = 0;
548 * Test whether an object exists.
551 object_exists(ObjectAddress address)
554 Oid indexoid = InvalidOid;
560 /* Sub-objects require special treatment. */
561 if (address.objectSubId != 0)
565 /* Currently, attributes are the only sub-objects. */
566 Assert(address.classId == RelationRelationId);
567 atttup = SearchSysCache2(ATTNUM, ObjectIdGetDatum(address.objectId),
568 Int16GetDatum(address.objectSubId));
569 if (!HeapTupleIsValid(atttup))
573 found = ((Form_pg_attribute) GETSTRUCT(atttup))->attisdropped;
574 ReleaseSysCache(atttup);
580 * For object types that have a relevant syscache, we use it; for
581 * everything else, we'll have to do an index-scan. This switch
582 * sets either the cache to be used for the syscache lookup, or the
583 * index to be used for the index scan.
585 switch (address.classId)
587 case RelationRelationId:
590 case RewriteRelationId:
591 indexoid = RewriteOidIndexId;
593 case TriggerRelationId:
594 indexoid = TriggerOidIndexId;
596 case ConstraintRelationId:
599 case DatabaseRelationId:
602 case TableSpaceRelationId:
603 cache = TABLESPACEOID;
605 case AuthIdRelationId:
608 case NamespaceRelationId:
609 cache = NAMESPACEOID;
611 case LanguageRelationId:
617 case ProcedureRelationId:
620 case OperatorRelationId:
623 case ConversionRelationId:
626 case OperatorClassRelationId:
629 case OperatorFamilyRelationId:
632 case LargeObjectRelationId:
634 * Weird backward compatibility hack: ObjectAddress notation uses
635 * LargeObjectRelationId for large objects, but since PostgreSQL
636 * 9.0, the relevant catalog is actually
637 * LargeObjectMetadataRelationId.
639 address.classId = LargeObjectMetadataRelationId;
640 indexoid = LargeObjectMetadataOidIndexId;
643 indexoid = CastOidIndexId;
645 case TSParserRelationId:
648 case TSDictionaryRelationId:
651 case TSTemplateRelationId:
652 cache = TSTEMPLATEOID;
654 case TSConfigRelationId:
657 case ExtensionRelationId:
658 indexoid = ExtensionOidIndexId;
661 elog(ERROR, "unrecognized classid: %u", address.classId);
664 /* Found a syscache? */
666 return SearchSysCacheExists1(cache, ObjectIdGetDatum(address.objectId));
668 /* No syscache, so examine the table directly. */
669 Assert(OidIsValid(indexoid));
670 ScanKeyInit(&skey[0],
671 ObjectIdAttributeNumber,
672 BTEqualStrategyNumber, F_OIDEQ,
673 ObjectIdGetDatum(address.objectId));
674 rel = heap_open(address.classId, AccessShareLock);
675 sd = systable_beginscan(rel, indexoid, true, SnapshotNow, 1, skey);
676 found = HeapTupleIsValid(systable_getnext(sd));
677 systable_endscan(sd);
678 heap_close(rel, AccessShareLock);