]> granicus.if.org Git - postgresql/blob - src/backend/catalog/objectaddress.c
Core support for "extensions", which are packages of SQL objects.
[postgresql] / src / backend / catalog / objectaddress.c
1 /*-------------------------------------------------------------------------
2  *
3  * objectaddress.c
4  *        functions for working with ObjectAddresses
5  *
6  * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        src/backend/catalog/objectaddress.c
12  *
13  *-------------------------------------------------------------------------
14  */
15
16 #include "postgres.h"
17
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"
67
68 static ObjectAddress get_object_address_unqualified(ObjectType objtype,
69                                                            List *qualname);
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,
77                                                 List *objargs);
78 static bool object_exists(ObjectAddress address);
79
80 /*
81  * Translate an object name and arguments (as passed by the parser) to an
82  * ObjectAddress.
83  *
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.
86  *
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.
95  *
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
98  * drop operation.
99  */
100 ObjectAddress
101 get_object_address(ObjectType objtype, List *objname, List *objargs,
102                                    Relation *relp, LOCKMODE lockmode)
103 {
104         ObjectAddress   address;
105         Relation                relation = NULL;
106
107         /* Some kind of lock must be taken. */
108         Assert(lockmode != NoLock);
109
110         switch (objtype)
111         {
112                 case OBJECT_INDEX:
113                 case OBJECT_SEQUENCE:
114                 case OBJECT_TABLE:
115                 case OBJECT_VIEW:
116                 case OBJECT_FOREIGN_TABLE:
117                         relation =
118                                 get_relation_by_qualified_name(objtype, objname, lockmode);
119                         address.classId = RelationRelationId;
120                         address.objectId = RelationGetRelid(relation);
121                         address.objectSubId = 0;
122                         break;
123                 case OBJECT_COLUMN:
124                         address =
125                                 get_object_address_attribute(objtype, objname, &relation,
126                                         lockmode);
127                         break;
128                 case OBJECT_RULE:
129                 case OBJECT_TRIGGER:
130                 case OBJECT_CONSTRAINT:
131                         address = get_object_address_relobject(objtype, objname, &relation);
132                         break;
133                 case OBJECT_DATABASE:
134                 case OBJECT_EXTENSION:
135                 case OBJECT_TABLESPACE:
136                 case OBJECT_ROLE:
137                 case OBJECT_SCHEMA:
138                 case OBJECT_LANGUAGE:
139                         address = get_object_address_unqualified(objtype, objname);
140                         break;
141                 case OBJECT_TYPE:
142                         address.classId = TypeRelationId;
143                         address.objectId =
144                                 typenameTypeId(NULL, makeTypeNameFromNameList(objname));
145                         address.objectSubId = 0;
146                         break;
147                 case OBJECT_AGGREGATE:
148                         address.classId = ProcedureRelationId;
149                         address.objectId = LookupAggNameTypeNames(objname, objargs, false);
150                         address.objectSubId = 0;
151                         break;
152                 case OBJECT_FUNCTION:
153                         address.classId = ProcedureRelationId;
154                         address.objectId = LookupFuncNameTypeNames(objname, objargs, false);
155                         address.objectSubId = 0;
156                         break;
157                 case OBJECT_OPERATOR:
158                         Assert(list_length(objargs) == 2);
159                         address.classId = OperatorRelationId;
160                         address.objectId =
161                                 LookupOperNameTypeNames(NULL, objname,
162                                                                                 (TypeName *) linitial(objargs),
163                                                                                 (TypeName *) lsecond(objargs),
164                                                                                 false, -1);
165                         address.objectSubId = 0;
166                         break;
167                 case OBJECT_CONVERSION:
168                         address.classId = ConversionRelationId;
169                         address.objectId = get_conversion_oid(objname, false);
170                         address.objectSubId = 0;
171                         break;
172                 case OBJECT_OPCLASS:
173                 case OBJECT_OPFAMILY:
174                         address = get_object_address_opcf(objtype, objname, objargs);
175                         break;
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))
182                                 ereport(ERROR,
183                                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
184                                                  errmsg("large object %u does not exist",
185                                                                 address.objectId)));
186                         break;
187                 case OBJECT_CAST:
188                         {
189                                 TypeName *sourcetype = (TypeName *) linitial(objname);
190                                 TypeName *targettype = (TypeName *) linitial(objargs);
191                                 Oid sourcetypeid = typenameTypeId(NULL, sourcetype);
192                                 Oid targettypeid = typenameTypeId(NULL, targettype);
193
194                                 address.classId = CastRelationId;
195                                 address.objectId =
196                                         get_cast_oid(sourcetypeid, targettypeid, false);
197                                 address.objectSubId = 0;
198                         }
199                         break;
200                 case OBJECT_TSPARSER:
201                         address.classId = TSParserRelationId;
202                         address.objectId = get_ts_parser_oid(objname, false);
203                         address.objectSubId = 0;
204                         break;
205                 case OBJECT_TSDICTIONARY:
206                         address.classId = TSDictionaryRelationId;
207                         address.objectId = get_ts_dict_oid(objname, false);
208                         address.objectSubId = 0;
209                         break;
210                 case OBJECT_TSTEMPLATE:
211                         address.classId = TSTemplateRelationId;
212                         address.objectId = get_ts_template_oid(objname, false);
213                         address.objectSubId = 0;
214                         break;
215                 case OBJECT_TSCONFIGURATION:
216                         address.classId = TSConfigRelationId;
217                         address.objectId = get_ts_config_oid(objname, false);
218                         address.objectSubId = 0;
219                         break;
220                 default:
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;
226         }
227
228         /*
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.
232          */
233         if (address.classId != RelationRelationId)
234         {
235                 if (IsSharedRelation(address.classId))
236                         LockSharedObject(address.classId, address.objectId, 0, lockmode);
237                 else
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);
243         }
244
245         /* Return the object address and the relation. */
246         *relp = relation;
247         return address;
248 }
249
250 /*
251  * Find an ObjectAddress for a type of object that is identified by an
252  * unqualified name.
253  */
254 static ObjectAddress
255 get_object_address_unqualified(ObjectType objtype, List *qualname)
256 {
257         const char *name;
258         ObjectAddress address;
259
260         /*
261          * The types of names handled by this function are not permitted to be
262          * schema-qualified or catalog-qualified.
263          */
264         if (list_length(qualname) != 1)
265         {
266                 const char *msg;
267
268                 switch (objtype)
269                 {
270                         case OBJECT_DATABASE:
271                                 msg = gettext_noop("database name cannot be qualified");
272                                 break;
273                         case OBJECT_EXTENSION:
274                                 msg = gettext_noop("extension name cannot be qualified");
275                                 break;
276                         case OBJECT_TABLESPACE:
277                                 msg = gettext_noop("tablespace name cannot be qualified");
278                                 break;
279                         case OBJECT_ROLE:
280                                 msg = gettext_noop("role name cannot be qualified");
281                                 break;
282                         case OBJECT_SCHEMA:
283                                 msg = gettext_noop("schema name cannot be qualified");
284                                 break;
285                         case OBJECT_LANGUAGE:
286                                 msg = gettext_noop("language name cannot be qualified");
287                                 break;
288                         default:
289                                 elog(ERROR, "unrecognized objtype: %d", (int) objtype);
290                                 msg = NULL;                     /* placate compiler */
291                 }
292                 ereport(ERROR,
293                                 (errcode(ERRCODE_SYNTAX_ERROR),
294                                  errmsg("%s", _(msg))));
295         }
296
297         /* Format is valid, extract the actual name. */
298         name = strVal(linitial(qualname));
299
300         /* Translate name to OID. */
301         switch (objtype)
302         {
303                 case OBJECT_DATABASE:
304                         address.classId = DatabaseRelationId;
305                         address.objectId = get_database_oid(name, false);
306                         address.objectSubId = 0;
307                         break;
308                 case OBJECT_EXTENSION:
309                         address.classId = ExtensionRelationId;
310                         address.objectId = get_extension_oid(name, false);
311                         address.objectSubId = 0;
312                         break;
313                 case OBJECT_TABLESPACE:
314                         address.classId = TableSpaceRelationId;
315                         address.objectId = get_tablespace_oid(name, false);
316                         address.objectSubId = 0;
317                         break;
318                 case OBJECT_ROLE:
319                         address.classId = AuthIdRelationId;
320                         address.objectId = get_role_oid(name, false);
321                         address.objectSubId = 0;
322                         break;
323                 case OBJECT_SCHEMA:
324                         address.classId = NamespaceRelationId;
325                         address.objectId = get_namespace_oid(name, false);
326                         address.objectSubId = 0;
327                         break;
328                 case OBJECT_LANGUAGE:
329                         address.classId = LanguageRelationId;
330                         address.objectId = get_language_oid(name, false);
331                         address.objectSubId = 0;
332                         break;
333                 default:
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;
339         }
340
341         return address;
342 }
343
344 /*
345  * Locate a relation by qualified name.
346  */
347 static Relation
348 get_relation_by_qualified_name(ObjectType objtype, List *objname,
349                                                            LOCKMODE lockmode)
350 {
351         Relation relation;
352
353         relation = relation_openrv(makeRangeVarFromNameList(objname), lockmode);
354         switch (objtype)
355         {
356                 case OBJECT_INDEX:
357                         if (relation->rd_rel->relkind != RELKIND_INDEX)
358                                 ereport(ERROR,
359                                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
360                                                  errmsg("\"%s\" is not an index",
361                                                                 RelationGetRelationName(relation))));
362                         break;
363                 case OBJECT_SEQUENCE:
364                         if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
365                                 ereport(ERROR,
366                                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
367                                                  errmsg("\"%s\" is not a sequence",
368                                                                 RelationGetRelationName(relation))));
369                         break;
370                 case OBJECT_TABLE:
371                         if (relation->rd_rel->relkind != RELKIND_RELATION)
372                                 ereport(ERROR,
373                                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
374                                                  errmsg("\"%s\" is not a table",
375                                                                 RelationGetRelationName(relation))));
376                         break;
377                 case OBJECT_VIEW:
378                         if (relation->rd_rel->relkind != RELKIND_VIEW)
379                                 ereport(ERROR,
380                                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
381                                                  errmsg("\"%s\" is not a view",
382                                                                 RelationGetRelationName(relation))));
383                         break;
384                 case OBJECT_FOREIGN_TABLE:
385                         if (relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
386                                 ereport(ERROR,
387                                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
388                                                  errmsg("\"%s\" is not a foreign table",
389                                                                 RelationGetRelationName(relation))));
390                         break;
391                 default:
392                         elog(ERROR, "unrecognized objtype: %d", (int) objtype);
393                         break;
394         }
395
396         return relation;
397 }
398
399 /*
400  * Find object address for an object that is attached to a relation.
401  *
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.
405  */
406 static ObjectAddress
407 get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
408 {
409         ObjectAddress address;
410         Relation        relation = NULL;
411         int                     nnames;
412         const char *depname;
413
414         /* Extract name of dependent object. */
415         depname = strVal(lfirst(list_tail(objname)));
416
417         /* Separate relation name from dependent object name. */
418         nnames = list_length(objname);
419         if (nnames < 2)
420         {
421                 Oid             reloid;
422
423                 /*
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
428                  * treatment.
429                  */
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);
436         }
437         else
438         {
439                 List       *relname;
440                 Oid                     reloid;
441
442                 /* Extract relation name and open relation. */
443                 relname = list_truncate(list_copy(objname), nnames - 1);
444                 relation = heap_openrv(makeRangeVarFromNameList(relname),
445                                                            AccessShareLock);
446                 reloid = RelationGetRelid(relation);
447
448                 switch (objtype)
449                 {
450                         case OBJECT_RULE:
451                                 address.classId = RewriteRelationId;
452                                 address.objectId = get_rewrite_oid(reloid, depname, false);
453                                 address.objectSubId = 0;
454                                 break;
455                         case OBJECT_TRIGGER:
456                                 address.classId = TriggerRelationId;
457                                 address.objectId = get_trigger_oid(reloid, depname, false);
458                                 address.objectSubId = 0;
459                                 break;
460                         case OBJECT_CONSTRAINT:
461                                 address.classId = ConstraintRelationId;
462                                 address.objectId = get_constraint_oid(reloid, depname, false);
463                                 address.objectSubId = 0;
464                                 break;
465                         default:
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;
471                 }
472         }
473
474         /* Done. */
475         *relp = relation;
476         return address;
477 }
478
479 /*
480  * Find the ObjectAddress for an attribute.
481  */
482 static ObjectAddress
483 get_object_address_attribute(ObjectType objtype, List *objname,
484                                                          Relation *relp, LOCKMODE lockmode)
485 {
486         ObjectAddress   address;
487         List       *relname;
488         Oid                     reloid;
489         Relation        relation;
490         const char *attname;
491
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);
497
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)
503                 ereport(ERROR,
504                                 (errcode(ERRCODE_UNDEFINED_COLUMN),
505                                  errmsg("column \"%s\" of relation \"%s\" does not exist",
506                                  attname, RelationGetRelationName(relation))));
507
508         *relp = relation;
509         return address;
510 }
511
512 /*
513  * Find the ObjectAddress for an opclass or opfamily.
514  */
515 static ObjectAddress
516 get_object_address_opcf(ObjectType objtype, List *objname, List *objargs)
517 {
518         Oid                     amoid;
519         ObjectAddress address;
520
521         Assert(list_length(objargs) == 1);
522         amoid = get_am_oid(strVal(linitial(objargs)), false);
523
524         switch (objtype)
525         {
526                 case OBJECT_OPCLASS:
527                         address.classId = OperatorClassRelationId;
528                         address.objectId = get_opclass_oid(amoid, objname, false);
529                         address.objectSubId = 0;
530                         break;
531                 case OBJECT_OPFAMILY:
532                         address.classId = OperatorFamilyRelationId;
533                         address.objectId = get_opfamily_oid(amoid, objname, false);
534                         address.objectSubId = 0;
535                         break;
536                 default:
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;
542         }
543
544         return address;
545 }
546
547 /*
548  * Test whether an object exists.
549  */
550 static bool
551 object_exists(ObjectAddress address)
552 {
553         int                     cache = -1;
554         Oid                     indexoid = InvalidOid;
555         Relation        rel;
556         ScanKeyData     skey[1];
557         SysScanDesc     sd;
558         bool            found;
559
560         /* Sub-objects require special treatment. */
561         if (address.objectSubId != 0)
562         {
563                 HeapTuple       atttup;
564
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))
570                         found = false;
571                 else
572                 {
573                         found = ((Form_pg_attribute) GETSTRUCT(atttup))->attisdropped;
574                         ReleaseSysCache(atttup);
575                 }
576                 return found;
577         }
578
579         /*
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.
584          */
585         switch (address.classId)
586         {
587                 case RelationRelationId:
588                         cache = RELOID;
589                         break;
590                 case RewriteRelationId:
591                         indexoid = RewriteOidIndexId;
592                         break;
593                 case TriggerRelationId:
594                         indexoid = TriggerOidIndexId;
595                         break;
596                 case ConstraintRelationId:
597                         cache = CONSTROID;
598                         break;
599                 case DatabaseRelationId:
600                         cache = DATABASEOID;
601                         break;
602                 case TableSpaceRelationId:
603                         cache = TABLESPACEOID;
604                         break;
605                 case AuthIdRelationId:
606                         cache = AUTHOID;
607                         break;
608                 case NamespaceRelationId:
609                         cache = NAMESPACEOID;
610                         break;
611                 case LanguageRelationId:
612                         cache = LANGOID;
613                         break;
614                 case TypeRelationId:
615                         cache = TYPEOID;
616                         break;
617                 case ProcedureRelationId:
618                         cache = PROCOID;
619                         break;
620                 case OperatorRelationId:
621                         cache = OPEROID;
622                         break;
623                 case ConversionRelationId:
624                         cache = CONVOID;
625                         break;
626                 case OperatorClassRelationId:
627                         cache = CLAOID;
628                         break;
629                 case OperatorFamilyRelationId:
630                         cache = OPFAMILYOID;
631                         break;
632                 case LargeObjectRelationId:
633                         /*
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.
638                          */
639                         address.classId = LargeObjectMetadataRelationId;
640                         indexoid = LargeObjectMetadataOidIndexId;
641                         break;
642                 case CastRelationId:
643                         indexoid = CastOidIndexId;
644                         break;
645                 case TSParserRelationId:
646                         cache = TSPARSEROID;
647                         break;
648                 case TSDictionaryRelationId:
649                         cache = TSDICTOID;
650                         break;
651                 case TSTemplateRelationId:
652                         cache = TSTEMPLATEOID;
653                         break;
654                 case TSConfigRelationId:
655                         cache = TSCONFIGOID;
656                         break;
657                 case ExtensionRelationId:
658                         indexoid = ExtensionOidIndexId;
659                         break;
660                 default:
661                         elog(ERROR, "unrecognized classid: %u", address.classId);
662         }
663
664         /* Found a syscache? */
665         if (cache != -1)
666                 return SearchSysCacheExists1(cache, ObjectIdGetDatum(address.objectId));
667
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);
679         return found;
680 }