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_language.h"
32 #include "catalog/pg_largeobject.h"
33 #include "catalog/pg_largeobject_metadata.h"
34 #include "catalog/pg_namespace.h"
35 #include "catalog/pg_opclass.h"
36 #include "catalog/pg_opfamily.h"
37 #include "catalog/pg_operator.h"
38 #include "catalog/pg_proc.h"
39 #include "catalog/pg_rewrite.h"
40 #include "catalog/pg_tablespace.h"
41 #include "catalog/pg_trigger.h"
42 #include "catalog/pg_ts_config.h"
43 #include "catalog/pg_ts_dict.h"
44 #include "catalog/pg_ts_parser.h"
45 #include "catalog/pg_ts_template.h"
46 #include "catalog/pg_type.h"
47 #include "commands/dbcommands.h"
48 #include "commands/defrem.h"
49 #include "commands/proclang.h"
50 #include "commands/tablespace.h"
51 #include "commands/trigger.h"
52 #include "nodes/makefuncs.h"
53 #include "parser/parse_func.h"
54 #include "parser/parse_oper.h"
55 #include "parser/parse_type.h"
56 #include "rewrite/rewriteSupport.h"
57 #include "storage/lmgr.h"
58 #include "utils/acl.h"
59 #include "utils/builtins.h"
60 #include "utils/fmgroids.h"
61 #include "utils/lsyscache.h"
62 #include "utils/syscache.h"
63 #include "utils/rel.h"
64 #include "utils/tqual.h"
66 static ObjectAddress get_object_address_unqualified(ObjectType objtype,
68 static Relation get_relation_by_qualified_name(ObjectType objtype,
69 List *objname, LOCKMODE lockmode);
70 static ObjectAddress get_object_address_relobject(ObjectType objtype,
71 List *objname, Relation *relp);
72 static ObjectAddress get_object_address_attribute(ObjectType objtype,
73 List *objname, Relation *relp, LOCKMODE lockmode);
74 static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname,
76 static bool object_exists(ObjectAddress address);
79 * Translate an object name and arguments (as passed by the parser) to an
82 * The returned object will be locked using the specified lockmode. If a
83 * sub-object is looked up, the parent object will be locked instead.
85 * If the object is a relation or a child object of a relation (e.g. an
86 * attribute or contraint), the relation is also opened and *relp receives
87 * the open relcache entry pointer; otherwise, *relp is set to NULL. This
88 * is a bit grotty but it makes life simpler, since the caller will
89 * typically need the relcache entry too. Caller must close the relcache
90 * entry when done with it. The relation is locked with the specified lockmode
91 * if the target object is the relation itself or an attribute, but for other
92 * child objects, only AccessShareLock is acquired on the relation.
94 * We don't currently provide a function to release the locks acquired here;
95 * typically, the lock must be held until commit to guard against a concurrent
99 get_object_address(ObjectType objtype, List *objname, List *objargs,
100 Relation *relp, LOCKMODE lockmode)
102 ObjectAddress address;
103 Relation relation = NULL;
105 /* Some kind of lock must be taken. */
106 Assert(lockmode != NoLock);
111 case OBJECT_SEQUENCE:
114 case OBJECT_FOREIGN_TABLE:
116 get_relation_by_qualified_name(objtype, objname, lockmode);
117 address.classId = RelationRelationId;
118 address.objectId = RelationGetRelid(relation);
119 address.objectSubId = 0;
123 get_object_address_attribute(objtype, objname, &relation,
128 case OBJECT_CONSTRAINT:
129 address = get_object_address_relobject(objtype, objname, &relation);
131 case OBJECT_DATABASE:
132 case OBJECT_TABLESPACE:
135 case OBJECT_LANGUAGE:
136 address = get_object_address_unqualified(objtype, objname);
139 address.classId = TypeRelationId;
141 typenameTypeId(NULL, makeTypeNameFromNameList(objname));
142 address.objectSubId = 0;
144 case OBJECT_AGGREGATE:
145 address.classId = ProcedureRelationId;
146 address.objectId = LookupAggNameTypeNames(objname, objargs, false);
147 address.objectSubId = 0;
149 case OBJECT_FUNCTION:
150 address.classId = ProcedureRelationId;
151 address.objectId = LookupFuncNameTypeNames(objname, objargs, false);
152 address.objectSubId = 0;
154 case OBJECT_OPERATOR:
155 Assert(list_length(objargs) == 2);
156 address.classId = OperatorRelationId;
158 LookupOperNameTypeNames(NULL, objname,
159 (TypeName *) linitial(objargs),
160 (TypeName *) lsecond(objargs),
162 address.objectSubId = 0;
164 case OBJECT_CONVERSION:
165 address.classId = ConversionRelationId;
166 address.objectId = get_conversion_oid(objname, false);
167 address.objectSubId = 0;
170 case OBJECT_OPFAMILY:
171 address = get_object_address_opcf(objtype, objname, objargs);
173 case OBJECT_LARGEOBJECT:
174 Assert(list_length(objname) == 1);
175 address.classId = LargeObjectRelationId;
176 address.objectId = oidparse(linitial(objname));
177 address.objectSubId = 0;
178 if (!LargeObjectExists(address.objectId))
180 (errcode(ERRCODE_UNDEFINED_OBJECT),
181 errmsg("large object %u does not exist",
186 TypeName *sourcetype = (TypeName *) linitial(objname);
187 TypeName *targettype = (TypeName *) linitial(objargs);
188 Oid sourcetypeid = typenameTypeId(NULL, sourcetype);
189 Oid targettypeid = typenameTypeId(NULL, targettype);
191 address.classId = CastRelationId;
193 get_cast_oid(sourcetypeid, targettypeid, false);
194 address.objectSubId = 0;
197 case OBJECT_TSPARSER:
198 address.classId = TSParserRelationId;
199 address.objectId = get_ts_parser_oid(objname, false);
200 address.objectSubId = 0;
202 case OBJECT_TSDICTIONARY:
203 address.classId = TSDictionaryRelationId;
204 address.objectId = get_ts_dict_oid(objname, false);
205 address.objectSubId = 0;
207 case OBJECT_TSTEMPLATE:
208 address.classId = TSTemplateRelationId;
209 address.objectId = get_ts_template_oid(objname, false);
210 address.objectSubId = 0;
212 case OBJECT_TSCONFIGURATION:
213 address.classId = TSConfigRelationId;
214 address.objectId = get_ts_config_oid(objname, false);
215 address.objectSubId = 0;
218 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
219 /* placate compiler, in case it thinks elog might return */
220 address.classId = InvalidOid;
221 address.objectId = InvalidOid;
222 address.objectSubId = 0;
226 * If we're dealing with a relation or attribute, then the relation is
227 * already locked. If we're dealing with any other type of object, we need
228 * to lock it and then verify that it still exists.
230 if (address.classId != RelationRelationId)
232 if (IsSharedRelation(address.classId))
233 LockSharedObject(address.classId, address.objectId, 0, lockmode);
235 LockDatabaseObject(address.classId, address.objectId, 0, lockmode);
236 /* Did it go away while we were waiting for the lock? */
237 if (!object_exists(address))
238 elog(ERROR, "cache lookup failed for class %u object %u subobj %d",
239 address.classId, address.objectId, address.objectSubId);
242 /* Return the object address and the relation. */
248 * Find an ObjectAddress for a type of object that is identified by an
252 get_object_address_unqualified(ObjectType objtype, List *qualname)
255 ObjectAddress address;
258 * The types of names handled by this function are not permitted to be
259 * schema-qualified or catalog-qualified.
261 if (list_length(qualname) != 1)
267 case OBJECT_DATABASE:
268 msg = gettext_noop("database name cannot be qualified");
270 case OBJECT_TABLESPACE:
271 msg = gettext_noop("tablespace name cannot be qualified");
274 msg = gettext_noop("role name cannot be qualified");
277 msg = gettext_noop("schema name cannot be qualified");
279 case OBJECT_LANGUAGE:
280 msg = gettext_noop("language name cannot be qualified");
283 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
284 msg = NULL; /* placate compiler */
287 (errcode(ERRCODE_SYNTAX_ERROR),
288 errmsg("%s", _(msg))));
291 /* Format is valid, extract the actual name. */
292 name = strVal(linitial(qualname));
294 /* Translate name to OID. */
297 case OBJECT_DATABASE:
298 address.classId = DatabaseRelationId;
299 address.objectId = get_database_oid(name, false);
300 address.objectSubId = 0;
302 case OBJECT_TABLESPACE:
303 address.classId = TableSpaceRelationId;
304 address.objectId = get_tablespace_oid(name, false);
305 address.objectSubId = 0;
308 address.classId = AuthIdRelationId;
309 address.objectId = get_role_oid(name, false);
310 address.objectSubId = 0;
313 address.classId = NamespaceRelationId;
314 address.objectId = get_namespace_oid(name, false);
315 address.objectSubId = 0;
317 case OBJECT_LANGUAGE:
318 address.classId = LanguageRelationId;
319 address.objectId = get_language_oid(name, false);
320 address.objectSubId = 0;
323 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
324 /* placate compiler, which doesn't know elog won't return */
325 address.classId = InvalidOid;
326 address.objectId = InvalidOid;
327 address.objectSubId = 0;
334 * Locate a relation by qualified name.
337 get_relation_by_qualified_name(ObjectType objtype, List *objname,
342 relation = relation_openrv(makeRangeVarFromNameList(objname), lockmode);
346 if (relation->rd_rel->relkind != RELKIND_INDEX)
348 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
349 errmsg("\"%s\" is not an index",
350 RelationGetRelationName(relation))));
352 case OBJECT_SEQUENCE:
353 if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
355 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
356 errmsg("\"%s\" is not a sequence",
357 RelationGetRelationName(relation))));
360 if (relation->rd_rel->relkind != RELKIND_RELATION)
362 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
363 errmsg("\"%s\" is not a table",
364 RelationGetRelationName(relation))));
367 if (relation->rd_rel->relkind != RELKIND_VIEW)
369 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
370 errmsg("\"%s\" is not a view",
371 RelationGetRelationName(relation))));
373 case OBJECT_FOREIGN_TABLE:
374 if (relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
376 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
377 errmsg("\"%s\" is not a foreign table",
378 RelationGetRelationName(relation))));
381 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
389 * Find object address for an object that is attached to a relation.
391 * Note that we take only an AccessShareLock on the relation. We need not
392 * pass down the LOCKMODE from get_object_address(), because that is the lock
393 * mode for the object itself, not the relation to which it is attached.
396 get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
398 ObjectAddress address;
399 Relation relation = NULL;
403 /* Extract name of dependent object. */
404 depname = strVal(lfirst(list_tail(objname)));
406 /* Separate relation name from dependent object name. */
407 nnames = list_length(objname);
413 * For compatibility with very old releases, we sometimes allow users
414 * to attempt to specify a rule without mentioning the relation name.
415 * If there's only rule by that name in the entire database, this will
416 * work. But objects other than rules don't get this special
419 if (objtype != OBJECT_RULE)
420 elog(ERROR, "must specify relation and object name");
421 address.classId = RewriteRelationId;
422 address.objectId = get_rewrite_oid_without_relid(depname, &reloid);
423 address.objectSubId = 0;
424 relation = heap_open(reloid, AccessShareLock);
431 /* Extract relation name and open relation. */
432 relname = list_truncate(list_copy(objname), nnames - 1);
433 relation = heap_openrv(makeRangeVarFromNameList(relname),
435 reloid = RelationGetRelid(relation);
440 address.classId = RewriteRelationId;
441 address.objectId = get_rewrite_oid(reloid, depname, false);
442 address.objectSubId = 0;
445 address.classId = TriggerRelationId;
446 address.objectId = get_trigger_oid(reloid, depname, false);
447 address.objectSubId = 0;
449 case OBJECT_CONSTRAINT:
450 address.classId = ConstraintRelationId;
451 address.objectId = get_constraint_oid(reloid, depname, false);
452 address.objectSubId = 0;
455 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
456 /* placate compiler, which doesn't know elog won't return */
457 address.classId = InvalidOid;
458 address.objectId = InvalidOid;
459 address.objectSubId = 0;
469 * Find the ObjectAddress for an attribute.
472 get_object_address_attribute(ObjectType objtype, List *objname,
473 Relation *relp, LOCKMODE lockmode)
475 ObjectAddress address;
481 /* Extract relation name and open relation. */
482 attname = strVal(lfirst(list_tail(objname)));
483 relname = list_truncate(list_copy(objname), list_length(objname) - 1);
484 relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
485 reloid = RelationGetRelid(relation);
487 /* Look up attribute and construct return value. */
488 address.classId = RelationRelationId;
489 address.objectId = reloid;
490 address.objectSubId = get_attnum(reloid, attname);
491 if (address.objectSubId == InvalidAttrNumber)
493 (errcode(ERRCODE_UNDEFINED_COLUMN),
494 errmsg("column \"%s\" of relation \"%s\" does not exist",
495 attname, RelationGetRelationName(relation))));
502 * Find the ObjectAddress for an opclass or opfamily.
505 get_object_address_opcf(ObjectType objtype, List *objname, List *objargs)
508 ObjectAddress address;
510 Assert(list_length(objargs) == 1);
511 amoid = get_am_oid(strVal(linitial(objargs)), false);
516 address.classId = OperatorClassRelationId;
517 address.objectId = get_opclass_oid(amoid, objname, false);
518 address.objectSubId = 0;
520 case OBJECT_OPFAMILY:
521 address.classId = OperatorFamilyRelationId;
522 address.objectId = get_opfamily_oid(amoid, objname, false);
523 address.objectSubId = 0;
526 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
527 /* placate compiler, which doesn't know elog won't return */
528 address.classId = InvalidOid;
529 address.objectId = InvalidOid;
530 address.objectSubId = 0;
537 * Test whether an object exists.
540 object_exists(ObjectAddress address)
543 Oid indexoid = InvalidOid;
549 /* Sub-objects require special treatment. */
550 if (address.objectSubId != 0)
554 /* Currently, attributes are the only sub-objects. */
555 Assert(address.classId == RelationRelationId);
556 atttup = SearchSysCache2(ATTNUM, ObjectIdGetDatum(address.objectId),
557 Int16GetDatum(address.objectSubId));
558 if (!HeapTupleIsValid(atttup))
562 found = ((Form_pg_attribute) GETSTRUCT(atttup))->attisdropped;
563 ReleaseSysCache(atttup);
569 * For object types that have a relevant syscache, we use it; for
570 * everything else, we'll have to do an index-scan. This switch
571 * sets either the cache to be used for the syscache lookup, or the
572 * index to be used for the index scan.
574 switch (address.classId)
576 case RelationRelationId:
579 case RewriteRelationId:
580 indexoid = RewriteOidIndexId;
582 case TriggerRelationId:
583 indexoid = TriggerOidIndexId;
585 case ConstraintRelationId:
588 case DatabaseRelationId:
591 case TableSpaceRelationId:
592 cache = TABLESPACEOID;
594 case AuthIdRelationId:
597 case NamespaceRelationId:
598 cache = NAMESPACEOID;
600 case LanguageRelationId:
606 case ProcedureRelationId:
609 case OperatorRelationId:
612 case ConversionRelationId:
615 case OperatorClassRelationId:
618 case OperatorFamilyRelationId:
621 case LargeObjectRelationId:
623 * Weird backward compatibility hack: ObjectAddress notation uses
624 * LargeObjectRelationId for large objects, but since PostgreSQL
625 * 9.0, the relevant catalog is actually
626 * LargeObjectMetadataRelationId.
628 address.classId = LargeObjectMetadataRelationId;
629 indexoid = LargeObjectMetadataOidIndexId;
632 indexoid = CastOidIndexId;
634 case TSParserRelationId:
637 case TSDictionaryRelationId:
640 case TSTemplateRelationId:
641 cache = TSTEMPLATEOID;
643 case TSConfigRelationId:
647 elog(ERROR, "unrecognized classid: %u", address.classId);
650 /* Found a syscache? */
652 return SearchSysCacheExists1(cache, ObjectIdGetDatum(address.objectId));
654 /* No syscache, so examine the table directly. */
655 Assert(OidIsValid(indexoid));
656 ScanKeyInit(&skey[0],
657 ObjectIdAttributeNumber,
658 BTEqualStrategyNumber, F_OIDEQ,
659 ObjectIdGetDatum(address.objectId));
660 rel = heap_open(address.classId, AccessShareLock);
661 sd = systable_beginscan(rel, indexoid, true, SnapshotNow, 1, skey);
662 found = HeapTupleIsValid(systable_getnext(sd));
663 systable_endscan(sd);
664 heap_close(rel, AccessShareLock);