*** a/contrib/pg_upgrade_support/pg_upgrade_support.c
--- b/contrib/pg_upgrade_support/pg_upgrade_support.c
***************
*** 151,156 **** create_empty_extension(PG_FUNCTION_ARGS)
--- 151,157 ----
  	Datum		extConfig;
  	Datum		extCondition;
  	List	   *requiredExtensions;
+ 	List       *features = NIL;	/* FIXME, get features from catalogs */
  
  	if (PG_ARGISNULL(4))
  		extConfig = PointerGetDatum(NULL);
***************
*** 190,196 **** create_empty_extension(PG_FUNCTION_ARGS)
  						 text_to_cstring(extVersion),
  						 extConfig,
  						 extCondition,
! 						 requiredExtensions);
  
  	PG_RETURN_VOID();
  }
--- 191,198 ----
  						 text_to_cstring(extVersion),
  						 extConfig,
  						 extCondition,
! 						 requiredExtensions,
! 						 features);
  
  	PG_RETURN_VOID();
  }
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 149,154 ****
--- 149,159 ----
       </row>
  
       <row>
+       <entry><link linkend="catalog-pg-extension"><structname>pg_extension_feature</structname></link></entry>
+       <entry>features provided by installed extensions</entry>
+      </row>
+ 
+      <row>
        <entry><link linkend="catalog-pg-foreign-data-wrapper"><structname>pg_foreign_data_wrapper</structname></link></entry>
        <entry>foreign-data wrapper definitions</entry>
       </row>
***************
*** 3047,3052 ****
--- 3052,3102 ----
    </para>
   </sect1>
  
+  <sect1 id="catalog-pg-extension-feature">
+   <title><structname>pg_extension_feature</structname></title>
+ 
+   <indexterm zone="catalog-pg-extension-feature">
+    <primary>pg_extension</primary>
+   </indexterm>
+ 
+   <para>
+    The catalog <structname>pg_extension_feature</structname> stores
+    information about the features provided by installed extensions.
+    See <xref linkend="extend-extensions"> for details about extensions.
+   </para>
+ 
+   <table>
+    <title><structname>pg_extension_features</> Columns</title>
+ 
+    <tgroup cols="4">
+     <thead>
+      <row>
+       <entry>Name</entry>
+       <entry>Type</entry>
+       <entry>References</entry>
+       <entry>Description</entry>
+      </row>
+     </thead>
+ 
+     <tbody>
+      <row>
+       <entry><structfield>extoid</structfield></entry>
+       <entry><type>oid</type></entry>
+       <entry><literal><link linkend="catalog-pg-extension"><structname>pg_extension</structname></link>.oid</literal></entry>
+       <entry>Oid of the extension that provides this feature</entry>
+      </row>
+ 
+      <row>
+       <entry><structfield>extfeature</structfield></entry>
+       <entry><type>name</type></entry>
+       <entry></entry>
+       <entry>Name of the feature</entry>
+      </row>
+ 
+     </tbody>
+    </tgroup>
+   </table>
+  </sect1>
  
   <sect1 id="catalog-pg-foreign-data-wrapper">
    <title><structname>pg_foreign_data_wrapper</structname></title>
***************
*** 6804,6814 ****
       <row>
        <entry><structfield>requires</structfield></entry>
        <entry><type>name[]</type></entry>
!       <entry>Names of prerequisite extensions,
         or <literal>NULL</literal> if none</entry>
       </row>
  
       <row>
        <entry><structfield>comment</structfield></entry>
        <entry><type>text</type></entry>
        <entry>Comment string from the extension's control file</entry>
--- 6854,6870 ----
       <row>
        <entry><structfield>requires</structfield></entry>
        <entry><type>name[]</type></entry>
!       <entry>Names of prerequisite features,
         or <literal>NULL</literal> if none</entry>
       </row>
  
       <row>
+       <entry><structfield>provides</structfield></entry>
+       <entry><type>name[]</type></entry>
+       <entry>Names of provided features</entry>
+      </row>
+ 
+      <row>
        <entry><structfield>comment</structfield></entry>
        <entry><type>text</type></entry>
        <entry>Comment string from the extension's control file</entry>
*** a/doc/src/sgml/extend.sgml
--- b/doc/src/sgml/extend.sgml
***************
*** 463,471 ****
        <term><varname>requires</varname> (<type>string</type>)</term>
        <listitem>
         <para>
!         A list of names of extensions that this extension depends on,
!         for example <literal>requires = 'foo, bar'</literal>.  Those
!         extensions must be installed before this one can be installed.
         </para>
        </listitem>
       </varlistentry>
--- 463,492 ----
        <term><varname>requires</varname> (<type>string</type>)</term>
        <listitem>
         <para>
!         A list of features that this extension depends on, for
!         example <literal>requires = 'foo, bar'</literal>. Those features
!         must be provided by an already installed extension before this one
!         can be installed.
!        </para>
!       </listitem>
!      </varlistentry>
! 
!      <varlistentry>
!       <term><varname>provides</varname> (<type>string</type>)</term>
!       <listitem>
!        <para>
!         A list of names of features that this extension provides, for
!         example <literal>provides = 'foo, extname_bugfix_12345'</literal>.
!         Those features can help providing finer dependencies: when updating
!         an existing extension you can add new features in this list so that
!         it's possible to depend on those new features. It also makes it
!         possible to deprecate features that an extension would no longer
!         provide.
!        </para>
!        <para>
!         The extension's name itself is always considered a member of
!         the <literal>provides</literal> list, so that you can entirely omit
!         this parameter.
         </para>
        </listitem>
       </varlistentry>
*** a/src/backend/catalog/Makefile
--- b/src/backend/catalog/Makefile
***************
*** 36,42 **** POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
  	pg_database.h pg_db_role_setting.h pg_tablespace.h pg_pltemplate.h \
  	pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
  	pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
! 	pg_ts_parser.h pg_ts_template.h pg_extension.h \
  	pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
  	pg_foreign_table.h \
  	pg_default_acl.h pg_seclabel.h pg_shseclabel.h pg_collation.h pg_range.h \
--- 36,42 ----
  	pg_database.h pg_db_role_setting.h pg_tablespace.h pg_pltemplate.h \
  	pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
  	pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
! 	pg_ts_parser.h pg_ts_template.h pg_extension.h pg_extension_feature.h \
  	pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
  	pg_foreign_table.h \
  	pg_default_acl.h pg_seclabel.h pg_shseclabel.h pg_collation.h pg_range.h \
*** a/src/backend/catalog/dependency.c
--- b/src/backend/catalog/dependency.c
***************
*** 34,39 ****
--- 34,40 ----
  #include "catalog/pg_default_acl.h"
  #include "catalog/pg_depend.h"
  #include "catalog/pg_extension.h"
+ #include "catalog/pg_extension_feature.h"
  #include "catalog/pg_foreign_data_wrapper.h"
  #include "catalog/pg_foreign_server.h"
  #include "catalog/pg_language.h"
***************
*** 157,163 **** static const Oid object_classes[MAX_OCLASS] = {
  	ForeignServerRelationId,	/* OCLASS_FOREIGN_SERVER */
  	UserMappingRelationId,		/* OCLASS_USER_MAPPING */
  	DefaultAclRelationId,		/* OCLASS_DEFACL */
! 	ExtensionRelationId			/* OCLASS_EXTENSION */
  };
  
  
--- 158,165 ----
  	ForeignServerRelationId,	/* OCLASS_FOREIGN_SERVER */
  	UserMappingRelationId,		/* OCLASS_USER_MAPPING */
  	DefaultAclRelationId,		/* OCLASS_DEFACL */
! 	ExtensionRelationId,		/* OCLASS_EXTENSION */
! 	ExtensionFeatureRelationId	/* OCLASS_EXTENSION_FEATURE */
  };
  
  
***************
*** 1161,1166 **** doDeletion(const ObjectAddress *object)
--- 1163,1172 ----
  			RemoveExtensionById(object->objectId);
  			break;
  
+ 		case OCLASS_EXTENSION_FEATURE:
+ 			RemoveExtensionFeatureById(object->objectId);
+ 			break;
+ 
  		default:
  			elog(ERROR, "unrecognized object class: %u",
  				 object->classId);
***************
*** 2173,2178 **** getObjectClass(const ObjectAddress *object)
--- 2179,2187 ----
  
  		case ExtensionRelationId:
  			return OCLASS_EXTENSION;
+ 
+ 		case ExtensionFeatureRelationId:
+ 			return OCLASS_EXTENSION_FEATURE;
  	}
  
  	/* shouldn't get here */
***************
*** 2807,2812 **** getObjectDescription(const ObjectAddress *object)
--- 2816,2833 ----
  				break;
  			}
  
+ 		case OCLASS_EXTENSION_FEATURE:
+ 			{
+ 				char	   *feature;
+ 
+ 				feature = get_extension_feature_name(object->objectId);
+ 				if (!feature)
+ 					elog(ERROR, "cache lookup failed for extension feature %u",
+ 						 object->objectId);
+ 				appendStringInfo(&buffer, _("extension feature %s"), feature);
+ 				break;
+ 			}
+ 
  		default:
  			appendStringInfo(&buffer, "unrecognized object %u %u %d",
  							 object->classId,
*** a/src/backend/catalog/system_views.sql
--- b/src/backend/catalog/system_views.sql
***************
*** 161,167 **** CREATE VIEW pg_available_extensions AS
  
  CREATE VIEW pg_available_extension_versions AS
      SELECT E.name, E.version, (X.extname IS NOT NULL) AS installed,
!            E.superuser, E.relocatable, E.schema, E.requires, E.comment
        FROM pg_available_extension_versions() AS E
             LEFT JOIN pg_extension AS X
               ON E.name = X.extname AND E.version = X.extversion;
--- 161,167 ----
  
  CREATE VIEW pg_available_extension_versions AS
      SELECT E.name, E.version, (X.extname IS NOT NULL) AS installed,
!            E.superuser, E.relocatable, E.schema, E.requires, E.provides, E.comment
        FROM pg_available_extension_versions() AS E
             LEFT JOIN pg_extension AS X
               ON E.name = X.extname AND E.version = X.extversion;
*** a/src/backend/commands/extension.c
--- b/src/backend/commands/extension.c
***************
*** 36,41 ****
--- 36,42 ----
  #include "catalog/pg_collation.h"
  #include "catalog/pg_depend.h"
  #include "catalog/pg_extension.h"
+ #include "catalog/pg_extension_feature.h"
  #include "catalog/pg_namespace.h"
  #include "catalog/pg_type.h"
  #include "commands/alter.h"
***************
*** 73,78 **** typedef struct ExtensionControlFile
--- 74,80 ----
  	bool		superuser;		/* must be superuser to install? */
  	int			encoding;		/* encoding of the script file, or -1 */
  	List	   *requires;		/* names of prerequisite extensions */
+ 	List	   *provides;		/* names of provided features */
  } ExtensionControlFile;
  
  /*
***************
*** 89,94 **** typedef struct ExtensionVersionInfo
--- 91,117 ----
  	struct ExtensionVersionInfo *previous;		/* current best predecessor */
  } ExtensionVersionInfo;
  
+ /*
+  * Data Structure to handle upgrading of extension features dependencies, and
+  * allow manage features that didn't change, added ones and removed ones.
+  */
+ struct feature
+ {
+ 	Oid   oid;				/* feature oid */
+ 	char *name;				/* feature name */
+ 	int   count;			/* feature usage count */
+ };
+ 
+ /* bsearch function to compare string and struct feature by name */
+ static int
+ cmpfeatname(const void *a, const void *b)
+ {
+ 	char  *p = (char *) a;
+ 	struct feature *f = (struct feature *) b;
+ 
+ 	return strcmp(p, f->name);
+ }
+ 
  /* Local functions */
  static List *find_update_path(List *evi_list,
  				 ExtensionVersionInfo *evi_start,
***************
*** 101,107 **** static void ApplyExtensionUpdates(Oid extensionOid,
  					  ExtensionControlFile *pcontrol,
  					  const char *initialVersion,
  					  List *updateVersions);
! 
  
  /*
   * get_extension_oid - given an extension name, look up the OID
--- 124,133 ----
  					  ExtensionControlFile *pcontrol,
  					  const char *initialVersion,
  					  List *updateVersions);
! static void insert_extension_features(const char *extName, ObjectAddress myself,
! 									  List *features);
! static void insert_extension_feature(Relation rel, ObjectAddress myself,
! 									 const char *feature);
  
  /*
   * get_extension_oid - given an extension name, look up the OID
***************
*** 228,233 **** get_extension_schema(Oid ext_oid)
--- 254,333 ----
  }
  
  /*
+  * Given a feature name, returns its pg_extension_feature oid.
+  */
+ static void
+ get_extension_feature_oids(const char *feature, bool missing_ok,
+ 						   Oid *extoid, Oid *featoid)
+ {
+ 	Relation	rel;
+ 	SysScanDesc scandesc;
+ 	HeapTuple	tuple;
+ 	ScanKeyData entry[1];
+ 
+ 	rel = heap_open(ExtensionFeatureRelationId, AccessShareLock);
+ 
+ 	ScanKeyInit(&entry[0],
+ 				Anum_pg_extension_feature_extfeature,
+ 				BTEqualStrategyNumber, F_NAMEEQ,
+ 				CStringGetDatum(feature));
+ 
+ 	scandesc = systable_beginscan(rel, ExtensionFeatureIndexId, true,
+ 								  SnapshotNow, 1, entry);
+ 
+ 	tuple = systable_getnext(scandesc);
+ 
+ 	/* We assume that there can be at most one matching tuple */
+ 	if (HeapTupleIsValid(tuple))
+ 	{
+ 		*extoid = ((Form_pg_extension_feature)tuple)->extoid;
+ 		*featoid = HeapTupleGetOid(tuple);
+ 	}
+ 	else
+ 	{
+ 		*extoid = InvalidOid;
+ 		*featoid = InvalidOid;
+ 	}
+ 
+ 	systable_endscan(scandesc);
+ 
+ 	heap_close(rel, AccessShareLock);
+ 
+ 	if (!OidIsValid(featoid) && !missing_ok)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 				 errmsg("extension's feature \"%s\" is not installed",
+ 						feature)));
+ }
+ 
+ /*
+  * Look up the prerequisite extensions, and build lists of their OIDs and
+  * the OIDs of their target schemas.
+  */
+ static void
+ get_required_extension_features(List *requires,
+ 								List **requiredFeatures,
+ 								List **requiredSchemas)
+ {
+ 	ListCell   *lc;
+ 
+ 	*requiredFeatures = NIL;
+ 	*requiredSchemas  = NIL;
+ 
+ 	foreach(lc, requires)
+ 	{
+ 		char	   *curreq = (char *) lfirst(lc);
+ 		Oid			reqext, featoid, reqschema;
+ 
+ 		/* use get_extension_providing error message for missing requirements */
+ 		get_extension_feature_oids(curreq, false, &reqext, &featoid);
+ 		reqschema = get_extension_schema(reqext);
+ 		*requiredFeatures = lappend_oid(*requiredFeatures, featoid);
+ 		*requiredSchemas = lappend_oid(*requiredSchemas, reqschema);
+ 	}
+ }
+ 
+ /*
   * Utility functions to check validity of extension and version names
   */
  static void
***************
*** 557,562 **** parse_extension_control_file(ExtensionControlFile *control,
--- 657,677 ----
  						item->name)));
  			}
  		}
+ 		else if (strcmp(item->name, "provides") == 0)
+ 		{
+ 			/* Need a modifiable copy of string */
+ 			char	   *rawnames = pstrdup(item->value);
+ 
+ 			/* Parse string into list of identifiers */
+ 			if (!SplitIdentifierString(rawnames, ',', &control->provides))
+ 			{
+ 				/* syntax error in name list */
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ 				 errmsg("parameter \"%s\" must be a list of extension names",
+ 						item->name)));
+ 			}
+ 		}
  		else
  			ereport(ERROR,
  					(errcode(ERRCODE_SYNTAX_ERROR),
***************
*** 1186,1192 **** CreateExtension(CreateExtensionStmt *stmt)
  	ExtensionControlFile *pcontrol;
  	ExtensionControlFile *control;
  	List	   *updateVersions;
! 	List	   *requiredExtensions;
  	List	   *requiredSchemas;
  	Oid			extensionOid;
  	ListCell   *lc;
--- 1301,1307 ----
  	ExtensionControlFile *pcontrol;
  	ExtensionControlFile *control;
  	List	   *updateVersions;
! 	List	   *requiredFeatures;
  	List	   *requiredSchemas;
  	Oid			extensionOid;
  	ListCell   *lc;
***************
*** 1414,1441 **** CreateExtension(CreateExtensionStmt *stmt)
  	 * Look up the prerequisite extensions, and build lists of their OIDs and
  	 * the OIDs of their target schemas.
  	 */
! 	requiredExtensions = NIL;
! 	requiredSchemas = NIL;
! 	foreach(lc, control->requires)
! 	{
! 		char	   *curreq = (char *) lfirst(lc);
! 		Oid			reqext;
! 		Oid			reqschema;
! 
! 		/*
! 		 * We intentionally don't use get_extension_oid's default error
! 		 * message here, because it would be confusing in this context.
! 		 */
! 		reqext = get_extension_oid(curreq, true);
! 		if (!OidIsValid(reqext))
! 			ereport(ERROR,
! 					(errcode(ERRCODE_UNDEFINED_OBJECT),
! 					 errmsg("required extension \"%s\" is not installed",
! 							curreq)));
! 		reqschema = get_extension_schema(reqext);
! 		requiredExtensions = lappend_oid(requiredExtensions, reqext);
! 		requiredSchemas = lappend_oid(requiredSchemas, reqschema);
! 	}
  
  	/*
  	 * Insert new tuple into pg_extension, and create dependency entries.
--- 1529,1537 ----
  	 * Look up the prerequisite extensions, and build lists of their OIDs and
  	 * the OIDs of their target schemas.
  	 */
! 	get_required_extension_features(control->requires,
! 									&requiredFeatures,
! 									&requiredSchemas);
  
  	/*
  	 * Insert new tuple into pg_extension, and create dependency entries.
***************
*** 1445,1451 **** CreateExtension(CreateExtensionStmt *stmt)
  										versionName,
  										PointerGetDatum(NULL),
  										PointerGetDatum(NULL),
! 										requiredExtensions);
  
  	/*
  	 * Apply any control-file comment on extension
--- 1541,1548 ----
  										versionName,
  										PointerGetDatum(NULL),
  										PointerGetDatum(NULL),
! 										requiredFeatures,
! 										control->provides);
  
  	/*
  	 * Apply any control-file comment on extension
***************
*** 1486,1492 **** Oid
  InsertExtensionTuple(const char *extName, Oid extOwner,
  					 Oid schemaOid, bool relocatable, const char *extVersion,
  					 Datum extConfig, Datum extCondition,
! 					 List *requiredExtensions)
  {
  	Oid			extensionOid;
  	Relation	rel;
--- 1583,1589 ----
  InsertExtensionTuple(const char *extName, Oid extOwner,
  					 Oid schemaOid, bool relocatable, const char *extVersion,
  					 Datum extConfig, Datum extCondition,
! 					 List *requiredFeatures, List *features)
  {
  	Oid			extensionOid;
  	Relation	rel;
***************
*** 1545,1561 **** InsertExtensionTuple(const char *extName, Oid extOwner,
  
  	recordDependencyOn(&myself, &nsp, DEPENDENCY_NORMAL);
  
! 	foreach(lc, requiredExtensions)
  	{
! 		Oid			reqext = lfirst_oid(lc);
! 		ObjectAddress otherext;
  
! 		otherext.classId = ExtensionRelationId;
! 		otherext.objectId = reqext;
! 		otherext.objectSubId = 0;
  
! 		recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
  	}
  	/* Post creation hook for new extension */
  	InvokeObjectAccessHook(OAT_POST_CREATE,
  						   ExtensionRelationId, extensionOid, 0);
--- 1642,1663 ----
  
  	recordDependencyOn(&myself, &nsp, DEPENDENCY_NORMAL);
  
! 	foreach(lc, requiredFeatures)
  	{
! 		Oid			reqfeat = lfirst_oid(lc);
! 		ObjectAddress feature;
  
! 		feature.classId = ExtensionFeatureRelationId;
! 		feature.objectId = reqfeat;
! 		feature.objectSubId = 0;
  
! 		recordDependencyOn(&myself, &feature, DEPENDENCY_NORMAL);
  	}
+ 	/*
+ 	 * Insert extension's features into pg_extension_feature catalog
+ 	 */
+ 	insert_extension_features(extName, myself, features);
+ 
  	/* Post creation hook for new extension */
  	InvokeObjectAccessHook(OAT_POST_CREATE,
  						   ExtensionRelationId, extensionOid, 0);
***************
*** 1615,1620 **** RemoveExtensionById(Oid extId)
--- 1717,1996 ----
  }
  
  /*
+  * Get an extension's feature name given its objectId
+  */
+ char *
+ get_extension_feature_name(Oid featoid)
+ {
+ 	Relation rel;
+ 	SysScanDesc scandesc;
+ 	HeapTuple	tuple;
+ 	ScanKeyData entry[1];
+ 	char *name;
+ 
+ 	rel = heap_open(ExtensionFeatureRelationId, AccessShareLock);
+ 
+ 	ScanKeyInit(&entry[0],
+ 				ObjectIdAttributeNumber,
+ 				BTEqualStrategyNumber, F_OIDEQ,
+ 				ObjectIdGetDatum(featoid));
+ 
+ 	scandesc = systable_beginscan(rel, ExtensionFeatureOidIndexId, true,
+ 								  SnapshotNow, 1, entry);
+ 
+ 	tuple = systable_getnext(scandesc);
+ 
+ 	/* We assume that there can be at most one matching tuple */
+ 	if (HeapTupleIsValid(tuple))
+ 	{
+ 		Form_pg_extension_feature f = (Form_pg_extension_feature) GETSTRUCT(tuple);
+ 		name = pstrdup(NameStr(f->extfeature));
+ 	}
+ 	else
+ 		name = NULL;
+ 
+ 	systable_endscan(scandesc);
+ 
+ 	heap_close(rel, AccessShareLock);
+ 
+ 	return name;
+ }
+ 
+ /*
+  * Insert provided features into the pg_extension_feature catalog
+  */
+ static void
+ insert_extension_features(const char *extName, ObjectAddress extObject,
+ 						  List *features)
+ {
+ 	Relation	rel;
+ 	ListCell   *lc;
+ 	bool        provides_itself = false;
+ 
+ 	rel = heap_open(ExtensionFeatureRelationId, RowExclusiveLock);
+ 
+ 	foreach(lc, features)
+ 	{
+ 		char       *feature = (char *) lfirst(lc);
+ 		insert_extension_feature(rel, extObject, feature);
+ 
+ 		provides_itself = (strcmp(feature, extName) == 0);
+ 	}
+ 
+ 	if (!provides_itself)
+ 		insert_extension_feature(rel, extObject, extName);
+ 
+ 	heap_close(rel, RowExclusiveLock);
+ }
+ 
+ static void
+ insert_extension_feature(Relation rel,
+ 						 ObjectAddress extObject, const char *feature)
+ {
+ 	Oid			featureOid;
+ 	Datum		values[Natts_pg_extension_feature];
+ 	bool		nulls[Natts_pg_extension_feature];
+ 	HeapTuple	tuple;
+ 	ObjectAddress myself;
+ 
+ 	/*
+ 	 * Build and insert the pg_extension_feature tuple
+ 	 */
+ 	memset(values, 0, sizeof(values));
+ 	memset(nulls, 0, sizeof(nulls));
+ 
+ 	values[Anum_pg_extension_feature_extoid - 1] =
+ 		ObjectIdGetDatum(extObject.objectId);
+ 	values[Anum_pg_extension_feature_extfeature - 1] =
+ 		DirectFunctionCall1(namein, CStringGetDatum(feature));
+ 
+ 	tuple = heap_form_tuple(rel->rd_att, values, nulls);
+ 
+ 	featureOid = simple_heap_insert(rel, tuple);
+ 	CatalogUpdateIndexes(rel, tuple);
+ 
+ 	heap_freetuple(tuple);
+ 
+ 	/* handle internal dependencies between the extension tuple and the
+ 	 * extension's feature tuple
+ 	 */
+ 	myself.classId = ExtensionFeatureRelationId;
+ 	myself.objectId = featureOid;
+ 	myself.objectSubId = 0;
+ 
+ 	recordDependencyOn(&extObject, &myself, DEPENDENCY_INTERNAL);
+ }
+ 
+ /* static struct feature * */
+ static int
+ list_extension_features(Oid extoid, struct feature **features)
+ {
+ 	int nbfeats = 0, size = 10;
+ 	Relation	rel, irel;
+ 	SysScanDesc scandesc;
+ 	HeapTuple	tuple;
+ 	ScanKeyData entry[1];
+ 
+ 	*features = (struct feature *) palloc(size * sizeof(struct feature));
+ 
+ 	rel = heap_open(ExtensionFeatureRelationId, AccessShareLock);
+ 	irel = index_open(ExtensionFeatureIndexId, AccessShareLock);
+ 
+ 	ScanKeyInit(&entry[0],
+ 				Anum_pg_extension_feature_extoid,
+ 				BTEqualStrategyNumber, F_OIDEQ,
+ 				ObjectIdGetDatum(extoid));
+ 
+ 	scandesc = systable_beginscan_ordered(rel, irel, SnapshotNow, 1, entry);
+ 
+ 	while (HeapTupleIsValid(tuple = systable_getnext_ordered(scandesc, ForwardScanDirection)))
+ 	{
+ 		Form_pg_extension_feature f = (Form_pg_extension_feature) GETSTRUCT(tuple);
+ 
+ 		if (nbfeats == size)
+ 		{
+ 			size += 10;
+ 			*features = repalloc(*features, size);
+ 		}
+ 		(*features)[nbfeats].oid   = HeapTupleGetOid(tuple);
+ 		(*features)[nbfeats].name  = pstrdup(NameStr(f->extfeature));
+ 		(*features)[nbfeats].count = 0;
+ 
+ 		nbfeats++;
+ 	}
+ 	systable_endscan_ordered(scandesc);
+ 
+ 	index_close(irel, AccessShareLock);
+ 	heap_close(rel, AccessShareLock);
+ 
+ 	return nbfeats;
+ }
+ 
+ /*
+  * Care about an extension's provided features changes:
+  *  - do nothing when the feature was already provided
+  *  - add new dependencies when a new feature is provided
+  *  - delete dependencies that are not provided anymore
+  */
+ static void
+ update_extension_feature_list(ExtensionControlFile *control,
+ 							  ObjectAddress ext)
+ {
+ 	Relation    rel;
+ 	struct feature *features;
+     int         nbfeats = list_extension_features(ext.objectId, &features);
+ 	int         i;
+ 	ListCell   *lc;
+ 
+ 	/*
+ 	 * Remove all this extension features dependencies, and add them again
+ 	 * while processing the new "provides" list. That allows to use the
+ 	 * pg_depend performDeletion() API to implement removing a feature from the
+ 	 * provide list: we have to skip the extension providing the feature itself
+ 	 * when following dependencies in DROP_RESTRICT mode.
+ 	 */
+ 	deleteDependencyRecordsForClass(ext.classId, ext.objectId,
+ 									ExtensionFeatureRelationId,
+ 									DEPENDENCY_INTERNAL);
+ 
+ 	/* Have that change visible now, for the performDeletion() call */
+ 	CommandCounterIncrement();
+ 
+ 	rel = heap_open(ExtensionFeatureRelationId, RowExclusiveLock);
+ 
+ 	foreach(lc, control->provides)
+ 	{
+ 		char  *feat = (char *) lfirst(lc);
+ 		struct feature *found = NULL;
+ 
+ 		found = (struct feature *)
+ 			bsearch(feat, features, nbfeats, sizeof(struct feature), &cmpfeatname);
+ 
+ 		if (found)
+ 		{
+ 			if (found->count > 0)
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_SYNTAX_ERROR),
+ 						 errmsg("conflicting or redundant options \"%s\"",
+ 								feat)));
+ 
+ 			found->count++;
+ 		}
+ 		else
+ 			insert_extension_feature(rel, ext, feat);
+ 	}
+ 
+ 	/* upgrade is done, remove features not provided anymore, and avoid
+ 	 * removing the extension's name (will not appear in control->provides)
+ 	 */
+ 	for(i=0; i < nbfeats; i++)
+ 	{
+ 		ObjectAddress feature;
+ 
+ 		feature.classId = ExtensionFeatureRelationId;
+ 		feature.objectId = features[i].oid;
+ 		feature.objectSubId = 0;
+ 
+ 		if (strcmp(features[i].name, control->name) == 0)
+ 			/*
+ 			 * The extension's name itself is not in the provide list but still
+ 			 * provided, we have to care about it separately.
+ 			 */
+ 			recordDependencyOn(&ext, &feature, DEPENDENCY_INTERNAL);
+ 
+ 		else if (features[i].count == 0)
+ 			/*
+ 			 * Drop the extension's feature that is no longer provided, raising
+ 			 * an error instead if some other extensions are still depending on
+ 			 * it (control->requires installs pg_depend entries for this case).
+ 			 */
+ 			performDeletion(&feature, DROP_RESTRICT);
+ 
+ 		else if (features[i].count > 0)
+ 			/*
+ 			 * Re-install the dependency entry, we removed it only to allow
+ 			 * using DROP_RESTRICT.
+ 			 */
+ 			recordDependencyOn(&ext, &feature, DEPENDENCY_INTERNAL);
+ 
+ 	}
+ 	heap_close(rel, RowExclusiveLock);
+ }
+ 
+ /*
+  * Extension feature's deletion.
+  *
+  * All we need do here is remove the pg_extension_feature tuple itself.
+  */
+ void
+ RemoveExtensionFeatureById(Oid extFeatId)
+ {
+ 	Relation	rel;
+ 	SysScanDesc scandesc;
+ 	HeapTuple	tuple;
+ 	ScanKeyData entry[1];
+ 
+ 	rel = heap_open(ExtensionFeatureRelationId, RowExclusiveLock);
+ 
+ 	ScanKeyInit(&entry[0],
+ 				ObjectIdAttributeNumber,
+ 				BTEqualStrategyNumber, F_OIDEQ,
+ 				ObjectIdGetDatum(extFeatId));
+ 	scandesc = systable_beginscan(rel, ExtensionFeatureOidIndexId, true,
+ 								  SnapshotNow, 1, entry);
+ 
+ 	tuple = systable_getnext(scandesc);
+ 
+ 	/* We assume that there can be at most one matching tuple */
+ 	if (HeapTupleIsValid(tuple))
+ 		simple_heap_delete(rel, &tuple->t_self);
+ 
+ 	systable_endscan(scandesc);
+ 
+ 	heap_close(rel, RowExclusiveLock);
+ }
+ 
+ /*
   * This function lists the available extensions (one row per primary control
   * file in the control directory).	We parse each control file and report the
   * interesting fields.
***************
*** 1836,1843 **** get_available_versions_for_extension(ExtensionControlFile *pcontrol,
  	{
  		ExtensionControlFile *control;
  		char	   *vername;
! 		Datum		values[7];
! 		bool		nulls[7];
  
  		/* must be a .sql file ... */
  		if (!is_extension_script_filename(de->d_name))
--- 2212,2219 ----
  	{
  		ExtensionControlFile *control;
  		char	   *vername;
! 		Datum		values[8];
! 		bool		nulls[8];
  
  		/* must be a .sql file ... */
  		if (!is_extension_script_filename(de->d_name))
***************
*** 1905,1915 **** get_available_versions_for_extension(ExtensionControlFile *pcontrol,
  								NAMEDATALEN, false, 'c');
  			values[5] = PointerGetDatum(a);
  		}
  		/* comment */
  		if (control->comment == NULL)
! 			nulls[6] = true;
  		else
! 			values[6] = CStringGetTextDatum(control->comment);
  
  		tuplestore_putvalues(tupstore, tupdesc, values, nulls);
  	}
--- 2281,2332 ----
  								NAMEDATALEN, false, 'c');
  			values[5] = PointerGetDatum(a);
  		}
+ 		/* provides */
+ 		nulls[6] = false;
+ 		if (control->provides == NIL)
+ 		{
+ 			Datum	   *datums;
+ 			ArrayType  *a;
+ 
+ 			datums = (Datum *) palloc(1 * sizeof(Datum));
+ 			datums[0] =
+ 				DirectFunctionCall1(namein, CStringGetDatum(pcontrol->name));
+ 			a = construct_array(datums, 1,
+ 								NAMEOID,
+ 								NAMEDATALEN, false, 'c');
+ 			values[6] = PointerGetDatum(a);
+ 		}
+ 		else
+ 		{
+ 			Datum	   *datums;
+ 			int			ndatums;
+ 			ArrayType  *a;
+ 			ListCell   *lc;
+ 
+ 			ndatums = 1 + list_length(control->provides);
+ 			datums = (Datum *) palloc(ndatums * sizeof(Datum));
+ 			ndatums = 0;
+ 			datums[ndatums++] =
+ 				DirectFunctionCall1(namein, CStringGetDatum(pcontrol->name));
+ 			foreach(lc, control->provides)
+ 			{
+ 				char	   *curreq = (char *) lfirst(lc);
+ 
+ 				/* don't add the extension's name more than once in there */
+ 				if (strcmp(curreq,pcontrol->name) != 0)
+ 					datums[ndatums++] =
+ 						DirectFunctionCall1(namein, CStringGetDatum(curreq));
+ 			}
+ 			a = construct_array(datums, ndatums,
+ 								NAMEOID,
+ 								NAMEDATALEN, false, 'c');
+ 			values[6] = PointerGetDatum(a);
+ 		}
  		/* comment */
  		if (control->comment == NULL)
! 			nulls[7] = true;
  		else
! 			values[7] = CStringGetTextDatum(control->comment);
  
  		tuplestore_putvalues(tupstore, tupdesc, values, nulls);
  	}
***************
*** 2505,2511 **** ApplyExtensionUpdates(Oid extensionOid,
  		ExtensionControlFile *control;
  		char	   *schemaName;
  		Oid			schemaOid;
! 		List	   *requiredExtensions;
  		List	   *requiredSchemas;
  		Relation	extRel;
  		ScanKeyData key[1];
--- 2922,2928 ----
  		ExtensionControlFile *control;
  		char	   *schemaName;
  		Oid			schemaOid;
! 		List	   *requiredFeatures;
  		List	   *requiredSchemas;
  		Relation	extRel;
  		ScanKeyData key[1];
***************
*** 2516,2522 **** ApplyExtensionUpdates(Oid extensionOid,
  		bool		nulls[Natts_pg_extension];
  		bool		repl[Natts_pg_extension];
  		ObjectAddress myself;
- 		ListCell   *lc;
  
  		/*
  		 * Fetch parameters for specific version (pcontrol is not changed)
--- 2933,2938 ----
***************
*** 2573,2630 **** ApplyExtensionUpdates(Oid extensionOid,
  		heap_close(extRel, RowExclusiveLock);
  
  		/*
! 		 * Look up the prerequisite extensions for this version, and build
! 		 * lists of their OIDs and the OIDs of their target schemas.
  		 */
- 		requiredExtensions = NIL;
- 		requiredSchemas = NIL;
- 		foreach(lc, control->requires)
- 		{
- 			char	   *curreq = (char *) lfirst(lc);
- 			Oid			reqext;
- 			Oid			reqschema;
- 
- 			/*
- 			 * We intentionally don't use get_extension_oid's default error
- 			 * message here, because it would be confusing in this context.
- 			 */
- 			reqext = get_extension_oid(curreq, true);
- 			if (!OidIsValid(reqext))
- 				ereport(ERROR,
- 						(errcode(ERRCODE_UNDEFINED_OBJECT),
- 						 errmsg("required extension \"%s\" is not installed",
- 								curreq)));
- 			reqschema = get_extension_schema(reqext);
- 			requiredExtensions = lappend_oid(requiredExtensions, reqext);
- 			requiredSchemas = lappend_oid(requiredSchemas, reqschema);
- 		}
- 
- 		/*
- 		 * Remove and recreate dependencies on prerequisite extensions
- 		 */
- 		deleteDependencyRecordsForClass(ExtensionRelationId, extensionOid,
- 										ExtensionRelationId,
- 										DEPENDENCY_NORMAL);
- 
  		myself.classId = ExtensionRelationId;
  		myself.objectId = extensionOid;
  		myself.objectSubId = 0;
  
! 		foreach(lc, requiredExtensions)
! 		{
! 			Oid			reqext = lfirst_oid(lc);
! 			ObjectAddress otherext;
! 
! 			otherext.classId = ExtensionRelationId;
! 			otherext.objectId = reqext;
! 			otherext.objectSubId = 0;
! 
! 			recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
! 		}
  
  		/*
  		 * Finally, execute the update script file
  		 */
  		execute_extension_script(extensionOid, control,
  								 oldVersionName, versionName,
  								 requiredSchemas,
--- 2989,3009 ----
  		heap_close(extRel, RowExclusiveLock);
  
  		/*
! 		 * Update extension features list and dependencies
  		 */
  		myself.classId = ExtensionRelationId;
  		myself.objectId = extensionOid;
  		myself.objectSubId = 0;
  
! 		update_extension_feature_list(control, myself);
  
  		/*
  		 * Finally, execute the update script file
  		 */
+ 		get_required_extension_features(control->requires,
+ 										&requiredFeatures,
+ 										&requiredSchemas);
+ 
  		execute_extension_script(extensionOid, control,
  								 oldVersionName, versionName,
  								 requiredSchemas,
*** a/src/include/catalog/dependency.h
--- b/src/include/catalog/dependency.h
***************
*** 146,151 **** typedef enum ObjectClass
--- 146,152 ----
  	OCLASS_USER_MAPPING,		/* pg_user_mapping */
  	OCLASS_DEFACL,				/* pg_default_acl */
  	OCLASS_EXTENSION,			/* pg_extension */
+ 	OCLASS_EXTENSION_FEATURE,	/* pg_extension_feature */
  	MAX_OCLASS					/* MUST BE LAST */
  } ObjectClass;
  
*** a/src/include/catalog/indexing.h
--- b/src/include/catalog/indexing.h
***************
*** 303,308 **** DECLARE_UNIQUE_INDEX(pg_extension_oid_index, 3080, on pg_extension using btree(o
--- 303,314 ----
  DECLARE_UNIQUE_INDEX(pg_extension_name_index, 3081, on pg_extension using btree(extname name_ops));
  #define ExtensionNameIndexId 3081
  
+ DECLARE_UNIQUE_INDEX(pg_extension_feature_oid_index, 3180, on pg_extension_feature using btree(oid oid_ops));
+ #define ExtensionFeatureOidIndexId 3180
+ 
+ DECLARE_UNIQUE_INDEX(pg_extension_feature_index, 3181, on pg_extension_feature using btree(extoid oid_ops, extfeature name_ops));
+ #define ExtensionFeatureIndexId 3181
+ 
  DECLARE_UNIQUE_INDEX(pg_range_rngtypid_index, 3542, on pg_range using btree(rngtypid oid_ops));
  #define RangeTypidIndexId					3542
  
*** /dev/null
--- b/src/include/catalog/pg_extension_feature.h
***************
*** 0 ****
--- 1,57 ----
+ /*-------------------------------------------------------------------------
+  *
+  * pg_extension_feature.h
+  *	  definition of the system "extension feature" relation
+  *	  (pg_extension_features), that traks what features an extension provides
+  *
+  *
+  * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * src/include/catalog/pg_extension_feature.h
+  *
+  * NOTES
+  *	  the genbki.pl script reads this file and generates .bki
+  *	  information from the DATA() statements.
+  *
+  *-------------------------------------------------------------------------
+  */
+ #ifndef PG_EXTENSION_FEATURE_H
+ #define PG_EXTENSION_FEATURE_H
+ 
+ #include "catalog/genbki.h"
+ 
+ /* ----------------
+  *		pg_extension_feature definition.  cpp turns this into
+  *		typedef struct FormData_pg_extension_feature
+  * ----------------
+  */
+ #define ExtensionFeatureRelationId 3179
+ 
+ CATALOG(pg_extension_feature,3179)
+ {
+ 	Oid			extoid;		/* extension Oid */
+ 	NameData	extfeature;		/* extension feature */
+ } FormData_pg_extension_feature;
+ 
+ /* ----------------
+  *		Form_pg_extension_feature corresponds to a pointer to a tuple with the
+  *		format of pg_extension_feature relation.
+  * ----------------
+  */
+ typedef FormData_pg_extension_feature *Form_pg_extension_feature;
+ /* ----------------
+  *		compiler constants for pg_extension_feature
+  * ----------------
+  */
+ 
+ #define Natts_pg_extension_feature				2
+ #define Anum_pg_extension_feature_extoid		1
+ #define Anum_pg_extension_feature_extfeature	2
+ 
+ /* ----------------
+  *		pg_extension_feature has no initial contents
+  * ----------------
+  */
+ 
+ #endif   /* PG_EXTENSION_FEATURE_H */
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
***************
*** 4316,4322 **** DESCR("less-equal-greater");
  /* Extensions */
  DATA(insert OID = 3082 (  pg_available_extensions		PGNSP PGUID 12 10 100 0 0 f f f t t s 0 0 2249 "" "{19,25,25}" "{o,o,o}" "{name,default_version,comment}" _null_ pg_available_extensions _null_ _null_ _null_ ));
  DESCR("list available extensions");
! DATA(insert OID = 3083 (  pg_available_extension_versions	PGNSP PGUID 12 10 100 0 0 f f f t t s 0 0 2249 "" "{19,25,16,16,19,1003,25}" "{o,o,o,o,o,o,o}" "{name,version,superuser,relocatable,schema,requires,comment}" _null_ pg_available_extension_versions _null_ _null_ _null_ ));
  DESCR("list available extension versions");
  DATA(insert OID = 3084 (  pg_extension_update_paths		PGNSP PGUID 12 10 100 0 0 f f f t t s 1 0 2249 "19" "{19,25,25,25}" "{i,o,o,o}" "{name,source,target,path}" _null_ pg_extension_update_paths _null_ _null_ _null_ ));
  DESCR("list an extension's version update paths");
--- 4316,4322 ----
  /* Extensions */
  DATA(insert OID = 3082 (  pg_available_extensions		PGNSP PGUID 12 10 100 0 0 f f f t t s 0 0 2249 "" "{19,25,25}" "{o,o,o}" "{name,default_version,comment}" _null_ pg_available_extensions _null_ _null_ _null_ ));
  DESCR("list available extensions");
! DATA(insert OID = 3083 (  pg_available_extension_versions	PGNSP PGUID 12 10 100 0 0 f f f t t s 0 0 2249 "" "{19,25,16,16,19,1003,1003,25}" "{o,o,o,o,o,o,o,o}" "{name,version,superuser,relocatable,schema,requires,provides,comment}" _null_ pg_available_extension_versions _null_ _null_ _null_ ));
  DESCR("list available extension versions");
  DATA(insert OID = 3084 (  pg_extension_update_paths		PGNSP PGUID 12 10 100 0 0 f f f t t s 1 0 2249 "19" "{19,25,25,25}" "{i,o,o,o}" "{name,source,target,path}" _null_ pg_extension_update_paths _null_ _null_ _null_ ));
  DESCR("list an extension's version update paths");
*** a/src/include/commands/extension.h
--- b/src/include/commands/extension.h
***************
*** 30,40 **** extern Oid	CurrentExtensionObject;
  extern void CreateExtension(CreateExtensionStmt *stmt);
  
  extern void RemoveExtensionById(Oid extId);
  
  extern Oid InsertExtensionTuple(const char *extName, Oid extOwner,
  					 Oid schemaOid, bool relocatable, const char *extVersion,
  					 Datum extConfig, Datum extCondition,
! 					 List *requiredExtensions);
  
  extern void ExecAlterExtensionStmt(AlterExtensionStmt *stmt);
  
--- 30,41 ----
  extern void CreateExtension(CreateExtensionStmt *stmt);
  
  extern void RemoveExtensionById(Oid extId);
+ extern void RemoveExtensionFeatureById(Oid extFeatId);
  
  extern Oid InsertExtensionTuple(const char *extName, Oid extOwner,
  					 Oid schemaOid, bool relocatable, const char *extVersion,
  					 Datum extConfig, Datum extCondition,
! 					 List *requiredExtensions, List *features);
  
  extern void ExecAlterExtensionStmt(AlterExtensionStmt *stmt);
  
***************
*** 45,48 **** extern char *get_extension_name(Oid ext_oid);
--- 46,51 ----
  
  extern void AlterExtensionNamespace(List *names, const char *newschema);
  
+ extern char * get_extension_feature_name(Oid featoid);
+ 
  #endif   /* EXTENSION_H */
*** a/src/test/regress/expected/rules.out
--- b/src/test/regress/expected/rules.out
***************
*** 1279,1285 **** SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
              viewname             |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   definition                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
  ---------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   iexit                           | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
!  pg_available_extension_versions | SELECT e.name, e.version, (x.extname IS NOT NULL) AS installed, e.superuser, e.relocatable, e.schema, e.requires, e.comment FROM (pg_available_extension_versions() e(name, version, superuser, relocatable, schema, requires, comment) LEFT JOIN pg_extension x ON (((e.name = x.extname) AND (e.version = x.extversion))));
   pg_available_extensions         | SELECT e.name, e.default_version, x.extversion AS installed_version, e.comment FROM (pg_available_extensions() e(name, default_version, comment) LEFT JOIN pg_extension x ON ((e.name = x.extname)));
   pg_cursors                      | SELECT c.name, c.statement, c.is_holdable, c.is_binary, c.is_scrollable, c.creation_time FROM pg_cursor() c(name, statement, is_holdable, is_binary, is_scrollable, creation_time);
   pg_group                        | SELECT pg_authid.rolname AS groname, pg_authid.oid AS grosysid, ARRAY(SELECT pg_auth_members.member FROM pg_auth_members WHERE (pg_auth_members.roleid = pg_authid.oid)) AS grolist FROM pg_authid WHERE (NOT pg_authid.rolcanlogin);
--- 1279,1285 ----
              viewname             |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   definition                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
  ---------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   iexit                           | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
!  pg_available_extension_versions | SELECT e.name, e.version, (x.extname IS NOT NULL) AS installed, e.superuser, e.relocatable, e.schema, e.requires, e.provides, e.comment FROM (pg_available_extension_versions() e(name, version, superuser, relocatable, schema, requires, provides, comment) LEFT JOIN pg_extension x ON (((e.name = x.extname) AND (e.version = x.extversion))));
   pg_available_extensions         | SELECT e.name, e.default_version, x.extversion AS installed_version, e.comment FROM (pg_available_extensions() e(name, default_version, comment) LEFT JOIN pg_extension x ON ((e.name = x.extname)));
   pg_cursors                      | SELECT c.name, c.statement, c.is_holdable, c.is_binary, c.is_scrollable, c.creation_time FROM pg_cursor() c(name, statement, is_holdable, is_binary, is_scrollable, creation_time);
   pg_group                        | SELECT pg_authid.rolname AS groname, pg_authid.oid AS grosysid, ARRAY(SELECT pg_auth_members.member FROM pg_auth_members WHERE (pg_auth_members.roleid = pg_authid.oid)) AS grolist FROM pg_authid WHERE (NOT pg_authid.rolcanlogin);
*** a/src/test/regress/expected/sanity_check.out
--- b/src/test/regress/expected/sanity_check.out
***************
*** 102,107 **** SELECT relname, relhasindex
--- 102,108 ----
   pg_description          | t
   pg_enum                 | t
   pg_extension            | t
+  pg_extension_feature    | t
   pg_foreign_data_wrapper | t
   pg_foreign_server       | t
   pg_foreign_table        | t
***************
*** 161,167 **** SELECT relname, relhasindex
   timetz_tbl              | f
   tinterval_tbl           | f
   varchar_tbl             | f
! (150 rows)
  
  --
  -- another sanity check: every system catalog that has OIDs should have
--- 162,168 ----
   timetz_tbl              | f
   tinterval_tbl           | f
   varchar_tbl             | f
! (151 rows)
  
  --
  -- another sanity check: every system catalog that has OIDs should have
