#include "parser/parse_type.h"
 #include "rewrite/rewriteSupport.h"
 #include "storage/lmgr.h"
+#include "storage/sinval.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
                        List *objname, bool missing_ok);
 static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname,
                        List *objargs, bool missing_ok);
-static bool object_exists(ObjectAddress address);
 static ObjectPropertyType *get_object_property_data(Oid class_id);
 
 /*
                   Relation *relp, LOCKMODE lockmode, bool missing_ok)
 {
    ObjectAddress address;
+   ObjectAddress old_address = {InvalidOid, InvalidOid, 0};
    Relation    relation = NULL;
+   uint64      inval_count;
 
    /* Some kind of lock must be taken. */
    Assert(lockmode != NoLock);
 
-   switch (objtype)
+   for (;;)
    {
-       case OBJECT_INDEX:
-       case OBJECT_SEQUENCE:
-       case OBJECT_TABLE:
-       case OBJECT_VIEW:
-       case OBJECT_FOREIGN_TABLE:
-           address =
-               get_relation_by_qualified_name(objtype, objname,
-                                              &relation, lockmode,
-                                              missing_ok);
-           break;
-       case OBJECT_COLUMN:
-           address =
-               get_object_address_attribute(objtype, objname,
-                                            &relation, lockmode,
-                                            missing_ok);
-           break;
-       case OBJECT_RULE:
-       case OBJECT_TRIGGER:
-       case OBJECT_CONSTRAINT:
-           address = get_object_address_relobject(objtype, objname,
-                                                  &relation, missing_ok);
-           break;
-       case OBJECT_DATABASE:
-       case OBJECT_EXTENSION:
-       case OBJECT_TABLESPACE:
-       case OBJECT_ROLE:
-       case OBJECT_SCHEMA:
-       case OBJECT_LANGUAGE:
-       case OBJECT_FDW:
-       case OBJECT_FOREIGN_SERVER:
-           address = get_object_address_unqualified(objtype,
-                                                    objname, missing_ok);
-           break;
-       case OBJECT_TYPE:
-       case OBJECT_DOMAIN:
-           address = get_object_address_type(objtype, objname, missing_ok);
-           break;
-       case OBJECT_AGGREGATE:
-           address.classId = ProcedureRelationId;
-           address.objectId =
-               LookupAggNameTypeNames(objname, objargs, missing_ok);
-           address.objectSubId = 0;
-           break;
-       case OBJECT_FUNCTION:
-           address.classId = ProcedureRelationId;
-           address.objectId =
-               LookupFuncNameTypeNames(objname, objargs, missing_ok);
-           address.objectSubId = 0;
-           break;
-       case OBJECT_OPERATOR:
-           Assert(list_length(objargs) == 2);
-           address.classId = OperatorRelationId;
-           address.objectId =
-               LookupOperNameTypeNames(NULL, objname,
-                                       (TypeName *) linitial(objargs),
-                                       (TypeName *) lsecond(objargs),
-                                       missing_ok, -1);
-           address.objectSubId = 0;
-           break;
-       case OBJECT_COLLATION:
-           address.classId = CollationRelationId;
-           address.objectId = get_collation_oid(objname, missing_ok);
-           address.objectSubId = 0;
-           break;
-       case OBJECT_CONVERSION:
-           address.classId = ConversionRelationId;
-           address.objectId = get_conversion_oid(objname, missing_ok);
-           address.objectSubId = 0;
-           break;
-       case OBJECT_OPCLASS:
-       case OBJECT_OPFAMILY:
-           address = get_object_address_opcf(objtype,
-                                             objname, objargs, missing_ok);
-           break;
-       case OBJECT_LARGEOBJECT:
-           Assert(list_length(objname) == 1);
-           address.classId = LargeObjectRelationId;
-           address.objectId = oidparse(linitial(objname));
-           address.objectSubId = 0;
-           if (!LargeObjectExists(address.objectId))
-           {
-               if (!missing_ok)
-               ereport(ERROR,
-                       (errcode(ERRCODE_UNDEFINED_OBJECT),
-                        errmsg("large object %u does not exist",
-                               address.objectId)));
-           }
-           break;
-       case OBJECT_CAST:
-           {
-               TypeName   *sourcetype = (TypeName *) linitial(objname);
-               TypeName   *targettype = (TypeName *) linitial(objargs);
-               Oid         sourcetypeid = typenameTypeId(NULL, sourcetype);
-               Oid         targettypeid = typenameTypeId(NULL, targettype);
+       /*
+        * Remember this value, so that, after looking up the object name
+        * and locking it, we can check whether any invalidation messages
+        * have been processed that might require a do-over.
+        */
+       inval_count = SharedInvalidMessageCounter;
 
-               address.classId = CastRelationId;
+       /* Look up object address. */   
+       switch (objtype)
+       {
+           case OBJECT_INDEX:
+           case OBJECT_SEQUENCE:
+           case OBJECT_TABLE:
+           case OBJECT_VIEW:
+           case OBJECT_FOREIGN_TABLE:
+               address =
+                   get_relation_by_qualified_name(objtype, objname,
+                                                  &relation, lockmode,
+                                                  missing_ok);
+               break;
+           case OBJECT_COLUMN:
+               address =
+                   get_object_address_attribute(objtype, objname,
+                                                &relation, lockmode,
+                                                missing_ok);
+               break;
+           case OBJECT_RULE:
+           case OBJECT_TRIGGER:
+           case OBJECT_CONSTRAINT:
+               address = get_object_address_relobject(objtype, objname,
+                                                      &relation, missing_ok);
+               break;
+           case OBJECT_DATABASE:
+           case OBJECT_EXTENSION:
+           case OBJECT_TABLESPACE:
+           case OBJECT_ROLE:
+           case OBJECT_SCHEMA:
+           case OBJECT_LANGUAGE:
+           case OBJECT_FDW:
+           case OBJECT_FOREIGN_SERVER:
+               address = get_object_address_unqualified(objtype,
+                                                        objname, missing_ok);
+               break;
+           case OBJECT_TYPE:
+           case OBJECT_DOMAIN:
+               address = get_object_address_type(objtype, objname, missing_ok);
+               break;
+           case OBJECT_AGGREGATE:
+               address.classId = ProcedureRelationId;
+               address.objectId =
+                   LookupAggNameTypeNames(objname, objargs, missing_ok);
+               address.objectSubId = 0;
+               break;
+           case OBJECT_FUNCTION:
+               address.classId = ProcedureRelationId;
+               address.objectId =
+                   LookupFuncNameTypeNames(objname, objargs, missing_ok);
+               address.objectSubId = 0;
+               break;
+           case OBJECT_OPERATOR:
+               Assert(list_length(objargs) == 2);
+               address.classId = OperatorRelationId;
                address.objectId =
-                   get_cast_oid(sourcetypeid, targettypeid, missing_ok);
+                   LookupOperNameTypeNames(NULL, objname,
+                                           (TypeName *) linitial(objargs),
+                                           (TypeName *) lsecond(objargs),
+                                           missing_ok, -1);
                address.objectSubId = 0;
+               break;
+           case OBJECT_COLLATION:
+               address.classId = CollationRelationId;
+               address.objectId = get_collation_oid(objname, missing_ok);
+               address.objectSubId = 0;
+               break;
+           case OBJECT_CONVERSION:
+               address.classId = ConversionRelationId;
+               address.objectId = get_conversion_oid(objname, missing_ok);
+               address.objectSubId = 0;
+               break;
+           case OBJECT_OPCLASS:
+           case OBJECT_OPFAMILY:
+               address = get_object_address_opcf(objtype,
+                                                 objname, objargs, missing_ok);
+               break;
+           case OBJECT_LARGEOBJECT:
+               Assert(list_length(objname) == 1);
+               address.classId = LargeObjectRelationId;
+               address.objectId = oidparse(linitial(objname));
+               address.objectSubId = 0;
+               if (!LargeObjectExists(address.objectId))
+               {
+                   if (!missing_ok)
+                   ereport(ERROR,
+                           (errcode(ERRCODE_UNDEFINED_OBJECT),
+                            errmsg("large object %u does not exist",
+                                   address.objectId)));
+               }
+               break;
+           case OBJECT_CAST:
+               {
+                   TypeName   *sourcetype = (TypeName *) linitial(objname);
+                   TypeName   *targettype = (TypeName *) linitial(objargs);
+                   Oid         sourcetypeid = typenameTypeId(NULL, sourcetype);
+                   Oid         targettypeid = typenameTypeId(NULL, targettype);
+
+                   address.classId = CastRelationId;
+                   address.objectId =
+                       get_cast_oid(sourcetypeid, targettypeid, missing_ok);
+                   address.objectSubId = 0;
+               }
+               break;
+           case OBJECT_TSPARSER:
+               address.classId = TSParserRelationId;
+               address.objectId = get_ts_parser_oid(objname, missing_ok);
+               address.objectSubId = 0;
+               break;
+           case OBJECT_TSDICTIONARY:
+               address.classId = TSDictionaryRelationId;
+               address.objectId = get_ts_dict_oid(objname, missing_ok);
+               address.objectSubId = 0;
+               break;
+           case OBJECT_TSTEMPLATE:
+               address.classId = TSTemplateRelationId;
+               address.objectId = get_ts_template_oid(objname, missing_ok);
+               address.objectSubId = 0;
+               break;
+           case OBJECT_TSCONFIGURATION:
+               address.classId = TSConfigRelationId;
+               address.objectId = get_ts_config_oid(objname, missing_ok);
+               address.objectSubId = 0;
+               break;
+           default:
+               elog(ERROR, "unrecognized objtype: %d", (int) objtype);
+               /* placate compiler, in case it thinks elog might return */
+               address.classId = InvalidOid;
+               address.objectId = InvalidOid;
+               address.objectSubId = 0;
+       }
+
+       /*
+        * If we could not find the supplied object, return without locking.
+        */
+       if (!OidIsValid(address.objectId))
+       {
+           Assert(missing_ok);
+           return address;
+       }
+
+       /*
+        * If we're retrying, see if we got the same answer as last time.  If
+        * so, we're done; if not, we locked the wrong thing, so give up our
+        * lock.
+        */
+       if (OidIsValid(old_address.classId))
+       {
+           if (old_address.classId == address.classId
+               && old_address.objectId == address.objectId
+               && old_address.objectSubId == address.objectSubId)
+               break;
+           if (old_address.classId != RelationRelationId)
+           {
+               if (IsSharedRelation(old_address.classId))
+                   UnlockSharedObject(old_address.classId,
+                                      old_address.objectId,
+                                      0, lockmode);
+               else
+                   UnlockDatabaseObject(old_address.classId,
+                                        old_address.objectId,
+                                        0, lockmode);
            }
-           break;
-       case OBJECT_TSPARSER:
-           address.classId = TSParserRelationId;
-           address.objectId = get_ts_parser_oid(objname, missing_ok);
-           address.objectSubId = 0;
-           break;
-       case OBJECT_TSDICTIONARY:
-           address.classId = TSDictionaryRelationId;
-           address.objectId = get_ts_dict_oid(objname, missing_ok);
-           address.objectSubId = 0;
-           break;
-       case OBJECT_TSTEMPLATE:
-           address.classId = TSTemplateRelationId;
-           address.objectId = get_ts_template_oid(objname, missing_ok);
-           address.objectSubId = 0;
-           break;
-       case OBJECT_TSCONFIGURATION:
-           address.classId = TSConfigRelationId;
-           address.objectId = get_ts_config_oid(objname, missing_ok);
-           address.objectSubId = 0;
-           break;
-       default:
-           elog(ERROR, "unrecognized objtype: %d", (int) objtype);
-           /* placate compiler, in case it thinks elog might return */
-           address.classId = InvalidOid;
-           address.objectId = InvalidOid;
-           address.objectSubId = 0;
-   }
+       }
 
-   /*
-    * If we could not find the supplied object, return without locking.
-    */
-   if (!OidIsValid(address.objectId))
-   {
-       Assert(missing_ok);
-       return address;
-   }
+       /*
+        * If we're dealing with a relation or attribute, then the relation is
+        * already locked.  Otherwise, we lock it now.
+        */
+       if (address.classId != RelationRelationId)
+       {
+           if (IsSharedRelation(address.classId))
+               LockSharedObject(address.classId, address.objectId, 0,
+                                lockmode);
+           else
+               LockDatabaseObject(address.classId, address.objectId, 0,
+                                  lockmode);
+       }
 
-   /*
-    * If we're dealing with a relation or attribute, then the relation is
-    * already locked.  If we're dealing with any other type of object, we
-    * need to lock it and then verify that it still exists.
-    */
-   if (address.classId != RelationRelationId)
-   {
-       if (IsSharedRelation(address.classId))
-           LockSharedObject(address.classId, address.objectId, 0, lockmode);
-       else
-           LockDatabaseObject(address.classId, address.objectId, 0, lockmode);
-       /* Did it go away while we were waiting for the lock? */
-       if (!object_exists(address))
-           elog(ERROR, "cache lookup failed for class %u object %u subobj %d",
-                address.classId, address.objectId, address.objectSubId);
+       /*
+        * At this point, we've resolved the name to an OID and locked the
+        * corresponding database object.  However, it's possible that by the
+        * time we acquire the lock on the object, concurrent DDL has modified
+        * the database in such a way that the name we originally looked up
+        * no longer resolves to that OID.
+        *
+        * We can be certain that this isn't an issue if (a) no shared
+        * invalidation messages have been processed or (b) we've locked a
+        * relation somewhere along the line.  All the relation name lookups
+        * in this module ultimately use RangeVarGetRelid() to acquire a
+        * relation lock, and that function protects against the same kinds of
+        * races we're worried about here.  Even when operating on a
+        * constraint, rule, or trigger, we still acquire AccessShareLock on
+        * the relation, which is enough to freeze out any concurrent DDL.
+        *
+        * In all other cases, however, it's possible that the name we looked
+        * up no longer refers to the object we locked, so we retry the
+        * lookup and see whether we get the same answer.
+        */
+        if (inval_count == SharedInvalidMessageCounter || relation != NULL)
+            break;
+        old_address = address;
    }
 
    /* Return the object address and the relation. */
    return address;
 }
 
-/*
- * Test whether an object exists.
- */
-static bool
-object_exists(ObjectAddress address)
-{
-   int         cache = -1;
-   Oid         indexoid = InvalidOid;
-   Relation    rel;
-   ScanKeyData skey[1];
-   SysScanDesc sd;
-   bool        found;
-   ObjectPropertyType     *property;
-
-   /* Sub-objects require special treatment. */
-   if (address.objectSubId != 0)
-   {
-       HeapTuple   atttup;
-
-       /* Currently, attributes are the only sub-objects. */
-       Assert(address.classId == RelationRelationId);
-       atttup = SearchSysCache2(ATTNUM, ObjectIdGetDatum(address.objectId),
-                                Int16GetDatum(address.objectSubId));
-       if (!HeapTupleIsValid(atttup))
-           found = false;
-       else
-       {
-           found = ((Form_pg_attribute) GETSTRUCT(atttup))->attisdropped;
-           ReleaseSysCache(atttup);
-       }
-       return found;
-   }
-
-   /*
-    * Weird backward compatibility hack: ObjectAddress notation uses
-    * LargeObjectRelationId for large objects, but since PostgreSQL
-    * 9.0, the relevant catalog is actually LargeObjectMetadataRelationId.
-    */
-   if (address.classId == LargeObjectRelationId)
-       address.classId = LargeObjectMetadataRelationId;
-
-   /*
-    * For object types that have a relevant syscache, we use it; for
-    * everything else, we'll have to do an index-scan.
-    */
-   property = get_object_property_data(address.classId);
-   cache = property->oid_catcache_id;
-   indexoid = property->oid_index_oid;
-
-   /* Found a syscache? */
-   if (cache != -1)
-       return SearchSysCacheExists1(cache, ObjectIdGetDatum(address.objectId));
-
-   /* No syscache, so examine the table directly. */
-   Assert(OidIsValid(indexoid));
-   ScanKeyInit(&skey[0],
-               ObjectIdAttributeNumber,
-               BTEqualStrategyNumber, F_OIDEQ,
-               ObjectIdGetDatum(address.objectId));
-   rel = heap_open(address.classId, AccessShareLock);
-   sd = systable_beginscan(rel, indexoid, true, SnapshotNow, 1, skey);
-   found = HeapTupleIsValid(systable_getnext(sd));
-   systable_endscan(sd);
-   heap_close(rel, AccessShareLock);
-   return found;
-}
-
 /*
  * Check ownership of an object previously identified by get_object_address.
  */