 src/backend/catalog/objectaddress.c |  613 +++++++++++++++++++++++++++++------
 src/include/catalog/objectaddress.h |   13 +
 2 files changed, 534 insertions(+), 92 deletions(-)

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 8feb601..2250058 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -82,6 +82,425 @@ static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname,
 						List *objargs, bool missing_ok);
 static bool object_exists(ObjectAddress address);
 
+/*
+ * ObjectProperty
+ *
+ * This array provides a common part of system object structure; to help
+ * consolidate routines to handle various kind of object classes.
+ */
+typedef struct
+{
+	ObjectType	objtype;			/* OBJECT_* defined at parsenodes.h */
+	const char *objtype_text;		/* text name of the object type */
+	Oid			class_id;			/* Oid of catalog */
+	Oid			index_id;			/* Oid of index to lookup by oid */
+	int			cacheid_by_oid;		/* cache id to lookup by oid */
+	int			cacheid_by_name;	/* cache id to lookup by name + schema */
+	AttrNumber	attnum_name;		/* attnum of name field */
+	AttrNumber	attnum_namespace;	/* attnum of namespace field */
+	AttrNumber	attnum_owner;		/* attnum of owner field */
+	AttrNumber	attnum_relid;		/* attnum of relid field */
+} ObjectPropertyType;
+
+static ObjectPropertyType ObjectProperty[] =
+{
+	{
+		OBJECT_AGGREGATE,
+		"aggregate",
+		ProcedureRelationId,
+		ProcedureOidIndexId,
+		PROCOID,
+		-1,
+		Anum_pg_proc_proname,
+		Anum_pg_proc_pronamespace,
+		Anum_pg_proc_proowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_ATTRIBUTE,
+		"attribute",
+		AttributeRelationId,
+		AttributeRelidNumIndexId,
+		ATTNUM,
+		-1,
+		Anum_pg_attribute_attname,
+		InvalidAttrNumber,
+		InvalidAttrNumber,
+		Anum_pg_attribute_attrelid,
+	},
+	{
+		OBJECT_CAST,
+		"cast",
+		CastRelationId,
+		CastOidIndexId,
+		-1,
+		-1,
+		InvalidAttrNumber,
+		InvalidAttrNumber,
+		InvalidAttrNumber,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_COLUMN,
+		"column",
+		AttributeRelationId,
+		AttributeRelidNumIndexId,
+		ATTNUM,
+		-1,
+		Anum_pg_attribute_attname,
+		InvalidAttrNumber,
+		InvalidAttrNumber,
+		Anum_pg_attribute_attrelid,
+	},
+	{
+		OBJECT_CONSTRAINT,
+		"constraint",
+		ConstraintRelationId,
+		ConstraintOidIndexId,
+		CONSTROID,
+		-1,
+		Anum_pg_constraint_conname,
+		Anum_pg_constraint_connamespace,
+		InvalidAttrNumber,
+		Anum_pg_constraint_conrelid,
+	},
+	{
+		OBJECT_COLLATION,
+		"collation",
+		CollationRelationId,
+		CollationOidIndexId,
+		COLLOID,
+		-1,
+		Anum_pg_collation_collname,
+		Anum_pg_collation_collnamespace,
+		Anum_pg_collation_collowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_CONVERSION,
+		"conversion",
+		ConversionRelationId,
+		ConversionOidIndexId,
+		CONVOID,
+		CONNAMENSP,
+		Anum_pg_conversion_conname,
+		Anum_pg_conversion_connamespace,
+		Anum_pg_conversion_conowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_DATABASE,
+		"database",
+		DatabaseRelationId,
+		DatabaseOidIndexId,
+		DATABASEOID,
+		-1,
+		Anum_pg_database_datname,
+		InvalidAttrNumber,
+		Anum_pg_database_datdba,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_DOMAIN,
+		"domain",
+		TypeRelationId,
+		TypeOidIndexId,
+		TYPEOID,
+		TYPENAMENSP,
+		Anum_pg_type_typname,
+		Anum_pg_type_typnamespace,
+		Anum_pg_type_typowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_EXTENSION,
+		"extension",
+		ExtensionRelationId,
+		ExtensionOidIndexId,
+		-1,
+		-1,
+		Anum_pg_extension_extname,
+		Anum_pg_extension_extnamespace,
+		Anum_pg_extension_extowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_FDW,
+		"foreign-data wrapper",
+		ForeignDataWrapperRelationId,
+		ForeignDataWrapperOidIndexId,
+		FOREIGNDATAWRAPPEROID,
+		FOREIGNDATAWRAPPERNAME,
+		Anum_pg_foreign_data_wrapper_fdwname,
+		InvalidAttrNumber,
+		Anum_pg_foreign_data_wrapper_fdwowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_FOREIGN_SERVER,
+		"server",
+		ForeignServerRelationId,
+		ForeignServerOidIndexId,
+		FOREIGNSERVEROID,
+		FOREIGNSERVERNAME,
+		Anum_pg_foreign_server_srvname,
+		InvalidAttrNumber,
+		Anum_pg_foreign_server_srvowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_FOREIGN_TABLE,
+		"foreign table",
+		RelationRelationId,
+		ClassOidIndexId,
+		RELOID,
+		RELNAMENSP,
+		Anum_pg_class_relname,
+		Anum_pg_class_relnamespace,
+		Anum_pg_class_relowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_FUNCTION,
+		"function",
+		ProcedureRelationId,
+		ProcedureOidIndexId,
+		PROCOID,
+		-1,
+		Anum_pg_proc_proname,
+		Anum_pg_proc_pronamespace,
+		Anum_pg_proc_proowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_INDEX,
+		"index",
+		RelationRelationId,
+		ClassOidIndexId,
+		RELOID,
+		RELNAMENSP,
+		Anum_pg_class_relname,
+		Anum_pg_class_relnamespace,
+		Anum_pg_class_relowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_LANGUAGE,
+		"language",
+		LanguageRelationId,
+		LanguageOidIndexId,
+		LANGOID,
+		LANGNAME,
+		Anum_pg_language_lanname,
+		InvalidAttrNumber,
+		Anum_pg_language_lanowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_LARGEOBJECT,
+		"large object",
+		LargeObjectMetadataRelationId,
+		LargeObjectMetadataOidIndexId,
+		-1,
+		-1,
+		InvalidAttrNumber,
+		InvalidAttrNumber,
+		Anum_pg_largeobject_metadata_lomowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_OPCLASS,
+		"operator class",
+		OperatorClassRelationId,
+		OpclassOidIndexId,
+		CLAOID,
+		-1,
+		Anum_pg_opclass_opcname,
+		Anum_pg_opclass_opcnamespace,
+		Anum_pg_opclass_opcowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_OPERATOR,
+		"operator",
+		OperatorRelationId,
+		OperatorOidIndexId,
+		OPEROID,
+		OPERNAMENSP,
+		Anum_pg_operator_oprname,
+		Anum_pg_operator_oprnamespace,
+		Anum_pg_operator_oprowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_OPFAMILY,
+		"operator family",
+		OperatorFamilyRelationId,
+		OpfamilyOidIndexId,
+		OPFAMILYOID,
+		-1,
+		Anum_pg_opfamily_opfname,
+		Anum_pg_opfamily_opfnamespace,
+		Anum_pg_opfamily_opfowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_ROLE,
+		"role",
+		AuthIdRelationId,
+		AuthIdOidIndexId,
+		AUTHOID,
+		AUTHNAME,
+		Anum_pg_authid_rolname,
+		InvalidAttrNumber,
+		InvalidAttrNumber,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_RULE,
+		"rule",
+		RewriteRelationId,
+		RewriteOidIndexId,
+		-1,
+		RULERELNAME,
+		Anum_pg_rewrite_ev_class,
+		InvalidAttrNumber,
+		InvalidAttrNumber,
+		Anum_pg_rewrite_ev_class,
+	},
+	{
+		OBJECT_SCHEMA,
+		"schema",
+		NamespaceRelationId,
+		NamespaceOidIndexId,
+		NAMESPACEOID,
+		NAMESPACENAME,
+		Anum_pg_namespace_nspname,
+		InvalidAttrNumber,
+		Anum_pg_namespace_nspowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_SEQUENCE,
+		"sequence",
+		RelationRelationId,
+		ClassOidIndexId,
+		RELOID,
+		RELNAMENSP,
+		Anum_pg_class_relname,
+		Anum_pg_class_relnamespace,
+		Anum_pg_class_relowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_TABLE,
+		"table",
+		RelationRelationId,
+		ClassOidIndexId,
+		RELOID,
+		RELNAMENSP,
+		Anum_pg_class_relname,
+		Anum_pg_class_relnamespace,
+		Anum_pg_class_relowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_TABLESPACE,
+		"tablespace",
+		TableSpaceRelationId,
+		TablespaceOidIndexId,
+		-1,
+		-1,
+		Anum_pg_tablespace_spcname,
+		InvalidAttrNumber,
+		Anum_pg_tablespace_spcowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_TRIGGER,
+		"trigger",
+		TriggerRelationId,
+		TriggerOidIndexId,
+		-1,
+		-1,
+		Anum_pg_trigger_tgname,
+		InvalidAttrNumber,
+		InvalidAttrNumber,
+		Anum_pg_trigger_tgrelid,
+	},
+	{
+		OBJECT_TSCONFIGURATION,
+		"text search configuration",
+		TSConfigRelationId,
+		TSConfigOidIndexId,
+		TSCONFIGOID,
+		TSCONFIGNAMENSP,
+		Anum_pg_ts_config_cfgname,
+		Anum_pg_ts_config_cfgnamespace,
+		Anum_pg_ts_config_cfgowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_TSDICTIONARY,
+		"text search dictionary",
+		TSDictionaryRelationId,
+		TSDictionaryOidIndexId,
+		TSDICTOID,
+		TSDICTNAMENSP,
+		Anum_pg_ts_dict_dictname,
+		Anum_pg_ts_dict_dictnamespace,
+		Anum_pg_ts_dict_dictowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_TSPARSER,
+		"text search parser",
+		TSParserRelationId,
+		TSParserOidIndexId,
+		TSPARSEROID,
+		TSPARSERNAMENSP,
+		Anum_pg_ts_parser_prsname,
+		Anum_pg_ts_parser_prsnamespace,
+		InvalidAttrNumber,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_TSTEMPLATE,
+		"text search template",
+		TSTemplateRelationId,
+		TSTemplateOidIndexId,
+		TSTEMPLATEOID,
+		TSTEMPLATENAMENSP,
+		Anum_pg_ts_template_tmplname,
+		Anum_pg_ts_template_tmplnamespace,
+		InvalidAttrNumber,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_TYPE,
+		"type",
+		TypeRelationId,
+		TypeOidIndexId,
+		TYPEOID,
+		TYPENAMENSP,
+		Anum_pg_type_typname,
+		Anum_pg_type_typnamespace,
+		Anum_pg_type_typowner,
+		InvalidAttrNumber,
+	},
+	{
+		OBJECT_VIEW,
+		"view",
+		RelationRelationId,
+		ClassOidIndexId,
+		RELOID,
+		RELNAMENSP,
+		Anum_pg_class_relname,
+		Anum_pg_class_relnamespace,
+		Anum_pg_class_relowner,
+		InvalidAttrNumber,
+	},
+};
 
 /*
  * Translate an object name and arguments (as passed by the parser) to an
@@ -667,11 +1086,85 @@ get_object_address_opcf(ObjectType objtype,
 }
 
 /*
+ * Returns property of the supplied object type
+ */
+static ObjectPropertyType *
+get_object_property(ObjectType objtype)
+{
+	int		index;
+
+	for (index = 0; index < lengthof(ObjectProperty); index++)
+	{
+		if (ObjectProperty[index].objtype == objtype)
+			return &ObjectProperty[index];
+
+	}
+	elog(ERROR, "unrecognized objtype: %d", (int) objtype);
+	return NULL;	/* be compiler quiet */
+}
+
+
+const char *
+get_object_property_typetext(ObjectType objtype)
+{
+	return get_object_property(objtype)->objtype_text;
+}
+
+Oid
+get_object_property_class_id(ObjectType objtype)
+{
+	return get_object_property(objtype)->class_id;
+}
+
+Oid
+get_object_property_index_id(ObjectType objtype)
+{
+	return get_object_property(objtype)->index_id;
+}
+
+int
+get_object_property_catid_by_oid(ObjectType objtype)
+{
+	return get_object_property(objtype)->cacheid_by_oid;
+}
+
+int
+get_object_property_catid_by_name(ObjectType objtype)
+{
+	return get_object_property(objtype)->cacheid_by_name;
+}
+
+AttrNumber
+get_object_property_attnum_name(ObjectType objtype)
+{
+	return get_object_property(objtype)->attnum_name;
+}
+
+AttrNumber
+get_object_property_attnum_namespace(ObjectType objtype)
+{
+	return get_object_property(objtype)->attnum_namespace;
+}
+
+AttrNumber
+get_object_property_attnum_owner(ObjectType objtype)
+{
+	return get_object_property(objtype)->attnum_owner;
+}
+
+AttrNumber
+get_object_property_attnum_relid(ObjectType objtype)
+{
+	return get_object_property(objtype)->attnum_relid;
+}
+
+/*
  * Test whether an object exists.
  */
 static bool
 object_exists(ObjectAddress address)
 {
+	int			index;
 	int			cache = -1;
 	Oid			indexoid = InvalidOid;
 	Relation	rel;
@@ -697,99 +1190,35 @@ object_exists(ObjectAddress address)
 		}
 		return found;
 	}
-
-	/*
-	 * For object types that have a relevant syscache, we use it; for
-	 * everything else, we'll have to do an index-scan.  This switch sets
-	 * either the cache to be used for the syscache lookup, or the index to be
-	 * used for the index scan.
-	 */
-	switch (address.classId)
+	else if (address.classId == LargeObjectRelationId)
 	{
-		case RelationRelationId:
-			cache = RELOID;
-			break;
-		case RewriteRelationId:
-			indexoid = RewriteOidIndexId;
-			break;
-		case TriggerRelationId:
-			indexoid = TriggerOidIndexId;
-			break;
-		case ConstraintRelationId:
-			cache = CONSTROID;
-			break;
-		case DatabaseRelationId:
-			cache = DATABASEOID;
-			break;
-		case TableSpaceRelationId:
-			cache = TABLESPACEOID;
-			break;
-		case AuthIdRelationId:
-			cache = AUTHOID;
-			break;
-		case NamespaceRelationId:
-			cache = NAMESPACEOID;
-			break;
-		case LanguageRelationId:
-			cache = LANGOID;
-			break;
-		case TypeRelationId:
-			cache = TYPEOID;
-			break;
-		case ProcedureRelationId:
-			cache = PROCOID;
-			break;
-		case OperatorRelationId:
-			cache = OPEROID;
-			break;
-		case CollationRelationId:
-			cache = COLLOID;
-			break;
-		case ConversionRelationId:
-			cache = CONVOID;
-			break;
-		case OperatorClassRelationId:
-			cache = CLAOID;
-			break;
-		case OperatorFamilyRelationId:
-			cache = OPFAMILYOID;
-			break;
-		case LargeObjectRelationId:
-
-			/*
-			 * Weird backward compatibility hack: ObjectAddress notation uses
-			 * LargeObjectRelationId for large objects, but since PostgreSQL
-			 * 9.0, the relevant catalog is actually
-			 * LargeObjectMetadataRelationId.
-			 */
-			address.classId = LargeObjectMetadataRelationId;
-			indexoid = LargeObjectMetadataOidIndexId;
-			break;
-		case CastRelationId:
-			indexoid = CastOidIndexId;
-			break;
-		case ForeignDataWrapperRelationId:
-			cache = FOREIGNDATAWRAPPEROID;
-			break;
-		case ForeignServerRelationId:
-			cache = FOREIGNSERVEROID;
-			break;
-		case TSParserRelationId:
-			cache = TSPARSEROID;
-			break;
-		case TSDictionaryRelationId:
-			cache = TSDICTOID;
-			break;
-		case TSTemplateRelationId:
-			cache = TSTEMPLATEOID;
-			break;
-		case TSConfigRelationId:
-			cache = TSCONFIGOID;
-			break;
-		case ExtensionRelationId:
-			indexoid = ExtensionOidIndexId;
-			break;
-		default:
+		/*
+		 * Weird backward compatibility hack: ObjectAddress notation uses
+		 * LargeObjectRelationId for large objects, but since PostgreSQL
+		 * 9.0, the relevant catalog is actually
+		 * LargeObjectMetadataRelationId.
+		 */
+		address.classId = LargeObjectMetadataRelationId;
+		indexoid = LargeObjectMetadataOidIndexId;
+	}
+	else
+	{
+		/*
+		 * For object types that have a relevant syscache, we use it; for
+		 * everything else, we'll have to do an index-scan.  This switch sets
+		 * either the cache to be used for the syscache lookup, or the index
+		 * to be used for the index scan.
+		 */
+		for (index = 0; index < lengthof(ObjectProperty); index++)
+		{
+			if (ObjectProperty[index].class_id == address.classId)
+			{
+				cache = ObjectProperty[index].cacheid_by_oid;
+				indexoid = ObjectProperty[index].index_id;
+				break;
+			}
+		}
+		if (index == lengthof(ObjectProperty))
 			elog(ERROR, "unrecognized classid: %u", address.classId);
 	}
 
diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h
index 2da6309..9ad2490 100644
--- a/src/include/catalog/objectaddress.h
+++ b/src/include/catalog/objectaddress.h
@@ -35,4 +35,17 @@ extern void check_object_ownership(Oid roleid,
 					   ObjectType objtype, ObjectAddress address,
 					   List *objname, List *objargs, Relation relation);
 
+/*
+ * Obtain property of object type
+ */
+extern const char  *get_object_property_typetext(ObjectType objtype);
+extern Oid			get_object_property_class_id(ObjectType objtype);
+extern Oid			get_object_property_index_id(ObjectType objtype);
+extern int			get_object_property_catid_by_oid(ObjectType objtype);
+extern int			get_object_property_catid_by_name(ObjectType objtype);
+extern AttrNumber	get_object_property_attnum_name(ObjectType objtype);
+extern AttrNumber	get_object_property_attnum_namespace(ObjectType objtype);
+extern AttrNumber	get_object_property_attnum_owner(ObjectType objtype);
+extern AttrNumber	get_object_property_attnum_relid(ObjectType objtype);
+
 #endif   /* PARSE_OBJECT_H */