 src/backend/catalog/objectaddress.c |  653 ++++++++++++++++++++++++++++++-----
 src/include/catalog/objectaddress.h |   13 +
 src/include/nodes/parsenodes.h      |    2 +-
 3 files changed, 575 insertions(+), 93 deletions(-)

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 8feb601..6094146 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -82,6 +82,463 @@ static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname,
 						List *objargs, bool missing_ok);
 static bool object_exists(ObjectAddress address);
 
+/*
+ * CatalogProperty
+ *
+ * It provides hint to the structure of corresponding system catalogs.
+ */
+typedef struct
+{
+	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 */
+} CatalogProperty;
+
+static CatalogProperty prop_pg_attribute = {
+	AttributeRelationId,
+	AttributeRelidNumIndexId,
+	ATTNUM,
+	-1,
+	Anum_pg_attribute_attname,
+	InvalidAttrNumber,
+	InvalidAttrNumber,
+	Anum_pg_attribute_attrelid,
+};
+static CatalogProperty prop_pg_authid = {
+	AuthIdRelationId,
+	AuthIdOidIndexId,
+	AUTHOID,
+	AUTHNAME,
+	Anum_pg_authid_rolname,
+	InvalidAttrNumber,
+	InvalidAttrNumber,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_cast = {
+	CastRelationId,
+	CastOidIndexId,
+	-1,
+	-1,
+	InvalidAttrNumber,
+	InvalidAttrNumber,
+	InvalidAttrNumber,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_class = {
+	RelationRelationId,
+	ClassOidIndexId,
+	RELOID,
+	RELNAMENSP,
+	Anum_pg_class_relname,
+	Anum_pg_class_relnamespace,
+	Anum_pg_class_relowner,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_constraint = {
+	ConstraintRelationId,
+	ConstraintOidIndexId,
+	CONSTROID,
+	-1,
+	Anum_pg_constraint_conname,
+	Anum_pg_constraint_connamespace,
+	InvalidAttrNumber,
+	Anum_pg_constraint_conrelid,
+};
+static CatalogProperty prop_pg_collation = {
+	CollationRelationId,
+	CollationOidIndexId,
+	COLLOID,
+	-1,
+	Anum_pg_collation_collname,
+	Anum_pg_collation_collnamespace,
+	Anum_pg_collation_collowner,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_conversion = {
+	ConversionRelationId,
+	ConversionOidIndexId,
+	CONVOID,
+	CONNAMENSP,
+	Anum_pg_conversion_conname,
+	Anum_pg_conversion_connamespace,
+	Anum_pg_conversion_conowner,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_database = {
+	DatabaseRelationId,
+	DatabaseOidIndexId,
+	DATABASEOID,
+	-1,
+	Anum_pg_database_datname,
+	InvalidAttrNumber,
+	Anum_pg_database_datdba,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_extension = {
+	ExtensionRelationId,
+	ExtensionOidIndexId,
+	-1,
+	-1,
+	Anum_pg_extension_extname,
+	Anum_pg_extension_extnamespace,
+	Anum_pg_extension_extowner,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_foreign_data_wrapper = {
+	ForeignDataWrapperRelationId,
+	ForeignDataWrapperOidIndexId,
+	FOREIGNDATAWRAPPEROID,
+	FOREIGNDATAWRAPPERNAME,
+	Anum_pg_foreign_data_wrapper_fdwname,
+	InvalidAttrNumber,
+	Anum_pg_foreign_data_wrapper_fdwowner,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_foreign_server = {
+	ForeignServerRelationId,
+	ForeignServerOidIndexId,
+	FOREIGNSERVEROID,
+	FOREIGNSERVERNAME,
+	Anum_pg_foreign_server_srvname,
+	InvalidAttrNumber,
+	Anum_pg_foreign_server_srvowner,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_language = {
+	LanguageRelationId,
+	LanguageOidIndexId,
+	LANGOID,
+	LANGNAME,
+	Anum_pg_language_lanname,
+	InvalidAttrNumber,
+	Anum_pg_language_lanowner,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_largeobject = {
+	LargeObjectMetadataRelationId,
+	LargeObjectMetadataOidIndexId,
+	-1,
+	-1,
+	InvalidAttrNumber,
+	InvalidAttrNumber,
+	Anum_pg_largeobject_metadata_lomowner,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_namespace = {
+	NamespaceRelationId,
+	NamespaceOidIndexId,
+	NAMESPACEOID,
+	NAMESPACENAME,
+	Anum_pg_namespace_nspname,
+	InvalidAttrNumber,
+	Anum_pg_namespace_nspowner,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_opclass = {
+	OperatorClassRelationId,
+	OpclassOidIndexId,
+	CLAOID,
+	-1,
+	Anum_pg_opclass_opcname,
+	Anum_pg_opclass_opcnamespace,
+	Anum_pg_opclass_opcowner,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_operator = {
+	OperatorRelationId,
+	OperatorOidIndexId,
+	OPEROID,
+	OPERNAMENSP,
+	Anum_pg_operator_oprname,
+	Anum_pg_operator_oprnamespace,
+	Anum_pg_operator_oprowner,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_opfamily = {
+	OperatorFamilyRelationId,
+	OpfamilyOidIndexId,
+	OPFAMILYOID,
+	-1,
+	Anum_pg_opfamily_opfname,
+	Anum_pg_opfamily_opfnamespace,
+	Anum_pg_opfamily_opfowner,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_proc = {
+	ProcedureRelationId,
+	ProcedureOidIndexId,
+	PROCOID,
+	-1,
+	Anum_pg_proc_proname,
+	Anum_pg_proc_pronamespace,
+	Anum_pg_proc_proowner,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_rewrite = {
+	RewriteRelationId,
+	RewriteOidIndexId,
+	-1,
+	RULERELNAME,
+	Anum_pg_rewrite_ev_class,
+	InvalidAttrNumber,
+	InvalidAttrNumber,
+	Anum_pg_rewrite_ev_class,
+};
+static CatalogProperty prop_pg_tablespace = {
+	TableSpaceRelationId,
+	TablespaceOidIndexId,
+	-1,
+	-1,
+	Anum_pg_tablespace_spcname,
+	InvalidAttrNumber,
+	Anum_pg_tablespace_spcowner,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_trigger = {
+	TriggerRelationId,
+	TriggerOidIndexId,
+	-1,
+	-1,
+	Anum_pg_trigger_tgname,
+	InvalidAttrNumber,
+	InvalidAttrNumber,
+	Anum_pg_trigger_tgrelid,
+};
+static CatalogProperty prop_pg_ts_config = {
+	TSConfigRelationId,
+	TSConfigOidIndexId,
+	TSCONFIGOID,
+	TSCONFIGNAMENSP,
+	Anum_pg_ts_config_cfgname,
+	Anum_pg_ts_config_cfgnamespace,
+	Anum_pg_ts_config_cfgowner,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_ts_dict = {
+	TSDictionaryRelationId,
+	TSDictionaryOidIndexId,
+	TSDICTOID,
+	TSDICTNAMENSP,
+	Anum_pg_ts_dict_dictname,
+	Anum_pg_ts_dict_dictnamespace,
+	Anum_pg_ts_dict_dictowner,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_ts_parser = {
+	TSParserRelationId,
+	TSParserOidIndexId,
+	TSPARSEROID,
+	TSPARSERNAMENSP,
+	Anum_pg_ts_parser_prsname,
+	Anum_pg_ts_parser_prsnamespace,
+	InvalidAttrNumber,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_ts_template = {
+	TSTemplateRelationId,
+	TSTemplateOidIndexId,
+	TSTEMPLATEOID,
+	TSTEMPLATENAMENSP,
+	Anum_pg_ts_template_tmplname,
+	Anum_pg_ts_template_tmplnamespace,
+	InvalidAttrNumber,
+	InvalidAttrNumber,
+};
+static CatalogProperty prop_pg_type = {
+	TypeRelationId,
+	TypeOidIndexId,
+	TYPEOID,
+	TYPENAMENSP,
+	Anum_pg_type_typname,
+	Anum_pg_type_typnamespace,
+	Anum_pg_type_typowner,
+	InvalidAttrNumber,
+};
+
+/*
+ * ObjectProperty
+ *
+ * This array provides a common part of system object structure; to help
+ * consolidate routines to handle various kind of object classes.
+ */
+static struct
+{
+	ObjectType		objtype;
+	const char		*objtype_text;
+	CatalogProperty	*objprop;
+}	ObjectProperty[] =
+{
+	{
+		OBJECT_AGGREGATE,
+		"aggregate",
+		&prop_pg_proc,
+	},
+	{
+		OBJECT_ATTRIBUTE,
+		"attribute",
+		&prop_pg_attribute,
+	},
+	{
+		OBJECT_CAST,
+		"cast",
+		&prop_pg_cast,
+	},
+	{
+		OBJECT_COLUMN,
+		"column",
+		&prop_pg_attribute,
+	},
+	{
+		OBJECT_CONSTRAINT,
+		"constraint",
+		&prop_pg_constraint,
+	},
+	{
+		OBJECT_COLLATION,
+		"collation",
+		&prop_pg_collation,
+	},
+	{
+		OBJECT_CONVERSION,
+		"conversion",
+		&prop_pg_conversion,
+	},
+	{
+		OBJECT_DATABASE,
+		"database",
+		&prop_pg_database,
+	},
+	{
+		OBJECT_DOMAIN,
+		"domain",
+		&prop_pg_type,
+	},
+	{
+		OBJECT_EXTENSION,
+		"extension",
+		&prop_pg_extension,
+	},
+	{
+		OBJECT_FDW,
+		"foreign-data wrapper",
+		&prop_pg_foreign_data_wrapper,
+	},
+	{
+		OBJECT_FOREIGN_SERVER,
+		"server",
+		&prop_pg_foreign_server,
+	},
+	{
+		OBJECT_FOREIGN_TABLE,
+		"foreign table",
+		&prop_pg_class,
+	},
+	{
+		OBJECT_FUNCTION,
+		"function",
+		&prop_pg_proc,
+	},
+	{
+		OBJECT_INDEX,
+		"index",
+		&prop_pg_class,
+	},
+	{
+		OBJECT_LANGUAGE,
+		"language",
+		&prop_pg_language,
+	},
+	{
+		OBJECT_LARGEOBJECT,
+		"large object",
+		&prop_pg_largeobject,
+	},
+	{
+		OBJECT_OPCLASS,
+		"operator class",
+		&prop_pg_opclass,
+	},
+	{
+		OBJECT_OPERATOR,
+		"operator",
+		&prop_pg_operator,
+	},
+	{
+		OBJECT_OPFAMILY,
+		"operator family",
+		&prop_pg_opfamily,
+	},
+	{
+		OBJECT_ROLE,
+		"role",
+		&prop_pg_authid,
+	},
+	{
+		OBJECT_RULE,
+		"rule",
+		&prop_pg_rewrite,
+	},
+	{
+		OBJECT_SCHEMA,
+		"schema",
+		&prop_pg_namespace,
+	},
+	{
+		OBJECT_SEQUENCE,
+		"sequence",
+		&prop_pg_class,
+	},
+	{
+		OBJECT_TABLE,
+		"table",
+		&prop_pg_class,
+	},
+	{
+		OBJECT_TABLESPACE,
+		"tablespace",
+		&prop_pg_tablespace,
+	},
+	{
+		OBJECT_TRIGGER,
+		"trigger",
+		&prop_pg_trigger,
+	},
+	{
+		OBJECT_TSCONFIGURATION,
+		"text search configuration",
+		&prop_pg_ts_config,
+	},
+	{
+		OBJECT_TSDICTIONARY,
+		"text search dictionary",
+		&prop_pg_ts_dict,
+	},
+	{
+		OBJECT_TSPARSER,
+		"text search parser",
+		&prop_pg_ts_parser,
+	},
+	{
+		OBJECT_TSTEMPLATE,
+		"text search template",
+		&prop_pg_ts_template,
+	},
+	{
+		OBJECT_TYPE,
+		"type",
+		&prop_pg_type,
+	},
+	{
+		OBJECT_VIEW,
+		"view",
+		&prop_pg_class,
+	},
+};
 
 /*
  * Translate an object name and arguments (as passed by the parser) to an
@@ -667,11 +1124,87 @@ get_object_address_opcf(ObjectType objtype,
 }
 
 /*
+ * Returns property of the supplied object type
+ */
+const char *
+get_object_property_typetext(ObjectType objtype)
+{
+	if (objtype < 0 || objtype >= lengthof(ObjectProperty))
+		elog(ERROR, "unrecognized objtype: %d", (int) objtype);
+	return ObjectProperty[(int)objtype].objtype_text;
+}
+
+Oid
+get_object_property_class_id(ObjectType objtype)
+{
+	if (objtype < 0 || objtype >= lengthof(ObjectProperty))
+		elog(ERROR, "unrecognized objtype: %d", (int) objtype);
+	return ObjectProperty[(int)objtype].objprop->class_id;
+}
+
+Oid
+get_object_property_index_id(ObjectType objtype)
+{
+	if (objtype < 0 || objtype >= lengthof(ObjectProperty))
+		elog(ERROR, "unrecognized objtype: %d", (int) objtype);
+	return ObjectProperty[(int)objtype].objprop->index_id;
+}
+
+int
+get_object_property_catid_by_oid(ObjectType objtype)
+{
+	if (objtype < 0 || objtype >= lengthof(ObjectProperty))
+		elog(ERROR, "unrecognized objtype: %d", (int) objtype);
+	return ObjectProperty[(int)objtype].objprop->cacheid_by_oid;
+}
+
+int
+get_object_property_catid_by_name(ObjectType objtype)
+{
+	if (objtype < 0 || objtype >= lengthof(ObjectProperty))
+		elog(ERROR, "unrecognized objtype: %d", (int) objtype);
+	return ObjectProperty[(int)objtype].objprop->cacheid_by_name;
+}
+
+AttrNumber
+get_object_property_attnum_name(ObjectType objtype)
+{
+	if (objtype < 0 || objtype >= lengthof(ObjectProperty))
+		elog(ERROR, "unrecognized objtype: %d", (int) objtype);
+	return ObjectProperty[(int)objtype].objprop->attnum_name;
+}
+
+AttrNumber
+get_object_property_attnum_namespace(ObjectType objtype)
+{
+	if (objtype < 0 || objtype >= lengthof(ObjectProperty))
+		elog(ERROR, "unrecognized objtype: %d", (int) objtype);
+	return ObjectProperty[(int)objtype].objprop->attnum_namespace;
+}
+
+AttrNumber
+get_object_property_attnum_owner(ObjectType objtype)
+{
+	if (objtype < 0 || objtype >= lengthof(ObjectProperty))
+		elog(ERROR, "unrecognized objtype: %d", (int) objtype);
+	return ObjectProperty[(int)objtype].objprop->attnum_owner;
+}
+
+AttrNumber
+get_object_property_attnum_relid(ObjectType objtype)
+{
+	if (objtype < 0 || objtype >= lengthof(ObjectProperty))
+		elog(ERROR, "unrecognized objtype: %d", (int) objtype);
+	return ObjectProperty[(int)objtype].objprop->attnum_relid;
+}
+
+/*
  * Test whether an object exists.
  */
 static bool
 object_exists(ObjectAddress address)
 {
+	int			objtype;
 	int			cache = -1;
 	Oid			indexoid = InvalidOid;
 	Relation	rel;
@@ -697,99 +1230,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 (objtype = 0; objtype < lengthof(ObjectProperty); objtype++)
+		{
+			if (ObjectProperty[objtype].objprop->class_id == address.classId)
+			{
+				cache = ObjectProperty[objtype].objprop->cacheid_by_oid;
+				indexoid = ObjectProperty[objtype].objprop->index_id;
+				break;
+			}
+		}
+		if (objtype == 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 */
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index a4fb3b5..8773cf9 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1103,7 +1103,7 @@ typedef struct SetOperationStmt
 
 typedef enum ObjectType
 {
-	OBJECT_AGGREGATE,
+	OBJECT_AGGREGATE = 0,
 	OBJECT_ATTRIBUTE,			/* type's attribute, when distinct from column */
 	OBJECT_CAST,
 	OBJECT_COLUMN,
