+ /*
+ * Remember this value, so that, after looking up the relation name
+ * and locking its OID, we can check whether any invalidation messages
+ * have been processed that might require a do-over.
+ */
+ inval_count = SharedInvalidMessageCounter;
+
+ /*
+ * Some non-default relpersistence value may have been specified. The
+ * parser never generates such a RangeVar in simple DML, but it can
+ * happen in contexts such as "CREATE TEMP TABLE foo (f1 int PRIMARY
+ * KEY)". Such a command will generate an added CREATE INDEX
+ * operation, which must be careful to find the temp table, even when
+ * pg_temp is not first in the search path.
+ */
+ if (relation->relpersistence == RELPERSISTENCE_TEMP)
+ {
+ if (!OidIsValid(myTempNamespace))
+ relId = InvalidOid; /* this probably can't happen? */
+ else
+ {
+ if (relation->schemaname)
+ {
+ Oid namespaceId;
+
+ namespaceId = LookupExplicitNamespace(relation->schemaname, missing_ok);
+
+ /*
+ * For missing_ok, allow a non-existant schema name to
+ * return InvalidOid.
+ */
+ if (namespaceId != myTempNamespace)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ errmsg("temporary tables cannot specify a schema name")));
+ }
+
+ relId = get_relname_relid(relation->relname, myTempNamespace);
+ }
+ }
+ else if (relation->schemaname)
+ {
+ Oid namespaceId;
+
+ /* use exact schema given */
+ namespaceId = LookupExplicitNamespace(relation->schemaname, missing_ok);
+ if (missing_ok && !OidIsValid(namespaceId))
+ relId = InvalidOid;
+ else
+ relId = get_relname_relid(relation->relname, namespaceId);
+ }
+ else
+ {
+ /* search the namespace path */
+ relId = RelnameGetRelid(relation->relname);
+ }
+
+ /*
+ * Invoke caller-supplied callback, if any.
+ *
+ * This callback is a good place to check permissions: we haven't
+ * taken the table lock yet (and it's really best to check permissions
+ * before locking anything!), but we've gotten far enough to know what
+ * OID we think we should lock. Of course, concurrent DDL might
+ * change things while we're waiting for the lock, but in that case
+ * the callback will be invoked again for the new OID.
+ */
+ if (callback)
+ callback(relation, relId, oldRelId, callback_arg);
+
+ /*
+ * If no lock requested, we assume the caller knows what they're
+ * doing. They should have already acquired a heavyweight lock on
+ * this relation earlier in the processing of this same statement, so
+ * it wouldn't be appropriate to AcceptInvalidationMessages() here, as
+ * that might pull the rug out from under them.
+ */
+ if (lockmode == NoLock)
+ break;
+
+ /*
+ * If, upon retry, we get back the same OID we did last time, then the
+ * invalidation messages we processed did not change the final answer.
+ * So we're done.
+ *
+ * If we got a different OID, we've locked the relation that used to
+ * have this name rather than the one that does now. So release the
+ * lock.
+ */
+ if (retry)
+ {
+ if (relId == oldRelId)
+ break;
+ if (OidIsValid(oldRelId))
+ UnlockRelationOid(oldRelId, lockmode);
+ }
+
+ /*
+ * Lock relation. This will also accept any pending invalidation
+ * messages. If we got back InvalidOid, indicating not found, then
+ * there's nothing to lock, but we accept invalidation messages
+ * anyway, to flush any negative catcache entries that may be
+ * lingering.
+ */
+ if (!OidIsValid(relId))
+ AcceptInvalidationMessages();
+ else if (!nowait)
+ LockRelationOid(relId, lockmode);
+ else if (!ConditionalLockRelationOid(relId, lockmode))
+ {
+ if (relation->schemaname)
+ ereport(ERROR,
+ (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+ errmsg("could not obtain lock on relation \"%s.%s\"",
+ relation->schemaname, relation->relname)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+ errmsg("could not obtain lock on relation \"%s\"",
+ relation->relname)));
+ }
+
+ /*
+ * If no invalidation message were processed, we're done!
+ */
+ if (inval_count == SharedInvalidMessageCounter)
+ break;
+
+ /*
+ * Something may have changed. Let's repeat the name lookup, to make
+ * sure this name still references the same relation it did
+ * previously.
+ */
+ retry = true;
+ oldRelId = relId;