[v9.2] DROP Reworks Part.0 - 'missing_ok' support of get_object_address

Started by Kohei KaiGaiover 14 years ago18 messages
#1Kohei KaiGai
kaigai@kaigai.gr.jp
1 attachment(s)

The attached patch is a preparation to rework implementation of DROP statement
using a common code. That intends to apply get_object_address() to resolve name
of objects to be removed, and eventually minimizes the number of places to put
permission checks.

Its first step is an enhancement of get_object_address; to accept 'missing_ok'
argument to handle cases when IF EXISTS clause is supplied.
If 'missing_ok' was true and the supplied name was not found, the patched
get_object_address() returns an ObjectAddress with InvalidOid as objectId.
If 'missing_ok' was false, its behavior is not changed.

Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>

Attachments:

pgsql-v9.2-drop-reworks-part-0.1.patchapplication/octet-stream; name=pgsql-v9.2-drop-reworks-part-0.1.patchDownload
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index bf25091..cb5ced4 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -72,15 +72,19 @@
 #include "utils/tqual.h"
 
 static ObjectAddress get_object_address_unqualified(ObjectType objtype,
-							   List *qualname);
-static Relation get_relation_by_qualified_name(ObjectType objtype,
-							   List *objname, LOCKMODE lockmode);
+							   List *qualname, bool missing_ok);
+static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
+							   List *objname, bool missing_ok,
+							   Relation *relp, LOCKMODE lockmode);
 static ObjectAddress get_object_address_relobject(ObjectType objtype,
-							 List *objname, Relation *relp);
+						   List *objname, bool missing_ok, Relation *relp);
 static ObjectAddress get_object_address_attribute(ObjectType objtype,
-						   List *objname, Relation *relp, LOCKMODE lockmode);
+						   List *objname, bool missing_ok,
+						   Relation *relp, LOCKMODE lockmode);
+static ObjectAddress get_object_address_typeobj(ObjectType objtype,
+						   List *objname, bool missing_ok);
 static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname,
-						List *objargs);
+						   List *objargs, bool missing_ok);
 static bool object_exists(ObjectAddress address);
 
 
@@ -106,7 +110,7 @@ static bool object_exists(ObjectAddress address);
  */
 ObjectAddress
 get_object_address(ObjectType objtype, List *objname, List *objargs,
-				   Relation *relp, LOCKMODE lockmode)
+				   bool missing_ok, Relation *relp, LOCKMODE lockmode)
 {
 	ObjectAddress address;
 	Relation	relation = NULL;
@@ -121,21 +125,20 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 		case OBJECT_TABLE:
 		case OBJECT_VIEW:
 		case OBJECT_FOREIGN_TABLE:
-			relation =
-				get_relation_by_qualified_name(objtype, objname, lockmode);
-			address.classId = RelationRelationId;
-			address.objectId = RelationGetRelid(relation);
-			address.objectSubId = 0;
+			address =
+				get_relation_by_qualified_name(objtype, objname, missing_ok,
+											   &relation, lockmode);
 			break;
 		case OBJECT_COLUMN:
 			address =
-				get_object_address_attribute(objtype, objname, &relation,
-											 lockmode);
+				get_object_address_attribute(objtype, objname, missing_ok,
+											 &relation, lockmode);
 			break;
 		case OBJECT_RULE:
 		case OBJECT_TRIGGER:
 		case OBJECT_CONSTRAINT:
-			address = get_object_address_relobject(objtype, objname, &relation);
+			address = get_object_address_relobject(objtype, objname,
+												   missing_ok, &relation);
 			break;
 		case OBJECT_DATABASE:
 		case OBJECT_EXTENSION:
@@ -145,23 +148,23 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 		case OBJECT_LANGUAGE:
 		case OBJECT_FDW:
 		case OBJECT_FOREIGN_SERVER:
-			address = get_object_address_unqualified(objtype, objname);
+			address = get_object_address_unqualified(objtype,
+													 objname, missing_ok);
 			break;
 		case OBJECT_TYPE:
 		case OBJECT_DOMAIN:
-			address.classId = TypeRelationId;
-			address.objectId =
-				typenameTypeId(NULL, makeTypeNameFromNameList(objname));
-			address.objectSubId = 0;
+			address = get_object_address_typeobj(objtype, objname, missing_ok);
 			break;
 		case OBJECT_AGGREGATE:
 			address.classId = ProcedureRelationId;
-			address.objectId = LookupAggNameTypeNames(objname, objargs, false);
+			address.objectId =
+				LookupAggNameTypeNames(objname, objargs, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_FUNCTION:
 			address.classId = ProcedureRelationId;
-			address.objectId = LookupFuncNameTypeNames(objname, objargs, false);
+			address.objectId =
+				LookupFuncNameTypeNames(objname, objargs, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_OPERATOR:
@@ -171,22 +174,23 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 				LookupOperNameTypeNames(NULL, objname,
 										(TypeName *) linitial(objargs),
 										(TypeName *) lsecond(objargs),
-										false, -1);
+										missing_ok, -1);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_COLLATION:
 			address.classId = CollationRelationId;
-			address.objectId = get_collation_oid(objname, false);
+			address.objectId = get_collation_oid(objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_CONVERSION:
 			address.classId = ConversionRelationId;
-			address.objectId = get_conversion_oid(objname, false);
+			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);
+			address = get_object_address_opcf(objtype,
+											  objname, objargs, missing_ok);
 			break;
 		case OBJECT_LARGEOBJECT:
 			Assert(list_length(objname) == 1);
@@ -194,10 +198,13 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 			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:
 			{
@@ -208,28 +215,28 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 
 				address.classId = CastRelationId;
 				address.objectId =
-					get_cast_oid(sourcetypeid, targettypeid, false);
+					get_cast_oid(sourcetypeid, targettypeid, missing_ok);
 				address.objectSubId = 0;
 			}
 			break;
 		case OBJECT_TSPARSER:
 			address.classId = TSParserRelationId;
-			address.objectId = get_ts_parser_oid(objname, false);
+			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, false);
+			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, false);
+			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, false);
+			address.objectId = get_ts_config_oid(objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		default:
@@ -241,6 +248,15 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 	}
 
 	/*
+	 * 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.	If we're dealing with any other type of object, we
 	 * need to lock it and then verify that it still exists.
@@ -267,7 +283,8 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
  * unqualified name.
  */
 static ObjectAddress
-get_object_address_unqualified(ObjectType objtype, List *qualname)
+get_object_address_unqualified(ObjectType objtype,
+							   List *qualname, bool missing_ok)
 {
 	const char *name;
 	ObjectAddress address;
@@ -323,42 +340,42 @@ get_object_address_unqualified(ObjectType objtype, List *qualname)
 	{
 		case OBJECT_DATABASE:
 			address.classId = DatabaseRelationId;
-			address.objectId = get_database_oid(name, false);
+			address.objectId = get_database_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_EXTENSION:
 			address.classId = ExtensionRelationId;
-			address.objectId = get_extension_oid(name, false);
+			address.objectId = get_extension_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_TABLESPACE:
 			address.classId = TableSpaceRelationId;
-			address.objectId = get_tablespace_oid(name, false);
+			address.objectId = get_tablespace_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_ROLE:
 			address.classId = AuthIdRelationId;
-			address.objectId = get_role_oid(name, false);
+			address.objectId = get_role_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_SCHEMA:
 			address.classId = NamespaceRelationId;
-			address.objectId = get_namespace_oid(name, false);
+			address.objectId = get_namespace_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_LANGUAGE:
 			address.classId = LanguageRelationId;
-			address.objectId = get_language_oid(name, false);
+			address.objectId = get_language_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_FDW:
 			address.classId = ForeignDataWrapperRelationId;
-			address.objectId = get_foreign_data_wrapper_oid(name, false);
+			address.objectId = get_foreign_data_wrapper_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_FOREIGN_SERVER:
 			address.classId = ForeignServerRelationId;
-			address.objectId = get_foreign_server_oid(name, false);
+			address.objectId = get_foreign_server_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		default:
@@ -375,13 +392,71 @@ get_object_address_unqualified(ObjectType objtype, List *qualname)
 /*
  * Locate a relation by qualified name.
  */
-static Relation
+static ObjectAddress
 get_relation_by_qualified_name(ObjectType objtype, List *objname,
-							   LOCKMODE lockmode)
+							   bool missing_ok,
+                               Relation *relp, LOCKMODE lockmode)
 {
+	ObjectAddress	address;
+	RangeVar   *range;
 	Relation	relation;
 
-	relation = relation_openrv(makeRangeVarFromNameList(objname), lockmode);
+	range = makeRangeVarFromNameList(objname);
+
+	address.classId = RelationRelationId;
+	address.objectId = RangeVarGetRelid(range, true);
+	address.objectSubId = 0;
+
+	/*
+	 * Because RangeVarGetRelid() cannot generate an error message
+	 * according to ObjectType, so we shall raise an error message
+	 * here.
+	 */
+	if (!OidIsValid(address.objectId))
+	{
+		if (!missing_ok)
+		{
+			switch (objtype)
+			{
+				case OBJECT_INDEX:
+					ereport(ERROR,
+							(errcode(ERRCODE_UNDEFINED_TABLE),
+							 errmsg("index \"%s\" does not exist",
+									NameListToString(objname))));
+					break;
+				case OBJECT_SEQUENCE:
+					ereport(ERROR,
+							(errcode(ERRCODE_UNDEFINED_TABLE),
+							 errmsg("sequence \"%s\" does not exist",
+									NameListToString(objname))));
+					break;
+				case OBJECT_TABLE:
+					ereport(ERROR,
+							(errcode(ERRCODE_UNDEFINED_TABLE),
+							 errmsg("table \"%s\" does not exist",
+									NameListToString(objname))));
+					break;
+				case OBJECT_VIEW:
+					ereport(ERROR,
+							(errcode(ERRCODE_UNDEFINED_TABLE),
+							 errmsg("view \"%s\" does not exist",
+									NameListToString(objname))));
+					break;
+				case OBJECT_FOREIGN_TABLE:
+					ereport(ERROR,
+							(errcode(ERRCODE_UNDEFINED_TABLE),
+							 errmsg("foreign table \"%s\" does not exist",
+									NameListToString(objname))));
+					break;
+				default:
+					elog(ERROR, "unrecognized objtype: %d", (int) objtype);
+					break;
+			}
+		}
+		return address;
+	}
+
+	relation = relation_open(address.objectId, lockmode);
 	switch (objtype)
 	{
 		case OBJECT_INDEX:
@@ -424,7 +499,10 @@ get_relation_by_qualified_name(ObjectType objtype, List *objname,
 			break;
 	}
 
-	return relation;
+	/* Done */
+	*relp = relation;
+
+	return address;
 }
 
 /*
@@ -435,10 +513,11 @@ get_relation_by_qualified_name(ObjectType objtype, List *objname,
  * mode for the object itself, not the relation to which it is attached.
  */
 static ObjectAddress
-get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
+get_object_address_relobject(ObjectType objtype, List *objname,
+							 bool missing_ok, Relation *relp)
 {
 	ObjectAddress address;
-	Relation	relation = NULL;
+	Oid			reloid;
 	int			nnames;
 	const char *depname;
 
@@ -449,8 +528,6 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
 	nnames = list_length(objname);
 	if (nnames < 2)
 	{
-		Oid			reloid;
-
 		/*
 		 * For compatibility with very old releases, we sometimes allow users
 		 * to attempt to specify a rule without mentioning the relation name.
@@ -461,36 +538,36 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
 		if (objtype != OBJECT_RULE)
 			elog(ERROR, "must specify relation and object name");
 		address.classId = RewriteRelationId;
-		address.objectId = get_rewrite_oid_without_relid(depname, &reloid);
+		address.objectId =
+			get_rewrite_oid_without_relid(depname, &reloid, missing_ok);
 		address.objectSubId = 0;
-		relation = heap_open(reloid, AccessShareLock);
 	}
 	else
 	{
 		List	   *relname;
-		Oid			reloid;
+		RangeVar   *range;
 
 		/* Extract relation name and open relation. */
 		relname = list_truncate(list_copy(objname), nnames - 1);
-		relation = heap_openrv(makeRangeVarFromNameList(relname),
-							   AccessShareLock);
-		reloid = RelationGetRelid(relation);
+		range = makeRangeVarFromNameList(relname);
+		reloid = RangeVarGetRelid(range, missing_ok);
 
 		switch (objtype)
 		{
 			case OBJECT_RULE:
 				address.classId = RewriteRelationId;
-				address.objectId = get_rewrite_oid(reloid, depname, false);
+				address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
 				address.objectSubId = 0;
 				break;
 			case OBJECT_TRIGGER:
 				address.classId = TriggerRelationId;
-				address.objectId = get_trigger_oid(reloid, depname, false);
+				address.objectId = get_trigger_oid(reloid, depname, missing_ok);
 				address.objectSubId = 0;
 				break;
 			case OBJECT_CONSTRAINT:
 				address.classId = ConstraintRelationId;
-				address.objectId = get_constraint_oid(reloid, depname, false);
+				address.objectId =
+					get_constraint_oid(reloid, depname, missing_ok);
 				address.objectSubId = 0;
 				break;
 			default:
@@ -503,7 +580,8 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
 	}
 
 	/* Done. */
-	*relp = relation;
+	if (OidIsValid(address.objectId))
+		*relp = heap_open(reloid, AccessShareLock);
 	return address;
 }
 
@@ -511,32 +589,90 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
  * Find the ObjectAddress for an attribute.
  */
 static ObjectAddress
-get_object_address_attribute(ObjectType objtype, List *objname,
+get_object_address_attribute(ObjectType objtype, List *objname, bool missing_ok,
 							 Relation *relp, LOCKMODE lockmode)
 {
 	ObjectAddress address;
+	RangeVar   *range;
 	List	   *relname;
 	Oid			reloid;
-	Relation	relation;
 	const char *attname;
+	AttrNumber	attnum;
 
-	/* Extract relation name and open relation. */
+	/* Extract relation and attribute name. */
 	attname = strVal(lfirst(list_tail(objname)));
 	relname = list_truncate(list_copy(objname), list_length(objname) - 1);
-	relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
-	reloid = RelationGetRelid(relation);
+	range = makeRangeVarFromNameList(relname);
+	reloid = RangeVarGetRelid(range, missing_ok);
+
+	/* Look up attribute */
+	if (!OidIsValid(reloid) ||
+		(attnum = get_attnum(reloid, attname)) == InvalidAttrNumber)
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_COLUMN),
+					 errmsg("column \"%s\" of relation \"%s\" does not exist",
+							attname, NameListToString(relname))));
+
+		address.classId = RelationRelationId;
+		address.objectId = InvalidOid;
+		address.objectSubId = InvalidAttrNumber;
+		return address;
+	}
 
-	/* Look up attribute and construct return value. */
+	/* Construct return value and open relation for locking */
 	address.classId = RelationRelationId;
-	address.objectId = reloid;
-	address.objectSubId = get_attnum(reloid, attname);
-	if (address.objectSubId == InvalidAttrNumber)
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_COLUMN),
-				 errmsg("column \"%s\" of relation \"%s\" does not exist",
-						attname, RelationGetRelationName(relation))));
+    address.objectId = reloid;
+	address.objectSubId = attnum;
+
+	*relp = relation_open(reloid, lockmode);
+
+	return address;
+}
+
+/*
+ * Find the ObjectAddress for a type or domain
+ */
+static ObjectAddress
+get_object_address_typeobj(ObjectType objtype,
+						   List *objname, bool missing_ok)
+{
+	ObjectAddress   address;
+	TypeName   *typename;
+	Type        tup;
+	typename = makeTypeNameFromNameList(objname);
+
+	tup = LookupTypeName(NULL, typename, NULL);
+	if (!HeapTupleIsValid(tup))
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("type \"%s\" does not exist",
+							TypeNameToString(typename))));
+
+		address.classId = TypeRelationId;
+		address.objectId = InvalidOid;
+		address.objectSubId = 0;
+		return address;
+	}
+
+	address.classId = TypeRelationId;
+	address.objectId = typeTypeId(tup);
+	address.objectSubId = 0;
+
+	if (objtype == OBJECT_DOMAIN)
+	{
+		if (((Form_pg_type) GETSTRUCT(tup))->typtype != TYPTYPE_DOMAIN)
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a domain",
+							TypeNameToString(typename))));
+	}
+
+	ReleaseSysCache(tup);
 
-	*relp = relation;
 	return address;
 }
 
@@ -544,7 +680,8 @@ get_object_address_attribute(ObjectType objtype, List *objname,
  * Find the ObjectAddress for an opclass or opfamily.
  */
 static ObjectAddress
-get_object_address_opcf(ObjectType objtype, List *objname, List *objargs)
+get_object_address_opcf(ObjectType objtype,
+						List *objname, List *objargs, bool missing_ok)
 {
 	Oid			amoid;
 	ObjectAddress address;
@@ -556,12 +693,12 @@ get_object_address_opcf(ObjectType objtype, List *objname, List *objargs)
 	{
 		case OBJECT_OPCLASS:
 			address.classId = OperatorClassRelationId;
-			address.objectId = get_opclass_oid(amoid, objname, false);
+			address.objectId = get_opclass_oid(amoid, objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_OPFAMILY:
 			address.classId = OperatorFamilyRelationId;
-			address.objectId = get_opfamily_oid(amoid, objname, false);
+			address.objectId = get_opfamily_oid(amoid, objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		default:
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index d09bef0..9b2368b 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -69,7 +69,7 @@ CommentObject(CommentStmt *stmt)
 	 * against concurrent DROP operations.
 	 */
 	address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								 &relation, ShareUpdateExclusiveLock);
+								 false, &relation, ShareUpdateExclusiveLock);
 
 	/* Require ownership of the target object. */
 	check_object_ownership(GetUserId(), stmt->objtype, address,
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index d848926..cf13200 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -2703,7 +2703,7 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
 	 * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
 	 */
 	object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								&relation, ShareUpdateExclusiveLock);
+								false, &relation, ShareUpdateExclusiveLock);
 
 	/* Permission check: must own target object, too */
 	check_object_ownership(GetUserId(), stmt->objtype, object,
diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c
index 7afb713..9b9dbd7 100644
--- a/src/backend/commands/seclabel.c
+++ b/src/backend/commands/seclabel.c
@@ -88,7 +88,7 @@ ExecSecLabelStmt(SecLabelStmt *stmt)
 	 * guard against concurrent modifications.
 	 */
 	address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								 &relation, ShareUpdateExclusiveLock);
+								 false, &relation, ShareUpdateExclusiveLock);
 
 	/* Require ownership of the target object. */
 	check_object_ownership(GetUserId(), stmt->objtype, address,
diff --git a/src/backend/rewrite/rewriteSupport.c b/src/backend/rewrite/rewriteSupport.c
index 7770d03..4d6f508 100644
--- a/src/backend/rewrite/rewriteSupport.c
+++ b/src/backend/rewrite/rewriteSupport.c
@@ -132,7 +132,8 @@ get_rewrite_oid(Oid relid, const char *rulename, bool missing_ok)
  * were unique across the entire database.
  */
 Oid
-get_rewrite_oid_without_relid(const char *rulename, Oid *reloid)
+get_rewrite_oid_without_relid(const char *rulename,
+							  Oid *reloid, bool missing_ok)
 {
 	Relation	RewriteRelation;
 	HeapScanDesc scanDesc;
@@ -151,20 +152,26 @@ get_rewrite_oid_without_relid(const char *rulename, Oid *reloid)
 
 	htup = heap_getnext(scanDesc, ForwardScanDirection);
 	if (!HeapTupleIsValid(htup))
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("rule \"%s\" does not exist", rulename)));
-
-	ruleoid = HeapTupleGetOid(htup);
-	if (reloid != NULL)
-		*reloid = ((Form_pg_rewrite) GETSTRUCT(htup))->ev_class;
-
-	if (HeapTupleIsValid(htup = heap_getnext(scanDesc, ForwardScanDirection)))
-		ereport(ERROR,
-				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("there are multiple rules named \"%s\"", rulename),
-				 errhint("Specify a relation name as well as a rule name.")));
-
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("rule \"%s\" does not exist", rulename)));
+		ruleoid = InvalidOid;
+	}
+	else
+	{
+		ruleoid = HeapTupleGetOid(htup);
+		if (reloid != NULL)
+			*reloid = ((Form_pg_rewrite) GETSTRUCT(htup))->ev_class;
+
+		htup = heap_getnext(scanDesc, ForwardScanDirection);
+		if (HeapTupleIsValid(htup))
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("there are multiple rules named \"%s\"", rulename),
+					 errhint("Specify a relation name as well as a rule name.")));
+	}
 	heap_endscan(scanDesc);
 	heap_close(RewriteRelation, AccessShareLock);
 
diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h
index 109a8a3..3eafb18 100644
--- a/src/include/catalog/objectaddress.h
+++ b/src/include/catalog/objectaddress.h
@@ -28,7 +28,8 @@ typedef struct ObjectAddress
 } ObjectAddress;
 
 extern ObjectAddress get_object_address(ObjectType objtype, List *objname,
-				   List *objargs, Relation *relp, LOCKMODE lockmode);
+										List *objargs, bool missing_ok,
+										Relation *relp, LOCKMODE lockmode);
 
 extern void check_object_ownership(Oid roleid,
 					   ObjectType objtype, ObjectAddress address,
diff --git a/src/include/rewrite/rewriteSupport.h b/src/include/rewrite/rewriteSupport.h
index 77417ba..22e6ca2 100644
--- a/src/include/rewrite/rewriteSupport.h
+++ b/src/include/rewrite/rewriteSupport.h
@@ -23,6 +23,7 @@ extern void SetRelationRuleStatus(Oid relationId, bool relHasRules,
 					  bool relIsBecomingView);
 
 extern Oid	get_rewrite_oid(Oid relid, const char *rulename, bool missing_ok);
-extern Oid	get_rewrite_oid_without_relid(const char *rulename, Oid *relid);
+extern Oid	get_rewrite_oid_without_relid(const char *rulename,
+										  Oid *relid, bool missing_ok);
 
 #endif   /* REWRITESUPPORT_H */
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index f84da45..9d5d2ba 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -4,7 +4,7 @@
 --
 CREATE TABLE tmp (initial int4);
 COMMENT ON TABLE tmp_wrong IS 'table comment';
-ERROR:  relation "tmp_wrong" does not exist
+ERROR:  table "tmp_wrong" does not exist
 COMMENT ON TABLE tmp IS 'table comment';
 COMMENT ON TABLE tmp IS NULL;
 ALTER TABLE tmp ADD COLUMN a int4 default 3;
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index c78d9ee..606f9ec 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -21,7 +21,7 @@ CREATE INDEX iix ON ihighway USING btree (name text_ops);
 CREATE INDEX six ON shighway USING btree (name text_ops);
 -- test comments
 COMMENT ON INDEX six_wrong IS 'bad index';
-ERROR:  relation "six_wrong" does not exist
+ERROR:  index "six_wrong" does not exist
 COMMENT ON INDEX six IS 'good index';
 COMMENT ON INDEX six IS NULL;
 --
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index f2c0685..253265f 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -17,7 +17,7 @@ CREATE VIEW toyemp AS
    FROM emp;
 -- Test comments
 COMMENT ON VIEW noview IS 'no view';
-ERROR:  relation "noview" does not exist
+ERROR:  view "noview" does not exist
 COMMENT ON VIEW toyemp IS 'is a view';
 COMMENT ON VIEW toyemp IS NULL;
 --
diff --git a/src/test/regress/expected/sequence.out b/src/test/regress/expected/sequence.out
index 13e1565..c986e9d 100644
--- a/src/test/regress/expected/sequence.out
+++ b/src/test/regress/expected/sequence.out
@@ -229,7 +229,7 @@ SELECT * FROM information_schema.sequences WHERE sequence_name IN ('sequence_tes
 
 -- Test comments
 COMMENT ON SEQUENCE asdf IS 'won''t work';
-ERROR:  relation "asdf" does not exist
+ERROR:  sequence "asdf" does not exist
 COMMENT ON SEQUENCE sequence_test2 IS 'will work';
 COMMENT ON SEQUENCE sequence_test2 IS NULL;
 -- Test lastval()
diff --git a/src/test/regress/output/security_label.source b/src/test/regress/output/security_label.source
index 4bc803d..4dacf6e 100644
--- a/src/test/regress/output/security_label.source
+++ b/src/test/regress/output/security_label.source
@@ -47,7 +47,7 @@ ERROR:  must be owner of relation seclabel_tbl2
 SECURITY LABEL ON TABLE seclabel_tbl1 IS 'secret';		-- fail (not superuser)
 ERROR:  only superuser can set 'secret' label
 SECURITY LABEL ON TABLE seclabel_tbl3 IS 'unclassified';	-- fail (not found)
-ERROR:  relation "seclabel_tbl3" does not exist
+ERROR:  table "seclabel_tbl3" does not exist
 SET SESSION AUTHORIZATION seclabel_user2;
 SECURITY LABEL ON TABLE seclabel_tbl1 IS 'unclassified';		-- fail
 ERROR:  must be owner of relation seclabel_tbl1
#2Robert Haas
robertmhaas@gmail.com
In reply to: Kohei KaiGai (#1)
Re: [v9.2] DROP Reworks Part.0 - 'missing_ok' support of get_object_address

On Tue, Jun 14, 2011 at 8:06 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

The attached patch is a preparation to rework implementation of DROP statement
using a common code. That intends to apply get_object_address() to resolve name
of objects to be removed, and eventually minimizes the number of places to put
permission checks.

Its first step is an enhancement of get_object_address; to accept 'missing_ok'
argument to handle cases when IF EXISTS clause is supplied.
If 'missing_ok' was true and the supplied name was not found, the patched
get_object_address() returns an ObjectAddress with InvalidOid as objectId.
If 'missing_ok' was false, its behavior is not changed.

Let's consistently make missing_ok the last argument to all of the
functions to which we're adding it.

I don't think it's a good idea for get_relation_by_qualified_name() to
be second-guessing the error message that RangeVarGetRelid() feels
like throwing.

I think that attempting to fetch the column foo.bar when foo doesn't
exist should be an error even if missing_ok is true. I believe that's
consistent with what we do elsewhere. (If it *were* necessary to open
the relation without failing if it's not there, you could use
try_relation_openrv instead of doing as you've done here.)

There is certainly a more compact way of writing the logic in
get_object_address_typeobj. Also, I think that function should be
called get_object_address_type(); the "obj" on the end seems
redundant.

Apart from those comments this looks pretty sensible.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#3Kohei KaiGai
kaigai@kaigai.gr.jp
In reply to: Robert Haas (#2)
1 attachment(s)
Re: [v9.2] DROP Reworks Part.0 - 'missing_ok' support of get_object_address

Thanks for your review.

2011/6/19 Robert Haas <robertmhaas@gmail.com>:

On Tue, Jun 14, 2011 at 8:06 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

The attached patch is a preparation to rework implementation of DROP statement
using a common code. That intends to apply get_object_address() to resolve name
of objects to be removed, and eventually minimizes the number of places to put
permission checks.

Its first step is an enhancement of get_object_address; to accept 'missing_ok'
argument to handle cases when IF EXISTS clause is supplied.
If 'missing_ok' was true and the supplied name was not found, the patched
get_object_address() returns an ObjectAddress with InvalidOid as objectId.
If 'missing_ok' was false, its behavior is not changed.

Let's consistently make missing_ok the last argument to all of the
functions to which we're adding it.

OK. I revised position of the 'missing_ok' argument.

I don't think it's a good idea for get_relation_by_qualified_name() to
be second-guessing the error message that RangeVarGetRelid() feels
like throwing.

OK. I revised the patch to provide 'true' on RangeVarGetRelid().
Its side effect is on error messages when user gives undefined object name.

I think that attempting to fetch the column foo.bar when foo doesn't
exist should be an error even if missing_ok is true.  I believe that's
consistent with what we do elsewhere.  (If it *were* necessary to open
the relation without failing if it's not there, you could use
try_relation_openrv instead of doing as you've done here.)

It was fixed. AlterTable() already open the relation (without missing_ok)
in the case when we drop a column, so I don't think we need to acquire
relation locks if the supplied column was missing.

There is certainly a more compact way of writing the logic in
get_object_address_typeobj.  Also, I think that function should be
called get_object_address_type(); the "obj" on the end seems
redundant.

I renamed the function name to get_object_address_type(), and
consolidate initialization of ObjectAddress variables.

Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>

Attachments:

pgsql-v9.2-drop-reworks-part-0.2.patchapplication/octet-stream; name=pgsql-v9.2-drop-reworks-part-0.2.patchDownload
 src/backend/catalog/objectaddress.c           |  241 +++++++++++++++++--------
 src/backend/commands/comment.c                |    2 +-
 src/backend/commands/extension.c              |    2 +-
 src/backend/commands/seclabel.c               |    2 +-
 src/backend/rewrite/rewriteSupport.c          |   37 +++--
 src/include/catalog/objectaddress.h           |    3 +-
 src/include/rewrite/rewriteSupport.h          |    3 +-
 src/test/regress/expected/alter_table.out     |    2 +-
 src/test/regress/expected/create_index.out    |    2 +-
 src/test/regress/expected/create_view.out     |    2 +-
 src/test/regress/expected/sequence.out        |    2 +-
 src/test/regress/output/security_label.source |    2 +-
 12 files changed, 200 insertions(+), 100 deletions(-)

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index bf25091..6d55664 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -72,15 +72,19 @@
 #include "utils/tqual.h"
 
 static ObjectAddress get_object_address_unqualified(ObjectType objtype,
-							   List *qualname);
-static Relation get_relation_by_qualified_name(ObjectType objtype,
-							   List *objname, LOCKMODE lockmode);
+							   List *qualname, bool missing_ok);
+static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
+							   List *objname, Relation *relp,
+							   LOCKMODE lockmode, bool missing_ok);
 static ObjectAddress get_object_address_relobject(ObjectType objtype,
-							 List *objname, Relation *relp);
+						   List *objname, Relation *relp, bool missing_ok);
 static ObjectAddress get_object_address_attribute(ObjectType objtype,
-						   List *objname, Relation *relp, LOCKMODE lockmode);
+						   List *objname, Relation *relp,
+						   LOCKMODE lockmode, bool missing_ok);
+static ObjectAddress get_object_address_type(ObjectType objtype,
+						   List *objname, bool missing_ok);
 static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname,
-						List *objargs);
+						   List *objargs, bool missing_ok);
 static bool object_exists(ObjectAddress address);
 
 
@@ -106,7 +110,7 @@ static bool object_exists(ObjectAddress address);
  */
 ObjectAddress
 get_object_address(ObjectType objtype, List *objname, List *objargs,
-				   Relation *relp, LOCKMODE lockmode)
+				   Relation *relp, LOCKMODE lockmode, bool missing_ok)
 {
 	ObjectAddress address;
 	Relation	relation = NULL;
@@ -121,21 +125,22 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 		case OBJECT_TABLE:
 		case OBJECT_VIEW:
 		case OBJECT_FOREIGN_TABLE:
-			relation =
-				get_relation_by_qualified_name(objtype, objname, lockmode);
-			address.classId = RelationRelationId;
-			address.objectId = RelationGetRelid(relation);
-			address.objectSubId = 0;
+			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);
+				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);
+			address = get_object_address_relobject(objtype, objname,
+												   &relation, missing_ok);
 			break;
 		case OBJECT_DATABASE:
 		case OBJECT_EXTENSION:
@@ -145,23 +150,23 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 		case OBJECT_LANGUAGE:
 		case OBJECT_FDW:
 		case OBJECT_FOREIGN_SERVER:
-			address = get_object_address_unqualified(objtype, objname);
+			address = get_object_address_unqualified(objtype,
+													 objname, missing_ok);
 			break;
 		case OBJECT_TYPE:
 		case OBJECT_DOMAIN:
-			address.classId = TypeRelationId;
-			address.objectId =
-				typenameTypeId(NULL, makeTypeNameFromNameList(objname));
-			address.objectSubId = 0;
+			address = get_object_address_type(objtype, objname, missing_ok);
 			break;
 		case OBJECT_AGGREGATE:
 			address.classId = ProcedureRelationId;
-			address.objectId = LookupAggNameTypeNames(objname, objargs, false);
+			address.objectId =
+				LookupAggNameTypeNames(objname, objargs, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_FUNCTION:
 			address.classId = ProcedureRelationId;
-			address.objectId = LookupFuncNameTypeNames(objname, objargs, false);
+			address.objectId =
+				LookupFuncNameTypeNames(objname, objargs, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_OPERATOR:
@@ -171,22 +176,23 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 				LookupOperNameTypeNames(NULL, objname,
 										(TypeName *) linitial(objargs),
 										(TypeName *) lsecond(objargs),
-										false, -1);
+										missing_ok, -1);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_COLLATION:
 			address.classId = CollationRelationId;
-			address.objectId = get_collation_oid(objname, false);
+			address.objectId = get_collation_oid(objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_CONVERSION:
 			address.classId = ConversionRelationId;
-			address.objectId = get_conversion_oid(objname, false);
+			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);
+			address = get_object_address_opcf(objtype,
+											  objname, objargs, missing_ok);
 			break;
 		case OBJECT_LARGEOBJECT:
 			Assert(list_length(objname) == 1);
@@ -194,10 +200,13 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 			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:
 			{
@@ -208,28 +217,28 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 
 				address.classId = CastRelationId;
 				address.objectId =
-					get_cast_oid(sourcetypeid, targettypeid, false);
+					get_cast_oid(sourcetypeid, targettypeid, missing_ok);
 				address.objectSubId = 0;
 			}
 			break;
 		case OBJECT_TSPARSER:
 			address.classId = TSParserRelationId;
-			address.objectId = get_ts_parser_oid(objname, false);
+			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, false);
+			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, false);
+			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, false);
+			address.objectId = get_ts_config_oid(objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		default:
@@ -241,6 +250,15 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 	}
 
 	/*
+	 * 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.	If we're dealing with any other type of object, we
 	 * need to lock it and then verify that it still exists.
@@ -267,7 +285,8 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
  * unqualified name.
  */
 static ObjectAddress
-get_object_address_unqualified(ObjectType objtype, List *qualname)
+get_object_address_unqualified(ObjectType objtype,
+							   List *qualname, bool missing_ok)
 {
 	const char *name;
 	ObjectAddress address;
@@ -323,42 +342,42 @@ get_object_address_unqualified(ObjectType objtype, List *qualname)
 	{
 		case OBJECT_DATABASE:
 			address.classId = DatabaseRelationId;
-			address.objectId = get_database_oid(name, false);
+			address.objectId = get_database_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_EXTENSION:
 			address.classId = ExtensionRelationId;
-			address.objectId = get_extension_oid(name, false);
+			address.objectId = get_extension_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_TABLESPACE:
 			address.classId = TableSpaceRelationId;
-			address.objectId = get_tablespace_oid(name, false);
+			address.objectId = get_tablespace_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_ROLE:
 			address.classId = AuthIdRelationId;
-			address.objectId = get_role_oid(name, false);
+			address.objectId = get_role_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_SCHEMA:
 			address.classId = NamespaceRelationId;
-			address.objectId = get_namespace_oid(name, false);
+			address.objectId = get_namespace_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_LANGUAGE:
 			address.classId = LanguageRelationId;
-			address.objectId = get_language_oid(name, false);
+			address.objectId = get_language_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_FDW:
 			address.classId = ForeignDataWrapperRelationId;
-			address.objectId = get_foreign_data_wrapper_oid(name, false);
+			address.objectId = get_foreign_data_wrapper_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_FOREIGN_SERVER:
 			address.classId = ForeignServerRelationId;
-			address.objectId = get_foreign_server_oid(name, false);
+			address.objectId = get_foreign_server_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		default:
@@ -375,13 +394,25 @@ get_object_address_unqualified(ObjectType objtype, List *qualname)
 /*
  * Locate a relation by qualified name.
  */
-static Relation
+static ObjectAddress
 get_relation_by_qualified_name(ObjectType objtype, List *objname,
-							   LOCKMODE lockmode)
+                               Relation *relp, LOCKMODE lockmode,
+							   bool missing_ok)
 {
+	ObjectAddress	address;
+	RangeVar   *range;
 	Relation	relation;
 
-	relation = relation_openrv(makeRangeVarFromNameList(objname), lockmode);
+	range = makeRangeVarFromNameList(objname);
+
+	address.classId = RelationRelationId;
+	address.objectId = RangeVarGetRelid(range, missing_ok);
+	address.objectSubId = 0;
+
+	if (!OidIsValid(address.objectId))
+		return address;
+
+	relation = relation_open(address.objectId, lockmode);
 	switch (objtype)
 	{
 		case OBJECT_INDEX:
@@ -424,7 +455,10 @@ get_relation_by_qualified_name(ObjectType objtype, List *objname,
 			break;
 	}
 
-	return relation;
+	/* Done */
+	*relp = relation;
+
+	return address;
 }
 
 /*
@@ -435,10 +469,11 @@ get_relation_by_qualified_name(ObjectType objtype, List *objname,
  * mode for the object itself, not the relation to which it is attached.
  */
 static ObjectAddress
-get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
+get_object_address_relobject(ObjectType objtype, List *objname,
+							 Relation *relp, bool missing_ok)
 {
 	ObjectAddress address;
-	Relation	relation = NULL;
+	Oid			reloid;
 	int			nnames;
 	const char *depname;
 
@@ -449,8 +484,6 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
 	nnames = list_length(objname);
 	if (nnames < 2)
 	{
-		Oid			reloid;
-
 		/*
 		 * For compatibility with very old releases, we sometimes allow users
 		 * to attempt to specify a rule without mentioning the relation name.
@@ -461,36 +494,36 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
 		if (objtype != OBJECT_RULE)
 			elog(ERROR, "must specify relation and object name");
 		address.classId = RewriteRelationId;
-		address.objectId = get_rewrite_oid_without_relid(depname, &reloid);
+		address.objectId =
+			get_rewrite_oid_without_relid(depname, &reloid, missing_ok);
 		address.objectSubId = 0;
-		relation = heap_open(reloid, AccessShareLock);
 	}
 	else
 	{
 		List	   *relname;
-		Oid			reloid;
+		RangeVar   *range;
 
 		/* Extract relation name and open relation. */
 		relname = list_truncate(list_copy(objname), nnames - 1);
-		relation = heap_openrv(makeRangeVarFromNameList(relname),
-							   AccessShareLock);
-		reloid = RelationGetRelid(relation);
+		range = makeRangeVarFromNameList(relname);
+		reloid = RangeVarGetRelid(range, missing_ok);
 
 		switch (objtype)
 		{
 			case OBJECT_RULE:
 				address.classId = RewriteRelationId;
-				address.objectId = get_rewrite_oid(reloid, depname, false);
+				address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
 				address.objectSubId = 0;
 				break;
 			case OBJECT_TRIGGER:
 				address.classId = TriggerRelationId;
-				address.objectId = get_trigger_oid(reloid, depname, false);
+				address.objectId = get_trigger_oid(reloid, depname, missing_ok);
 				address.objectSubId = 0;
 				break;
 			case OBJECT_CONSTRAINT:
 				address.classId = ConstraintRelationId;
-				address.objectId = get_constraint_oid(reloid, depname, false);
+				address.objectId =
+					get_constraint_oid(reloid, depname, missing_ok);
 				address.objectSubId = 0;
 				break;
 			default:
@@ -503,7 +536,8 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
 	}
 
 	/* Done. */
-	*relp = relation;
+	if (OidIsValid(address.objectId))
+		*relp = heap_open(reloid, AccessShareLock);
 	return address;
 }
 
@@ -512,31 +546,87 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
  */
 static ObjectAddress
 get_object_address_attribute(ObjectType objtype, List *objname,
-							 Relation *relp, LOCKMODE lockmode)
+							 Relation *relp, LOCKMODE lockmode,
+							 bool missing_ok)
 {
 	ObjectAddress address;
+	RangeVar   *range;
 	List	   *relname;
 	Oid			reloid;
-	Relation	relation;
 	const char *attname;
+	AttrNumber	attnum;
 
-	/* Extract relation name and open relation. */
+	/* Extract relation and attribute name. */
 	attname = strVal(lfirst(list_tail(objname)));
 	relname = list_truncate(list_copy(objname), list_length(objname) - 1);
-	relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
-	reloid = RelationGetRelid(relation);
+	range = makeRangeVarFromNameList(relname);
+	reloid = RangeVarGetRelid(range, false);
+
+	/* Look up attribute */
+	attnum = get_attnum(reloid, attname);
+	if (attnum == InvalidAttrNumber)
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_COLUMN),
+					 errmsg("column \"%s\" of relation \"%s\" does not exist",
+							attname, NameListToString(relname))));
+
+		address.classId = RelationRelationId;
+		address.objectId = InvalidOid;
+		address.objectSubId = InvalidAttrNumber;
+		return address;
+	}
 
-	/* Look up attribute and construct return value. */
+	/* Construct return value and open relation for locking */
 	address.classId = RelationRelationId;
-	address.objectId = reloid;
-	address.objectSubId = get_attnum(reloid, attname);
-	if (address.objectSubId == InvalidAttrNumber)
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_COLUMN),
-				 errmsg("column \"%s\" of relation \"%s\" does not exist",
-						attname, RelationGetRelationName(relation))));
+    address.objectId = reloid;
+	address.objectSubId = attnum;
+
+	*relp = relation_open(reloid, lockmode);
+
+	return address;
+}
+
+/*
+ * Find the ObjectAddress for a type or domain
+ */
+static ObjectAddress
+get_object_address_type(ObjectType objtype,
+						List *objname, bool missing_ok)
+{
+	ObjectAddress   address;
+	TypeName   *typename;
+	Type        tup;
+	typename = makeTypeNameFromNameList(objname);
+
+	address.classId = TypeRelationId;
+	address.objectId = InvalidOid;
+	address.objectSubId = 0;
+
+	tup = LookupTypeName(NULL, typename, NULL);
+	if (!HeapTupleIsValid(tup))
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("type \"%s\" does not exist",
+							TypeNameToString(typename))));
+		return address;
+	}
+	address.objectId = typeTypeId(tup);
+
+	if (objtype == OBJECT_DOMAIN)
+	{
+		if (((Form_pg_type) GETSTRUCT(tup))->typtype != TYPTYPE_DOMAIN)
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a domain",
+							TypeNameToString(typename))));
+	}
+
+	ReleaseSysCache(tup);
 
-	*relp = relation;
 	return address;
 }
 
@@ -544,7 +634,8 @@ get_object_address_attribute(ObjectType objtype, List *objname,
  * Find the ObjectAddress for an opclass or opfamily.
  */
 static ObjectAddress
-get_object_address_opcf(ObjectType objtype, List *objname, List *objargs)
+get_object_address_opcf(ObjectType objtype,
+						List *objname, List *objargs, bool missing_ok)
 {
 	Oid			amoid;
 	ObjectAddress address;
@@ -556,12 +647,12 @@ get_object_address_opcf(ObjectType objtype, List *objname, List *objargs)
 	{
 		case OBJECT_OPCLASS:
 			address.classId = OperatorClassRelationId;
-			address.objectId = get_opclass_oid(amoid, objname, false);
+			address.objectId = get_opclass_oid(amoid, objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_OPFAMILY:
 			address.classId = OperatorFamilyRelationId;
-			address.objectId = get_opfamily_oid(amoid, objname, false);
+			address.objectId = get_opfamily_oid(amoid, objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		default:
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index d09bef0..c3374c1 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -69,7 +69,7 @@ CommentObject(CommentStmt *stmt)
 	 * against concurrent DROP operations.
 	 */
 	address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								 &relation, ShareUpdateExclusiveLock);
+								 &relation, ShareUpdateExclusiveLock, false);
 
 	/* Require ownership of the target object. */
 	check_object_ownership(GetUserId(), stmt->objtype, address,
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index d848926..b68952f 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -2703,7 +2703,7 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
 	 * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
 	 */
 	object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								&relation, ShareUpdateExclusiveLock);
+								&relation, ShareUpdateExclusiveLock, false);
 
 	/* Permission check: must own target object, too */
 	check_object_ownership(GetUserId(), stmt->objtype, object,
diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c
index 7afb713..51a5567 100644
--- a/src/backend/commands/seclabel.c
+++ b/src/backend/commands/seclabel.c
@@ -88,7 +88,7 @@ ExecSecLabelStmt(SecLabelStmt *stmt)
 	 * guard against concurrent modifications.
 	 */
 	address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								 &relation, ShareUpdateExclusiveLock);
+								 &relation, ShareUpdateExclusiveLock, false);
 
 	/* Require ownership of the target object. */
 	check_object_ownership(GetUserId(), stmt->objtype, address,
diff --git a/src/backend/rewrite/rewriteSupport.c b/src/backend/rewrite/rewriteSupport.c
index 7770d03..4d6f508 100644
--- a/src/backend/rewrite/rewriteSupport.c
+++ b/src/backend/rewrite/rewriteSupport.c
@@ -132,7 +132,8 @@ get_rewrite_oid(Oid relid, const char *rulename, bool missing_ok)
  * were unique across the entire database.
  */
 Oid
-get_rewrite_oid_without_relid(const char *rulename, Oid *reloid)
+get_rewrite_oid_without_relid(const char *rulename,
+							  Oid *reloid, bool missing_ok)
 {
 	Relation	RewriteRelation;
 	HeapScanDesc scanDesc;
@@ -151,20 +152,26 @@ get_rewrite_oid_without_relid(const char *rulename, Oid *reloid)
 
 	htup = heap_getnext(scanDesc, ForwardScanDirection);
 	if (!HeapTupleIsValid(htup))
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("rule \"%s\" does not exist", rulename)));
-
-	ruleoid = HeapTupleGetOid(htup);
-	if (reloid != NULL)
-		*reloid = ((Form_pg_rewrite) GETSTRUCT(htup))->ev_class;
-
-	if (HeapTupleIsValid(htup = heap_getnext(scanDesc, ForwardScanDirection)))
-		ereport(ERROR,
-				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("there are multiple rules named \"%s\"", rulename),
-				 errhint("Specify a relation name as well as a rule name.")));
-
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("rule \"%s\" does not exist", rulename)));
+		ruleoid = InvalidOid;
+	}
+	else
+	{
+		ruleoid = HeapTupleGetOid(htup);
+		if (reloid != NULL)
+			*reloid = ((Form_pg_rewrite) GETSTRUCT(htup))->ev_class;
+
+		htup = heap_getnext(scanDesc, ForwardScanDirection);
+		if (HeapTupleIsValid(htup))
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("there are multiple rules named \"%s\"", rulename),
+					 errhint("Specify a relation name as well as a rule name.")));
+	}
 	heap_endscan(scanDesc);
 	heap_close(RewriteRelation, AccessShareLock);
 
diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h
index 109a8a3..300b81d 100644
--- a/src/include/catalog/objectaddress.h
+++ b/src/include/catalog/objectaddress.h
@@ -28,7 +28,8 @@ typedef struct ObjectAddress
 } ObjectAddress;
 
 extern ObjectAddress get_object_address(ObjectType objtype, List *objname,
-				   List *objargs, Relation *relp, LOCKMODE lockmode);
+										List *objargs, Relation *relp,
+										LOCKMODE lockmode, bool missing_ok);
 
 extern void check_object_ownership(Oid roleid,
 					   ObjectType objtype, ObjectAddress address,
diff --git a/src/include/rewrite/rewriteSupport.h b/src/include/rewrite/rewriteSupport.h
index 77417ba..22e6ca2 100644
--- a/src/include/rewrite/rewriteSupport.h
+++ b/src/include/rewrite/rewriteSupport.h
@@ -23,6 +23,7 @@ extern void SetRelationRuleStatus(Oid relationId, bool relHasRules,
 					  bool relIsBecomingView);
 
 extern Oid	get_rewrite_oid(Oid relid, const char *rulename, bool missing_ok);
-extern Oid	get_rewrite_oid_without_relid(const char *rulename, Oid *relid);
+extern Oid	get_rewrite_oid_without_relid(const char *rulename,
+										  Oid *relid, bool missing_ok);
 
 #endif   /* REWRITESUPPORT_H */
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index f84da45..9d5d2ba 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -4,7 +4,7 @@
 --
 CREATE TABLE tmp (initial int4);
 COMMENT ON TABLE tmp_wrong IS 'table comment';
-ERROR:  relation "tmp_wrong" does not exist
+ERROR:  table "tmp_wrong" does not exist
 COMMENT ON TABLE tmp IS 'table comment';
 COMMENT ON TABLE tmp IS NULL;
 ALTER TABLE tmp ADD COLUMN a int4 default 3;
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index c78d9ee..606f9ec 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -21,7 +21,7 @@ CREATE INDEX iix ON ihighway USING btree (name text_ops);
 CREATE INDEX six ON shighway USING btree (name text_ops);
 -- test comments
 COMMENT ON INDEX six_wrong IS 'bad index';
-ERROR:  relation "six_wrong" does not exist
+ERROR:  index "six_wrong" does not exist
 COMMENT ON INDEX six IS 'good index';
 COMMENT ON INDEX six IS NULL;
 --
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index f2c0685..253265f 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -17,7 +17,7 @@ CREATE VIEW toyemp AS
    FROM emp;
 -- Test comments
 COMMENT ON VIEW noview IS 'no view';
-ERROR:  relation "noview" does not exist
+ERROR:  view "noview" does not exist
 COMMENT ON VIEW toyemp IS 'is a view';
 COMMENT ON VIEW toyemp IS NULL;
 --
diff --git a/src/test/regress/expected/sequence.out b/src/test/regress/expected/sequence.out
index 13e1565..c986e9d 100644
--- a/src/test/regress/expected/sequence.out
+++ b/src/test/regress/expected/sequence.out
@@ -229,7 +229,7 @@ SELECT * FROM information_schema.sequences WHERE sequence_name IN ('sequence_tes
 
 -- Test comments
 COMMENT ON SEQUENCE asdf IS 'won''t work';
-ERROR:  relation "asdf" does not exist
+ERROR:  sequence "asdf" does not exist
 COMMENT ON SEQUENCE sequence_test2 IS 'will work';
 COMMENT ON SEQUENCE sequence_test2 IS NULL;
 -- Test lastval()
diff --git a/src/test/regress/output/security_label.source b/src/test/regress/output/security_label.source
index 4bc803d..4dacf6e 100644
--- a/src/test/regress/output/security_label.source
+++ b/src/test/regress/output/security_label.source
@@ -47,7 +47,7 @@ ERROR:  must be owner of relation seclabel_tbl2
 SECURITY LABEL ON TABLE seclabel_tbl1 IS 'secret';		-- fail (not superuser)
 ERROR:  only superuser can set 'secret' label
 SECURITY LABEL ON TABLE seclabel_tbl3 IS 'unclassified';	-- fail (not found)
-ERROR:  relation "seclabel_tbl3" does not exist
+ERROR:  table "seclabel_tbl3" does not exist
 SET SESSION AUTHORIZATION seclabel_user2;
 SECURITY LABEL ON TABLE seclabel_tbl1 IS 'unclassified';		-- fail
 ERROR:  must be owner of relation seclabel_tbl1
#4Kohei KaiGai
kaigai@kaigai.gr.jp
In reply to: Kohei KaiGai (#3)
1 attachment(s)
Re: [v9.2] DROP Reworks Part.0 - 'missing_ok' support of get_object_address

Sorry, the previous revision did not update regression test part
towards the latest one.

2011/6/19 Kohei KaiGai <kaigai@kaigai.gr.jp>:

Thanks for your review.

2011/6/19 Robert Haas <robertmhaas@gmail.com>:

On Tue, Jun 14, 2011 at 8:06 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

The attached patch is a preparation to rework implementation of DROP statement
using a common code. That intends to apply get_object_address() to resolve name
of objects to be removed, and eventually minimizes the number of places to put
permission checks.

Its first step is an enhancement of get_object_address; to accept 'missing_ok'
argument to handle cases when IF EXISTS clause is supplied.
If 'missing_ok' was true and the supplied name was not found, the patched
get_object_address() returns an ObjectAddress with InvalidOid as objectId.
If 'missing_ok' was false, its behavior is not changed.

Let's consistently make missing_ok the last argument to all of the
functions to which we're adding it.

OK. I revised position of the 'missing_ok' argument.

I don't think it's a good idea for get_relation_by_qualified_name() to
be second-guessing the error message that RangeVarGetRelid() feels
like throwing.

OK. I revised the patch to provide 'true' on RangeVarGetRelid().
Its side effect is on error messages when user gives undefined object name.

I think that attempting to fetch the column foo.bar when foo doesn't
exist should be an error even if missing_ok is true.  I believe that's
consistent with what we do elsewhere.  (If it *were* necessary to open
the relation without failing if it's not there, you could use
try_relation_openrv instead of doing as you've done here.)

It was fixed. AlterTable() already open the relation (without missing_ok)
in the case when we drop a column, so I don't think we need to acquire
relation locks if the supplied column was missing.

There is certainly a more compact way of writing the logic in
get_object_address_typeobj.  Also, I think that function should be
called get_object_address_type(); the "obj" on the end seems
redundant.

I renamed the function name to get_object_address_type(), and
consolidate initialization of ObjectAddress variables.

Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>

--
KaiGai Kohei <kaigai@kaigai.gr.jp>

Attachments:

pgsql-v9.2-drop-reworks-part-0.3.patchapplication/octet-stream; name=pgsql-v9.2-drop-reworks-part-0.3.patchDownload
 src/backend/catalog/objectaddress.c  |  241 +++++++++++++++++++++++-----------
 src/backend/commands/comment.c       |    2 +-
 src/backend/commands/extension.c     |    2 +-
 src/backend/commands/seclabel.c      |    2 +-
 src/backend/rewrite/rewriteSupport.c |   37 +++--
 src/include/catalog/objectaddress.h  |    3 +-
 src/include/rewrite/rewriteSupport.h |    3 +-
 7 files changed, 195 insertions(+), 95 deletions(-)

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index bf25091..6d55664 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -72,15 +72,19 @@
 #include "utils/tqual.h"
 
 static ObjectAddress get_object_address_unqualified(ObjectType objtype,
-							   List *qualname);
-static Relation get_relation_by_qualified_name(ObjectType objtype,
-							   List *objname, LOCKMODE lockmode);
+							   List *qualname, bool missing_ok);
+static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
+							   List *objname, Relation *relp,
+							   LOCKMODE lockmode, bool missing_ok);
 static ObjectAddress get_object_address_relobject(ObjectType objtype,
-							 List *objname, Relation *relp);
+						   List *objname, Relation *relp, bool missing_ok);
 static ObjectAddress get_object_address_attribute(ObjectType objtype,
-						   List *objname, Relation *relp, LOCKMODE lockmode);
+						   List *objname, Relation *relp,
+						   LOCKMODE lockmode, bool missing_ok);
+static ObjectAddress get_object_address_type(ObjectType objtype,
+						   List *objname, bool missing_ok);
 static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname,
-						List *objargs);
+						   List *objargs, bool missing_ok);
 static bool object_exists(ObjectAddress address);
 
 
@@ -106,7 +110,7 @@ static bool object_exists(ObjectAddress address);
  */
 ObjectAddress
 get_object_address(ObjectType objtype, List *objname, List *objargs,
-				   Relation *relp, LOCKMODE lockmode)
+				   Relation *relp, LOCKMODE lockmode, bool missing_ok)
 {
 	ObjectAddress address;
 	Relation	relation = NULL;
@@ -121,21 +125,22 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 		case OBJECT_TABLE:
 		case OBJECT_VIEW:
 		case OBJECT_FOREIGN_TABLE:
-			relation =
-				get_relation_by_qualified_name(objtype, objname, lockmode);
-			address.classId = RelationRelationId;
-			address.objectId = RelationGetRelid(relation);
-			address.objectSubId = 0;
+			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);
+				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);
+			address = get_object_address_relobject(objtype, objname,
+												   &relation, missing_ok);
 			break;
 		case OBJECT_DATABASE:
 		case OBJECT_EXTENSION:
@@ -145,23 +150,23 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 		case OBJECT_LANGUAGE:
 		case OBJECT_FDW:
 		case OBJECT_FOREIGN_SERVER:
-			address = get_object_address_unqualified(objtype, objname);
+			address = get_object_address_unqualified(objtype,
+													 objname, missing_ok);
 			break;
 		case OBJECT_TYPE:
 		case OBJECT_DOMAIN:
-			address.classId = TypeRelationId;
-			address.objectId =
-				typenameTypeId(NULL, makeTypeNameFromNameList(objname));
-			address.objectSubId = 0;
+			address = get_object_address_type(objtype, objname, missing_ok);
 			break;
 		case OBJECT_AGGREGATE:
 			address.classId = ProcedureRelationId;
-			address.objectId = LookupAggNameTypeNames(objname, objargs, false);
+			address.objectId =
+				LookupAggNameTypeNames(objname, objargs, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_FUNCTION:
 			address.classId = ProcedureRelationId;
-			address.objectId = LookupFuncNameTypeNames(objname, objargs, false);
+			address.objectId =
+				LookupFuncNameTypeNames(objname, objargs, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_OPERATOR:
@@ -171,22 +176,23 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 				LookupOperNameTypeNames(NULL, objname,
 										(TypeName *) linitial(objargs),
 										(TypeName *) lsecond(objargs),
-										false, -1);
+										missing_ok, -1);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_COLLATION:
 			address.classId = CollationRelationId;
-			address.objectId = get_collation_oid(objname, false);
+			address.objectId = get_collation_oid(objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_CONVERSION:
 			address.classId = ConversionRelationId;
-			address.objectId = get_conversion_oid(objname, false);
+			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);
+			address = get_object_address_opcf(objtype,
+											  objname, objargs, missing_ok);
 			break;
 		case OBJECT_LARGEOBJECT:
 			Assert(list_length(objname) == 1);
@@ -194,10 +200,13 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 			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:
 			{
@@ -208,28 +217,28 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 
 				address.classId = CastRelationId;
 				address.objectId =
-					get_cast_oid(sourcetypeid, targettypeid, false);
+					get_cast_oid(sourcetypeid, targettypeid, missing_ok);
 				address.objectSubId = 0;
 			}
 			break;
 		case OBJECT_TSPARSER:
 			address.classId = TSParserRelationId;
-			address.objectId = get_ts_parser_oid(objname, false);
+			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, false);
+			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, false);
+			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, false);
+			address.objectId = get_ts_config_oid(objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		default:
@@ -241,6 +250,15 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 	}
 
 	/*
+	 * 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.	If we're dealing with any other type of object, we
 	 * need to lock it and then verify that it still exists.
@@ -267,7 +285,8 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
  * unqualified name.
  */
 static ObjectAddress
-get_object_address_unqualified(ObjectType objtype, List *qualname)
+get_object_address_unqualified(ObjectType objtype,
+							   List *qualname, bool missing_ok)
 {
 	const char *name;
 	ObjectAddress address;
@@ -323,42 +342,42 @@ get_object_address_unqualified(ObjectType objtype, List *qualname)
 	{
 		case OBJECT_DATABASE:
 			address.classId = DatabaseRelationId;
-			address.objectId = get_database_oid(name, false);
+			address.objectId = get_database_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_EXTENSION:
 			address.classId = ExtensionRelationId;
-			address.objectId = get_extension_oid(name, false);
+			address.objectId = get_extension_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_TABLESPACE:
 			address.classId = TableSpaceRelationId;
-			address.objectId = get_tablespace_oid(name, false);
+			address.objectId = get_tablespace_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_ROLE:
 			address.classId = AuthIdRelationId;
-			address.objectId = get_role_oid(name, false);
+			address.objectId = get_role_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_SCHEMA:
 			address.classId = NamespaceRelationId;
-			address.objectId = get_namespace_oid(name, false);
+			address.objectId = get_namespace_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_LANGUAGE:
 			address.classId = LanguageRelationId;
-			address.objectId = get_language_oid(name, false);
+			address.objectId = get_language_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_FDW:
 			address.classId = ForeignDataWrapperRelationId;
-			address.objectId = get_foreign_data_wrapper_oid(name, false);
+			address.objectId = get_foreign_data_wrapper_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_FOREIGN_SERVER:
 			address.classId = ForeignServerRelationId;
-			address.objectId = get_foreign_server_oid(name, false);
+			address.objectId = get_foreign_server_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		default:
@@ -375,13 +394,25 @@ get_object_address_unqualified(ObjectType objtype, List *qualname)
 /*
  * Locate a relation by qualified name.
  */
-static Relation
+static ObjectAddress
 get_relation_by_qualified_name(ObjectType objtype, List *objname,
-							   LOCKMODE lockmode)
+                               Relation *relp, LOCKMODE lockmode,
+							   bool missing_ok)
 {
+	ObjectAddress	address;
+	RangeVar   *range;
 	Relation	relation;
 
-	relation = relation_openrv(makeRangeVarFromNameList(objname), lockmode);
+	range = makeRangeVarFromNameList(objname);
+
+	address.classId = RelationRelationId;
+	address.objectId = RangeVarGetRelid(range, missing_ok);
+	address.objectSubId = 0;
+
+	if (!OidIsValid(address.objectId))
+		return address;
+
+	relation = relation_open(address.objectId, lockmode);
 	switch (objtype)
 	{
 		case OBJECT_INDEX:
@@ -424,7 +455,10 @@ get_relation_by_qualified_name(ObjectType objtype, List *objname,
 			break;
 	}
 
-	return relation;
+	/* Done */
+	*relp = relation;
+
+	return address;
 }
 
 /*
@@ -435,10 +469,11 @@ get_relation_by_qualified_name(ObjectType objtype, List *objname,
  * mode for the object itself, not the relation to which it is attached.
  */
 static ObjectAddress
-get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
+get_object_address_relobject(ObjectType objtype, List *objname,
+							 Relation *relp, bool missing_ok)
 {
 	ObjectAddress address;
-	Relation	relation = NULL;
+	Oid			reloid;
 	int			nnames;
 	const char *depname;
 
@@ -449,8 +484,6 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
 	nnames = list_length(objname);
 	if (nnames < 2)
 	{
-		Oid			reloid;
-
 		/*
 		 * For compatibility with very old releases, we sometimes allow users
 		 * to attempt to specify a rule without mentioning the relation name.
@@ -461,36 +494,36 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
 		if (objtype != OBJECT_RULE)
 			elog(ERROR, "must specify relation and object name");
 		address.classId = RewriteRelationId;
-		address.objectId = get_rewrite_oid_without_relid(depname, &reloid);
+		address.objectId =
+			get_rewrite_oid_without_relid(depname, &reloid, missing_ok);
 		address.objectSubId = 0;
-		relation = heap_open(reloid, AccessShareLock);
 	}
 	else
 	{
 		List	   *relname;
-		Oid			reloid;
+		RangeVar   *range;
 
 		/* Extract relation name and open relation. */
 		relname = list_truncate(list_copy(objname), nnames - 1);
-		relation = heap_openrv(makeRangeVarFromNameList(relname),
-							   AccessShareLock);
-		reloid = RelationGetRelid(relation);
+		range = makeRangeVarFromNameList(relname);
+		reloid = RangeVarGetRelid(range, missing_ok);
 
 		switch (objtype)
 		{
 			case OBJECT_RULE:
 				address.classId = RewriteRelationId;
-				address.objectId = get_rewrite_oid(reloid, depname, false);
+				address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
 				address.objectSubId = 0;
 				break;
 			case OBJECT_TRIGGER:
 				address.classId = TriggerRelationId;
-				address.objectId = get_trigger_oid(reloid, depname, false);
+				address.objectId = get_trigger_oid(reloid, depname, missing_ok);
 				address.objectSubId = 0;
 				break;
 			case OBJECT_CONSTRAINT:
 				address.classId = ConstraintRelationId;
-				address.objectId = get_constraint_oid(reloid, depname, false);
+				address.objectId =
+					get_constraint_oid(reloid, depname, missing_ok);
 				address.objectSubId = 0;
 				break;
 			default:
@@ -503,7 +536,8 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
 	}
 
 	/* Done. */
-	*relp = relation;
+	if (OidIsValid(address.objectId))
+		*relp = heap_open(reloid, AccessShareLock);
 	return address;
 }
 
@@ -512,31 +546,87 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
  */
 static ObjectAddress
 get_object_address_attribute(ObjectType objtype, List *objname,
-							 Relation *relp, LOCKMODE lockmode)
+							 Relation *relp, LOCKMODE lockmode,
+							 bool missing_ok)
 {
 	ObjectAddress address;
+	RangeVar   *range;
 	List	   *relname;
 	Oid			reloid;
-	Relation	relation;
 	const char *attname;
+	AttrNumber	attnum;
 
-	/* Extract relation name and open relation. */
+	/* Extract relation and attribute name. */
 	attname = strVal(lfirst(list_tail(objname)));
 	relname = list_truncate(list_copy(objname), list_length(objname) - 1);
-	relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
-	reloid = RelationGetRelid(relation);
+	range = makeRangeVarFromNameList(relname);
+	reloid = RangeVarGetRelid(range, false);
+
+	/* Look up attribute */
+	attnum = get_attnum(reloid, attname);
+	if (attnum == InvalidAttrNumber)
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_COLUMN),
+					 errmsg("column \"%s\" of relation \"%s\" does not exist",
+							attname, NameListToString(relname))));
+
+		address.classId = RelationRelationId;
+		address.objectId = InvalidOid;
+		address.objectSubId = InvalidAttrNumber;
+		return address;
+	}
 
-	/* Look up attribute and construct return value. */
+	/* Construct return value and open relation for locking */
 	address.classId = RelationRelationId;
-	address.objectId = reloid;
-	address.objectSubId = get_attnum(reloid, attname);
-	if (address.objectSubId == InvalidAttrNumber)
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_COLUMN),
-				 errmsg("column \"%s\" of relation \"%s\" does not exist",
-						attname, RelationGetRelationName(relation))));
+    address.objectId = reloid;
+	address.objectSubId = attnum;
+
+	*relp = relation_open(reloid, lockmode);
+
+	return address;
+}
+
+/*
+ * Find the ObjectAddress for a type or domain
+ */
+static ObjectAddress
+get_object_address_type(ObjectType objtype,
+						List *objname, bool missing_ok)
+{
+	ObjectAddress   address;
+	TypeName   *typename;
+	Type        tup;
+	typename = makeTypeNameFromNameList(objname);
+
+	address.classId = TypeRelationId;
+	address.objectId = InvalidOid;
+	address.objectSubId = 0;
+
+	tup = LookupTypeName(NULL, typename, NULL);
+	if (!HeapTupleIsValid(tup))
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("type \"%s\" does not exist",
+							TypeNameToString(typename))));
+		return address;
+	}
+	address.objectId = typeTypeId(tup);
+
+	if (objtype == OBJECT_DOMAIN)
+	{
+		if (((Form_pg_type) GETSTRUCT(tup))->typtype != TYPTYPE_DOMAIN)
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a domain",
+							TypeNameToString(typename))));
+	}
+
+	ReleaseSysCache(tup);
 
-	*relp = relation;
 	return address;
 }
 
@@ -544,7 +634,8 @@ get_object_address_attribute(ObjectType objtype, List *objname,
  * Find the ObjectAddress for an opclass or opfamily.
  */
 static ObjectAddress
-get_object_address_opcf(ObjectType objtype, List *objname, List *objargs)
+get_object_address_opcf(ObjectType objtype,
+						List *objname, List *objargs, bool missing_ok)
 {
 	Oid			amoid;
 	ObjectAddress address;
@@ -556,12 +647,12 @@ get_object_address_opcf(ObjectType objtype, List *objname, List *objargs)
 	{
 		case OBJECT_OPCLASS:
 			address.classId = OperatorClassRelationId;
-			address.objectId = get_opclass_oid(amoid, objname, false);
+			address.objectId = get_opclass_oid(amoid, objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_OPFAMILY:
 			address.classId = OperatorFamilyRelationId;
-			address.objectId = get_opfamily_oid(amoid, objname, false);
+			address.objectId = get_opfamily_oid(amoid, objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		default:
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index 587a689..de4d5de 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -69,7 +69,7 @@ CommentObject(CommentStmt *stmt)
 	 * against concurrent DROP operations.
 	 */
 	address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								 &relation, ShareUpdateExclusiveLock);
+								 &relation, ShareUpdateExclusiveLock, false);
 
 	/* Require ownership of the target object. */
 	check_object_ownership(GetUserId(), stmt->objtype, address,
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index d848926..b68952f 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -2703,7 +2703,7 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
 	 * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
 	 */
 	object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								&relation, ShareUpdateExclusiveLock);
+								&relation, ShareUpdateExclusiveLock, false);
 
 	/* Permission check: must own target object, too */
 	check_object_ownership(GetUserId(), stmt->objtype, object,
diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c
index 7afb713..51a5567 100644
--- a/src/backend/commands/seclabel.c
+++ b/src/backend/commands/seclabel.c
@@ -88,7 +88,7 @@ ExecSecLabelStmt(SecLabelStmt *stmt)
 	 * guard against concurrent modifications.
 	 */
 	address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								 &relation, ShareUpdateExclusiveLock);
+								 &relation, ShareUpdateExclusiveLock, false);
 
 	/* Require ownership of the target object. */
 	check_object_ownership(GetUserId(), stmt->objtype, address,
diff --git a/src/backend/rewrite/rewriteSupport.c b/src/backend/rewrite/rewriteSupport.c
index 7770d03..4d6f508 100644
--- a/src/backend/rewrite/rewriteSupport.c
+++ b/src/backend/rewrite/rewriteSupport.c
@@ -132,7 +132,8 @@ get_rewrite_oid(Oid relid, const char *rulename, bool missing_ok)
  * were unique across the entire database.
  */
 Oid
-get_rewrite_oid_without_relid(const char *rulename, Oid *reloid)
+get_rewrite_oid_without_relid(const char *rulename,
+							  Oid *reloid, bool missing_ok)
 {
 	Relation	RewriteRelation;
 	HeapScanDesc scanDesc;
@@ -151,20 +152,26 @@ get_rewrite_oid_without_relid(const char *rulename, Oid *reloid)
 
 	htup = heap_getnext(scanDesc, ForwardScanDirection);
 	if (!HeapTupleIsValid(htup))
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("rule \"%s\" does not exist", rulename)));
-
-	ruleoid = HeapTupleGetOid(htup);
-	if (reloid != NULL)
-		*reloid = ((Form_pg_rewrite) GETSTRUCT(htup))->ev_class;
-
-	if (HeapTupleIsValid(htup = heap_getnext(scanDesc, ForwardScanDirection)))
-		ereport(ERROR,
-				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("there are multiple rules named \"%s\"", rulename),
-				 errhint("Specify a relation name as well as a rule name.")));
-
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("rule \"%s\" does not exist", rulename)));
+		ruleoid = InvalidOid;
+	}
+	else
+	{
+		ruleoid = HeapTupleGetOid(htup);
+		if (reloid != NULL)
+			*reloid = ((Form_pg_rewrite) GETSTRUCT(htup))->ev_class;
+
+		htup = heap_getnext(scanDesc, ForwardScanDirection);
+		if (HeapTupleIsValid(htup))
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("there are multiple rules named \"%s\"", rulename),
+					 errhint("Specify a relation name as well as a rule name.")));
+	}
 	heap_endscan(scanDesc);
 	heap_close(RewriteRelation, AccessShareLock);
 
diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h
index 109a8a3..300b81d 100644
--- a/src/include/catalog/objectaddress.h
+++ b/src/include/catalog/objectaddress.h
@@ -28,7 +28,8 @@ typedef struct ObjectAddress
 } ObjectAddress;
 
 extern ObjectAddress get_object_address(ObjectType objtype, List *objname,
-				   List *objargs, Relation *relp, LOCKMODE lockmode);
+										List *objargs, Relation *relp,
+										LOCKMODE lockmode, bool missing_ok);
 
 extern void check_object_ownership(Oid roleid,
 					   ObjectType objtype, ObjectAddress address,
diff --git a/src/include/rewrite/rewriteSupport.h b/src/include/rewrite/rewriteSupport.h
index 77417ba..22e6ca2 100644
--- a/src/include/rewrite/rewriteSupport.h
+++ b/src/include/rewrite/rewriteSupport.h
@@ -23,6 +23,7 @@ extern void SetRelationRuleStatus(Oid relationId, bool relHasRules,
 					  bool relIsBecomingView);
 
 extern Oid	get_rewrite_oid(Oid relid, const char *rulename, bool missing_ok);
-extern Oid	get_rewrite_oid_without_relid(const char *rulename, Oid *relid);
+extern Oid	get_rewrite_oid_without_relid(const char *rulename,
+										  Oid *relid, bool missing_ok);
 
 #endif   /* REWRITESUPPORT_H */
#5Robert Haas
robertmhaas@gmail.com
In reply to: Kohei KaiGai (#4)
1 attachment(s)
Re: [v9.2] DROP Reworks Part.0 - 'missing_ok' support of get_object_address

On Sun, Jun 19, 2011 at 7:40 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

Sorry, the previous revision did not update regression test part
towards the latest one.

Some of the refactoring you've done here seems likely to break things,
because you're basically making the relation locking happen later than
it does not, and that's going to cause problems.
get_object_address_relobject() is a particularly egregious
rearrangement. It seems to me that the right formula is to call
relation_openrv() if missing_ok is false, and try_relation_openrv() if
missing_ok is true. But that's sort of a pain, so I propose to first
apply the attached patch, which gets rid of try_relation_openrv() and
try_heap_openrv() and instead adds a missing_ok argument to
relation_openrv() and heap_openrv(). If we do this, then the
missing_ok argument can just be passed through all the way down.

Thoughts? Comments? Objections?

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

Attachments:

there-is-no-try.patchapplication/octet-stream; name=there-is-no-try.patchDownload
diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 19b98fb..9d639f0 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -2044,7 +2044,7 @@ get_rel_from_relname(text *relname_text, LOCKMODE lockmode, AclMode aclmode)
 	AclResult	aclresult;
 
 	relvar = makeRangeVarFromNameList(textToQualifiedNameList(relname_text));
-	rel = heap_openrv(relvar, lockmode);
+	rel = heap_openrv(relvar, lockmode, false);
 
 	aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
 								  aclmode);
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index ef27cd4..9c535f9 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -184,7 +184,7 @@ bt_page_stats(PG_FUNCTION_ARGS)
 				 (errmsg("must be superuser to use pageinspect functions"))));
 
 	relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-	rel = relation_openrv(relrv, AccessShareLock);
+	rel = relation_openrv(relrv, AccessShareLock, false);
 
 	if (!IS_INDEX(rel) || !IS_BTREE(rel))
 		elog(ERROR, "relation \"%s\" is not a btree index",
@@ -302,7 +302,7 @@ bt_page_items(PG_FUNCTION_ARGS)
 		fctx = SRF_FIRSTCALL_INIT();
 
 		relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-		rel = relation_openrv(relrv, AccessShareLock);
+		rel = relation_openrv(relrv, AccessShareLock, false);
 
 		if (!IS_INDEX(rel) || !IS_BTREE(rel))
 			elog(ERROR, "relation \"%s\" is not a btree index",
@@ -451,7 +451,7 @@ bt_metap(PG_FUNCTION_ARGS)
 				 (errmsg("must be superuser to use pageinspect functions"))));
 
 	relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-	rel = relation_openrv(relrv, AccessShareLock);
+	rel = relation_openrv(relrv, AccessShareLock, false);
 
 	if (!IS_INDEX(rel) || !IS_BTREE(rel))
 		elog(ERROR, "relation \"%s\" is not a btree index",
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 2607576..427e916 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -106,7 +106,7 @@ get_raw_page_internal(text *relname, ForkNumber forknum, BlockNumber blkno)
 				 (errmsg("must be superuser to use raw functions"))));
 
 	relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-	rel = relation_openrv(relrv, AccessShareLock);
+	rel = relation_openrv(relrv, AccessShareLock, false);
 
 	/* Check that this relation has storage */
 	if (rel->rd_rel->relkind == RELKIND_VIEW)
diff --git a/contrib/pgrowlocks/pgrowlocks.c b/contrib/pgrowlocks/pgrowlocks.c
index 302bb5c..72c150c 100644
--- a/contrib/pgrowlocks/pgrowlocks.c
+++ b/contrib/pgrowlocks/pgrowlocks.c
@@ -90,7 +90,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
 
 		relname = PG_GETARG_TEXT_P(0);
 		relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-		rel = heap_openrv(relrv, AccessShareLock);
+		rel = heap_openrv(relrv, AccessShareLock, false);
 
 		/* check permissions: must have SELECT on table */
 		aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index fd2cc92..7900eae 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -101,7 +101,7 @@ pgstatindex(PG_FUNCTION_ARGS)
 				 (errmsg("must be superuser to use pgstattuple functions"))));
 
 	relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-	rel = relation_openrv(relrv, AccessShareLock);
+	rel = relation_openrv(relrv, AccessShareLock, false);
 
 	if (!IS_INDEX(rel) || !IS_BTREE(rel))
 		elog(ERROR, "relation \"%s\" is not a btree index",
@@ -270,7 +270,7 @@ pg_relpages(PG_FUNCTION_ARGS)
 				 (errmsg("must be superuser to use pgstattuple functions"))));
 
 	relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-	rel = relation_openrv(relrv, AccessShareLock);
+	rel = relation_openrv(relrv, AccessShareLock, false);
 
 	/* note: this will work OK on non-local temp tables */
 
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index e5ddd87..654af20 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -169,7 +169,7 @@ pgstattuple(PG_FUNCTION_ARGS)
 
 	/* open relation */
 	relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-	rel = relation_openrv(relrv, AccessShareLock);
+	rel = relation_openrv(relrv, AccessShareLock, false);
 
 	PG_RETURN_DATUM(pgstat_relation(rel, fcinfo));
 }
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index b947c11..0a64627 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -974,45 +974,14 @@ try_relation_open(Oid relationId, LOCKMODE lockmode)
  *		relation_openrv - open any relation specified by a RangeVar
  *
  *		Same as relation_open, but the relation is specified by a RangeVar.
- * ----------------
- */
-Relation
-relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
-{
-	Oid			relOid;
-
-	/*
-	 * Check for shared-cache-inval messages before trying to open the
-	 * relation.  This is needed to cover the case where the name identifies a
-	 * rel that has been dropped and recreated since the start of our
-	 * transaction: if we don't flush the old syscache entry then we'll latch
-	 * onto that entry and suffer an error when we do RelationIdGetRelation.
-	 * Note that relation_open does not need to do this, since a relation's
-	 * OID never changes.
-	 *
-	 * We skip this if asked for NoLock, on the assumption that the caller has
-	 * already ensured some appropriate lock is held.
-	 */
-	if (lockmode != NoLock)
-		AcceptInvalidationMessages();
-
-	/* Look up the appropriate relation using namespace search */
-	relOid = RangeVarGetRelid(relation, false);
-
-	/* Let relation_open do the rest */
-	return relation_open(relOid, lockmode);
-}
-
-/* ----------------
- *		try_relation_openrv - open any relation specified by a RangeVar
  *
- *		Same as relation_openrv, but return NULL instead of failing for
+ *		If missing_ok is true, return NULL instead of failing for
  *		relation-not-found.  (Note that some other causes, such as
  *		permissions problems, will still result in an ereport.)
  * ----------------
  */
 Relation
-try_relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
+relation_openrv(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok)
 {
 	Oid			relOid;
 
@@ -1032,7 +1001,7 @@ try_relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
 		AcceptInvalidationMessages();
 
 	/* Look up the appropriate relation using namespace search */
-	relOid = RangeVarGetRelid(relation, true);
+	relOid = RangeVarGetRelid(relation, missing_ok);
 
 	/* Return NULL on not-found */
 	if (!OidIsValid(relOid))
@@ -1104,39 +1073,11 @@ heap_open(Oid relationId, LOCKMODE lockmode)
  * ----------------
  */
 Relation
-heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
-{
-	Relation	r;
-
-	r = relation_openrv(relation, lockmode);
-
-	if (r->rd_rel->relkind == RELKIND_INDEX)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is an index",
-						RelationGetRelationName(r))));
-	else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is a composite type",
-						RelationGetRelationName(r))));
-
-	return r;
-}
-
-/* ----------------
- *		try_heap_openrv - open a heap relation specified
- *		by a RangeVar node
- *
- *		As above, but return NULL instead of failing for relation-not-found.
- * ----------------
- */
-Relation
-try_heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
+heap_openrv(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok)
 {
 	Relation	r;
 
-	r = try_relation_openrv(relation, lockmode);
+	r = relation_openrv(relation, lockmode, missing_ok);
 
 	if (r)
 	{
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index fc093cc..4533648 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -623,7 +623,7 @@ boot_openrel(char *relname)
 	elog(DEBUG4, "open relation %s, attrsize %d",
 		 relname, (int) ATTRIBUTE_FIXED_PART_SIZE);
 
-	boot_reldesc = heap_openrv(makeRangeVar(NULL, relname, -1), NoLock);
+	boot_reldesc = heap_openrv(makeRangeVar(NULL, relname, -1), NoLock, false);
 	numattr = boot_reldesc->rd_rel->relnatts;
 	for (i = 0; i < numattr; i++)
 	{
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index bf25091..b8a4cc3 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -381,7 +381,8 @@ get_relation_by_qualified_name(ObjectType objtype, List *objname,
 {
 	Relation	relation;
 
-	relation = relation_openrv(makeRangeVarFromNameList(objname), lockmode);
+	relation = relation_openrv(makeRangeVarFromNameList(objname), lockmode,
+							   false);
 	switch (objtype)
 	{
 		case OBJECT_INDEX:
@@ -473,7 +474,7 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
 		/* Extract relation name and open relation. */
 		relname = list_truncate(list_copy(objname), nnames - 1);
 		relation = heap_openrv(makeRangeVarFromNameList(relname),
-							   AccessShareLock);
+							   AccessShareLock, false);
 		reloid = RelationGetRelid(relation);
 
 		switch (objtype)
@@ -523,7 +524,8 @@ get_object_address_attribute(ObjectType objtype, List *objname,
 	/* Extract relation name and open relation. */
 	attname = strVal(lfirst(list_tail(objname)));
 	relname = list_truncate(list_copy(objname), list_length(objname) - 1);
-	relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
+	relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode,
+							   false);
 	reloid = RelationGetRelid(relation);
 
 	/* Look up attribute and construct return value. */
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index b059f9d..6634480 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -81,7 +81,8 @@ BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid)
 {
 	Relation	rel;
 
-	rel = heap_openrv(makeRangeVar(NULL, relName, -1), AccessExclusiveLock);
+	rel = heap_openrv(makeRangeVar(NULL, relName, -1), AccessExclusiveLock,
+					  false);
 
 	/* Note: during bootstrap may see uncataloged relation */
 	if (rel->rd_rel->relkind != RELKIND_RELATION &&
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 9a7649b..cb00369 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -115,7 +115,7 @@ cluster(ClusterStmt *stmt, bool isTopLevel)
 		Relation	rel;
 
 		/* Find and lock the table */
-		rel = heap_openrv(stmt->relation, AccessExclusiveLock);
+		rel = heap_openrv(stmt->relation, AccessExclusiveLock, false);
 
 		tableOid = RelationGetRelid(rel);
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 5742903..4eaaebd 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -758,7 +758,8 @@ DoCopy(const CopyStmt *stmt, const char *queryString)
 
 		/* Open and lock the relation, using the appropriate lock type. */
 		rel = heap_openrv(stmt->relation,
-						  (is_from ? RowExclusiveLock : AccessShareLock));
+						  (is_from ? RowExclusiveLock : AccessShareLock),
+						  false);
 
 		rte = makeNode(RangeTblEntry);
 		rte->rtekind = RTE_RELATION;
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b7c021d..f59e4dd 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -175,7 +175,8 @@ DefineIndex(RangeVar *heapRelation,
 	 * (but not VACUUM).
 	 */
 	rel = heap_openrv(heapRelation,
-					  (concurrent ? ShareUpdateExclusiveLock : ShareLock));
+					  (concurrent ? ShareUpdateExclusiveLock : ShareLock),
+					  false);
 
 	relationId = RelationGetRelid(rel);
 	namespaceId = RelationGetNamespace(rel);
@@ -505,7 +506,7 @@ DefineIndex(RangeVar *heapRelation,
 	 */
 
 	/* Open and lock the parent heap relation */
-	rel = heap_openrv(heapRelation, ShareUpdateExclusiveLock);
+	rel = heap_openrv(heapRelation, ShareUpdateExclusiveLock, false);
 
 	/* And the target index relation */
 	indexRelation = index_open(indexRelationId, RowExclusiveLock);
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index be04177..a5b407c 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1392,7 +1392,7 @@ process_owned_by(Relation seqrel, List *owned_by)
 
 		/* Open and lock rel to ensure it won't go away meanwhile */
 		rel = makeRangeVarFromNameList(relname);
-		tablerel = relation_openrv(rel, AccessShareLock);
+		tablerel = relation_openrv(rel, AccessShareLock, false);
 
 		/* Must be a regular table */
 		if (tablerel->rd_rel->relkind != RELKIND_RELATION)
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 557d541..4d6b44d 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -861,7 +861,7 @@ ExecuteTruncate(TruncateStmt *stmt)
 		bool		recurse = interpretInhOption(rv->inhOpt);
 		Oid			myrelid;
 
-		rel = heap_openrv(rv, AccessExclusiveLock);
+		rel = heap_openrv(rv, AccessExclusiveLock, false);
 		myrelid = RelationGetRelid(rel);
 		/* don't throw error for "TRUNCATE foo, foo" */
 		if (list_member_oid(relids, myrelid))
@@ -1345,7 +1345,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
 		 * parent's relhassubclass field, leading to a "tuple concurrently
 		 * updated" error.
 		 */
-		relation = heap_openrv(parent, ShareUpdateExclusiveLock);
+		relation = heap_openrv(parent, ShareUpdateExclusiveLock, false);
 
 		if (relation->rd_rel->relkind != RELKIND_RELATION)
 			ereport(ERROR,
@@ -2457,7 +2457,7 @@ AlterTable(AlterTableStmt *stmt)
 	/*
 	 * Acquire same level of lock as already acquired during parsing.
 	 */
-	rel = relation_openrv(stmt->relation, lockmode);
+	rel = relation_openrv(stmt->relation, lockmode, false);
 
 	CheckTableNotInUse(rel, "ALTER TABLE");
 
@@ -5479,7 +5479,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
 	Oid			indexOid;
 	Oid			constrOid;
 
-	pkrel = heap_openrv(fkconstraint->pktable, lockmode);
+	pkrel = heap_openrv(fkconstraint->pktable, lockmode, false);
 
 	/*
 	 * Validity checks (permission checks wait till we have the column
@@ -7265,7 +7265,7 @@ ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode)
 					IndexStmt  *stmt = (IndexStmt *) stm;
 					AlterTableCmd *newcmd;
 
-					rel = relation_openrv(stmt->relation, lockmode);
+					rel = relation_openrv(stmt->relation, lockmode, false);
 					tab = ATGetQueueEntry(wqueue, rel);
 					newcmd = makeNode(AlterTableCmd);
 					newcmd->subtype = AT_ReAddIndex;
@@ -7280,7 +7280,7 @@ ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode)
 					AlterTableStmt *stmt = (AlterTableStmt *) stm;
 					ListCell   *lcmd;
 
-					rel = relation_openrv(stmt->relation, lockmode);
+					rel = relation_openrv(stmt->relation, lockmode, false);
 					tab = ATGetQueueEntry(wqueue, rel);
 					foreach(lcmd, stmt->cmds)
 					{
@@ -8063,7 +8063,7 @@ ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
 	 * A self-exclusive lock is needed here.  See the similar case in
 	 * MergeAttributes() for a full explanation.
 	 */
-	parent_rel = heap_openrv(parent, ShareUpdateExclusiveLock);
+	parent_rel = heap_openrv(parent, ShareUpdateExclusiveLock, false);
 
 	/*
 	 * Must be owner of both parent and child -- child was checked by
@@ -8437,7 +8437,7 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
 	 * TABLE doesn't lock parent tables at all.  We need some lock since we'll
 	 * be inspecting the parent's schema.
 	 */
-	parent_rel = heap_openrv(parent, AccessShareLock);
+	parent_rel = heap_openrv(parent, AccessShareLock, false);
 
 	/*
 	 * We don't bother to check ownership of the parent table --- ownership of
@@ -8910,7 +8910,7 @@ AlterTableNamespace(RangeVar *relation, const char *newschema,
 	Oid			nspOid;
 	Relation	classRel;
 
-	rel = relation_openrv(relation, lockmode);
+	rel = relation_openrv(relation, lockmode, false);
 
 	relid = RelationGetRelid(rel);
 	oldNspOid = RelationGetNamespace(rel);
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 798d8a8..5b3a23c 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -150,7 +150,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 	 * triggers we would need to take an AccessExclusiveLock to add one of
 	 * those, just as we do with ON SELECT rules.
 	 */
-	rel = heap_openrv(stmt->relation, ShareRowExclusiveLock);
+	rel = heap_openrv(stmt->relation, ShareRowExclusiveLock, false);
 
 	/*
 	 * Triggers must be on tables or views, and there are additional
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 5359e69..3134882 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -826,7 +826,7 @@ parserOpenTable(ParseState *pstate, const RangeVar *relation, int lockmode)
 	ParseCallbackState pcbstate;
 
 	setup_parser_errposition_callback(&pcbstate, pstate, relation->location);
-	rel = try_heap_openrv(relation, lockmode);
+	rel = heap_openrv(relation, lockmode, true);
 	if (rel == NULL)
 	{
 		if (relation->schemaname)
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 622efe5..1800283 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -1656,7 +1656,7 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
 				int			count;
 
 				Assert(IsA(inh, RangeVar));
-				rel = heap_openrv(inh, AccessShareLock);
+				rel = heap_openrv(inh, AccessShareLock, false);
 				if (rel->rd_rel->relkind != RELKIND_RELATION)
 					ereport(ERROR,
 							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
@@ -1830,7 +1830,8 @@ transformIndexStmt(IndexStmt *stmt, const char *queryString)
 	 * already hold a higher lock.
 	 */
 	rel = heap_openrv(stmt->relation,
-				  (stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock));
+				  (stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock),
+					  false);
 
 	/* Set up pstate */
 	pstate = make_parsestate(NULL);
@@ -1928,7 +1929,7 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
 	 * DefineQueryRewrite(), and we don't want to grab a lesser lock
 	 * beforehand.
 	 */
-	rel = heap_openrv(stmt->relation, AccessExclusiveLock);
+	rel = heap_openrv(stmt->relation, AccessExclusiveLock, false);
 
 	/* Set up pstate */
 	pstate = make_parsestate(NULL);
@@ -2252,7 +2253,7 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString)
 	 * new commands we add after this must not upgrade the lock level
 	 * requested here.
 	 */
-	rel = relation_openrv(stmt->relation, lockmode);
+	rel = relation_openrv(stmt->relation, lockmode, false);
 
 	/* Set up pstate and CreateStmtContext */
 	pstate = make_parsestate(NULL);
diff --git a/src/backend/utils/adt/tid.c b/src/backend/utils/adt/tid.c
index 69e89b8..32f6da5 100644
--- a/src/backend/utils/adt/tid.c
+++ b/src/backend/utils/adt/tid.c
@@ -370,7 +370,7 @@ currtid_byrelname(PG_FUNCTION_ARGS)
 	AclResult	aclresult;
 
 	relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-	rel = heap_openrv(relrv, AccessShareLock);
+	rel = heap_openrv(relrv, AccessShareLock, false);
 
 	aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
 								  ACL_SELECT);
diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c
index aa249fa..a4c5510 100644
--- a/src/backend/utils/fmgr/funcapi.c
+++ b/src/backend/utils/fmgr/funcapi.c
@@ -1160,7 +1160,7 @@ RelationNameGetTupleDesc(const char *relname)
 	/* Open relation and copy the tuple description */
 	relname_list = stringToQualifiedNameList(relname);
 	relvar = makeRangeVarFromNameList(relname_list);
-	rel = relation_openrv(relvar, AccessShareLock);
+	rel = relation_openrv(relvar, AccessShareLock, false);
 	tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
 	relation_close(rel, AccessShareLock);
 
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index 4dbc393..a5c3ee6 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -49,13 +49,13 @@ typedef enum
 /* in heap/heapam.c */
 extern Relation relation_open(Oid relationId, LOCKMODE lockmode);
 extern Relation try_relation_open(Oid relationId, LOCKMODE lockmode);
-extern Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode);
-extern Relation try_relation_openrv(const RangeVar *relation, LOCKMODE lockmode);
+extern Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode,
+				bool missing_ok);
 extern void relation_close(Relation relation, LOCKMODE lockmode);
 
 extern Relation heap_open(Oid relationId, LOCKMODE lockmode);
-extern Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode);
-extern Relation try_heap_openrv(const RangeVar *relation, LOCKMODE lockmode);
+extern Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode,
+			bool missing_ok);
 
 #define heap_close(r,l)  relation_close(r,l)
 
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index 7b952b2..96c51bf 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -493,8 +493,8 @@ pltcl_init_load_unknown(Tcl_Interp *interp)
 	 * This is for backwards compatibility.  To ensure that the table
 	 * is trustworthy, we require it to be owned by a superuser.
 	 ************************************************************/
-	pmrel = try_relation_openrv(makeRangeVar(NULL, "pltcl_modules", -1),
-								AccessShareLock);
+	pmrel = relation_openrv(makeRangeVar(NULL, "pltcl_modules", -1),
+							AccessShareLock, false);
 	if (pmrel == NULL)
 		return;
 	/* must be table or view, else ignore */
#6Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#5)
Re: [v9.2] DROP Reworks Part.0 - 'missing_ok' support of get_object_address

Robert Haas <robertmhaas@gmail.com> writes:

Some of the refactoring you've done here seems likely to break things,
because you're basically making the relation locking happen later than
it does not, and that's going to cause problems.
get_object_address_relobject() is a particularly egregious
rearrangement. It seems to me that the right formula is to call
relation_openrv() if missing_ok is false, and try_relation_openrv() if
missing_ok is true. But that's sort of a pain, so I propose to first
apply the attached patch, which gets rid of try_relation_openrv() and
try_heap_openrv() and instead adds a missing_ok argument to
relation_openrv() and heap_openrv(). If we do this, then the
missing_ok argument can just be passed through all the way down.

Thoughts? Comments? Objections?

At least the last hunk (in pltcl.c) seems to have the flag backwards.

regards, tom lane

#7Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#6)
1 attachment(s)
Re: [v9.2] DROP Reworks Part.0 - 'missing_ok' support of get_object_address

On Tue, Jun 21, 2011 at 11:04 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

Some of the refactoring you've done here seems likely to break things,
because you're basically making the relation locking happen later than
it does not, and that's going to cause problems.
get_object_address_relobject() is a particularly egregious
rearrangement.  It seems to me that the right formula is to call
relation_openrv() if missing_ok is false, and try_relation_openrv() if
missing_ok is true.  But that's sort of a pain, so I propose to first
apply the attached patch, which gets rid of try_relation_openrv() and
try_heap_openrv() and instead adds a missing_ok argument to
relation_openrv() and heap_openrv().  If we do this, then the
missing_ok argument can just be passed through all the way down.

Thoughts?  Comments?  Objections?

At least the last hunk (in pltcl.c) seems to have the flag backwards.

Ah, nuts. Sorry. I think that and parse_relation.c are the only
places where the try variants are used; nobody else is willing to
fail, and everyone else is passing false.

Revised patch attached.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

Attachments:

there-is-no-try-v2.patchapplication/octet-stream; name=there-is-no-try-v2.patchDownload
diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 19b98fb..9d639f0 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -2044,7 +2044,7 @@ get_rel_from_relname(text *relname_text, LOCKMODE lockmode, AclMode aclmode)
 	AclResult	aclresult;
 
 	relvar = makeRangeVarFromNameList(textToQualifiedNameList(relname_text));
-	rel = heap_openrv(relvar, lockmode);
+	rel = heap_openrv(relvar, lockmode, false);
 
 	aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
 								  aclmode);
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index ef27cd4..9c535f9 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -184,7 +184,7 @@ bt_page_stats(PG_FUNCTION_ARGS)
 				 (errmsg("must be superuser to use pageinspect functions"))));
 
 	relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-	rel = relation_openrv(relrv, AccessShareLock);
+	rel = relation_openrv(relrv, AccessShareLock, false);
 
 	if (!IS_INDEX(rel) || !IS_BTREE(rel))
 		elog(ERROR, "relation \"%s\" is not a btree index",
@@ -302,7 +302,7 @@ bt_page_items(PG_FUNCTION_ARGS)
 		fctx = SRF_FIRSTCALL_INIT();
 
 		relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-		rel = relation_openrv(relrv, AccessShareLock);
+		rel = relation_openrv(relrv, AccessShareLock, false);
 
 		if (!IS_INDEX(rel) || !IS_BTREE(rel))
 			elog(ERROR, "relation \"%s\" is not a btree index",
@@ -451,7 +451,7 @@ bt_metap(PG_FUNCTION_ARGS)
 				 (errmsg("must be superuser to use pageinspect functions"))));
 
 	relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-	rel = relation_openrv(relrv, AccessShareLock);
+	rel = relation_openrv(relrv, AccessShareLock, false);
 
 	if (!IS_INDEX(rel) || !IS_BTREE(rel))
 		elog(ERROR, "relation \"%s\" is not a btree index",
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 2607576..427e916 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -106,7 +106,7 @@ get_raw_page_internal(text *relname, ForkNumber forknum, BlockNumber blkno)
 				 (errmsg("must be superuser to use raw functions"))));
 
 	relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-	rel = relation_openrv(relrv, AccessShareLock);
+	rel = relation_openrv(relrv, AccessShareLock, false);
 
 	/* Check that this relation has storage */
 	if (rel->rd_rel->relkind == RELKIND_VIEW)
diff --git a/contrib/pgrowlocks/pgrowlocks.c b/contrib/pgrowlocks/pgrowlocks.c
index 302bb5c..72c150c 100644
--- a/contrib/pgrowlocks/pgrowlocks.c
+++ b/contrib/pgrowlocks/pgrowlocks.c
@@ -90,7 +90,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
 
 		relname = PG_GETARG_TEXT_P(0);
 		relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-		rel = heap_openrv(relrv, AccessShareLock);
+		rel = heap_openrv(relrv, AccessShareLock, false);
 
 		/* check permissions: must have SELECT on table */
 		aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index fd2cc92..7900eae 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -101,7 +101,7 @@ pgstatindex(PG_FUNCTION_ARGS)
 				 (errmsg("must be superuser to use pgstattuple functions"))));
 
 	relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-	rel = relation_openrv(relrv, AccessShareLock);
+	rel = relation_openrv(relrv, AccessShareLock, false);
 
 	if (!IS_INDEX(rel) || !IS_BTREE(rel))
 		elog(ERROR, "relation \"%s\" is not a btree index",
@@ -270,7 +270,7 @@ pg_relpages(PG_FUNCTION_ARGS)
 				 (errmsg("must be superuser to use pgstattuple functions"))));
 
 	relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-	rel = relation_openrv(relrv, AccessShareLock);
+	rel = relation_openrv(relrv, AccessShareLock, false);
 
 	/* note: this will work OK on non-local temp tables */
 
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index e5ddd87..654af20 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -169,7 +169,7 @@ pgstattuple(PG_FUNCTION_ARGS)
 
 	/* open relation */
 	relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-	rel = relation_openrv(relrv, AccessShareLock);
+	rel = relation_openrv(relrv, AccessShareLock, false);
 
 	PG_RETURN_DATUM(pgstat_relation(rel, fcinfo));
 }
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 7bb4a87..f515f50 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -974,45 +974,14 @@ try_relation_open(Oid relationId, LOCKMODE lockmode)
  *		relation_openrv - open any relation specified by a RangeVar
  *
  *		Same as relation_open, but the relation is specified by a RangeVar.
- * ----------------
- */
-Relation
-relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
-{
-	Oid			relOid;
-
-	/*
-	 * Check for shared-cache-inval messages before trying to open the
-	 * relation.  This is needed to cover the case where the name identifies a
-	 * rel that has been dropped and recreated since the start of our
-	 * transaction: if we don't flush the old syscache entry then we'll latch
-	 * onto that entry and suffer an error when we do RelationIdGetRelation.
-	 * Note that relation_open does not need to do this, since a relation's
-	 * OID never changes.
-	 *
-	 * We skip this if asked for NoLock, on the assumption that the caller has
-	 * already ensured some appropriate lock is held.
-	 */
-	if (lockmode != NoLock)
-		AcceptInvalidationMessages();
-
-	/* Look up the appropriate relation using namespace search */
-	relOid = RangeVarGetRelid(relation, false);
-
-	/* Let relation_open do the rest */
-	return relation_open(relOid, lockmode);
-}
-
-/* ----------------
- *		try_relation_openrv - open any relation specified by a RangeVar
  *
- *		Same as relation_openrv, but return NULL instead of failing for
+ *		If missing_ok is true, return NULL instead of failing for
  *		relation-not-found.  (Note that some other causes, such as
  *		permissions problems, will still result in an ereport.)
  * ----------------
  */
 Relation
-try_relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
+relation_openrv(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok)
 {
 	Oid			relOid;
 
@@ -1032,7 +1001,7 @@ try_relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
 		AcceptInvalidationMessages();
 
 	/* Look up the appropriate relation using namespace search */
-	relOid = RangeVarGetRelid(relation, true);
+	relOid = RangeVarGetRelid(relation, missing_ok);
 
 	/* Return NULL on not-found */
 	if (!OidIsValid(relOid))
@@ -1104,39 +1073,11 @@ heap_open(Oid relationId, LOCKMODE lockmode)
  * ----------------
  */
 Relation
-heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
-{
-	Relation	r;
-
-	r = relation_openrv(relation, lockmode);
-
-	if (r->rd_rel->relkind == RELKIND_INDEX)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is an index",
-						RelationGetRelationName(r))));
-	else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is a composite type",
-						RelationGetRelationName(r))));
-
-	return r;
-}
-
-/* ----------------
- *		try_heap_openrv - open a heap relation specified
- *		by a RangeVar node
- *
- *		As above, but return NULL instead of failing for relation-not-found.
- * ----------------
- */
-Relation
-try_heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
+heap_openrv(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok)
 {
 	Relation	r;
 
-	r = try_relation_openrv(relation, lockmode);
+	r = relation_openrv(relation, lockmode, missing_ok);
 
 	if (r)
 	{
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index fc093cc..4533648 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -623,7 +623,7 @@ boot_openrel(char *relname)
 	elog(DEBUG4, "open relation %s, attrsize %d",
 		 relname, (int) ATTRIBUTE_FIXED_PART_SIZE);
 
-	boot_reldesc = heap_openrv(makeRangeVar(NULL, relname, -1), NoLock);
+	boot_reldesc = heap_openrv(makeRangeVar(NULL, relname, -1), NoLock, false);
 	numattr = boot_reldesc->rd_rel->relnatts;
 	for (i = 0; i < numattr; i++)
 	{
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index bf25091..b8a4cc3 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -381,7 +381,8 @@ get_relation_by_qualified_name(ObjectType objtype, List *objname,
 {
 	Relation	relation;
 
-	relation = relation_openrv(makeRangeVarFromNameList(objname), lockmode);
+	relation = relation_openrv(makeRangeVarFromNameList(objname), lockmode,
+							   false);
 	switch (objtype)
 	{
 		case OBJECT_INDEX:
@@ -473,7 +474,7 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
 		/* Extract relation name and open relation. */
 		relname = list_truncate(list_copy(objname), nnames - 1);
 		relation = heap_openrv(makeRangeVarFromNameList(relname),
-							   AccessShareLock);
+							   AccessShareLock, false);
 		reloid = RelationGetRelid(relation);
 
 		switch (objtype)
@@ -523,7 +524,8 @@ get_object_address_attribute(ObjectType objtype, List *objname,
 	/* Extract relation name and open relation. */
 	attname = strVal(lfirst(list_tail(objname)));
 	relname = list_truncate(list_copy(objname), list_length(objname) - 1);
-	relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
+	relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode,
+							   false);
 	reloid = RelationGetRelid(relation);
 
 	/* Look up attribute and construct return value. */
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index b059f9d..6634480 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -81,7 +81,8 @@ BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid)
 {
 	Relation	rel;
 
-	rel = heap_openrv(makeRangeVar(NULL, relName, -1), AccessExclusiveLock);
+	rel = heap_openrv(makeRangeVar(NULL, relName, -1), AccessExclusiveLock,
+					  false);
 
 	/* Note: during bootstrap may see uncataloged relation */
 	if (rel->rd_rel->relkind != RELKIND_RELATION &&
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 9a7649b..cb00369 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -115,7 +115,7 @@ cluster(ClusterStmt *stmt, bool isTopLevel)
 		Relation	rel;
 
 		/* Find and lock the table */
-		rel = heap_openrv(stmt->relation, AccessExclusiveLock);
+		rel = heap_openrv(stmt->relation, AccessExclusiveLock, false);
 
 		tableOid = RelationGetRelid(rel);
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 5742903..4eaaebd 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -758,7 +758,8 @@ DoCopy(const CopyStmt *stmt, const char *queryString)
 
 		/* Open and lock the relation, using the appropriate lock type. */
 		rel = heap_openrv(stmt->relation,
-						  (is_from ? RowExclusiveLock : AccessShareLock));
+						  (is_from ? RowExclusiveLock : AccessShareLock),
+						  false);
 
 		rte = makeNode(RangeTblEntry);
 		rte->rtekind = RTE_RELATION;
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b7c021d..f59e4dd 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -175,7 +175,8 @@ DefineIndex(RangeVar *heapRelation,
 	 * (but not VACUUM).
 	 */
 	rel = heap_openrv(heapRelation,
-					  (concurrent ? ShareUpdateExclusiveLock : ShareLock));
+					  (concurrent ? ShareUpdateExclusiveLock : ShareLock),
+					  false);
 
 	relationId = RelationGetRelid(rel);
 	namespaceId = RelationGetNamespace(rel);
@@ -505,7 +506,7 @@ DefineIndex(RangeVar *heapRelation,
 	 */
 
 	/* Open and lock the parent heap relation */
-	rel = heap_openrv(heapRelation, ShareUpdateExclusiveLock);
+	rel = heap_openrv(heapRelation, ShareUpdateExclusiveLock, false);
 
 	/* And the target index relation */
 	indexRelation = index_open(indexRelationId, RowExclusiveLock);
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index be04177..a5b407c 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1392,7 +1392,7 @@ process_owned_by(Relation seqrel, List *owned_by)
 
 		/* Open and lock rel to ensure it won't go away meanwhile */
 		rel = makeRangeVarFromNameList(relname);
-		tablerel = relation_openrv(rel, AccessShareLock);
+		tablerel = relation_openrv(rel, AccessShareLock, false);
 
 		/* Must be a regular table */
 		if (tablerel->rd_rel->relkind != RELKIND_RELATION)
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index b2ba11c..afd066f 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -862,7 +862,7 @@ ExecuteTruncate(TruncateStmt *stmt)
 		bool		recurse = interpretInhOption(rv->inhOpt);
 		Oid			myrelid;
 
-		rel = heap_openrv(rv, AccessExclusiveLock);
+		rel = heap_openrv(rv, AccessExclusiveLock, false);
 		myrelid = RelationGetRelid(rel);
 		/* don't throw error for "TRUNCATE foo, foo" */
 		if (list_member_oid(relids, myrelid))
@@ -1346,7 +1346,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
 		 * parent's relhassubclass field, leading to a "tuple concurrently
 		 * updated" error.
 		 */
-		relation = heap_openrv(parent, ShareUpdateExclusiveLock);
+		relation = heap_openrv(parent, ShareUpdateExclusiveLock, false);
 
 		if (relation->rd_rel->relkind != RELKIND_RELATION)
 			ereport(ERROR,
@@ -2458,7 +2458,7 @@ AlterTable(AlterTableStmt *stmt)
 	/*
 	 * Acquire same level of lock as already acquired during parsing.
 	 */
-	rel = relation_openrv(stmt->relation, lockmode);
+	rel = relation_openrv(stmt->relation, lockmode, false);
 
 	CheckTableNotInUse(rel, "ALTER TABLE");
 
@@ -5481,7 +5481,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
 	Oid			indexOid;
 	Oid			constrOid;
 
-	pkrel = heap_openrv(fkconstraint->pktable, lockmode);
+	pkrel = heap_openrv(fkconstraint->pktable, lockmode, false);
 
 	/*
 	 * Validity checks (permission checks wait till we have the column
@@ -7270,7 +7270,7 @@ ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode)
 					IndexStmt  *stmt = (IndexStmt *) stm;
 					AlterTableCmd *newcmd;
 
-					rel = relation_openrv(stmt->relation, lockmode);
+					rel = relation_openrv(stmt->relation, lockmode, false);
 					tab = ATGetQueueEntry(wqueue, rel);
 					newcmd = makeNode(AlterTableCmd);
 					newcmd->subtype = AT_ReAddIndex;
@@ -7285,7 +7285,7 @@ ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode)
 					AlterTableStmt *stmt = (AlterTableStmt *) stm;
 					ListCell   *lcmd;
 
-					rel = relation_openrv(stmt->relation, lockmode);
+					rel = relation_openrv(stmt->relation, lockmode, false);
 					tab = ATGetQueueEntry(wqueue, rel);
 					foreach(lcmd, stmt->cmds)
 					{
@@ -8068,7 +8068,7 @@ ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
 	 * A self-exclusive lock is needed here.  See the similar case in
 	 * MergeAttributes() for a full explanation.
 	 */
-	parent_rel = heap_openrv(parent, ShareUpdateExclusiveLock);
+	parent_rel = heap_openrv(parent, ShareUpdateExclusiveLock, false);
 
 	/*
 	 * Must be owner of both parent and child -- child was checked by
@@ -8442,7 +8442,7 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
 	 * TABLE doesn't lock parent tables at all.  We need some lock since we'll
 	 * be inspecting the parent's schema.
 	 */
-	parent_rel = heap_openrv(parent, AccessShareLock);
+	parent_rel = heap_openrv(parent, AccessShareLock, false);
 
 	/*
 	 * We don't bother to check ownership of the parent table --- ownership of
@@ -8915,7 +8915,7 @@ AlterTableNamespace(RangeVar *relation, const char *newschema,
 	Oid			nspOid;
 	Relation	classRel;
 
-	rel = relation_openrv(relation, lockmode);
+	rel = relation_openrv(relation, lockmode, false);
 
 	relid = RelationGetRelid(rel);
 	oldNspOid = RelationGetNamespace(rel);
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 798d8a8..5b3a23c 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -150,7 +150,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 	 * triggers we would need to take an AccessExclusiveLock to add one of
 	 * those, just as we do with ON SELECT rules.
 	 */
-	rel = heap_openrv(stmt->relation, ShareRowExclusiveLock);
+	rel = heap_openrv(stmt->relation, ShareRowExclusiveLock, false);
 
 	/*
 	 * Triggers must be on tables or views, and there are additional
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 5359e69..3134882 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -826,7 +826,7 @@ parserOpenTable(ParseState *pstate, const RangeVar *relation, int lockmode)
 	ParseCallbackState pcbstate;
 
 	setup_parser_errposition_callback(&pcbstate, pstate, relation->location);
-	rel = try_heap_openrv(relation, lockmode);
+	rel = heap_openrv(relation, lockmode, true);
 	if (rel == NULL)
 	{
 		if (relation->schemaname)
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 8744654..4efab09 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -1663,7 +1663,7 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
 				int			count;
 
 				Assert(IsA(inh, RangeVar));
-				rel = heap_openrv(inh, AccessShareLock);
+				rel = heap_openrv(inh, AccessShareLock, false);
 				if (rel->rd_rel->relkind != RELKIND_RELATION)
 					ereport(ERROR,
 							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
@@ -1837,7 +1837,8 @@ transformIndexStmt(IndexStmt *stmt, const char *queryString)
 	 * already hold a higher lock.
 	 */
 	rel = heap_openrv(stmt->relation,
-				  (stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock));
+				  (stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock),
+					  false);
 
 	/* Set up pstate */
 	pstate = make_parsestate(NULL);
@@ -1935,7 +1936,7 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
 	 * DefineQueryRewrite(), and we don't want to grab a lesser lock
 	 * beforehand.
 	 */
-	rel = heap_openrv(stmt->relation, AccessExclusiveLock);
+	rel = heap_openrv(stmt->relation, AccessExclusiveLock, false);
 
 	/* Set up pstate */
 	pstate = make_parsestate(NULL);
@@ -2259,7 +2260,7 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString)
 	 * new commands we add after this must not upgrade the lock level
 	 * requested here.
 	 */
-	rel = relation_openrv(stmt->relation, lockmode);
+	rel = relation_openrv(stmt->relation, lockmode, false);
 
 	/* Set up pstate and CreateStmtContext */
 	pstate = make_parsestate(NULL);
diff --git a/src/backend/utils/adt/tid.c b/src/backend/utils/adt/tid.c
index 69e89b8..32f6da5 100644
--- a/src/backend/utils/adt/tid.c
+++ b/src/backend/utils/adt/tid.c
@@ -370,7 +370,7 @@ currtid_byrelname(PG_FUNCTION_ARGS)
 	AclResult	aclresult;
 
 	relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-	rel = heap_openrv(relrv, AccessShareLock);
+	rel = heap_openrv(relrv, AccessShareLock, false);
 
 	aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
 								  ACL_SELECT);
diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c
index aa249fa..a4c5510 100644
--- a/src/backend/utils/fmgr/funcapi.c
+++ b/src/backend/utils/fmgr/funcapi.c
@@ -1160,7 +1160,7 @@ RelationNameGetTupleDesc(const char *relname)
 	/* Open relation and copy the tuple description */
 	relname_list = stringToQualifiedNameList(relname);
 	relvar = makeRangeVarFromNameList(relname_list);
-	rel = relation_openrv(relvar, AccessShareLock);
+	rel = relation_openrv(relvar, AccessShareLock, false);
 	tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
 	relation_close(rel, AccessShareLock);
 
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index fc65761..5391e86 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -49,13 +49,13 @@ typedef enum
 /* in heap/heapam.c */
 extern Relation relation_open(Oid relationId, LOCKMODE lockmode);
 extern Relation try_relation_open(Oid relationId, LOCKMODE lockmode);
-extern Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode);
-extern Relation try_relation_openrv(const RangeVar *relation, LOCKMODE lockmode);
+extern Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode,
+				bool missing_ok);
 extern void relation_close(Relation relation, LOCKMODE lockmode);
 
 extern Relation heap_open(Oid relationId, LOCKMODE lockmode);
-extern Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode);
-extern Relation try_heap_openrv(const RangeVar *relation, LOCKMODE lockmode);
+extern Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode,
+			bool missing_ok);
 
 #define heap_close(r,l)  relation_close(r,l)
 
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index 7b952b2..e89c485 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -493,8 +493,8 @@ pltcl_init_load_unknown(Tcl_Interp *interp)
 	 * This is for backwards compatibility.  To ensure that the table
 	 * is trustworthy, we require it to be owned by a superuser.
 	 ************************************************************/
-	pmrel = try_relation_openrv(makeRangeVar(NULL, "pltcl_modules", -1),
-								AccessShareLock);
+	pmrel = relation_openrv(makeRangeVar(NULL, "pltcl_modules", -1),
+							AccessShareLock, true);
 	if (pmrel == NULL)
 		return;
 	/* must be table or view, else ignore */
#8Noah Misch
noah@leadboat.com
In reply to: Robert Haas (#7)
Re: [v9.2] DROP Reworks Part.0 - 'missing_ok' support of get_object_address

On Tue, Jun 21, 2011 at 11:11:41PM -0400, Robert Haas wrote:

On Tue, Jun 21, 2011 at 11:04 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

Some of the refactoring you've done here seems likely to break things,
because you're basically making the relation locking happen later than
it does not, and that's going to cause problems.
get_object_address_relobject() is a particularly egregious
rearrangement. ?It seems to me that the right formula is to call
relation_openrv() if missing_ok is false, and try_relation_openrv() if
missing_ok is true. ?But that's sort of a pain, so I propose to first
apply the attached patch, which gets rid of try_relation_openrv() and
try_heap_openrv() and instead adds a missing_ok argument to
relation_openrv() and heap_openrv(). ?If we do this, then the
missing_ok argument can just be passed through all the way down.

Thoughts? ?Comments? ?Objections?

At least the last hunk (in pltcl.c) seems to have the flag backwards.

Ah, nuts. Sorry. I think that and parse_relation.c are the only
places where the try variants are used; nobody else is willing to
fail, and everyone else is passing false.

Revised patch attached.

All existing call sites updated by this patch hardcode the flag, and only 3?
proposed call sites would take advantage of the ability to not do so. The
try_relation_openrv() case is fairly rare and likely to remain that way. Given
that, I mildly prefer the code as it is, even if that means doing "missing_ok ?
try_relation_openrv() : relation_openrv()" in a few places. Could always wrap
that in a static function of objectaddress.c.

#9Robert Haas
robertmhaas@gmail.com
In reply to: Noah Misch (#8)
Re: [v9.2] DROP Reworks Part.0 - 'missing_ok' support of get_object_address

On Wed, Jun 22, 2011 at 6:18 AM, Noah Misch <noah@leadboat.com> wrote:

On Tue, Jun 21, 2011 at 11:11:41PM -0400, Robert Haas wrote:

On Tue, Jun 21, 2011 at 11:04 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

Some of the refactoring you've done here seems likely to break things,
because you're basically making the relation locking happen later than
it does not, and that's going to cause problems.
get_object_address_relobject() is a particularly egregious
rearrangement. ?It seems to me that the right formula is to call
relation_openrv() if missing_ok is false, and try_relation_openrv() if
missing_ok is true. ?But that's sort of a pain, so I propose to first
apply the attached patch, which gets rid of try_relation_openrv() and
try_heap_openrv() and instead adds a missing_ok argument to
relation_openrv() and heap_openrv(). ?If we do this, then the
missing_ok argument can just be passed through all the way down.

Thoughts? ?Comments? ?Objections?

At least the last hunk (in pltcl.c) seems to have the flag backwards.

Ah, nuts.  Sorry.  I think that and parse_relation.c are the only
places where the try variants are used; nobody else is willing to
fail, and everyone else is passing false.

Revised patch attached.

All existing call sites updated by this patch hardcode the flag, and only 3?
proposed call sites would take advantage of the ability to not do so.  The
try_relation_openrv() case is fairly rare and likely to remain that way.  Given
that, I mildly prefer the code as it is, even if that means doing "missing_ok ?
try_relation_openrv() : relation_openrv()" in a few places.  Could always wrap
that in a static function of objectaddress.c.

I don't really like the idea of having a static function in
objectaddress.c, because I think there will eventually be more callers
who sometimes want to pass missing_ok = true and other times pass
missing_ok = false. Plus, it seems a little nutty to have a function
that, depending on whether its argument is true or false, calls one of
two other functions which are virtually cut-and-paste copies of each
other, except that one internally has true and the other false. I
just work here, though.

Another option might be to leave heap_openrv() and relation_openrv()
alone and add a missing_ok argument to try_heap_openrv() and
try_relation_openrv(). Passing true would give the same behavior as
presently; passing false would make them behave like the non-try
version.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#10Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#9)
Re: [v9.2] DROP Reworks Part.0 - 'missing_ok' support of get_object_address

Robert Haas <robertmhaas@gmail.com> writes:

Another option might be to leave heap_openrv() and relation_openrv()
alone and add a missing_ok argument to try_heap_openrv() and
try_relation_openrv().

+1 for that, although the try_ prefix might be inappropriate naming
now; how about cond_relation_openrv?

regards, tom lane

#11Alvaro Herrera
alvherre@commandprompt.com
In reply to: Robert Haas (#9)
Re: [v9.2] DROP Reworks Part.0 - 'missing_ok' support of get_object_address

Excerpts from Robert Haas's message of mié jun 22 08:56:02 -0400 2011:

Another option might be to leave heap_openrv() and relation_openrv()
alone and add a missing_ok argument to try_heap_openrv() and
try_relation_openrv(). Passing true would give the same behavior as
presently; passing false would make them behave like the non-try
version.

That would be pretty weird, having two functions, one of them sometimes
doing the same thing as the other one.

I understand Noah's concern but I think your original proposal was saner
than both options presented so far.

--
Álvaro Herrera <alvherre@commandprompt.com>
The PostgreSQL Company - Command Prompt, Inc.
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

#12Robert Haas
robertmhaas@gmail.com
In reply to: Alvaro Herrera (#11)
Re: [v9.2] DROP Reworks Part.0 - 'missing_ok' support of get_object_address

On Wed, Jun 22, 2011 at 12:51 PM, Alvaro Herrera
<alvherre@commandprompt.com> wrote:

Excerpts from Robert Haas's message of mié jun 22 08:56:02 -0400 2011:

Another option might be to leave heap_openrv() and relation_openrv()
alone and add a missing_ok argument to try_heap_openrv() and
try_relation_openrv().  Passing true would give the same behavior as
presently; passing false would make them behave like the non-try
version.

That would be pretty weird, having two functions, one of them sometimes
doing the same thing as the other one.

I understand Noah's concern but I think your original proposal was saner
than both options presented so far.

I agree with you. If we had a whole pile of options it might be worth
having heap_openrv() and heap_openrv_extended() so as not to
complicate the simple case, but since there's no forseeable need to
add anything other than missing_ok, my gut is to just add it and call
it good.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#13Kohei KaiGai
kaigai@kaigai.gr.jp
In reply to: Robert Haas (#12)
1 attachment(s)
Re: [v9.2] DROP Reworks Part.0 - 'missing_ok' support of get_object_address

I revised my patch based on your "there-is-no-try-v2.patch".
It enabled to implement 'missing_ok' support without modification of
orders to solve the object name and relation locking.

Thanks,

2011/6/22 Robert Haas <robertmhaas@gmail.com>:

On Wed, Jun 22, 2011 at 12:51 PM, Alvaro Herrera
<alvherre@commandprompt.com> wrote:

Excerpts from Robert Haas's message of mié jun 22 08:56:02 -0400 2011:

Another option might be to leave heap_openrv() and relation_openrv()
alone and add a missing_ok argument to try_heap_openrv() and
try_relation_openrv().  Passing true would give the same behavior as
presently; passing false would make them behave like the non-try
version.

That would be pretty weird, having two functions, one of them sometimes
doing the same thing as the other one.

I understand Noah's concern but I think your original proposal was saner
than both options presented so far.

I agree with you.  If we had a whole pile of options it might be worth
having heap_openrv() and heap_openrv_extended() so as not to
complicate the simple case, but since there's no forseeable need to
add anything other than missing_ok, my gut is to just add it and call
it good.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
KaiGai Kohei <kaigai@kaigai.gr.jp>

Attachments:

pgsql-v9.2-drop-reworks-part-0.v4.patchapplication/octet-stream; name=pgsql-v9.2-drop-reworks-part-0.v4.patchDownload
 src/backend/catalog/objectaddress.c  |  211 ++++++++++++++++++++++++----------
 src/backend/commands/comment.c       |    2 +-
 src/backend/commands/extension.c     |    2 +-
 src/backend/commands/seclabel.c      |    2 +-
 src/backend/rewrite/rewriteSupport.c |   37 ++++---
 src/include/catalog/objectaddress.h  |    3 +-
 src/include/rewrite/rewriteSupport.h |    3 +-
 7 files changed, 179 insertions(+), 81 deletions(-)

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index b8a4cc3..da84fe8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -72,15 +72,19 @@
 #include "utils/tqual.h"
 
 static ObjectAddress get_object_address_unqualified(ObjectType objtype,
-							   List *qualname);
-static Relation get_relation_by_qualified_name(ObjectType objtype,
-							   List *objname, LOCKMODE lockmode);
+							   List *qualname, bool missing_ok);
+static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
+							   List *objname, Relation *relp,
+							   LOCKMODE lockmode, bool missing_ok);
 static ObjectAddress get_object_address_relobject(ObjectType objtype,
-							 List *objname, Relation *relp);
+						   List *objname, Relation *relp, bool missing_ok);
 static ObjectAddress get_object_address_attribute(ObjectType objtype,
-						   List *objname, Relation *relp, LOCKMODE lockmode);
+						   List *objname, Relation *relp,
+						   LOCKMODE lockmode, bool missing_ok);
+static ObjectAddress get_object_address_type(ObjectType objtype,
+						   List *objname, bool missing_ok);
 static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname,
-						List *objargs);
+						   List *objargs, bool missing_ok);
 static bool object_exists(ObjectAddress address);
 
 
@@ -106,7 +110,7 @@ static bool object_exists(ObjectAddress address);
  */
 ObjectAddress
 get_object_address(ObjectType objtype, List *objname, List *objargs,
-				   Relation *relp, LOCKMODE lockmode)
+				   Relation *relp, LOCKMODE lockmode, bool missing_ok)
 {
 	ObjectAddress address;
 	Relation	relation = NULL;
@@ -121,21 +125,22 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 		case OBJECT_TABLE:
 		case OBJECT_VIEW:
 		case OBJECT_FOREIGN_TABLE:
-			relation =
-				get_relation_by_qualified_name(objtype, objname, lockmode);
-			address.classId = RelationRelationId;
-			address.objectId = RelationGetRelid(relation);
-			address.objectSubId = 0;
+			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);
+				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);
+			address = get_object_address_relobject(objtype, objname,
+												   &relation, missing_ok);
 			break;
 		case OBJECT_DATABASE:
 		case OBJECT_EXTENSION:
@@ -145,23 +150,23 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 		case OBJECT_LANGUAGE:
 		case OBJECT_FDW:
 		case OBJECT_FOREIGN_SERVER:
-			address = get_object_address_unqualified(objtype, objname);
+			address = get_object_address_unqualified(objtype,
+													 objname, missing_ok);
 			break;
 		case OBJECT_TYPE:
 		case OBJECT_DOMAIN:
-			address.classId = TypeRelationId;
-			address.objectId =
-				typenameTypeId(NULL, makeTypeNameFromNameList(objname));
-			address.objectSubId = 0;
+			address = get_object_address_type(objtype, objname, missing_ok);
 			break;
 		case OBJECT_AGGREGATE:
 			address.classId = ProcedureRelationId;
-			address.objectId = LookupAggNameTypeNames(objname, objargs, false);
+			address.objectId =
+				LookupAggNameTypeNames(objname, objargs, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_FUNCTION:
 			address.classId = ProcedureRelationId;
-			address.objectId = LookupFuncNameTypeNames(objname, objargs, false);
+			address.objectId =
+				LookupFuncNameTypeNames(objname, objargs, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_OPERATOR:
@@ -171,22 +176,23 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 				LookupOperNameTypeNames(NULL, objname,
 										(TypeName *) linitial(objargs),
 										(TypeName *) lsecond(objargs),
-										false, -1);
+										missing_ok, -1);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_COLLATION:
 			address.classId = CollationRelationId;
-			address.objectId = get_collation_oid(objname, false);
+			address.objectId = get_collation_oid(objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_CONVERSION:
 			address.classId = ConversionRelationId;
-			address.objectId = get_conversion_oid(objname, false);
+			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);
+			address = get_object_address_opcf(objtype,
+											  objname, objargs, missing_ok);
 			break;
 		case OBJECT_LARGEOBJECT:
 			Assert(list_length(objname) == 1);
@@ -194,10 +200,13 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 			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:
 			{
@@ -208,28 +217,28 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 
 				address.classId = CastRelationId;
 				address.objectId =
-					get_cast_oid(sourcetypeid, targettypeid, false);
+					get_cast_oid(sourcetypeid, targettypeid, missing_ok);
 				address.objectSubId = 0;
 			}
 			break;
 		case OBJECT_TSPARSER:
 			address.classId = TSParserRelationId;
-			address.objectId = get_ts_parser_oid(objname, false);
+			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, false);
+			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, false);
+			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, false);
+			address.objectId = get_ts_config_oid(objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		default:
@@ -241,6 +250,15 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 	}
 
 	/*
+	 * 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.	If we're dealing with any other type of object, we
 	 * need to lock it and then verify that it still exists.
@@ -267,7 +285,8 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
  * unqualified name.
  */
 static ObjectAddress
-get_object_address_unqualified(ObjectType objtype, List *qualname)
+get_object_address_unqualified(ObjectType objtype,
+							   List *qualname, bool missing_ok)
 {
 	const char *name;
 	ObjectAddress address;
@@ -323,42 +342,42 @@ get_object_address_unqualified(ObjectType objtype, List *qualname)
 	{
 		case OBJECT_DATABASE:
 			address.classId = DatabaseRelationId;
-			address.objectId = get_database_oid(name, false);
+			address.objectId = get_database_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_EXTENSION:
 			address.classId = ExtensionRelationId;
-			address.objectId = get_extension_oid(name, false);
+			address.objectId = get_extension_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_TABLESPACE:
 			address.classId = TableSpaceRelationId;
-			address.objectId = get_tablespace_oid(name, false);
+			address.objectId = get_tablespace_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_ROLE:
 			address.classId = AuthIdRelationId;
-			address.objectId = get_role_oid(name, false);
+			address.objectId = get_role_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_SCHEMA:
 			address.classId = NamespaceRelationId;
-			address.objectId = get_namespace_oid(name, false);
+			address.objectId = get_namespace_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_LANGUAGE:
 			address.classId = LanguageRelationId;
-			address.objectId = get_language_oid(name, false);
+			address.objectId = get_language_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_FDW:
 			address.classId = ForeignDataWrapperRelationId;
-			address.objectId = get_foreign_data_wrapper_oid(name, false);
+			address.objectId = get_foreign_data_wrapper_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_FOREIGN_SERVER:
 			address.classId = ForeignServerRelationId;
-			address.objectId = get_foreign_server_oid(name, false);
+			address.objectId = get_foreign_server_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		default:
@@ -375,14 +394,23 @@ get_object_address_unqualified(ObjectType objtype, List *qualname)
 /*
  * Locate a relation by qualified name.
  */
-static Relation
+static ObjectAddress
 get_relation_by_qualified_name(ObjectType objtype, List *objname,
-							   LOCKMODE lockmode)
+                               Relation *relp, LOCKMODE lockmode,
+							   bool missing_ok)
 {
+	ObjectAddress	address;
 	Relation	relation;
 
-	relation = relation_openrv(makeRangeVarFromNameList(objname), lockmode,
-							   false);
+	address.classId = RelationRelationId;
+	address.objectId = InvalidOid;
+	address.objectSubId = 0;
+
+	relation = relation_openrv(makeRangeVarFromNameList(objname),
+							   lockmode, missing_ok);
+	if (!relation)
+		return address;
+
 	switch (objtype)
 	{
 		case OBJECT_INDEX:
@@ -425,7 +453,11 @@ get_relation_by_qualified_name(ObjectType objtype, List *objname,
 			break;
 	}
 
-	return relation;
+	/* Done */
+	address.objectId = RelationGetRelid(relation);
+	*relp = relation;
+
+	return address;
 }
 
 /*
@@ -436,7 +468,8 @@ get_relation_by_qualified_name(ObjectType objtype, List *objname,
  * mode for the object itself, not the relation to which it is attached.
  */
 static ObjectAddress
-get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
+get_object_address_relobject(ObjectType objtype, List *objname,
+							 Relation *relp, bool missing_ok)
 {
 	ObjectAddress address;
 	Relation	relation = NULL;
@@ -462,9 +495,9 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
 		if (objtype != OBJECT_RULE)
 			elog(ERROR, "must specify relation and object name");
 		address.classId = RewriteRelationId;
-		address.objectId = get_rewrite_oid_without_relid(depname, &reloid);
+		address.objectId =
+			get_rewrite_oid_without_relid(depname, &reloid, missing_ok);
 		address.objectSubId = 0;
-		relation = heap_open(reloid, AccessShareLock);
 	}
 	else
 	{
@@ -481,17 +514,18 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
 		{
 			case OBJECT_RULE:
 				address.classId = RewriteRelationId;
-				address.objectId = get_rewrite_oid(reloid, depname, false);
+				address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
 				address.objectSubId = 0;
 				break;
 			case OBJECT_TRIGGER:
 				address.classId = TriggerRelationId;
-				address.objectId = get_trigger_oid(reloid, depname, false);
+				address.objectId = get_trigger_oid(reloid, depname, missing_ok);
 				address.objectSubId = 0;
 				break;
 			case OBJECT_CONSTRAINT:
 				address.classId = ConstraintRelationId;
-				address.objectId = get_constraint_oid(reloid, depname, false);
+				address.objectId =
+					get_constraint_oid(reloid, depname, missing_ok);
 				address.objectSubId = 0;
 				break;
 			default:
@@ -513,13 +547,15 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
  */
 static ObjectAddress
 get_object_address_attribute(ObjectType objtype, List *objname,
-							 Relation *relp, LOCKMODE lockmode)
+							 Relation *relp, LOCKMODE lockmode,
+							 bool missing_ok)
 {
 	ObjectAddress address;
 	List	   *relname;
 	Oid			reloid;
 	Relation	relation;
 	const char *attname;
+	AttrNumber	attnum;
 
 	/* Extract relation name and open relation. */
 	attname = strVal(lfirst(list_tail(objname)));
@@ -529,24 +565,77 @@ get_object_address_attribute(ObjectType objtype, List *objname,
 	reloid = RelationGetRelid(relation);
 
 	/* Look up attribute and construct return value. */
+	attnum = get_attnum(reloid, attname);
+	if (attnum == InvalidAttrNumber)
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_COLUMN),
+					 errmsg("column \"%s\" of relation \"%s\" does not exist",
+							attname, NameListToString(relname))));
+
+		address.classId = RelationRelationId;
+		address.objectId = InvalidOid;
+		address.objectSubId = InvalidAttrNumber;
+		return address;
+	}
+
 	address.classId = RelationRelationId;
 	address.objectId = reloid;
-	address.objectSubId = get_attnum(reloid, attname);
-	if (address.objectSubId == InvalidAttrNumber)
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_COLUMN),
-				 errmsg("column \"%s\" of relation \"%s\" does not exist",
-						attname, RelationGetRelationName(relation))));
+	address.objectSubId = attnum;
 
 	*relp = relation;
 	return address;
 }
 
 /*
+ * Find the ObjectAddress for a type or domain
+ */
+static ObjectAddress
+get_object_address_type(ObjectType objtype,
+						List *objname, bool missing_ok)
+{
+	ObjectAddress   address;
+	TypeName   *typename;
+	Type        tup;
+	typename = makeTypeNameFromNameList(objname);
+
+	address.classId = TypeRelationId;
+	address.objectId = InvalidOid;
+	address.objectSubId = 0;
+
+	tup = LookupTypeName(NULL, typename, NULL);
+	if (!HeapTupleIsValid(tup))
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("type \"%s\" does not exist",
+							TypeNameToString(typename))));
+		return address;
+	}
+	address.objectId = typeTypeId(tup);
+
+	if (objtype == OBJECT_DOMAIN)
+	{
+		if (((Form_pg_type) GETSTRUCT(tup))->typtype != TYPTYPE_DOMAIN)
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a domain",
+							TypeNameToString(typename))));
+	}
+
+	ReleaseSysCache(tup);
+
+	return address;
+}
+
+/*
  * Find the ObjectAddress for an opclass or opfamily.
  */
 static ObjectAddress
-get_object_address_opcf(ObjectType objtype, List *objname, List *objargs)
+get_object_address_opcf(ObjectType objtype,
+						List *objname, List *objargs, bool missing_ok)
 {
 	Oid			amoid;
 	ObjectAddress address;
@@ -558,12 +647,12 @@ get_object_address_opcf(ObjectType objtype, List *objname, List *objargs)
 	{
 		case OBJECT_OPCLASS:
 			address.classId = OperatorClassRelationId;
-			address.objectId = get_opclass_oid(amoid, objname, false);
+			address.objectId = get_opclass_oid(amoid, objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_OPFAMILY:
 			address.classId = OperatorFamilyRelationId;
-			address.objectId = get_opfamily_oid(amoid, objname, false);
+			address.objectId = get_opfamily_oid(amoid, objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		default:
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index 587a689..de4d5de 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -69,7 +69,7 @@ CommentObject(CommentStmt *stmt)
 	 * against concurrent DROP operations.
 	 */
 	address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								 &relation, ShareUpdateExclusiveLock);
+								 &relation, ShareUpdateExclusiveLock, false);
 
 	/* Require ownership of the target object. */
 	check_object_ownership(GetUserId(), stmt->objtype, address,
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 5869569..08fb3d5 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -2703,7 +2703,7 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
 	 * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
 	 */
 	object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								&relation, ShareUpdateExclusiveLock);
+								&relation, ShareUpdateExclusiveLock, false);
 
 	/* Permission check: must own target object, too */
 	check_object_ownership(GetUserId(), stmt->objtype, object,
diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c
index 7afb713..51a5567 100644
--- a/src/backend/commands/seclabel.c
+++ b/src/backend/commands/seclabel.c
@@ -88,7 +88,7 @@ ExecSecLabelStmt(SecLabelStmt *stmt)
 	 * guard against concurrent modifications.
 	 */
 	address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								 &relation, ShareUpdateExclusiveLock);
+								 &relation, ShareUpdateExclusiveLock, false);
 
 	/* Require ownership of the target object. */
 	check_object_ownership(GetUserId(), stmt->objtype, address,
diff --git a/src/backend/rewrite/rewriteSupport.c b/src/backend/rewrite/rewriteSupport.c
index 7770d03..4d6f508 100644
--- a/src/backend/rewrite/rewriteSupport.c
+++ b/src/backend/rewrite/rewriteSupport.c
@@ -132,7 +132,8 @@ get_rewrite_oid(Oid relid, const char *rulename, bool missing_ok)
  * were unique across the entire database.
  */
 Oid
-get_rewrite_oid_without_relid(const char *rulename, Oid *reloid)
+get_rewrite_oid_without_relid(const char *rulename,
+							  Oid *reloid, bool missing_ok)
 {
 	Relation	RewriteRelation;
 	HeapScanDesc scanDesc;
@@ -151,20 +152,26 @@ get_rewrite_oid_without_relid(const char *rulename, Oid *reloid)
 
 	htup = heap_getnext(scanDesc, ForwardScanDirection);
 	if (!HeapTupleIsValid(htup))
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("rule \"%s\" does not exist", rulename)));
-
-	ruleoid = HeapTupleGetOid(htup);
-	if (reloid != NULL)
-		*reloid = ((Form_pg_rewrite) GETSTRUCT(htup))->ev_class;
-
-	if (HeapTupleIsValid(htup = heap_getnext(scanDesc, ForwardScanDirection)))
-		ereport(ERROR,
-				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("there are multiple rules named \"%s\"", rulename),
-				 errhint("Specify a relation name as well as a rule name.")));
-
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("rule \"%s\" does not exist", rulename)));
+		ruleoid = InvalidOid;
+	}
+	else
+	{
+		ruleoid = HeapTupleGetOid(htup);
+		if (reloid != NULL)
+			*reloid = ((Form_pg_rewrite) GETSTRUCT(htup))->ev_class;
+
+		htup = heap_getnext(scanDesc, ForwardScanDirection);
+		if (HeapTupleIsValid(htup))
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("there are multiple rules named \"%s\"", rulename),
+					 errhint("Specify a relation name as well as a rule name.")));
+	}
 	heap_endscan(scanDesc);
 	heap_close(RewriteRelation, AccessShareLock);
 
diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h
index 109a8a3..300b81d 100644
--- a/src/include/catalog/objectaddress.h
+++ b/src/include/catalog/objectaddress.h
@@ -28,7 +28,8 @@ typedef struct ObjectAddress
 } ObjectAddress;
 
 extern ObjectAddress get_object_address(ObjectType objtype, List *objname,
-				   List *objargs, Relation *relp, LOCKMODE lockmode);
+										List *objargs, Relation *relp,
+										LOCKMODE lockmode, bool missing_ok);
 
 extern void check_object_ownership(Oid roleid,
 					   ObjectType objtype, ObjectAddress address,
diff --git a/src/include/rewrite/rewriteSupport.h b/src/include/rewrite/rewriteSupport.h
index 77417ba..22e6ca2 100644
--- a/src/include/rewrite/rewriteSupport.h
+++ b/src/include/rewrite/rewriteSupport.h
@@ -23,6 +23,7 @@ extern void SetRelationRuleStatus(Oid relationId, bool relHasRules,
 					  bool relIsBecomingView);
 
 extern Oid	get_rewrite_oid(Oid relid, const char *rulename, bool missing_ok);
-extern Oid	get_rewrite_oid_without_relid(const char *rulename, Oid *relid);
+extern Oid	get_rewrite_oid_without_relid(const char *rulename,
+										  Oid *relid, bool missing_ok);
 
 #endif   /* REWRITESUPPORT_H */
#14Robert Haas
robertmhaas@gmail.com
In reply to: Robert Haas (#12)
1 attachment(s)
Re: [v9.2] DROP Reworks Part.0 - 'missing_ok' support of get_object_address

On Wed, Jun 22, 2011 at 1:36 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Wed, Jun 22, 2011 at 12:51 PM, Alvaro Herrera
<alvherre@commandprompt.com> wrote:

Excerpts from Robert Haas's message of mié jun 22 08:56:02 -0400 2011:

Another option might be to leave heap_openrv() and relation_openrv()
alone and add a missing_ok argument to try_heap_openrv() and
try_relation_openrv().  Passing true would give the same behavior as
presently; passing false would make them behave like the non-try
version.

That would be pretty weird, having two functions, one of them sometimes
doing the same thing as the other one.

I understand Noah's concern but I think your original proposal was saner
than both options presented so far.

I agree with you.  If we had a whole pile of options it might be worth
having heap_openrv() and heap_openrv_extended() so as not to
complicate the simple case, but since there's no forseeable need to
add anything other than missing_ok, my gut is to just add it and call
it good.

On further review, my gut is having second thoughts. This patch is an
awful lot smaller and easier to verify correctness if I just mess with
the "try" calls and not the regular ones; and it avoids both
back-patching hazards for us and hoops for third-party loadable
modules that are using the non-try versions of those functions to jump
through.

Third try attached...

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

Attachments:

there-is-no-try-v3.patchapplication/octet-stream; name=there-is-no-try-v3.patchDownload
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index a48e057..59314ab 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -1004,7 +1004,7 @@ relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
 }
 
 /* ----------------
- *		try_relation_openrv - open any relation specified by a RangeVar
+ *		relation_openrv_extended - open any relation specified by a RangeVar
  *
  *		Same as relation_openrv, but return NULL instead of failing for
  *		relation-not-found.  (Note that some other causes, such as
@@ -1012,7 +1012,8 @@ relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
  * ----------------
  */
 Relation
-try_relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
+relation_openrv_extended(const RangeVar *relation, LOCKMODE lockmode,
+						 bool missing_ok)
 {
 	Oid			relOid;
 
@@ -1032,7 +1033,7 @@ try_relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
 		AcceptInvalidationMessages();
 
 	/* Look up the appropriate relation using namespace search */
-	relOid = RangeVarGetRelid(relation, true);
+	relOid = RangeVarGetRelid(relation, missing_ok);
 
 	/* Return NULL on not-found */
 	if (!OidIsValid(relOid))
@@ -1125,18 +1126,19 @@ heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
 }
 
 /* ----------------
- *		try_heap_openrv - open a heap relation specified
+ *		heap_openrv_extended - open a heap relation specified
  *		by a RangeVar node
  *
  *		As above, but return NULL instead of failing for relation-not-found.
  * ----------------
  */
 Relation
-try_heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
+heap_openrv_extended(const RangeVar *relation, LOCKMODE lockmode,
+					 bool missing_ok)
 {
 	Relation	r;
 
-	r = try_relation_openrv(relation, lockmode);
+	r = relation_openrv_extended(relation, lockmode, missing_ok);
 
 	if (r)
 	{
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 5359e69..edfb1f1 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -826,7 +826,7 @@ parserOpenTable(ParseState *pstate, const RangeVar *relation, int lockmode)
 	ParseCallbackState pcbstate;
 
 	setup_parser_errposition_callback(&pcbstate, pstate, relation->location);
-	rel = try_heap_openrv(relation, lockmode);
+	rel = heap_openrv_extended(relation, lockmode, true);
 	if (rel == NULL)
 	{
 		if (relation->schemaname)
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index ee474d6..56036a8 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -50,12 +50,14 @@ typedef enum
 extern Relation relation_open(Oid relationId, LOCKMODE lockmode);
 extern Relation try_relation_open(Oid relationId, LOCKMODE lockmode);
 extern Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode);
-extern Relation try_relation_openrv(const RangeVar *relation, LOCKMODE lockmode);
+extern Relation relation_openrv_extended(const RangeVar *relation,
+						 LOCKMODE lockmode, bool missing_ok);
 extern void relation_close(Relation relation, LOCKMODE lockmode);
 
 extern Relation heap_open(Oid relationId, LOCKMODE lockmode);
 extern Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode);
-extern Relation try_heap_openrv(const RangeVar *relation, LOCKMODE lockmode);
+extern Relation heap_openrv_extended(const RangeVar *relation,
+					 LOCKMODE lockmode, bool missing_ok);
 
 #define heap_close(r,l)  relation_close(r,l)
 
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index 7b952b2..f517144 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -493,8 +493,8 @@ pltcl_init_load_unknown(Tcl_Interp *interp)
 	 * This is for backwards compatibility.  To ensure that the table
 	 * is trustworthy, we require it to be owned by a superuser.
 	 ************************************************************/
-	pmrel = try_relation_openrv(makeRangeVar(NULL, "pltcl_modules", -1),
-								AccessShareLock);
+	pmrel = relation_openrv_extended(makeRangeVar(NULL, "pltcl_modules", -1),
+									 AccessShareLock, true);
 	if (pmrel == NULL)
 		return;
 	/* must be table or view, else ignore */
#15Noah Misch
noah@leadboat.com
In reply to: Robert Haas (#14)
Re: [v9.2] DROP Reworks Part.0 - 'missing_ok' support of get_object_address

On Mon, Jun 27, 2011 at 01:28:30PM -0400, Robert Haas wrote:

On Wed, Jun 22, 2011 at 1:36 PM, Robert Haas <robertmhaas@gmail.com> wrote:

I agree with you. ?If we had a whole pile of options it might be worth
having heap_openrv() and heap_openrv_extended() so as not to
complicate the simple case, but since there's no forseeable need to
add anything other than missing_ok, my gut is to just add it and call
it good.

On further review, my gut is having second thoughts. This patch is an
awful lot smaller and easier to verify correctness if I just mess with
the "try" calls and not the regular ones; and it avoids both
back-patching hazards for us and hoops for third-party loadable
modules that are using the non-try versions of those functions to jump
through.

+1. (Note that the function header comments need a few more updates.)

#16Robert Haas
robertmhaas@gmail.com
In reply to: Noah Misch (#15)
Re: [v9.2] DROP Reworks Part.0 - 'missing_ok' support of get_object_address

On Mon, Jun 27, 2011 at 2:59 PM, Noah Misch <noah@leadboat.com> wrote:

On Mon, Jun 27, 2011 at 01:28:30PM -0400, Robert Haas wrote:

On Wed, Jun 22, 2011 at 1:36 PM, Robert Haas <robertmhaas@gmail.com> wrote:

I agree with you. ?If we had a whole pile of options it might be worth
having heap_openrv() and heap_openrv_extended() so as not to
complicate the simple case, but since there's no forseeable need to
add anything other than missing_ok, my gut is to just add it and call
it good.

On further review, my gut is having second thoughts.  This patch is an
awful lot smaller and easier to verify correctness if I just mess with
the "try" calls and not the regular ones; and it avoids both
back-patching hazards for us and hoops for third-party loadable
modules that are using the non-try versions of those functions to jump
through.

+1.  (Note that the function header comments need a few more updates.)

Oh, good catch, thanks. Committed with some further comment changes.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#17Kohei KaiGai
kaigai@kaigai.gr.jp
In reply to: Robert Haas (#16)
1 attachment(s)
Re: [v9.2] DROP Reworks Part.0 - 'missing_ok' support of get_object_address

The attached patch is rebased one towards the latest tree, using
relation_openrv_extended().

Although it is not a matter in this patch itself, I found a problem on
the upcoming patch
that consolidate routines associated with DropStmt.
Existing RemoveRelations() acquires a lock on the table owning an
index to be removed
in the case when OBJECT_INDEX is supplied.
However, the revised get_object_address() opens the supplied relation
(= index) in same
time with lookup of its name. So, we may break down the
relation_openrv_extended()
into a pair of RangeVarGetRelid() and relation_open().

Any good idea?

2011/6/27 Robert Haas <robertmhaas@gmail.com>:

On Mon, Jun 27, 2011 at 2:59 PM, Noah Misch <noah@leadboat.com> wrote:

On Mon, Jun 27, 2011 at 01:28:30PM -0400, Robert Haas wrote:

On Wed, Jun 22, 2011 at 1:36 PM, Robert Haas <robertmhaas@gmail.com> wrote:

I agree with you. ?If we had a whole pile of options it might be worth
having heap_openrv() and heap_openrv_extended() so as not to
complicate the simple case, but since there's no forseeable need to
add anything other than missing_ok, my gut is to just add it and call
it good.

On further review, my gut is having second thoughts.  This patch is an
awful lot smaller and easier to verify correctness if I just mess with
the "try" calls and not the regular ones; and it avoids both
back-patching hazards for us and hoops for third-party loadable
modules that are using the non-try versions of those functions to jump
through.

+1.  (Note that the function header comments need a few more updates.)

Oh, good catch, thanks.  Committed with some further comment changes.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
KaiGai Kohei <kaigai@kaigai.gr.jp>

Attachments:

pgsql-v9.2-drop-reworks-part-0.v5.patchapplication/octet-stream; name=pgsql-v9.2-drop-reworks-part-0.v5.patchDownload
 src/backend/catalog/objectaddress.c  |  210 ++++++++++++++++++++++++----------
 src/backend/commands/comment.c       |    2 +-
 src/backend/commands/extension.c     |    2 +-
 src/backend/commands/seclabel.c      |    2 +-
 src/backend/rewrite/rewriteSupport.c |   37 ++++---
 src/include/catalog/objectaddress.h  |    3 +-
 src/include/rewrite/rewriteSupport.h |    3 +-
 7 files changed, 179 insertions(+), 80 deletions(-)

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index bf25091..c6bedbe 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -72,15 +72,19 @@
 #include "utils/tqual.h"
 
 static ObjectAddress get_object_address_unqualified(ObjectType objtype,
-							   List *qualname);
-static Relation get_relation_by_qualified_name(ObjectType objtype,
-							   List *objname, LOCKMODE lockmode);
+							   List *qualname, bool missing_ok);
+static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
+							   List *objname, Relation *relp,
+							   LOCKMODE lockmode, bool missing_ok);
 static ObjectAddress get_object_address_relobject(ObjectType objtype,
-							 List *objname, Relation *relp);
+						   List *objname, Relation *relp, bool missing_ok);
 static ObjectAddress get_object_address_attribute(ObjectType objtype,
-						   List *objname, Relation *relp, LOCKMODE lockmode);
+						   List *objname, Relation *relp,
+						   LOCKMODE lockmode, bool missing_ok);
+static ObjectAddress get_object_address_type(ObjectType objtype,
+						   List *objname, bool missing_ok);
 static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname,
-						List *objargs);
+						   List *objargs, bool missing_ok);
 static bool object_exists(ObjectAddress address);
 
 
@@ -106,7 +110,7 @@ static bool object_exists(ObjectAddress address);
  */
 ObjectAddress
 get_object_address(ObjectType objtype, List *objname, List *objargs,
-				   Relation *relp, LOCKMODE lockmode)
+				   Relation *relp, LOCKMODE lockmode, bool missing_ok)
 {
 	ObjectAddress address;
 	Relation	relation = NULL;
@@ -121,21 +125,22 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 		case OBJECT_TABLE:
 		case OBJECT_VIEW:
 		case OBJECT_FOREIGN_TABLE:
-			relation =
-				get_relation_by_qualified_name(objtype, objname, lockmode);
-			address.classId = RelationRelationId;
-			address.objectId = RelationGetRelid(relation);
-			address.objectSubId = 0;
+			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);
+				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);
+			address = get_object_address_relobject(objtype, objname,
+												   &relation, missing_ok);
 			break;
 		case OBJECT_DATABASE:
 		case OBJECT_EXTENSION:
@@ -145,23 +150,23 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 		case OBJECT_LANGUAGE:
 		case OBJECT_FDW:
 		case OBJECT_FOREIGN_SERVER:
-			address = get_object_address_unqualified(objtype, objname);
+			address = get_object_address_unqualified(objtype,
+													 objname, missing_ok);
 			break;
 		case OBJECT_TYPE:
 		case OBJECT_DOMAIN:
-			address.classId = TypeRelationId;
-			address.objectId =
-				typenameTypeId(NULL, makeTypeNameFromNameList(objname));
-			address.objectSubId = 0;
+			address = get_object_address_type(objtype, objname, missing_ok);
 			break;
 		case OBJECT_AGGREGATE:
 			address.classId = ProcedureRelationId;
-			address.objectId = LookupAggNameTypeNames(objname, objargs, false);
+			address.objectId =
+				LookupAggNameTypeNames(objname, objargs, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_FUNCTION:
 			address.classId = ProcedureRelationId;
-			address.objectId = LookupFuncNameTypeNames(objname, objargs, false);
+			address.objectId =
+				LookupFuncNameTypeNames(objname, objargs, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_OPERATOR:
@@ -171,22 +176,23 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 				LookupOperNameTypeNames(NULL, objname,
 										(TypeName *) linitial(objargs),
 										(TypeName *) lsecond(objargs),
-										false, -1);
+										missing_ok, -1);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_COLLATION:
 			address.classId = CollationRelationId;
-			address.objectId = get_collation_oid(objname, false);
+			address.objectId = get_collation_oid(objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_CONVERSION:
 			address.classId = ConversionRelationId;
-			address.objectId = get_conversion_oid(objname, false);
+			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);
+			address = get_object_address_opcf(objtype,
+											  objname, objargs, missing_ok);
 			break;
 		case OBJECT_LARGEOBJECT:
 			Assert(list_length(objname) == 1);
@@ -194,10 +200,13 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 			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:
 			{
@@ -208,28 +217,28 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 
 				address.classId = CastRelationId;
 				address.objectId =
-					get_cast_oid(sourcetypeid, targettypeid, false);
+					get_cast_oid(sourcetypeid, targettypeid, missing_ok);
 				address.objectSubId = 0;
 			}
 			break;
 		case OBJECT_TSPARSER:
 			address.classId = TSParserRelationId;
-			address.objectId = get_ts_parser_oid(objname, false);
+			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, false);
+			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, false);
+			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, false);
+			address.objectId = get_ts_config_oid(objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		default:
@@ -241,6 +250,15 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 	}
 
 	/*
+	 * 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.	If we're dealing with any other type of object, we
 	 * need to lock it and then verify that it still exists.
@@ -267,7 +285,8 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
  * unqualified name.
  */
 static ObjectAddress
-get_object_address_unqualified(ObjectType objtype, List *qualname)
+get_object_address_unqualified(ObjectType objtype,
+							   List *qualname, bool missing_ok)
 {
 	const char *name;
 	ObjectAddress address;
@@ -323,42 +342,42 @@ get_object_address_unqualified(ObjectType objtype, List *qualname)
 	{
 		case OBJECT_DATABASE:
 			address.classId = DatabaseRelationId;
-			address.objectId = get_database_oid(name, false);
+			address.objectId = get_database_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_EXTENSION:
 			address.classId = ExtensionRelationId;
-			address.objectId = get_extension_oid(name, false);
+			address.objectId = get_extension_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_TABLESPACE:
 			address.classId = TableSpaceRelationId;
-			address.objectId = get_tablespace_oid(name, false);
+			address.objectId = get_tablespace_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_ROLE:
 			address.classId = AuthIdRelationId;
-			address.objectId = get_role_oid(name, false);
+			address.objectId = get_role_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_SCHEMA:
 			address.classId = NamespaceRelationId;
-			address.objectId = get_namespace_oid(name, false);
+			address.objectId = get_namespace_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_LANGUAGE:
 			address.classId = LanguageRelationId;
-			address.objectId = get_language_oid(name, false);
+			address.objectId = get_language_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_FDW:
 			address.classId = ForeignDataWrapperRelationId;
-			address.objectId = get_foreign_data_wrapper_oid(name, false);
+			address.objectId = get_foreign_data_wrapper_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_FOREIGN_SERVER:
 			address.classId = ForeignServerRelationId;
-			address.objectId = get_foreign_server_oid(name, false);
+			address.objectId = get_foreign_server_oid(name, missing_ok);
 			address.objectSubId = 0;
 			break;
 		default:
@@ -375,13 +394,23 @@ get_object_address_unqualified(ObjectType objtype, List *qualname)
 /*
  * Locate a relation by qualified name.
  */
-static Relation
+static ObjectAddress
 get_relation_by_qualified_name(ObjectType objtype, List *objname,
-							   LOCKMODE lockmode)
+							   Relation *relp, LOCKMODE lockmode,
+							   bool missing_ok)
 {
 	Relation	relation;
+	ObjectAddress	address;
+
+	address.classId = RelationRelationId;
+	address.objectId = InvalidOid;
+	address.objectSubId = 0;
+
+	relation = relation_openrv_extended(makeRangeVarFromNameList(objname),
+										lockmode, missing_ok);
+	if (!relation)
+		return address;
 
-	relation = relation_openrv(makeRangeVarFromNameList(objname), lockmode);
 	switch (objtype)
 	{
 		case OBJECT_INDEX:
@@ -424,7 +453,11 @@ get_relation_by_qualified_name(ObjectType objtype, List *objname,
 			break;
 	}
 
-	return relation;
+	/* Done */
+	address.objectId = RelationGetRelid(relation);
+	*relp = relation;
+
+	return address;
 }
 
 /*
@@ -435,7 +468,8 @@ get_relation_by_qualified_name(ObjectType objtype, List *objname,
  * mode for the object itself, not the relation to which it is attached.
  */
 static ObjectAddress
-get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
+get_object_address_relobject(ObjectType objtype, List *objname,
+							 Relation *relp, bool missing_ok)
 {
 	ObjectAddress address;
 	Relation	relation = NULL;
@@ -461,9 +495,9 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
 		if (objtype != OBJECT_RULE)
 			elog(ERROR, "must specify relation and object name");
 		address.classId = RewriteRelationId;
-		address.objectId = get_rewrite_oid_without_relid(depname, &reloid);
+		address.objectId =
+			get_rewrite_oid_without_relid(depname, &reloid, missing_ok);
 		address.objectSubId = 0;
-		relation = heap_open(reloid, AccessShareLock);
 	}
 	else
 	{
@@ -480,17 +514,18 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
 		{
 			case OBJECT_RULE:
 				address.classId = RewriteRelationId;
-				address.objectId = get_rewrite_oid(reloid, depname, false);
+				address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
 				address.objectSubId = 0;
 				break;
 			case OBJECT_TRIGGER:
 				address.classId = TriggerRelationId;
-				address.objectId = get_trigger_oid(reloid, depname, false);
+				address.objectId = get_trigger_oid(reloid, depname, missing_ok);
 				address.objectSubId = 0;
 				break;
 			case OBJECT_CONSTRAINT:
 				address.classId = ConstraintRelationId;
-				address.objectId = get_constraint_oid(reloid, depname, false);
+				address.objectId =
+					get_constraint_oid(reloid, depname, missing_ok);
 				address.objectSubId = 0;
 				break;
 			default:
@@ -512,13 +547,15 @@ get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp)
  */
 static ObjectAddress
 get_object_address_attribute(ObjectType objtype, List *objname,
-							 Relation *relp, LOCKMODE lockmode)
+							 Relation *relp, LOCKMODE lockmode,
+							 bool missing_ok)
 {
 	ObjectAddress address;
 	List	   *relname;
 	Oid			reloid;
 	Relation	relation;
 	const char *attname;
+	AttrNumber	attnum;
 
 	/* Extract relation name and open relation. */
 	attname = strVal(lfirst(list_tail(objname)));
@@ -527,24 +564,77 @@ get_object_address_attribute(ObjectType objtype, List *objname,
 	reloid = RelationGetRelid(relation);
 
 	/* Look up attribute and construct return value. */
+	attnum = get_attnum(reloid, attname);
+	if (attnum == InvalidAttrNumber)
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_COLUMN),
+					 errmsg("column \"%s\" of relation \"%s\" does not exist",
+							attname, NameListToString(relname))));
+
+		address.classId = RelationRelationId;
+		address.objectId = InvalidOid;
+		address.objectSubId = InvalidAttrNumber;
+		return address;
+	}
+
 	address.classId = RelationRelationId;
 	address.objectId = reloid;
-	address.objectSubId = get_attnum(reloid, attname);
-	if (address.objectSubId == InvalidAttrNumber)
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_COLUMN),
-				 errmsg("column \"%s\" of relation \"%s\" does not exist",
-						attname, RelationGetRelationName(relation))));
+	address.objectSubId = attnum;
 
 	*relp = relation;
 	return address;
 }
 
 /*
+ * Find the ObjectAddress for a type or domain
+ */
+static ObjectAddress
+get_object_address_type(ObjectType objtype,
+						List *objname, bool missing_ok)
+{
+	ObjectAddress   address;
+	TypeName   *typename;
+	Type        tup;
+	typename = makeTypeNameFromNameList(objname);
+
+	address.classId = TypeRelationId;
+	address.objectId = InvalidOid;
+	address.objectSubId = 0;
+
+	tup = LookupTypeName(NULL, typename, NULL);
+	if (!HeapTupleIsValid(tup))
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("type \"%s\" does not exist",
+							TypeNameToString(typename))));
+		return address;
+	}
+	address.objectId = typeTypeId(tup);
+
+	if (objtype == OBJECT_DOMAIN)
+	{
+		if (((Form_pg_type) GETSTRUCT(tup))->typtype != TYPTYPE_DOMAIN)
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a domain",
+							TypeNameToString(typename))));
+	}
+
+	ReleaseSysCache(tup);
+
+	return address;
+}
+
+/*
  * Find the ObjectAddress for an opclass or opfamily.
  */
 static ObjectAddress
-get_object_address_opcf(ObjectType objtype, List *objname, List *objargs)
+get_object_address_opcf(ObjectType objtype,
+						List *objname, List *objargs, bool missing_ok)
 {
 	Oid			amoid;
 	ObjectAddress address;
@@ -556,12 +646,12 @@ get_object_address_opcf(ObjectType objtype, List *objname, List *objargs)
 	{
 		case OBJECT_OPCLASS:
 			address.classId = OperatorClassRelationId;
-			address.objectId = get_opclass_oid(amoid, objname, false);
+			address.objectId = get_opclass_oid(amoid, objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_OPFAMILY:
 			address.classId = OperatorFamilyRelationId;
-			address.objectId = get_opfamily_oid(amoid, objname, false);
+			address.objectId = get_opfamily_oid(amoid, objname, missing_ok);
 			address.objectSubId = 0;
 			break;
 		default:
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index 587a689..de4d5de 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -69,7 +69,7 @@ CommentObject(CommentStmt *stmt)
 	 * against concurrent DROP operations.
 	 */
 	address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								 &relation, ShareUpdateExclusiveLock);
+								 &relation, ShareUpdateExclusiveLock, false);
 
 	/* Require ownership of the target object. */
 	check_object_ownership(GetUserId(), stmt->objtype, address,
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 5869569..08fb3d5 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -2703,7 +2703,7 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
 	 * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
 	 */
 	object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								&relation, ShareUpdateExclusiveLock);
+								&relation, ShareUpdateExclusiveLock, false);
 
 	/* Permission check: must own target object, too */
 	check_object_ownership(GetUserId(), stmt->objtype, object,
diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c
index 7afb713..51a5567 100644
--- a/src/backend/commands/seclabel.c
+++ b/src/backend/commands/seclabel.c
@@ -88,7 +88,7 @@ ExecSecLabelStmt(SecLabelStmt *stmt)
 	 * guard against concurrent modifications.
 	 */
 	address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								 &relation, ShareUpdateExclusiveLock);
+								 &relation, ShareUpdateExclusiveLock, false);
 
 	/* Require ownership of the target object. */
 	check_object_ownership(GetUserId(), stmt->objtype, address,
diff --git a/src/backend/rewrite/rewriteSupport.c b/src/backend/rewrite/rewriteSupport.c
index 7770d03..4d6f508 100644
--- a/src/backend/rewrite/rewriteSupport.c
+++ b/src/backend/rewrite/rewriteSupport.c
@@ -132,7 +132,8 @@ get_rewrite_oid(Oid relid, const char *rulename, bool missing_ok)
  * were unique across the entire database.
  */
 Oid
-get_rewrite_oid_without_relid(const char *rulename, Oid *reloid)
+get_rewrite_oid_without_relid(const char *rulename,
+							  Oid *reloid, bool missing_ok)
 {
 	Relation	RewriteRelation;
 	HeapScanDesc scanDesc;
@@ -151,20 +152,26 @@ get_rewrite_oid_without_relid(const char *rulename, Oid *reloid)
 
 	htup = heap_getnext(scanDesc, ForwardScanDirection);
 	if (!HeapTupleIsValid(htup))
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("rule \"%s\" does not exist", rulename)));
-
-	ruleoid = HeapTupleGetOid(htup);
-	if (reloid != NULL)
-		*reloid = ((Form_pg_rewrite) GETSTRUCT(htup))->ev_class;
-
-	if (HeapTupleIsValid(htup = heap_getnext(scanDesc, ForwardScanDirection)))
-		ereport(ERROR,
-				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("there are multiple rules named \"%s\"", rulename),
-				 errhint("Specify a relation name as well as a rule name.")));
-
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("rule \"%s\" does not exist", rulename)));
+		ruleoid = InvalidOid;
+	}
+	else
+	{
+		ruleoid = HeapTupleGetOid(htup);
+		if (reloid != NULL)
+			*reloid = ((Form_pg_rewrite) GETSTRUCT(htup))->ev_class;
+
+		htup = heap_getnext(scanDesc, ForwardScanDirection);
+		if (HeapTupleIsValid(htup))
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("there are multiple rules named \"%s\"", rulename),
+					 errhint("Specify a relation name as well as a rule name.")));
+	}
 	heap_endscan(scanDesc);
 	heap_close(RewriteRelation, AccessShareLock);
 
diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h
index 109a8a3..300b81d 100644
--- a/src/include/catalog/objectaddress.h
+++ b/src/include/catalog/objectaddress.h
@@ -28,7 +28,8 @@ typedef struct ObjectAddress
 } ObjectAddress;
 
 extern ObjectAddress get_object_address(ObjectType objtype, List *objname,
-				   List *objargs, Relation *relp, LOCKMODE lockmode);
+										List *objargs, Relation *relp,
+										LOCKMODE lockmode, bool missing_ok);
 
 extern void check_object_ownership(Oid roleid,
 					   ObjectType objtype, ObjectAddress address,
diff --git a/src/include/rewrite/rewriteSupport.h b/src/include/rewrite/rewriteSupport.h
index 77417ba..22e6ca2 100644
--- a/src/include/rewrite/rewriteSupport.h
+++ b/src/include/rewrite/rewriteSupport.h
@@ -23,6 +23,7 @@ extern void SetRelationRuleStatus(Oid relationId, bool relHasRules,
 					  bool relIsBecomingView);
 
 extern Oid	get_rewrite_oid(Oid relid, const char *rulename, bool missing_ok);
-extern Oid	get_rewrite_oid_without_relid(const char *rulename, Oid *relid);
+extern Oid	get_rewrite_oid_without_relid(const char *rulename,
+										  Oid *relid, bool missing_ok);
 
 #endif   /* REWRITESUPPORT_H */
#18Robert Haas
robertmhaas@gmail.com
In reply to: Kohei KaiGai (#17)
Re: [v9.2] DROP Reworks Part.0 - 'missing_ok' support of get_object_address

On Mon, Jun 27, 2011 at 4:40 PM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

The attached patch is rebased one towards the latest tree, using
relation_openrv_extended().

Committed.

Although it is not a matter in this patch itself, I found a problem on
the upcoming patch
that consolidate routines associated with DropStmt.
Existing RemoveRelations() acquires a lock on the table owning an
index to be removed
in the case when OBJECT_INDEX is supplied.
However, the revised get_object_address() opens the supplied relation
(= index) in same
time with lookup of its name. So, we may break down the
relation_openrv_extended()
into a pair of RangeVarGetRelid() and relation_open().

Not without looking at the patch. I will respond on that thread when
I've read through it more thoroughly.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company