*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 55,60 ****
--- 55,61 ----
  #include "utils/guc.h"
  #include "utils/ps_status.h"
  #include "utils/relmapper.h"
+ #include "utils/cfparser.h"
  #include "pg_trace.h"
  
  
***************
*** 5018,5117 **** str_time(pg_time_t tnow)
  }
  
  /*
-  * Parse one line from recovery.conf. 'cmdline' is the raw line from the
-  * file. If the line is parsed successfully, returns true, false indicates
-  * syntax error. On success, *key_p and *value_p are set to the parameter
-  * name and value on the line, respectively. If the line is an empty line,
-  * consisting entirely of whitespace and comments, function returns true
-  * and *keyp_p and *value_p are set to NULL.
-  *
-  * The pointers returned in *key_p and *value_p point to an internal buffer
-  * that is valid only until the next call of parseRecoveryCommandFile().
-  */
- static bool
- parseRecoveryCommandFileLine(char *cmdline, char **key_p, char **value_p)
- {
- 	char	   *ptr;
- 	char	   *bufp;
- 	char	   *key;
- 	char	   *value;
- 	static char *buf = NULL;
- 
- 	*key_p = *value_p = NULL;
- 
- 	/*
- 	 * Allocate the buffer on first use. It's used to hold both the parameter
- 	 * name and value.
- 	 */
- 	if (buf == NULL)
- 		buf = malloc(MAXPGPATH + 1);
- 	bufp = buf;
- 
- 	/* Skip any whitespace at the beginning of line */
- 	for (ptr = cmdline; *ptr; ptr++)
- 	{
- 		if (!isspace((unsigned char) *ptr))
- 			break;
- 	}
- 	/* Ignore empty lines */
- 	if (*ptr == '\0' || *ptr == '#')
- 		return true;
- 
- 	/* Read the parameter name */
- 	key = bufp;
- 	while (*ptr && !isspace((unsigned char) *ptr) &&
- 		   *ptr != '=' && *ptr != '\'')
- 		*(bufp++) = *(ptr++);
- 	*(bufp++) = '\0';
- 
- 	/* Skip to the beginning quote of the parameter value */
- 	ptr = strchr(ptr, '\'');
- 	if (!ptr)
- 		return false;
- 	ptr++;
- 
- 	/* Read the parameter value to *bufp. Collapse any '' escapes as we go. */
- 	value = bufp;
- 	for (;;)
- 	{
- 		if (*ptr == '\'')
- 		{
- 			ptr++;
- 			if (*ptr == '\'')
- 				*(bufp++) = '\'';
- 			else
- 			{
- 				/* end of parameter */
- 				*bufp = '\0';
- 				break;
- 			}
- 		}
- 		else if (*ptr == '\0')
- 			return false;		/* unterminated quoted string */
- 		else
- 			*(bufp++) = *ptr;
- 
- 		ptr++;
- 	}
- 	*(bufp++) = '\0';
- 
- 	/* Check that there's no garbage after the value */
- 	while (*ptr)
- 	{
- 		if (*ptr == '#')
- 			break;
- 		if (!isspace((unsigned char) *ptr))
- 			return false;
- 		ptr++;
- 	}
- 
- 	/* Success! */
- 	*key_p = key;
- 	*value_p = value;
- 	return true;
- }
- 
- /*
   * See if there is a recovery command file (recovery.conf), and if so
   * read in parameters for archive recovery and XLOG streaming.
   *
--- 5019,5024 ----
*** a/src/backend/catalog/Makefile
--- b/src/backend/catalog/Makefile
***************
*** 39,44 **** POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
--- 39,45 ----
  	pg_ts_parser.h pg_ts_template.h \
  	pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
  	pg_default_acl.h pg_seclabel.h \
+ 	pg_extension.h \
  	toasting.h indexing.h \
      )
  
*** a/src/backend/catalog/dependency.c
--- b/src/backend/catalog/dependency.c
***************
*** 34,39 ****
--- 34,40 ----
  #include "catalog/pg_database.h"
  #include "catalog/pg_default_acl.h"
  #include "catalog/pg_depend.h"
+ #include "catalog/pg_extension.h"
  #include "catalog/pg_foreign_data_wrapper.h"
  #include "catalog/pg_foreign_server.h"
  #include "catalog/pg_language.h"
***************
*** 55,60 ****
--- 56,62 ----
  #include "commands/comment.h"
  #include "commands/dbcommands.h"
  #include "commands/defrem.h"
+ #include "commands/extension.h"
  #include "commands/proclang.h"
  #include "commands/schemacmds.h"
  #include "commands/seclabel.h"
***************
*** 152,158 **** static const Oid object_classes[MAX_OCLASS] = {
  	ForeignDataWrapperRelationId,		/* OCLASS_FDW */
  	ForeignServerRelationId,	/* OCLASS_FOREIGN_SERVER */
  	UserMappingRelationId,		/* OCLASS_USER_MAPPING */
! 	DefaultAclRelationId		/* OCLASS_DEFACL */
  };
  
  
--- 154,161 ----
  	ForeignDataWrapperRelationId,		/* OCLASS_FDW */
  	ForeignServerRelationId,	/* OCLASS_FOREIGN_SERVER */
  	UserMappingRelationId,		/* OCLASS_USER_MAPPING */
! 	DefaultAclRelationId,		/* OCLASS_DEFACL */
! 	ExtensionRelationId 		/* OCLASS_EXTENSION */
  };
  
  
***************
*** 1148,1153 **** doDeletion(const ObjectAddress *object)
--- 1151,1160 ----
  			RemoveUserMappingById(object->objectId);
  			break;
  
+ 		case OCLASS_EXTENSION:
+ 			RemoveExtensionById(object->objectId);
+ 			break;
+ 
  		case OCLASS_DEFACL:
  			RemoveDefaultACLById(object->objectId);
  			break;
***************
*** 2082,2087 **** getObjectClass(const ObjectAddress *object)
--- 2089,2098 ----
  		case DefaultAclRelationId:
  			Assert(object->objectSubId == 0);
  			return OCLASS_DEFACL;
+ 
+ 		case ExtensionRelationId:
+ 			Assert(object->objectSubId == 0);
+ 			return OCLASS_EXTENSION;
  	}
  
  	/* shouldn't get here */
***************
*** 2563,2568 **** getObjectDescription(const ObjectAddress *object)
--- 2574,2591 ----
  				break;
  			}
  
+ 		case OCLASS_EXTENSION:
+ 			{
+ 				char	   *extension;
+ 
+ 				extension = get_extension_name(object->objectId);
+ 				if (!extension)
+ 					elog(ERROR, "cache lookup failed for extension %u",
+ 						 object->objectId);
+ 				appendStringInfo(&buffer, _("extension %s"), extension);
+ 				break;
+ 			}
+ 
  		case OCLASS_TBLSPACE:
  			{
  				char	   *tblspace;
*** a/src/backend/catalog/heap.c
--- b/src/backend/catalog/heap.c
***************
*** 49,54 ****
--- 49,55 ----
  #include "catalog/pg_type.h"
  #include "catalog/pg_type_fn.h"
  #include "catalog/storage.h"
+ #include "commands/extension.h"
  #include "commands/tablecmds.h"
  #include "commands/typecmds.h"
  #include "miscadmin.h"
***************
*** 1139,1145 **** heap_create_with_catalog(const char *relname,
  	/*
  	 * Make a dependency link to force the relation to be deleted if its
  	 * namespace is.  Also make a dependency link to its owner, as well as
! 	 * dependencies for any roles mentioned in the default ACL.
  	 *
  	 * For composite types, these dependencies are tracked for the pg_type
  	 * entry, so we needn't record them here.  Likewise, TOAST tables don't
--- 1140,1147 ----
  	/*
  	 * Make a dependency link to force the relation to be deleted if its
  	 * namespace is.  Also make a dependency link to its owner, as well as
! 	 * dependencies for any roles mentioned in the default ACL. Record a
! 	 * dependancy to the extension we're part of if any.
  	 *
  	 * For composite types, these dependencies are tracked for the pg_type
  	 * entry, so we needn't record them here.  Likewise, TOAST tables don't
***************
*** 1186,1191 **** heap_create_with_catalog(const char *relname,
--- 1188,1198 ----
  								  0, NULL,
  								  nnewmembers, newmembers);
  		}
+ 
+ 		if (create_extension != NULL )
+ 		{
+ 			recordDependencyOn(&myself, create_extension, DEPENDENCY_INTERNAL);
+ 		}
  	}
  
  	/*
*** a/src/backend/catalog/objectaddress.c
--- b/src/backend/catalog/objectaddress.c
***************
*** 28,33 ****
--- 28,34 ----
  #include "catalog/pg_constraint.h"
  #include "catalog/pg_conversion.h"
  #include "catalog/pg_database.h"
+ #include "catalog/pg_extension.h"
  #include "catalog/pg_language.h"
  #include "catalog/pg_largeobject.h"
  #include "catalog/pg_largeobject_metadata.h"
***************
*** 47,52 ****
--- 48,54 ----
  #include "commands/dbcommands.h"
  #include "commands/defrem.h"
  #include "commands/proclang.h"
+ #include "commands/extension.h"
  #include "commands/tablespace.h"
  #include "commands/trigger.h"
  #include "nodes/makefuncs.h"
***************
*** 128,133 **** get_object_address(ObjectType objtype, List *objname, List *objargs,
--- 130,136 ----
  			address = get_object_address_relobject(objtype, objname, &relation);
  			break;
  		case OBJECT_DATABASE:
+ 		case OBJECT_EXTENSION:
  		case OBJECT_TABLESPACE:
  		case OBJECT_ROLE:
  		case OBJECT_SCHEMA:
***************
*** 266,271 **** get_object_address_unqualified(ObjectType objtype, List *qualname)
--- 269,277 ----
  			case OBJECT_DATABASE:
  				msg = gettext_noop("database name cannot be qualified");
  				break;
+ 			case OBJECT_EXTENSION:
+ 				msg = gettext_noop("extension name cannot be qualified");
+ 				break;
  			case OBJECT_TABLESPACE:
  				msg = gettext_noop("tablespace name cannot be qualified");
  				break;
***************
*** 298,303 **** get_object_address_unqualified(ObjectType objtype, List *qualname)
--- 304,314 ----
  			address.objectId = get_database_oid(name, false);
  			address.objectSubId = 0;
  			break;
+ 		case OBJECT_EXTENSION:
+ 			address.classId = ExtensionRelationId;
+ 			address.objectId = get_extension_oid(name, false);
+ 			address.objectSubId = 0;
+ 			break;
  		case OBJECT_TABLESPACE:
  			address.classId = TableSpaceRelationId;
  			address.objectId = get_tablespace_oid(name, false);
***************
*** 635,640 **** object_exists(ObjectAddress address)
--- 646,654 ----
  		case TSConfigRelationId:
  			cache = TSCONFIGOID;
  			break;
+ 		case ExtensionRelationId:
+ 			indexoid = ExtensionOidIndexId;
+ 			break;
  		default:
  			elog(ERROR, "unrecognized classid: %u", address.classId);
  	}
*** a/src/backend/catalog/pg_aggregate.c
--- b/src/backend/catalog/pg_aggregate.c
***************
*** 32,37 ****
--- 32,38 ----
  #include "utils/lsyscache.h"
  #include "utils/rel.h"
  #include "utils/syscache.h"
+ #include "commands/extension.h"
  
  
  static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types,
***************
*** 293,298 **** AggregateCreate(const char *aggName,
--- 294,305 ----
  		referenced.objectSubId = 0;
  		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  	}
+ 
+ 	/* Depends on currently installed extension, if any */
+ 	if (create_extension != NULL )
+ 	{
+ 		recordDependencyOn(&myself, create_extension, DEPENDENCY_INTERNAL);
+ 	}
  }
  
  /*
*** a/src/backend/catalog/pg_conversion.c
--- b/src/backend/catalog/pg_conversion.c
***************
*** 30,35 ****
--- 30,36 ----
  #include "utils/rel.h"
  #include "utils/syscache.h"
  #include "utils/tqual.h"
+ #include "commands/extension.h"
  
  /*
   * ConversionCreate
***************
*** 131,136 **** ConversionCreate(const char *conname, Oid connamespace,
--- 132,143 ----
  	recordDependencyOnOwner(ConversionRelationId, HeapTupleGetOid(tup),
  							conowner);
  
+ 	/* Depends on currently installed extension, if any */
+ 	if (create_extension != NULL )
+ 	{
+ 		recordDependencyOn(&myself, create_extension, DEPENDENCY_INTERNAL);
+ 	}
+ 
  	heap_freetuple(tup);
  	heap_close(rel, RowExclusiveLock);
  
*** a/src/backend/catalog/pg_namespace.c
--- b/src/backend/catalog/pg_namespace.c
***************
*** 21,26 ****
--- 21,27 ----
  #include "utils/builtins.h"
  #include "utils/rel.h"
  #include "utils/syscache.h"
+ #include "commands/extension.h"
  
  
  /* ----------------
***************
*** 75,79 **** NamespaceCreate(const char *nspName, Oid ownerId)
--- 76,92 ----
  	/* Record dependency on owner */
  	recordDependencyOnOwner(NamespaceRelationId, nspoid, ownerId);
  
+ 	/* Record dependency on extension, if we're in a CREATE EXTENSION */
+ 	if (create_extension != NULL )
+ 	{
+ 		ObjectAddress myself;
+ 
+ 		myself.classId = NamespaceRelationId;
+ 		myself.objectId = nspoid;
+ 		myself.objectSubId = 0;
+ 
+ 		recordDependencyOn(&myself, create_extension, DEPENDENCY_INTERNAL);
+ 	}
+ 
  	return nspoid;
  }
*** a/src/backend/catalog/pg_operator.c
--- b/src/backend/catalog/pg_operator.c
***************
*** 33,38 ****
--- 33,39 ----
  #include "utils/lsyscache.h"
  #include "utils/rel.h"
  #include "utils/syscache.h"
+ #include "commands/extension.h"
  
  
  static Oid OperatorGet(const char *operatorName,
***************
*** 846,849 **** makeOperatorDependencies(HeapTuple tuple)
--- 847,856 ----
  	/* Dependency on owner */
  	recordDependencyOnOwner(OperatorRelationId, HeapTupleGetOid(tuple),
  							oper->oprowner);
+ 
+ 	/* Dependency on extension */
+ 	if (create_extension != NULL )
+ 	{
+ 		recordDependencyOn(&myself, create_extension, DEPENDENCY_INTERNAL);
+ 	}
  }
*** a/src/backend/catalog/pg_proc.c
--- b/src/backend/catalog/pg_proc.c
***************
*** 35,40 ****
--- 35,41 ----
  #include "utils/builtins.h"
  #include "utils/lsyscache.h"
  #include "utils/syscache.h"
+ #include "commands/extension.h"
  
  
  Datum		fmgr_internal_validator(PG_FUNCTION_ARGS);
***************
*** 614,619 **** ProcedureCreate(const char *procedureName,
--- 615,626 ----
  							  nnewmembers, newmembers);
  	}
  
+ 	/* dependency on extension */
+ 	if (create_extension != NULL )
+ 	{
+ 		recordDependencyOn(&myself, create_extension, DEPENDENCY_INTERNAL);
+ 	}
+ 
  	heap_freetuple(tup);
  
  	heap_close(rel, RowExclusiveLock);
*** a/src/backend/catalog/pg_type.c
--- b/src/backend/catalog/pg_type.c
***************
*** 31,36 ****
--- 31,38 ----
  #include "utils/lsyscache.h"
  #include "utils/rel.h"
  #include "utils/syscache.h"
+ #include "commands/extension.h"
+ 
  
  Oid			binary_upgrade_next_pg_type_oid = InvalidOid;
  
***************
*** 625,630 **** GenerateTypeDependencies(Oid typeNamespace,
--- 627,638 ----
  	/* Normal dependency on the default expression. */
  	if (defaultExpr)
  		recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
+ 
+ 	/* dependency on extension */
+ 	if (create_extension != NULL )
+ 	{
+ 		recordDependencyOn(&myself, create_extension, DEPENDENCY_INTERNAL);
+ 	}
  }
  
  /*
*** a/src/backend/commands/Makefile
--- b/src/backend/commands/Makefile
***************
*** 14,20 **** include $(top_builddir)/src/Makefile.global
  
  OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o  \
  	constraint.o conversioncmds.o copy.o \
! 	dbcommands.o define.o discard.o explain.o foreigncmds.o functioncmds.o \
  	indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
  	portalcmds.o prepare.o proclang.o \
  	schemacmds.o seclabel.o sequence.o tablecmds.o tablespace.o trigger.o \
--- 14,21 ----
  
  OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o  \
  	constraint.o conversioncmds.o copy.o \
! 	dbcommands.o define.o discard.o \
! 	extension.o explain.o foreigncmds.o functioncmds.o \
  	indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
  	portalcmds.o prepare.o proclang.o \
  	schemacmds.o seclabel.o sequence.o tablecmds.o tablespace.o trigger.o \
*** a/src/backend/commands/comment.c
--- b/src/backend/commands/comment.c
***************
*** 142,147 **** CommentObject(CommentStmt *stmt)
--- 142,153 ----
  						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  					 errmsg("must be superuser to comment on procedural language")));
  			break;
+ 		case OBJECT_EXTENSION:
+ 			if (!superuser())
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 					 errmsg("must be superuser to comment on extension")));
+ 			break;
  		case OBJECT_OPCLASS:
  			if (!pg_opclass_ownercheck(address.objectId, GetUserId()))
  				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
*** /dev/null
--- b/src/backend/commands/extension.c
***************
*** 0 ****
--- 1,456 ----
+ /*-------------------------------------------------------------------------
+  *
+  * extension.c
+  *	  Commands to manipulate extensions
+  *
+  * Extensions in PostgreSQL allow user defined behavior plugged in at
+  * runtime. They will typically create SQL objects that you want to avoid
+  * dumping, issuing a single CREATE EXTENSION foo; command instead.
+  *
+  * All we need internally to manage an extension is an OID so that the
+  * dependant objects can get associated with it. An extension is created by
+  * populating the pg_extension catalog from a "control" file, containing
+  * some parameters.
+  *
+  * The extension control file format is the most simple name = value, we
+  * don't need anything more there. The SQL file to execute commands from is
+  * hardcoded to `pg_config --sharedir`/<extension>.install.sql.
+  *
+  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *	  src/backend/commands/extension.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include <unistd.h>
+ #include <dirent.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ 
+ #include "nodes/parsenodes.h"
+ #include "miscadmin.h"
+ #include "catalog/pg_extension.h"
+ #include "commands/extension.h"
+ #include "storage/fd.h"
+ #include "utils/builtins.h"
+ #include "utils/cfparser.h"
+ #include "utils/rel.h"
+ #include "access/heapam.h"
+ #include "catalog/indexing.h"
+ #include "catalog/dependency.h"
+ #include "utils/memutils.h"
+ #include "utils/syscache.h"
+ #include "utils/tqual.h"
+ #include "utils/builtins.h"
+ #include "utils/fmgroids.h"
+ #include "access/sysattr.h"
+ 
+ /*
+  * See commands/extension.h for details.
+  */
+ ObjectAddress *create_extension = NULL;
+ 
+ char *
+ get_extension_install_filename(const char *extname)
+ {
+ 	char		sharepath[MAXPGPATH];
+ 	char	   *result;
+ 
+ 	get_share_path(my_exec_path, sharepath);
+ 	result = palloc(MAXPGPATH);
+ 	snprintf(result, MAXPGPATH, "%s/contrib/%s.sql", sharepath, extname);
+ 
+ 	return result;
+ }
+ 
+ char *
+ get_extension_control_filename(const char *extname)
+ {
+ 	char		sharepath[MAXPGPATH];
+ 	char	   *result;
+ 
+ 	get_share_path(my_exec_path, sharepath);
+ 	result = palloc(MAXPGPATH);
+ 	snprintf(result, MAXPGPATH, "%s/contrib/%s.control", sharepath, extname);
+ 
+ 	return result;
+ }
+ 
+ /*
+  * The control file is supposed to be very short, half a dozen lines, and
+  * reading it is only allowed to superuser, so we don't even try to minimize
+  * memory allocation risks here.
+  *
+  * Also note that only happens in CREATE EXTENSION.
+  */
+ ExtensionControlFile *
+ read_extension_control_file(const char *filename)
+ {
+ 	int64       fsize = -1;
+ 	struct stat fst;
+ 	FILE	   *file;
+ 	char		line[MAXPGPATH];
+ 	bool		syntaxError = false;
+ 	ExtensionControlFile *control =
+ 		(ExtensionControlFile *)palloc(sizeof(ExtensionControlFile));
+ 
+ 	/*
+ 	 * Stat the file to get its size, then read its content into memory so
+ 	 * that we can "parse" it.
+ 	 */
+ 	if (stat(filename, &fst) < 0)
+ 		ereport(ERROR,
+ 				(errcode_for_file_access(),
+ 				 errmsg("could not stat file \"%s\": %m", filename)));
+ 
+ 	fsize = Int64GetDatum((int64) fst.st_size);
+ 
+ 	if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
+ 		ereport(ERROR,
+ 				(errcode_for_file_access(),
+ 				 errmsg("could not open file \"%s\" for reading: %m",
+ 						filename)));
+ 
+ 	if (ferror(file))
+ 		ereport(ERROR,
+ 				(errcode_for_file_access(),
+ 				 errmsg("could not read file \"%s\": %m", filename)));
+ 
+ 	/*
+ 	 * Prepare our ExtensionControlFile structure with default values, then
+ 	 * "parse" the control file.
+ 	 *
+ 	 * The parsing uses directly the code for parsing Recovery Commands as
+ 	 * we're abusing the exact same format here.
+ 	 */
+ 	control->name = NULL;
+ 	control->version = NULL;
+ 	control->custom_class = NULL;
+ 
+ 	while (fgets(line, sizeof(line), file) != NULL)
+ 	{
+ 		char	   *tok1;
+ 		char	   *tok2;
+ 
+ 		if (!parseRecoveryCommandFileLine(line, &tok1, &tok2))
+ 		{
+ 			syntaxError = true;
+ 			break;
+ 		}
+ 		if (tok1 == NULL)
+ 			continue;
+ 
+ 		if (strcmp(tok1, "name") == 0)
+ 		{
+ 			control->name = pstrdup(tok2);
+ 		}
+ 		if (strcmp(tok1, "version") == 0)
+ 		{
+ 			control->version = pstrdup(tok2);
+ 		}
+ 		if (strcmp(tok1, "custom_class") == 0)
+ 		{
+ 			control->custom_class = pstrdup(tok2);
+ 		}
+ 	}
+ 
+ 	if( control->name == NULL )
+ 		ereport(FATAL,
+ 				(errmsg("Missing a name parameter in file: %s", filename)));
+ 
+ 	if (syntaxError)
+ 		ereport(FATAL,
+ 				(errmsg("syntax error in extension control file: %s", line),
+ 				 errhint("Lines should have the format parameter = 'value'.")));
+ 
+ 	FreeFile(file);
+ 	return control;
+ }
+ 
+ /*
+  * Create an extension
+  *
+  * Only superusers can create an extension.
+  */
+ void
+ CreateExtension(CreateExtensionStmt *stmt)
+ {
+ 	ExtensionControlFile *control;
+ 	Relation	rel;
+ 	Datum		values[Natts_pg_extension];
+ 	bool		nulls[Natts_pg_extension];
+ 	HeapTuple	tuple;
+ 	Oid			extensionoid;
+ 	text       *filename;
+ 
+ 	/* Must be super user */
+ 	if (!superuser())
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 				 errmsg("permission denied to create extension \"%s\"",
+ 						stmt->extname),
+ 				 errhint("Must be superuser to create an extension.")));
+ 
+ 	if( InvalidOid != get_extension_oid(stmt->extname, true) )
+ 	{
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("extension \"%s\" already exists", stmt->extname)));
+ 	}
+ 
+ 	control = read_extension_control_file(
+ 		get_extension_control_filename(stmt->extname));
+ 
+ 	/*
+ 	 * Insert tuple into pg_extension.
+ 	 *
+ 	 * We use ExclusiveLock here so that there's only CREATE EXTENSION
+ 	 * possible at any given time. It's necessary because of the way the
+ 	 * global variable create_extension is handled, and it seems like a
+ 	 * restriction that's easy to live with.
+ 	 */
+ 	rel = heap_open(ExtensionRelationId, ExclusiveLock);
+ 
+ 	memset(values, 0, sizeof(values));
+ 	MemSet(nulls, false, sizeof(nulls));
+ 
+ 	values[Anum_pg_extension_extname - 1] =
+ 		DirectFunctionCall1(namein, CStringGetDatum(control->name));
+ 
+ 	if( control->version == NULL )
+ 		nulls[Anum_pg_extension_extversion - 1] = true;
+ 	else
+ 		values[Anum_pg_extension_extversion - 1] =
+ 			CStringGetTextDatum(control->version);
+ 
+ 	if( control->custom_class == NULL )
+ 		nulls[Anum_pg_extension_custom_class - 1] = true;
+ 	else
+ 		values[Anum_pg_extension_custom_class - 1] =
+ 			CStringGetTextDatum(control->custom_class);
+ 
+ 	tuple = heap_form_tuple(rel->rd_att, values, nulls);
+ 	extensionoid = simple_heap_insert(rel, tuple);
+ 	CatalogUpdateIndexes(rel, tuple);
+ 	heap_freetuple(tuple);
+ 	heap_close(rel, ExclusiveLock);
+ 
+ 	/*
+ 	 * Set the global create_extension so that any object created in the
+ 	 * script has a dependancy recorded towards the extension here.
+ 	 */
+ 	create_extension = (ObjectAddress *)palloc(sizeof(ObjectAddress));
+ 	create_extension->classId = ExtensionRelationId;
+ 	create_extension->objectId = extensionoid;
+ 	create_extension->objectSubId = 0;
+ 
+ 	elog(NOTICE,
+ 		 "Installing extension '%s' from '%s'",
+ 		 stmt->extname,
+ 		 get_extension_install_filename(stmt->extname));
+ 
+ 	filename = cstring_to_text(get_extension_install_filename(stmt->extname));
+ 	DirectFunctionCall1(pg_execute_from_file, PointerGetDatum(filename));
+ 
+ 	/* reset the current_extension dependancy tracker */
+ 	pfree(create_extension);
+ 	create_extension = NULL;
+ 
+ 	return;
+ }
+ 
+ /*
+  * Drop an extension
+  */
+ void
+ DropExtension(DropExtensionStmt *stmt)
+ {
+ 	char	   *extname = stmt->extname;
+ 	Relation	rel;
+ 	HeapScanDesc scandesc;
+ 	HeapTuple	tuple;
+ 	ScanKeyData entry[1];
+ 	Oid			extensionoid;
+ 	ObjectAddress object;
+ 
+ 	/* Must be super user */
+ 	if (!superuser())
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 				 errmsg("permission denied to drop extension \"%s\"",
+ 						stmt->extname),
+ 				 errhint("Must be superuser to drop an extension.")));
+ 
+ 	/*
+ 	 * Find the target tuple
+ 	 */
+ 	rel = heap_open(ExtensionRelationId, RowExclusiveLock);
+ 
+ 	ScanKeyInit(&entry[0],
+ 				Anum_pg_extension_extname,
+ 				BTEqualStrategyNumber, F_NAMEEQ,
+ 				CStringGetDatum(extname));
+ 	scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
+ 	tuple = heap_getnext(scandesc, ForwardScanDirection);
+ 
+ 	if (!HeapTupleIsValid(tuple))
+ 	{
+ 		if (!stmt->missing_ok)
+ 		{
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 					 errmsg("extension \"%s\" does not exist", extname)));
+ 		}
+ 		else
+ 		{
+ 			ereport(NOTICE,
+ 					(errmsg("extension \"%s\" does not exist, skipping",
+ 							extname)));
+ 			/* XXX I assume I need one or both of these next two calls */
+ 			heap_endscan(scandesc);
+ 			heap_close(rel, RowExclusiveLock);
+ 		}
+ 		return;
+ 	}
+ 	extensionoid = HeapTupleGetOid(tuple);
+ 	heap_endscan(scandesc);
+ 	heap_close(rel, RowExclusiveLock);
+ 
+ 	/*
+ 	 * Do the deletion
+ 	 */
+ 	object.classId = ExtensionRelationId;
+ 	object.objectId = extensionoid;
+ 	object.objectSubId = 0;
+ 
+ 	performDeletion(&object, stmt->behavior);
+ 
+ 	return;
+ }
+ 
+ /*
+  * get_extension_oid - given an extension name, look up the OID
+  *
+  * If missing_ok is false, throw an error if extension name not found.  If
+  * true, just return InvalidOid.
+  */
+ Oid
+ get_extension_oid(const char *extname, bool missing_ok)
+ {
+ 	Oid			result;
+ 	Relation	rel;
+ 	HeapScanDesc scandesc;
+ 	HeapTuple	tuple;
+ 	ScanKeyData entry[1];
+ 
+ 	rel = heap_open(ExtensionRelationId, AccessShareLock);
+ 
+ 	ScanKeyInit(&entry[0],
+ 				Anum_pg_extension_extname,
+ 				BTEqualStrategyNumber, F_NAMEEQ,
+ 				CStringGetDatum(extname));
+ 	scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
+ 	tuple = heap_getnext(scandesc, ForwardScanDirection);
+ 
+ 	/* We assume that there can be at most one matching tuple */
+ 	if (HeapTupleIsValid(tuple))
+ 		result = HeapTupleGetOid(tuple);
+ 	else
+ 		result = InvalidOid;
+ 
+ 	heap_endscan(scandesc);
+ 	heap_close(rel, AccessShareLock);
+ 
+ 	if (!OidIsValid(result) && !missing_ok)
+         ereport(ERROR,
+                 (errcode(ERRCODE_UNDEFINED_OBJECT),
+                  errmsg("extension \"%s\" does not exist",
+                         extname)));
+ 
+ 	return result;
+ }
+ 
+ /*
+  * get_extension_name - given an extension OID, look up the name
+  *
+  * Returns a palloc'd string, or NULL if no such tablespace.
+  */
+ char *
+ get_extension_name(Oid ext_oid)
+ {
+ 	char	   *result;
+ 	Relation	rel;
+ 	HeapScanDesc scandesc;
+ 	HeapTuple	tuple;
+ 	ScanKeyData entry[1];
+ 
+ 	/*
+ 	 * Search pg_extension.  We use a heapscan here even though there is an
+ 	 * index on oid, on the theory that pg_extension will usually have just a
+ 	 * few entries and so an indexed lookup is a waste of effort.
+ 	 */
+ 	rel = heap_open(ExtensionRelationId, AccessShareLock);
+ 
+ 	ScanKeyInit(&entry[0],
+ 				ObjectIdAttributeNumber,
+ 				BTEqualStrategyNumber, F_OIDEQ,
+ 				ObjectIdGetDatum(ext_oid));
+ 	scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
+ 	tuple = heap_getnext(scandesc, ForwardScanDirection);
+ 
+ 	/* We assume that there can be at most one matching tuple */
+ 	if (HeapTupleIsValid(tuple))
+ 		result = pstrdup(NameStr(((Form_pg_extension) GETSTRUCT(tuple))->extname));
+ 	else
+ 		result = NULL;
+ 
+ 	heap_endscan(scandesc);
+ 	heap_close(rel, AccessShareLock);
+ 
+ 	return result;
+ }
+ 
+ /*
+  * Drop extension by OID.  This is called to clean up dependencies.
+  */
+ char *
+ RemoveExtensionById(Oid extId)
+ {
+ 	char	   *result;
+ 	Relation	rel;
+ 	HeapScanDesc scandesc;
+ 	HeapTuple	tuple;
+ 	ScanKeyData entry[1];
+ 
+ 	/*
+ 	 * Search pg_extension.  We use a heapscan here even though there is an
+ 	 * index on oid, on the theory that pg_extension will usually have just a
+ 	 * few entries and so an indexed lookup is a waste of effort.
+ 	 */
+ 	rel = heap_open(ExtensionRelationId, AccessShareLock);
+ 
+ 	ScanKeyInit(&entry[0],
+ 				ObjectIdAttributeNumber,
+ 				BTEqualStrategyNumber, F_OIDEQ,
+ 				ObjectIdGetDatum(extId));
+ 	scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
+ 	tuple = heap_getnext(scandesc, ForwardScanDirection);
+ 
+ 	/* We assume that there can be at most one matching tuple */
+ 	if (HeapTupleIsValid(tuple))
+ 		result = pstrdup(NameStr(((Form_pg_extension) GETSTRUCT(tuple))->extname));
+ 	else
+ 		result = NULL;
+ 
+ 	simple_heap_delete(rel, &tuple->t_self);
+ 
+ 	heap_endscan(scandesc);
+ 	heap_close(rel, AccessShareLock);
+ 
+ 	return result;
+ }
*** a/src/backend/commands/foreigncmds.c
--- b/src/backend/commands/foreigncmds.c
***************
*** 32,37 ****
--- 32,38 ----
  #include "utils/lsyscache.h"
  #include "utils/rel.h"
  #include "utils/syscache.h"
+ #include "commands/extension.h"
  
  
  /*
***************
*** 411,416 **** CreateForeignDataWrapper(CreateFdwStmt *stmt)
--- 412,423 ----
  		referenced.objectId = fdwvalidator;
  		referenced.objectSubId = 0;
  		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+ 
+ 		/* dependency on extension */
+ 		if (create_extension != NULL )
+ 		{
+ 			recordDependencyOn(&myself, create_extension, DEPENDENCY_INTERNAL);
+ 		}
  	}
  
  	recordDependencyOnOwner(ForeignDataWrapperRelationId, fdwId, ownerId);
***************
*** 696,701 **** CreateForeignServer(CreateForeignServerStmt *stmt)
--- 703,714 ----
  
  	recordDependencyOnOwner(ForeignServerRelationId, srvId, ownerId);
  
+ 	/* dependency on extension */
+ 	if (create_extension != NULL )
+ 	{
+ 		recordDependencyOn(&myself, create_extension, DEPENDENCY_INTERNAL);
+ 	}
+ 
  	heap_close(rel, NoLock);
  }
  
***************
*** 967,972 **** CreateUserMapping(CreateUserMappingStmt *stmt)
--- 980,991 ----
  		/* Record the mapped user dependency */
  		recordDependencyOnOwner(UserMappingRelationId, umId, useId);
  
+ 	/* dependency on extension */
+ 	if (create_extension != NULL )
+ 	{
+ 		recordDependencyOn(&myself, create_extension, DEPENDENCY_INTERNAL);
+ 	}
+ 
  	heap_close(rel, NoLock);
  }
  
*** a/src/backend/commands/functioncmds.c
--- b/src/backend/commands/functioncmds.c
***************
*** 61,67 ****
  #include "utils/rel.h"
  #include "utils/syscache.h"
  #include "utils/tqual.h"
! 
  
  static void AlterFunctionOwner_internal(Relation rel, HeapTuple tup,
  							Oid newOwnerId);
--- 61,67 ----
  #include "utils/rel.h"
  #include "utils/syscache.h"
  #include "utils/tqual.h"
! #include "commands/extension.h"
  
  static void AlterFunctionOwner_internal(Relation rel, HeapTuple tup,
  							Oid newOwnerId);
***************
*** 1744,1749 **** CreateCast(CreateCastStmt *stmt)
--- 1744,1754 ----
  		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  	}
  
+ 	if (create_extension != NULL )
+ 	{
+ 		recordDependencyOn(&myself, create_extension, DEPENDENCY_INTERNAL);
+ 	}
+ 
  	heap_freetuple(tuple);
  
  	heap_close(relation, RowExclusiveLock);
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
***************
*** 42,47 ****
--- 42,48 ----
  #include "utils/rel.h"
  #include "utils/syscache.h"
  #include "utils/tqual.h"
+ #include "commands/extension.h"
  
  
  /*
***************
*** 306,311 **** CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid)
--- 307,318 ----
  	/* dependency on owner */
  	recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
  
+ 	/* dependency on extension */
+ 	if (create_extension != NULL )
+ 	{
+ 		recordDependencyOn(&myself, create_extension, DEPENDENCY_INTERNAL);
+ 	}
+ 
  	heap_close(rel, RowExclusiveLock);
  
  	return opfamilyoid;
***************
*** 693,698 **** DefineOpClass(CreateOpClassStmt *stmt)
--- 700,711 ----
  	/* dependency on owner */
  	recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
  
+ 	/* dependency on extension */
+ 	if (create_extension != NULL )
+ 	{
+ 		recordDependencyOn(&myself, create_extension, DEPENDENCY_INTERNAL);
+ 	}
+ 
  	heap_close(rel, RowExclusiveLock);
  }
  
*** a/src/backend/commands/proclang.c
--- b/src/backend/commands/proclang.c
***************
*** 36,41 ****
--- 36,42 ----
  #include "utils/rel.h"
  #include "utils/syscache.h"
  #include "utils/tqual.h"
+ #include "commands/extension.h"
  
  
  typedef struct
***************
*** 425,430 **** create_proc_lang(const char *languageName, bool replace,
--- 426,437 ----
  		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  	}
  
+ 	/* dependency on extension */
+ 	if (create_extension != NULL )
+ 	{
+ 		recordDependencyOn(&myself, create_extension, DEPENDENCY_INTERNAL);
+ 	}
+ 
  	heap_close(rel, RowExclusiveLock);
  }
  
*** a/src/backend/commands/tsearchcmds.c
--- b/src/backend/commands/tsearchcmds.c
***************
*** 46,51 ****
--- 46,52 ----
  #include "utils/rel.h"
  #include "utils/syscache.h"
  #include "utils/tqual.h"
+ #include "commands/extension.h"
  
  
  static void MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
***************
*** 154,159 **** makeParserDependencies(HeapTuple tuple)
--- 155,166 ----
  		referenced.objectId = prs->prsheadline;
  		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  	}
+ 
+ 	/* dependency on extension */
+ 	if (create_extension != NULL )
+ 	{
+ 		recordDependencyOn(&myself, create_extension, DEPENDENCY_INTERNAL);
+ 	}
  }
  
  /*
***************
*** 423,428 **** makeDictionaryDependencies(HeapTuple tuple)
--- 430,441 ----
  	referenced.objectId = dict->dicttemplate;
  	referenced.objectSubId = 0;
  	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+ 
+ 	/* dependency on extension, if in create extension */
+ 	if (create_extension != NULL )
+ 	{
+ 		recordDependencyOn(&myself, create_extension, DEPENDENCY_INTERNAL);
+ 	}
  }
  
  /*
***************
*** 965,970 **** makeTSTemplateDependencies(HeapTuple tuple)
--- 978,989 ----
  		referenced.objectId = tmpl->tmplinit;
  		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  	}
+ 
+ 	/* dependency on extension, if in create extension */
+ 	if (create_extension != NULL )
+ 	{
+ 		recordDependencyOn(&myself, create_extension, DEPENDENCY_INTERNAL);
+ 	}
  }
  
  /*
***************
*** 1289,1294 **** makeConfigurationDependencies(HeapTuple tuple, bool removeOld,
--- 1308,1319 ----
  	/* Record 'em (this includes duplicate elimination) */
  	record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
  
+ 	/* dependencies on extension being created, if any */
+ 	if (create_extension != NULL )
+ 	{
+ 		recordDependencyOn(&myself, create_extension, DEPENDENCY_INTERNAL);
+ 	}
+ 
  	free_object_addresses(addrs);
  }
  
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
***************
*** 3087,3092 **** _copyDiscardStmt(DiscardStmt *from)
--- 3087,3114 ----
  	return newnode;
  }
  
+ static CreateExtensionStmt *
+ _copyCreateExtensionStmt(CreateExtensionStmt *from)
+ {
+ 	CreateExtensionStmt *newnode = makeNode(CreateExtensionStmt);
+ 
+ 	COPY_STRING_FIELD(extname);
+ 
+ 	return newnode;
+ }
+ 
+ static DropExtensionStmt *
+ _copyDropExtensionStmt(DropExtensionStmt *from)
+ {
+ 	DropExtensionStmt *newnode = makeNode(DropExtensionStmt);
+ 
+ 	COPY_STRING_FIELD(extname);
+ 	COPY_SCALAR_FIELD(missing_ok);
+ 	COPY_SCALAR_FIELD(behavior);
+ 
+ 	return newnode;
+ }
+ 
  static CreateTableSpaceStmt *
  _copyCreateTableSpaceStmt(CreateTableSpaceStmt *from)
  {
*** a/src/backend/nodes/equalfuncs.c
--- b/src/backend/nodes/equalfuncs.c
***************
*** 1587,1592 **** _equalDropTableSpaceStmt(DropTableSpaceStmt *a, DropTableSpaceStmt *b)
--- 1587,1610 ----
  }
  
  static bool
+ _equalCreateExtensionStmt(CreateExtensionStmt *a, CreateExtensionStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(extname);
+ 
+ 	return true;
+ }
+ 
+ static bool
+ _equalDropExtensionStmt(DropExtensionStmt *a, DropExtensionStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(extname);
+ 	COMPARE_SCALAR_FIELD(missing_ok);
+ 	COMPARE_SCALAR_FIELD(behavior);
+ 
+ 	return true;
+ }
+ 
+ static bool
  _equalAlterTableSpaceOptionsStmt(AlterTableSpaceOptionsStmt *a,
  								 AlterTableSpaceOptionsStmt *b)
  {
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 190,196 **** static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
  		AlterDefaultPrivilegesStmt DefACLAction
  		AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
  		ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
! 		CreateDomainStmt CreateGroupStmt CreateOpClassStmt
  		CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt
  		CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
  		CreateFdwStmt CreateForeignServerStmt CreateAssertStmt CreateTrigStmt
--- 190,196 ----
  		AlterDefaultPrivilegesStmt DefACLAction
  		AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
  		ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
! 		CreateDomainStmt CreateExtensionStmt CreateGroupStmt CreateOpClassStmt
  		CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt
  		CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
  		CreateFdwStmt CreateForeignServerStmt CreateAssertStmt CreateTrigStmt
***************
*** 198,204 **** static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
  		CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt
  		DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
  		DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
! 		DropUserStmt DropdbStmt DropTableSpaceStmt DropFdwStmt
  		DropForeignServerStmt DropUserMappingStmt ExplainStmt FetchStmt
  		GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt
  		LockStmt NotifyStmt ExplainableStmt PreparableStmt
--- 198,204 ----
  		CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt
  		DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
  		DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
! 		DropUserStmt DropdbStmt DropTableSpaceStmt DropFdwStmt DropExtensionStmt
  		DropForeignServerStmt DropUserMappingStmt ExplainStmt FetchStmt
  		GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt
  		LockStmt NotifyStmt ExplainableStmt PreparableStmt
***************
*** 484,490 **** static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
  	DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP
  
  	EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EXCEPT
! 	EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
  
  	FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOLLOWING FOR FORCE FOREIGN FORWARD
  	FREEZE FROM FULL FUNCTION FUNCTIONS
--- 484,490 ----
  	DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP
  
  	EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EXCEPT
! 	EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTENSION EXTERNAL EXTRACT
  
  	FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOLLOWING FOR FORCE FOREIGN FORWARD
  	FREEZE FROM FULL FUNCTION FUNCTIONS
***************
*** 680,685 **** stmt :
--- 680,686 ----
  			| CreateCastStmt
  			| CreateConversionStmt
  			| CreateDomainStmt
+ 			| CreateExtensionStmt
  			| CreateFdwStmt
  			| CreateForeignServerStmt
  			| CreateFunctionStmt
***************
*** 705,710 **** stmt :
--- 706,712 ----
  			| DoStmt
  			| DropAssertStmt
  			| DropCastStmt
+ 			| DropExtensionStmt
  			| DropFdwStmt
  			| DropForeignServerStmt
  			| DropGroupStmt
***************
*** 3081,3086 **** opt_procedural:
--- 3083,3128 ----
  /*****************************************************************************
   *
   * 		QUERY:
+  *             CREATE EXTENSION extension
+  *
+  *****************************************************************************/
+ 
+ CreateExtensionStmt: CREATE EXTENSION name
+ 				{
+ 					CreateExtensionStmt *n = makeNode(CreateExtensionStmt);
+ 					n->extname = $3;
+ 					$$ = (Node *) n;
+ 				}
+ 		;
+ 
+ /*****************************************************************************
+  *
+  * 		QUERY :
+  *				DROP EXTENSION <extension> [ RESTRICT | CASCADE ]
+  *
+  ****************************************************************************/
+ 
+ DropExtensionStmt: DROP EXTENSION name opt_drop_behavior
+ 				{
+ 					DropExtensionStmt *n = makeNode(DropExtensionStmt);
+ 					n->extname = $3;
+ 					n->missing_ok = false;
+ 					n->behavior = $4;
+ 					$$ = (Node *) n;
+ 				}
+ 				|  DROP EXTENSION IF_P EXISTS name opt_drop_behavior
+                 {
+ 					DropExtensionStmt *n = makeNode(DropExtensionStmt);
+ 					n->extname = $5;
+ 					n->missing_ok = true;
+ 					n->behavior = $6;
+ 					$$ = (Node *) n;
+ 				}
+ 		;
+ 
+ /*****************************************************************************
+  *
+  * 		QUERY:
   *             CREATE TABLESPACE tablespace LOCATION '/path/to/tablespace/'
   *
   *****************************************************************************/
***************
*** 4184,4190 **** opt_restart_seqs:
   *
   *	COMMENT ON [ [ DATABASE | DOMAIN | INDEX | SEQUENCE | TABLE | TYPE | VIEW |
   *				   CONVERSION | LANGUAGE | OPERATOR CLASS | LARGE OBJECT |
!  *				   CAST | COLUMN | SCHEMA | TABLESPACE | ROLE |
   *				   TEXT SEARCH PARSER | TEXT SEARCH DICTIONARY |
   *				   TEXT SEARCH TEMPLATE |
   *				   TEXT SEARCH CONFIGURATION ] <objname> |
--- 4226,4232 ----
   *
   *	COMMENT ON [ [ DATABASE | DOMAIN | INDEX | SEQUENCE | TABLE | TYPE | VIEW |
   *				   CONVERSION | LANGUAGE | OPERATOR CLASS | LARGE OBJECT |
!  *				   CAST | COLUMN | SCHEMA | TABLESPACE | EXTENSION | ROLE |
   *				   TEXT SEARCH PARSER | TEXT SEARCH DICTIONARY |
   *				   TEXT SEARCH TEMPLATE |
   *				   TEXT SEARCH CONFIGURATION ] <objname> |
***************
*** 4363,4368 **** comment_type:
--- 4405,4411 ----
  			| VIEW								{ $$ = OBJECT_VIEW; }
  			| CONVERSION_P						{ $$ = OBJECT_CONVERSION; }
  			| TABLESPACE						{ $$ = OBJECT_TABLESPACE; }
+ 			| EXTENSION 						{ $$ = OBJECT_EXTENSION; }
  			| ROLE								{ $$ = OBJECT_ROLE; }
  		;
  
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 32,37 ****
--- 32,38 ----
  #include "commands/defrem.h"
  #include "commands/discard.h"
  #include "commands/explain.h"
+ #include "commands/extension.h"
  #include "commands/lockcmds.h"
  #include "commands/portalcmds.h"
  #include "commands/prepare.h"
***************
*** 175,180 **** check_xact_readonly(Node *parsetree)
--- 176,182 ----
  		case T_CreateConversionStmt:
  		case T_CreatedbStmt:
  		case T_CreateDomainStmt:
+ 		case T_CreateExtensionStmt:
  		case T_CreateFunctionStmt:
  		case T_CreateRoleStmt:
  		case T_IndexStmt:
***************
*** 194,199 **** check_xact_readonly(Node *parsetree)
--- 196,202 ----
  		case T_DropCastStmt:
  		case T_DropStmt:
  		case T_DropdbStmt:
+ 		case T_DropExtensionStmt:
  		case T_DropTableSpaceStmt:
  		case T_RemoveFuncStmt:
  		case T_DropRoleStmt:
***************
*** 557,562 **** standard_ProcessUtility(Node *parsetree,
--- 560,573 ----
  			}
  			break;
  
+ 		case T_CreateExtensionStmt:
+ 			CreateExtension((CreateExtensionStmt *) parsetree);
+ 			break;
+ 
+ 		case T_DropExtensionStmt:
+ 			DropExtension((DropExtensionStmt *) parsetree);
+ 			break;
+ 
  		case T_CreateTableSpaceStmt:
  			PreventTransactionChain(isTopLevel, "CREATE TABLESPACE");
  			CreateTableSpace((CreateTableSpaceStmt *) parsetree);
***************
*** 1498,1503 **** CreateCommandTag(Node *parsetree)
--- 1509,1522 ----
  			tag = "CREATE TABLE";
  			break;
  
+ 		case T_CreateExtensionStmt:
+ 			tag = "CREATE EXTENSION";
+ 			break;
+ 
+ 		case T_DropExtensionStmt:
+ 			tag = "DROP EXTENSION";
+ 			break;
+ 
  		case T_CreateTableSpaceStmt:
  			tag = "CREATE TABLESPACE";
  			break;
***************
*** 2292,2297 **** GetCommandLogLevel(Node *parsetree)
--- 2311,2324 ----
  			lev = LOGSTMT_DDL;
  			break;
  
+ 		case T_CreateExtensionStmt:
+ 			lev = LOGSTMT_DDL;
+ 			break;
+ 
+ 		case T_DropExtensionStmt:
+ 			lev = LOGSTMT_DDL;
+ 			break;
+ 
  		case T_CreateTableSpaceStmt:
  			lev = LOGSTMT_DDL;
  			break;
*** a/src/backend/utils/adt/genfile.c
--- b/src/backend/utils/adt/genfile.c
***************
*** 7,12 ****
--- 7,13 ----
   * Copyright (c) 2004-2010, PostgreSQL Global Development Group
   *
   * Author: Andreas Pflug <pgadmin@pse-consulting.de>
+  *         Dimitri Fontaine <dimitri@2ndQuadrant.fr>
   *
   * IDENTIFICATION
   *	  src/backend/utils/adt/genfile.c
***************
*** 30,35 ****
--- 31,46 ----
  #include "utils/memutils.h"
  #include "utils/timestamp.h"
  
+ #include "tcop/pquery.h"
+ #include "tcop/tcopprot.h"
+ #include "tcop/utility.h"
+ #include "access/transam.h"
+ #include "access/xact.h"
+ #include "utils/resowner.h"
+ #include "utils/snapmgr.h"
+ #include "parser/analyze.h"
+ #include "access/printtup.h"
+ 
  typedef struct
  {
  	char	   *location;
***************
*** 264,266 **** pg_ls_dir(PG_FUNCTION_ARGS)
--- 275,459 ----
  
  	SRF_RETURN_DONE(funcctx);
  }
+ 
+ /*
+  * Read a file then execute the SQL commands it contains.
+  */
+ Datum
+ pg_execute_from_file(PG_FUNCTION_ARGS)
+ {
+ 	text	   *filename_t = PG_GETARG_TEXT_P(0);
+ 	char	   *filename;
+ 	FILE       *file;
+ 	int64       fsize = -1, nbytes;
+ 	struct stat fst;
+ 	char       *query_string = NULL;
+ 
+ 	CommandDest dest = DestNone;
+ 	MemoryContext oldcontext;
+ 	List	   *parsetree_list;
+ 	ListCell   *parsetree_item;
+ 	bool		save_log_statement_stats = log_statement_stats;
+ 	bool		was_logged = false;
+ 	bool		isTopLevel;
+ 	char		msec_str[32];
+ 
+ 	if (!superuser())
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 				 (errmsg("must be superuser to get file information"))));
+ 
+ 	/*
+ 	 * Only superuser can call pg_execute_from_file, and CREATE EXTENSION
+ 	 * uses that too. Don't double check the PATH. Also note that
+ 	 * extension's install files are not in $PGDATA but `pg_config
+ 	 * --sharedir`.
+ 	 */
+ 	filename = text_to_cstring(filename_t);
+ 
+ 	if (stat(filename, &fst) < 0)
+ 		ereport(ERROR,
+ 				(errcode_for_file_access(),
+ 				 errmsg("could not stat file \"%s\": %m", filename)));
+ 
+ 	fsize = Int64GetDatum((int64) fst.st_size);
+ 
+ 	if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
+ 		ereport(ERROR,
+ 				(errcode_for_file_access(),
+ 				 errmsg("could not open file \"%s\" for reading: %m",
+ 						filename)));
+ 
+ 	if (ferror(file))
+ 		ereport(ERROR,
+ 				(errcode_for_file_access(),
+ 				 errmsg("could not read file \"%s\": %m", filename)));
+ 
+ 	query_string = (char *)palloc((fsize+1)*sizeof(char));
+ 	memset(query_string, 0, fsize+1);
+ 	nbytes = fread(query_string, 1, (size_t) fsize, file);
+ 	pg_verifymbstr(query_string, nbytes, false);
+ 	FreeFile(file);
+ 
+ 	/*
+ 	elog(NOTICE, "pg_execute_from_file('%s') read %d/%d bytes:", filename, nbytes, fsize);
+ 	elog(NOTICE, "%s", query_string);
+ 	 */
+ 
+ 	/*
+ 	 * Code pasted from postgres.c:exec_simple_query, main differences are:
+ 	 * - don't override unnamed portal, name it after filename instead
+ 	 * - don't start nor finish a transaction
+ 	 * - don't set stats or tracing markers
+ 	 */
+ 	oldcontext = MemoryContextSwitchTo(MessageContext);
+ 	parsetree_list = pg_parse_query(query_string);
+ 	MemoryContextSwitchTo(oldcontext);
+ 
+ 	isTopLevel = false;
+ 
+ 	foreach(parsetree_item, parsetree_list)
+ 	{
+ 		Node	   *parsetree = (Node *) lfirst(parsetree_item);
+ 		bool		snapshot_set = false;
+ 		const char *commandTag;
+ 		char		completionTag[COMPLETION_TAG_BUFSIZE];
+ 		List	   *querytree_list,
+ 				   *plantree_list;
+ 		Portal		portal;
+ 		DestReceiver *receiver;
+ 		int16		format = 0; /* TEXT */
+ 
+ 		commandTag = CreateCommandTag(parsetree);
+ 
+ 		/* If we got a cancel signal in parsing or prior command, quit */
+ 		CHECK_FOR_INTERRUPTS();
+ 
+ 		/*
+ 		 * Set up a snapshot if parse analysis/planning will need one.
+ 		 */
+ 		if (analyze_requires_snapshot(parsetree))
+ 		{
+ 			PushActiveSnapshot(GetTransactionSnapshot());
+ 			snapshot_set = true;
+ 		}
+ 
+ 		/*
+ 		 * OK to analyze, rewrite, and plan this query.
+ 		 *
+ 		 * Switch to appropriate context for constructing querytrees (again,
+ 		 * these must outlive the execution context).
+ 		 */
+ 		oldcontext = MemoryContextSwitchTo(MessageContext);
+ 
+ 		querytree_list = pg_analyze_and_rewrite(parsetree, query_string,
+ 												NULL, 0);
+ 
+ 		plantree_list = pg_plan_queries(querytree_list, 0, NULL);
+ 
+ 		/* Done with the snapshot used for parsing/planning */
+ 		if (snapshot_set)
+ 			PopActiveSnapshot();
+ 
+ 		/* If we got a cancel signal in analysis or planning, quit */
+ 		CHECK_FOR_INTERRUPTS();
+ 
+ 		/*
+ 		 * Create a portal to run the query or queries in. Name if after the
+ 		 * given filename. If there already is one, silently drop it.
+ 		 */
+ 		portal = CreatePortal(filename, true, true);
+ 		/* Don't display the portal in pg_cursors */
+ 		portal->visible = false;
+ 
+ 		/*
+ 		 * We don't have to copy anything into the portal, because everything
+ 		 * we are passing here is in MessageContext, which will outlive the
+ 		 * portal anyway.
+ 		 */
+ 		PortalDefineQuery(portal,
+ 						  NULL,
+ 						  query_string,
+ 						  commandTag,
+ 						  plantree_list,
+ 						  NULL);
+ 
+ 		/*
+ 		 * Start the portal.  No parameters here.
+ 		 */
+ 		PortalStart(portal, NULL, InvalidSnapshot);
+ 		PortalSetResultFormat(portal, 1, &format);
+ 
+ 		/*
+ 		 * Now we can create the destination receiver object.
+ 		 */
+ 		receiver = CreateDestReceiver(dest);
+ 		if (dest == DestRemote)
+ 			SetRemoteDestReceiverParams(receiver, portal);
+ 
+ 		/*
+ 		 * Switch back to transaction context for execution.
+ 		 */
+ 		MemoryContextSwitchTo(oldcontext);
+ 
+ 		/*
+ 		 * Run the portal to completion, and then drop it (and the receiver).
+ 		 */
+ 		(void) PortalRun(portal,
+ 						 FETCH_ALL,
+ 						 isTopLevel,
+ 						 receiver,
+ 						 receiver,
+ 						 completionTag);
+ 
+ 		(*receiver->rDestroy) (receiver);
+ 
+ 		PortalDrop(portal, false);
+ 
+ 		if (!IsA(parsetree, TransactionStmt) && lnext(parsetree_item) != NULL)
+ 		{
+ 			CommandCounterIncrement();
+ 		}
+ 	}
+ 	PG_RETURN_VOID();
+ }
*** a/src/backend/utils/misc/Makefile
--- b/src/backend/utils/misc/Makefile
***************
*** 15,21 **** include $(top_builddir)/src/Makefile.global
  override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS)
  
  OBJS = guc.o help_config.o pg_rusage.o ps_status.o superuser.o tzparser.o \
!        rbtree.o
  
  # This location might depend on the installation directories. Therefore
  # we can't subsitute it into pg_config.h.
--- 15,21 ----
  override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS)
  
  OBJS = guc.o help_config.o pg_rusage.o ps_status.o superuser.o tzparser.o \
!        rbtree.o cfparser.o
  
  # This location might depend on the installation directories. Therefore
  # we can't subsitute it into pg_config.h.
*** /dev/null
--- b/src/backend/utils/misc/cfparser.c
***************
*** 0 ****
--- 1,112 ----
+ /*-------------------------------------------------------------------------
+  *
+  * cfparser.c
+  *	  Function for parsing RecoveryCommandFile lines
+  *
+  * This very simple file format (varible = value) is now also used in the
+  * extension control file format
+  *
+  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * IDENTIFICATION
+  *	  src/backend/utils/misc/cfparser.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ 
+ #include "postgres.h"
+ 
+ /*
+  * Parse one line from recovery.conf. 'cmdline' is the raw line from the
+  * file. If the line is parsed successfully, returns true, false indicates
+  * syntax error. On success, *key_p and *value_p are set to the parameter
+  * name and value on the line, respectively. If the line is an empty line,
+  * consisting entirely of whitespace and comments, function returns true
+  * and *keyp_p and *value_p are set to NULL.
+  *
+  * The pointers returned in *key_p and *value_p point to an internal buffer
+  * that is valid only until the next call of parseRecoveryCommandFile().
+  */
+ bool
+ parseRecoveryCommandFileLine(char *cmdline, char **key_p, char **value_p)
+ {
+ 	char	   *ptr;
+ 	char	   *bufp;
+ 	char	   *key;
+ 	char	   *value;
+ 	static char *buf = NULL;
+ 
+ 	*key_p = *value_p = NULL;
+ 
+ 	/*
+ 	 * Allocate the buffer on first use. It's used to hold both the parameter
+ 	 * name and value.
+ 	 */
+ 	if (buf == NULL)
+ 		buf = malloc(MAXPGPATH + 1);
+ 	bufp = buf;
+ 
+ 	/* Skip any whitespace at the beginning of line */
+ 	for (ptr = cmdline; *ptr; ptr++)
+ 	{
+ 		if (!isspace((unsigned char) *ptr))
+ 			break;
+ 	}
+ 	/* Ignore empty lines */
+ 	if (*ptr == '\0' || *ptr == '#')
+ 		return true;
+ 
+ 	/* Read the parameter name */
+ 	key = bufp;
+ 	while (*ptr && !isspace((unsigned char) *ptr) &&
+ 		   *ptr != '=' && *ptr != '\'')
+ 		*(bufp++) = *(ptr++);
+ 	*(bufp++) = '\0';
+ 
+ 	/* Skip to the beginning quote of the parameter value */
+ 	ptr = strchr(ptr, '\'');
+ 	if (!ptr)
+ 		return false;
+ 	ptr++;
+ 
+ 	/* Read the parameter value to *bufp. Collapse any '' escapes as we go. */
+ 	value = bufp;
+ 	for (;;)
+ 	{
+ 		if (*ptr == '\'')
+ 		{
+ 			ptr++;
+ 			if (*ptr == '\'')
+ 				*(bufp++) = '\'';
+ 			else
+ 			{
+ 				/* end of parameter */
+ 				*bufp = '\0';
+ 				break;
+ 			}
+ 		}
+ 		else if (*ptr == '\0')
+ 			return false;		/* unterminated quoted string */
+ 		else
+ 			*(bufp++) = *ptr;
+ 
+ 		ptr++;
+ 	}
+ 	*(bufp++) = '\0';
+ 
+ 	/* Check that there's no garbage after the value */
+ 	while (*ptr)
+ 	{
+ 		if (*ptr == '#')
+ 			break;
+ 		if (!isspace((unsigned char) *ptr))
+ 			return false;
+ 		ptr++;
+ 	}
+ 
+ 	/* Success! */
+ 	*key_p = key;
+ 	*value_p = value;
+ 	return true;
+ }
*** a/src/bin/pg_dump/common.c
--- b/src/bin/pg_dump/common.c
***************
*** 78,83 **** static int	strInArray(const char *pattern, char **arr, int arr_size);
--- 78,84 ----
  TableInfo *
  getSchemaData(int *numTablesPtr)
  {
+ 	ExtensionInfo *extinfo;
  	NamespaceInfo *nsinfo;
  	AggInfo    *agginfo;
  	InhInfo    *inhinfo;
***************
*** 94,99 **** getSchemaData(int *numTablesPtr)
--- 95,101 ----
  	FdwInfo    *fdwinfo;
  	ForeignServerInfo *srvinfo;
  	DefaultACLInfo *daclinfo;
+ 	int			numExtensions;
  	int			numNamespaces;
  	int			numAggregates;
  	int			numInherits;
***************
*** 112,117 **** getSchemaData(int *numTablesPtr)
--- 114,123 ----
  	int			numDefaultACLs;
  
  	if (g_verbose)
+ 		write_msg(NULL, "reading extensions\n");
+ 	extinfo = getExtensions(&numExtensions);
+ 
+ 	if (g_verbose)
  		write_msg(NULL, "reading schemas\n");
  	nsinfo = getNamespaces(&numNamespaces);
  
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 157,162 **** static int	findSecLabels(Archive *fout, Oid classoid, Oid objoid,
--- 157,163 ----
  						  SecLabelItem **items);
  static int	collectSecLabels(Archive *fout, SecLabelItem **items);
  static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
+ static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
  static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
  static void dumpType(Archive *fout, TypeInfo *tyinfo);
  static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
***************
*** 2376,2381 **** binary_upgrade_set_relfilenodes(PQExpBuffer upgrade_buffer, Oid pg_class_oid,
--- 2377,2456 ----
  }
  
  /*
+  * getExtensions:
+  *	  read all extensions in the system catalogs and return them in the
+  * ExtensionInfo* structure
+  *
+  *	numExtensions is set to the number of extensions read in
+  */
+ ExtensionInfo *
+ getExtensions(int *numExtensions)
+ {
+ 	PGresult   *res;
+ 	int			ntups;
+ 	int			i;
+ 	PQExpBuffer query;
+ 	ExtensionInfo *extinfo = NULL;
+ 	int			i_tableoid;
+ 	int			i_oid;
+ 	int			i_extname;
+ 	int			i_extversion;
+ 	int			i_extcclass;
+ 
+ 	/*
+ 	 * Before 9.1, there are no extensions.
+ 	 */
+ 	if (g_fout->remoteVersion < 90100)
+ 	{
+ 		*numExtensions = 0;
+ 		return extinfo;
+ 	}
+ 
+ 	query = createPQExpBuffer();
+ 
+ 	/* Make sure we are in proper schema */
+ 	selectSourceSchema("pg_catalog");
+ 
+ 	/*
+ 	 * we fetch all namespaces including system ones, so that every object we
+ 	 * read in can be linked to a containing namespace.
+ 	 */
+ 	appendPQExpBuffer(query,
+ 					  "SELECT tableoid, oid, extname, extversion, custom_class "
+ 					  "FROM pg_extension");
+ 
+ 	res = PQexec(g_conn, query->data);
+ 	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+ 
+ 	ntups = PQntuples(res);
+ 
+ 	extinfo = (ExtensionInfo *) malloc(ntups * sizeof(ExtensionInfo));
+ 
+ 	i_tableoid = PQfnumber(res, "tableoid");
+ 	i_oid = PQfnumber(res, "oid");
+ 	i_extname = PQfnumber(res, "extname");
+ 	i_extversion = PQfnumber(res, "extversion");
+ 	i_extcclass = PQfnumber(res, "custom_class");
+ 
+ 	for (i = 0; i < ntups; i++)
+ 	{
+ 		extinfo[i].dobj.objType = DO_EXTENSION;
+ 		extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
+ 		extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+ 		AssignDumpId(&extinfo[i].dobj);
+ 		extinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_extname));
+ 		extinfo[i].extversion = strdup(PQgetvalue(res, i, i_extversion));
+ 		extinfo[i].custom_class = strdup(PQgetvalue(res, i, i_extcclass));
+ 	}
+ 
+ 	PQclear(res);
+ 	destroyPQExpBuffer(query);
+ 
+ 	*numExtensions = ntups;
+ 	return extinfo;
+ }
+ 
+ /*
   * getNamespaces:
   *	  read all namespaces in the system catalogs and return them in the
   * NamespaceInfo* structure
***************
*** 2439,2448 **** getNamespaces(int *numNamespaces)
  	 * we fetch all namespaces including system ones, so that every object we
  	 * read in can be linked to a containing namespace.
  	 */
! 	appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
! 					  "(%s nspowner) AS rolname, "
! 					  "nspacl FROM pg_namespace",
! 					  username_subquery);
  
  	res = PQexec(g_conn, query->data);
  	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
--- 2514,2569 ----
  	 * we fetch all namespaces including system ones, so that every object we
  	 * read in can be linked to a containing namespace.
  	 */
! 	if (g_fout->remoteVersion >= 90100)
! 	{
! 		/*
! 		 * So we want the namespaces, but we want to filter out any
! 		 * namespace created by an extension's script. That's unless the
! 		 * user went over his head and created objects into the extension's
! 		 * schema: we now want the schema not to be filtered out to avoid:
! 		 *
! 		 *   pg_dump: schema with OID 77869 does not exist
! 		 */
! 		appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
! 						  "(%s nspowner) AS rolname, "
! 						  "n.nspacl "
! 						  "  FROM pg_namespace n "
! 						  " WHERE n.nspname != 'information_schema' "
! 						  "   AND CASE WHEN (SELECT count(*) "
! 						  "                    FROM pg_depend "
! 						  "                   WHERE refobjid = n.oid and deptype != 'p') > 0 "
! 						  "            THEN EXISTS( "
! 						  "WITH RECURSIVE depends AS ( "
! 						  " select n.oid as nsp, objid, refobjid, array[refobjid] as deps "
! 						  "   from pg_depend "
! 						  "  where refobjid = n.oid and deptype != 'p' "
! 						  " UNION ALL "
! 						  " select p.nsp, p.objid, d.refobjid, deps || d.refobjid "
! 						  "   from pg_depend d JOIN depends p ON d.objid = p.objid "
! 						  "  where d.deptype != 'p' and not d.refobjid = any(deps) "
! 						  ") "
! 						  "  SELECT nsp, objid, array_agg(distinct refobjid) "
! 						  "    FROM depends "
! 						  "GROUP BY nsp, objid "
! 						  "  HAVING NOT array_agg(distinct refobjid) && array(select oid from pg_extension) "
! 						  ") "
! 						  "            ELSE true "
! 						  "        END "
! 						  "UNION ALL "
! 						  "SELECT n.tableoid, n.oid, n.nspname,  "
! 						  "(%s nspowner) AS rolname, "
! 						  "nspacl FROM pg_namespace n "
! 						  "WHERE n.nspname = 'information_schema'",
! 						  username_subquery,
! 						  username_subquery);
! 	}
! 	else
! 	{
! 		appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
! 						  "(%s nspowner) AS rolname, "
! 						  "nspacl FROM pg_namespace",
! 						  username_subquery);
! 	}
  
  	res = PQexec(g_conn, query->data);
  	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
***************
*** 2559,2565 **** getTypes(int *numTypes)
  	 * we include even the built-in types because those may be used as array
  	 * elements by user-defined types
  	 *
! 	 * we filter out the built-in types when we dump out the types
  	 *
  	 * same approach for undefined (shell) types and array types
  	 *
--- 2680,2687 ----
  	 * we include even the built-in types because those may be used as array
  	 * elements by user-defined types
  	 *
! 	 * we filter out the built-in types when we dump out the types, and from
! 	 * 9.1 we also filter out types that depend on an extension
  	 *
  	 * same approach for undefined (shell) types and array types
  	 *
***************
*** 2574,2580 **** getTypes(int *numTypes)
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	if (g_fout->remoteVersion >= 80300)
  	{
  		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
  						  "typnamespace, "
--- 2696,2721 ----
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	if (g_fout->remoteVersion >= 90100)
! 	{
! 		appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
! 						  "t.typnamespace, "
! 						  "(%s typowner) AS rolname, "
! 						  "t.typinput::oid AS typinput, "
! 						  "t.typoutput::oid AS typoutput, t.typelem, t.typrelid, "
! 						  "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
! 						  "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
! 						  "t.typtype, t.typisdefined, "
! 						  "t.typname[0] = '_' AND t.typelem != 0 AND "
! 						  "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
! 						  "FROM pg_type t "
! 						  "LEFT JOIN pg_depend d ON d.objid = t.oid and d.deptype = 'i' "
! 						  "and d.refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass "
! 						  "LEFT JOIN pg_extension x ON d.refobjid = x.oid "
! 						  "WHERE x.oid IS NULL",
! 						  username_subquery);
! 	}
! 	else if (g_fout->remoteVersion >= 80300)
  	{
  		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
  						  "typnamespace, "
***************
*** 2806,2812 **** getOperators(int *numOprs)
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	if (g_fout->remoteVersion >= 70300)
  	{
  		appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
  						  "oprnamespace, "
--- 2947,2966 ----
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	if (g_fout->remoteVersion >= 90100)
! 	{
! 		appendPQExpBuffer(query, "SELECT o.tableoid, o.oid, o.oprname, "
! 						  "o.oprnamespace, "
! 						  "(%s oprowner) AS rolname, "
! 						  "o.oprcode::oid AS oprcode "
! 						  "FROM pg_operator o "
! 						  "LEFT JOIN pg_depend d ON d.objid = o.oid and d.deptype = 'i' "
! 						  "and d.refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass "
! 						  "LEFT JOIN pg_extension x ON d.refobjid = x.oid "
! 						  "WHERE x.oid IS NULL",
! 						  username_subquery);
! 	}
! 	else if (g_fout->remoteVersion >= 70300)
  	{
  		appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
  						  "oprnamespace, "
***************
*** 2985,2991 **** getOpclasses(int *numOpclasses)
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	if (g_fout->remoteVersion >= 70300)
  	{
  		appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
  						  "opcnamespace, "
--- 3139,3157 ----
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	if (g_fout->remoteVersion >= 90100)
! 	{
! 		appendPQExpBuffer(query, "SELECT o.tableoid, o.oid, o.opcname, "
! 						  "o.opcnamespace, "
! 						  "(%s opcowner) AS rolname "
! 						  "FROM pg_opclass o "
! 						  "LEFT JOIN pg_depend d ON d.objid = o.oid and d.deptype = 'i' "
! 						  "and d.refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass "
! 						  "LEFT JOIN pg_extension x ON d.refobjid = x.oid "
! 						  "WHERE x.oid IS NULL",
! 						  username_subquery);
! 	}
! 	else if (g_fout->remoteVersion >= 70300)
  	{
  		appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
  						  "opcnamespace, "
***************
*** 3091,3101 **** getOpfamilies(int *numOpfamilies)
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
! 					  "opfnamespace, "
! 					  "(%s opfowner) AS rolname "
! 					  "FROM pg_opfamily",
! 					  username_subquery);
  
  	res = PQexec(g_conn, query->data);
  	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
--- 3257,3282 ----
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	if (g_fout->remoteVersion >= 90100)
! 	{
! 		appendPQExpBuffer(query, "SELECT o.tableoid, o.oid, o.opfname, "
! 						  "o.opfnamespace, "
! 						  "(%s opfowner) AS rolname "
! 						  "FROM pg_opfamily o "
! 						  "LEFT JOIN pg_depend d ON d.objid = o.oid and d.deptype = 'i' "
! 						  "and d.refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass "
! 						  "LEFT JOIN pg_extension x ON d.refobjid = x.oid "
! 						  "WHERE x.oid IS NULL",
! 						  username_subquery);
! 	}
! 	else
! 	{
! 		appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
! 						  "opfnamespace, "
! 						  "(%s opfowner) AS rolname "
! 						  "FROM pg_opfamily",
! 						  username_subquery);
! 	}
  
  	res = PQexec(g_conn, query->data);
  	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
***************
*** 3169,3175 **** getAggregates(int *numAggs)
  
  	/* find all user-defined aggregates */
  
! 	if (g_fout->remoteVersion >= 80200)
  	{
  		appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
  						  "pronamespace AS aggnamespace, "
--- 3350,3372 ----
  
  	/* find all user-defined aggregates */
  
! 	if (g_fout->remoteVersion >= 90100)
! 	{
! 		appendPQExpBuffer(query, "SELECT a.tableoid, a.oid, a.proname AS aggname, "
! 						  "a.pronamespace AS aggnamespace, "
! 						  "a.pronargs, a.proargtypes, "
! 						  "(%s proowner) AS rolname, "
! 						  "a.proacl AS aggacl "
! 						  "FROM pg_proc a "
! 						  "LEFT JOIN pg_depend d ON d.objid = a.oid and d.deptype = 'i' "
! 						  "and d.refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass "
! 						  "LEFT JOIN pg_extension x ON d.refobjid = x.oid "
! 						  "WHERE x.oid IS NULL AND proisagg "
! 						  "AND pronamespace != "
! 			   "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
! 						  username_subquery);
! 	}
! 	else if (g_fout->remoteVersion >= 80200)
  	{
  		appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
  						  "pronamespace AS aggnamespace, "
***************
*** 3315,3321 **** getFuncs(int *numFuncs)
  
  	/* find all user-defined funcs */
  
! 	if (g_fout->remoteVersion >= 70300)
  	{
  		appendPQExpBuffer(query,
  						  "SELECT tableoid, oid, proname, prolang, "
--- 3512,3535 ----
  
  	/* find all user-defined funcs */
  
! 	if (g_fout->remoteVersion >= 90100)
! 	{
! 		appendPQExpBuffer(query,
! 						  "SELECT f.tableoid, f.oid, f.proname, f.prolang, "
! 						  "f.pronargs, f.proargtypes, f.prorettype, f.proacl, "
! 						  "f.pronamespace, "
! 						  "(%s proowner) AS rolname "
! 						  "FROM pg_proc f "
! 						  "LEFT JOIN pg_depend d ON d.objid = f.oid and d.deptype = 'i' "
! 						  "and d.refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass "
! 						  "LEFT JOIN pg_extension x ON d.refobjid = x.oid "
! 						  "WHERE x.oid IS NULL AND NOT proisagg "
! 						  "AND pronamespace != "
! 						  "(SELECT oid FROM pg_namespace "
! 						  "WHERE nspname = 'pg_catalog')",
! 						  username_subquery);
! 	}
! 	else if (g_fout->remoteVersion >= 70300)
  	{
  		appendPQExpBuffer(query,
  						  "SELECT tableoid, oid, proname, prolang, "
***************
*** 3477,3483 **** getTables(int *numTables)
  	 * we cannot correctly identify inherited columns, owned sequences, etc.
  	 */
  
! 	if (g_fout->remoteVersion >= 90000)
  	{
  		/*
  		 * Left join to pick up dependency info linking sequences to their
--- 3691,3734 ----
  	 * we cannot correctly identify inherited columns, owned sequences, etc.
  	 */
  
! 	if (g_fout->remoteVersion >= 90100)
! 	{
! 		/*
! 		 * Left join to pick up dependency info linking sequences to their
! 		 * owning column, if any (note this dependency is AUTO as of 8.2)
! 		 */
! 		appendPQExpBuffer(query,
! 						  "SELECT c.tableoid, c.oid, c.relname, "
! 						  "c.relacl, c.relkind, c.relnamespace, "
! 						  "(%s c.relowner) AS rolname, "
! 						  "c.relchecks, c.relhastriggers, "
! 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
! 						  "c.relfrozenxid, "
! 						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
! 						  "d.refobjid AS owning_tab, "
! 						  "d.refobjsubid AS owning_col, "
! 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
! 						"array_to_string(c.reloptions, ', ') AS reloptions, "
! 						  "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
! 						  "FROM pg_class c "
! 						  "LEFT JOIN pg_depend d ON "
! 						  "(c.relkind = '%c' AND "
! 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
! 						  "d.objsubid = 0 AND "
! 						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
! 						  "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
! 						  "LEFT JOIN pg_depend dx ON dx.objid = c.oid and dx.deptype = 'i' "
! 						  "and dx.refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass "
! 						  "LEFT JOIN pg_extension x ON dx.refobjid = x.oid "
! 						  "WHERE x.oid IS NULL "
! 						  "AND c.relkind in ('%c', '%c', '%c', '%c') "
! 						  "ORDER BY c.oid",
! 						  username_subquery,
! 						  RELKIND_SEQUENCE,
! 						  RELKIND_RELATION, RELKIND_SEQUENCE,
! 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
! 	}
! 	else if (g_fout->remoteVersion >= 90000)
  	{
  		/*
  		 * Left join to pick up dependency info linking sequences to their
***************
*** 4838,4844 **** getProcLangs(int *numProcLangs)
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	if (g_fout->remoteVersion >= 90000)
  	{
  		/* pg_language has a laninline column */
  		appendPQExpBuffer(query, "SELECT tableoid, oid, "
--- 5089,5110 ----
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	if (g_fout->remoteVersion >= 90100)
! 	{
! 		/* pg_language has a laninline column */
! 		appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
! 						  "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
! 						  "l.laninline, l.lanvalidator, l.lanacl, "
! 						  "(%s lanowner) AS lanowner "
! 						  "FROM pg_language l "
! 						  "LEFT JOIN pg_depend d ON d.objid = l.oid and d.deptype = 'i' "
! 						  "and d.refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass "
! 						  "LEFT JOIN pg_extension x ON d.refobjid = x.oid "
! 						  "WHERE x.oid IS NULL and lanispl "
! 						  "ORDER BY oid",
! 						  username_subquery);
! 	}
! 	else if (g_fout->remoteVersion >= 90000)
  	{
  		/* pg_language has a laninline column */
  		appendPQExpBuffer(query, "SELECT tableoid, oid, "
***************
*** 4992,4998 **** getCasts(int *numCasts)
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	if (g_fout->remoteVersion >= 80400)
  	{
  		appendPQExpBuffer(query, "SELECT tableoid, oid, "
  						  "castsource, casttarget, castfunc, castcontext, "
--- 5258,5276 ----
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	if (g_fout->remoteVersion >= 90100)
! 	{
! 		appendPQExpBuffer(query, "SELECT c.tableoid, c.oid, "
! 						  "c.castsource, c.casttarget, c.castfunc, c.castcontext, "
! 						  "c.castmethod "
! 						  "FROM pg_cast c "
! 						  "LEFT JOIN pg_depend d ON d.objid = c.oid and d.deptype = 'i' "
! 						  "and d.refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass "
! 						  "LEFT JOIN pg_extension x ON d.refobjid = x.oid "
! 						  "WHERE x.oid IS NULL "
! 						  "ORDER BY 3,4");
! 	}
! 	else if (g_fout->remoteVersion >= 80400)
  	{
  		appendPQExpBuffer(query, "SELECT tableoid, oid, "
  						  "castsource, casttarget, castfunc, castcontext, "
***************
*** 5586,5595 **** getTSParsers(int *numTSParsers)
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
! 					  "prsstart::oid, prstoken::oid, "
! 					  "prsend::oid, prsheadline::oid, prslextype::oid "
! 					  "FROM pg_ts_parser");
  
  	res = PQexec(g_conn, query->data);
  	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
--- 5864,5887 ----
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	if (g_fout->remoteVersion >= 90100)
! 	{
! 		appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, p.prsname, p.prsnamespace, "
! 						  "p.prsstart::oid, p.prstoken::oid, "
! 						  "p.prsend::oid, p.prsheadline::oid, p.prslextype::oid "
! 						  "FROM pg_ts_parser p "
! 						  "LEFT JOIN pg_depend d ON d.objid = p.oid and d.deptype = 'i' "
! 						  "and d.refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass "
! 						  "LEFT JOIN pg_extension x ON d.refobjid = x.oid "
! 						  "WHERE x.oid IS NULL");
! 	}
! 	else
! 	{
! 		appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
! 						  "prsstart::oid, prstoken::oid, "
! 						  "prsend::oid, prsheadline::oid, prslextype::oid "
! 						  "FROM pg_ts_parser");
! 	}
  
  	res = PQexec(g_conn, query->data);
  	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
***************
*** 5668,5678 **** getTSDictionaries(int *numTSDicts)
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
! 					  "dictnamespace, (%s dictowner) AS rolname, "
! 					  "dicttemplate, dictinitoption "
! 					  "FROM pg_ts_dict",
! 					  username_subquery);
  
  	res = PQexec(g_conn, query->data);
  	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
--- 5960,5985 ----
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	if (g_fout->remoteVersion >= 90100)
! 	{
! 		appendPQExpBuffer(query, "SELECT tsd.tableoid, tsd.oid, tsd.dictname, "
! 						  "tsd.dictnamespace, (%s dictowner) AS rolname, "
! 						  "tsd.dicttemplate, tsd.dictinitoption "
! 						  "FROM pg_ts_dict tsd "
! 						  "LEFT JOIN pg_depend d ON d.objid = tsd.oid and d.deptype = 'i' "
! 						  "and d.refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass "
! 						  "LEFT JOIN pg_extension x ON d.refobjid = x.oid "
! 						  "WHERE x.oid IS NULL",
! 						  username_subquery);
! 	}
! 	else
! 	{
! 		appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
! 						  "dictnamespace, (%s dictowner) AS rolname, "
! 						  "dicttemplate, dictinitoption "
! 						  "FROM pg_ts_dict",
! 						  username_subquery);
! 	}
  
  	res = PQexec(g_conn, query->data);
  	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
***************
*** 5749,5757 **** getTSTemplates(int *numTSTemplates)
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
! 					  "tmplnamespace, tmplinit::oid, tmpllexize::oid "
! 					  "FROM pg_ts_template");
  
  	res = PQexec(g_conn, query->data);
  	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
--- 6056,6077 ----
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	if (g_fout->remoteVersion >= 90100)
! 	{
! 		appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.tmplname, "
! 						  "t.tmplnamespace, t.tmplinit::oid, t.tmpllexize::oid "
! 						  "FROM pg_ts_template t "
! 						  "LEFT JOIN pg_depend d ON d.objid = t.oid and d.deptype = 'i' "
! 						  "and d.refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass "
! 						  "LEFT JOIN pg_extension x ON d.refobjid = x.oid "
! 						  "WHERE x.oid IS NULL");
! 	}
! 	else
! 	{
! 		appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
! 						  "tmplnamespace, tmplinit::oid, tmpllexize::oid "
! 						  "FROM pg_ts_template");
! 	}
  
  	res = PQexec(g_conn, query->data);
  	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
***************
*** 5823,5832 **** getTSConfigurations(int *numTSConfigs)
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
! 					  "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
! 					  "FROM pg_ts_config",
! 					  username_subquery);
  
  	res = PQexec(g_conn, query->data);
  	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
--- 6143,6166 ----
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	if (g_fout->remoteVersion >= 90100)
! 	{
! 		appendPQExpBuffer(query, "SELECT c.tableoid, c.oid, c.cfgname, "
! 						  "c.cfgnamespace, (%s cfgowner) AS rolname, c.cfgparser "
! 						  "FROM pg_ts_config c "
! 						  "LEFT JOIN pg_depend d ON d.objid = c.oid and d.deptype = 'i' "
! 						  "and d.refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass "
! 						  "LEFT JOIN pg_extension x ON d.refobjid = x.oid "
! 						  "WHERE x.oid IS NULL",
! 						  username_subquery);
! 	}
! 	else
! 	{
! 		appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
! 						  "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
! 						  "FROM pg_ts_config",
! 						  username_subquery);
! 	}
  
  	res = PQexec(g_conn, query->data);
  	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
***************
*** 5899,5911 **** getForeignDataWrappers(int *numForeignDataWrappers)
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
! 		"(%s fdwowner) AS rolname, fdwvalidator::pg_catalog.regproc, fdwacl,"
! 					  "array_to_string(ARRAY("
! 		 "		SELECT option_name || ' ' || quote_literal(option_value) "
! 	   "		FROM pg_options_to_table(fdwoptions)), ', ') AS fdwoptions "
! 					  "FROM pg_foreign_data_wrapper",
! 					  username_subquery);
  
  	res = PQexec(g_conn, query->data);
  	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
--- 6233,6262 ----
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	if (g_fout->remoteVersion >= 90100)
! 	{
! 		appendPQExpBuffer(query, "SELECT fdw.tableoid, fdw.oid, fdw.fdwname, "
! 						  "(%s fdwowner) AS rolname, fdw.fdwvalidator::pg_catalog.regproc, fdwacl,"
! 						  "array_to_string(ARRAY("
! 						  "		SELECT option_name || ' ' || quote_literal(option_value) "
! 						  "		FROM pg_options_to_table(fdw.fdwoptions)), ', ') AS fdwoptions "
! 						  "FROM pg_foreign_data_wrapper fdw "
! 						  "LEFT JOIN pg_depend d ON d.objid = fdw.oid and d.deptype = 'i' "
! 						  "and d.refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass "
! 						  "LEFT JOIN pg_extension x ON d.refobjid = x.oid "
! 						  "WHERE x.oid IS NULL",
! 						  username_subquery);
! 	}
! 	else
! 	{
! 		appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
! 						  "(%s fdwowner) AS rolname, fdwvalidator::pg_catalog.regproc, fdwacl,"
! 						  "array_to_string(ARRAY("
! 						  "		SELECT option_name || ' ' || quote_literal(option_value) "
! 						  "		FROM pg_options_to_table(fdwoptions)), ', ') AS fdwoptions "
! 						  "FROM pg_foreign_data_wrapper",
! 						  username_subquery);
! 	}
  
  	res = PQexec(g_conn, query->data);
  	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
***************
*** 5983,5996 **** getForeignServers(int *numForeignServers)
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
! 					  "(%s srvowner) AS rolname, "
! 					  "srvfdw, srvtype, srvversion, srvacl,"
! 					  "array_to_string(ARRAY("
! 		 "		SELECT option_name || ' ' || quote_literal(option_value) "
! 	   "		FROM pg_options_to_table(srvoptions)), ', ') AS srvoptions "
! 					  "FROM pg_foreign_server",
! 					  username_subquery);
  
  	res = PQexec(g_conn, query->data);
  	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
--- 6334,6365 ----
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	if (g_fout->remoteVersion >= 90100)
! 	{
! 		appendPQExpBuffer(query, "SELECT fs.tableoid, fs.oid, fs.srvname, "
! 						  "(%s srvowner) AS rolname, "
! 						  "fs.srvfdw, fs.srvtype, fs.srvversion, fs.srvacl,"
! 						  "array_to_string(ARRAY("
! 						  "		SELECT option_name || ' ' || quote_literal(option_value) "
! 						  "		FROM pg_options_to_table(fs.srvoptions)), ', ') AS srvoptions "
! 						  "FROM pg_foreign_server fs "
! 						  "LEFT JOIN pg_depend d ON d.objid = fs.oid and d.deptype = 'i' "
! 						  "and d.refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass "
! 						  "LEFT JOIN pg_extension x ON d.refobjid = x.oid "
! 						  "WHERE x.oid IS NULL",
! 						  username_subquery);
! 	}
! 	else
! 	{
! 		appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
! 						  "(%s srvowner) AS rolname, "
! 						  "srvfdw, srvtype, srvversion, srvacl,"
! 						  "array_to_string(ARRAY("
! 						  "		SELECT option_name || ' ' || quote_literal(option_value) "
! 						  "		FROM pg_options_to_table(srvoptions)), ', ') AS srvoptions "
! 						  "FROM pg_foreign_server",
! 						  username_subquery);
! 	}
  
  	res = PQexec(g_conn, query->data);
  	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
***************
*** 6467,6472 **** dumpDumpableObject(Archive *fout, DumpableObject *dobj)
--- 6836,6844 ----
  {
  	switch (dobj->objType)
  	{
+ 		case DO_EXTENSION:
+ 			dumpExtension(fout, (ExtensionInfo *) dobj);
+ 			break;
  		case DO_NAMESPACE:
  			dumpNamespace(fout, (NamespaceInfo *) dobj);
  			break;
***************
*** 6563,6568 **** dumpDumpableObject(Archive *fout, DumpableObject *dobj)
--- 6935,6986 ----
  }
  
  /*
+  * dumpExtension
+  *	  writes out to fout the queries to recreate an extension
+  */
+ static void
+ dumpExtension(Archive *fout, ExtensionInfo *extinfo)
+ {
+ 	PQExpBuffer q;
+ 	PQExpBuffer delq;
+ 	char	   *qextname;
+ 
+ 	/* Skip if not to be dumped */
+ 	if (!extinfo->dobj.dump || dataOnly)
+ 		return;
+ 
+ 	q = createPQExpBuffer();
+ 	delq = createPQExpBuffer();
+ 
+ 	qextname = strdup(fmtId(extinfo->dobj.name));
+ 
+ 	appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
+ 
+ 	appendPQExpBuffer(q, "CREATE EXTENSION %s;\n", qextname);
+ 
+ 	ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
+ 				 extinfo->dobj.name,
+ 				 NULL, NULL,
+ 				 "",
+ 				 false, "EXTENSION", SECTION_PRE_DATA,
+ 				 q->data, delq->data, NULL,
+ 				 extinfo->dobj.dependencies, extinfo->dobj.nDeps,
+ 				 NULL, NULL);
+ 
+ 	/* Dump Extension Comments */
+ 	resetPQExpBuffer(q);
+ 	appendPQExpBuffer(q, "EXTENSION %s", qextname);
+ 	dumpComment(fout, q->data,
+ 				NULL, "",
+ 				extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
+ 
+ 	free(qextname);
+ 
+ 	destroyPQExpBuffer(q);
+ 	destroyPQExpBuffer(delq);
+ }
+ 
+ /*
   * dumpNamespace
   *	  writes out to fout the queries to recreate a user-defined namespace
   */
*** a/src/bin/pg_dump/pg_dump.h
--- b/src/bin/pg_dump/pg_dump.h
***************
*** 88,93 **** typedef struct SimpleStringList
--- 88,94 ----
  typedef enum
  {
  	/* When modifying this enum, update priority tables in pg_dump_sort.c! */
+ 	DO_EXTENSION,
  	DO_NAMESPACE,
  	DO_TYPE,
  	DO_SHELL_TYPE,
***************
*** 132,137 **** typedef struct _dumpableObject
--- 133,146 ----
  	int			allocDeps;		/* allocated size of dependencies[] */
  } DumpableObject;
  
+ typedef struct _extensionInfo
+ {
+ 	DumpableObject dobj;
+ 	char	   *extname;
+ 	char	   *extversion;
+ 	char	   *custom_class;
+ } ExtensionInfo;
+ 
  typedef struct _namespaceInfo
  {
  	DumpableObject dobj;
***************
*** 511,516 **** extern void sortDumpableObjectsByTypeOid(DumpableObject **objs, int numObjs);
--- 520,526 ----
  /*
   * version specific routines
   */
+ extern ExtensionInfo *getExtensions(int *numExtensions);
  extern NamespaceInfo *getNamespaces(int *numNamespaces);
  extern TypeInfo *getTypes(int *numTypes);
  extern FuncInfo *getFuncs(int *numFuncs);
*** a/src/bin/pg_dump/pg_dump_sort.c
--- b/src/bin/pg_dump/pg_dump_sort.c
***************
*** 28,33 **** static const char *modulename = gettext_noop("sorter");
--- 28,34 ----
   */
  static const int oldObjectTypePriority[] =
  {
+ 	1,							/* DO_EXTENSION */
  	1,							/* DO_NAMESPACE */
  	2,							/* DO_TYPE */
  	2,							/* DO_SHELL_TYPE */
***************
*** 65,70 **** static const int oldObjectTypePriority[] =
--- 66,72 ----
   */
  static const int newObjectTypePriority[] =
  {
+ 	1,							/* DO_EXTENSION */
  	1,							/* DO_NAMESPACE */
  	3,							/* DO_TYPE */
  	3,							/* DO_SHELL_TYPE */
***************
*** 1018,1023 **** describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
--- 1020,1030 ----
  {
  	switch (obj->objType)
  	{
+ 		case DO_EXTENSION:
+ 			snprintf(buf, bufsize,
+ 					 "EXTENSION %s  (ID %d OID %u)",
+ 					 obj->name, obj->dumpId, obj->catId.oid);
+ 			return;
  		case DO_NAMESPACE:
  			snprintf(buf, bufsize,
  					 "SCHEMA %s  (ID %d OID %u)",
*** a/src/bin/psql/command.c
--- b/src/bin/psql/command.c
***************
*** 488,493 **** exec_command(const char *cmd,
--- 488,496 ----
  						break;
  				}
  				break;
+ 			case 'x':          /* Extensions */
+ 				success = listExtensions(pattern, show_verbose);
+ 				break;
  			default:
  				status = PSQL_CMD_UNKNOWN;
  		}
*** a/src/bin/psql/describe.c
--- b/src/bin/psql/describe.c
***************
*** 2720,2725 **** listSchemas(const char *pattern, bool verbose)
--- 2720,2770 ----
  	return true;
  }
  
+ /*
+  * \dx
+  *
+  * Describes extensions
+  */
+ bool
+ listExtensions(const char *pattern, bool verbose)
+ {
+ 	PQExpBufferData buf;
+ 	PGresult   *res;
+ 	printQueryOpt myopt = pset.popt;
+ 
+ 	initPQExpBuffer(&buf);
+ 	printfPQExpBuffer(&buf,
+ 					  "SELECT x.extname AS \"%s\", x.extversion AS \"%s\", "
+                       "x.custom_class AS \"%s\", d.description as \"%s\" "
+ 					  " FROM pg_catalog.pg_extension x \n"
+ 					  " LEFT JOIN pg_description d on x.oid = d.objoid "
+ 					  " and d.classoid = 3696",
+ 					  gettext_noop("Name"),
+ 					  gettext_noop("Version"),
+ 					  gettext_noop("Custom Class"),
+ 					  gettext_noop("Description"));
+ 
+ 	processSQLNamePattern(pset.db, &buf, pattern, false, false,
+ 						  NULL, "x.extname", NULL,
+ 						  NULL);
+ 
+ 	appendPQExpBuffer(&buf, "ORDER BY 1;");
+ 
+ 	res = PSQLexec(buf.data, false);
+ 	termPQExpBuffer(&buf);
+ 	if (!res)
+ 		return false;
+ 
+ 	myopt.nullPrint = NULL;
+ 	myopt.title = _("List of extensions");
+ 	myopt.translate_header = true;
+ 
+ 	printQuery(res, &myopt, pset.queryFout, pset.logfile);
+ 
+ 	PQclear(res);
+ 	return true;
+ }
+ 
  
  /*
   * \dFp
*** a/src/bin/psql/describe.h
--- b/src/bin/psql/describe.h
***************
*** 54,59 **** extern bool listTSDictionaries(const char *pattern, bool verbose);
--- 54,62 ----
  /* \dFt */
  extern bool listTSTemplates(const char *pattern, bool verbose);
  
+ /* \dx */
+ bool listExtensions(const char *pattern, bool verbose);
+ 
  /* \l */
  extern bool listAllDbs(bool verbose);
  
*** a/src/bin/psql/help.c
--- b/src/bin/psql/help.c
***************
*** 219,224 **** slashUsage(unsigned short int pager)
--- 219,225 ----
  	fprintf(output, _("  \\dT[S+] [PATTERN]      list data types\n"));
  	fprintf(output, _("  \\du[+]  [PATTERN]      list roles (users)\n"));
  	fprintf(output, _("  \\dv[S+] [PATTERN]      list views\n"));
+ 	fprintf(output, _("  \\dx     [PATTERN]      list extensions\n"));
  	fprintf(output, _("  \\l[+]                  list all databases\n"));
  	fprintf(output, _("  \\sf[+] FUNCNAME        show a function's definition\n"));
  	fprintf(output, _("  \\z      [PATTERN]      same as \\dp\n"));
*** a/src/include/catalog/dependency.h
--- b/src/include/catalog/dependency.h
***************
*** 138,143 **** typedef enum ObjectClass
--- 138,144 ----
  	OCLASS_FOREIGN_SERVER,		/* pg_foreign_server */
  	OCLASS_USER_MAPPING,		/* pg_user_mapping */
  	OCLASS_DEFACL,				/* pg_default_acl */
+ 	OCLASS_EXTENSION,           /* pg_extension */
  	MAX_OCLASS					/* MUST BE LAST */
  } ObjectClass;
  
*** a/src/include/catalog/indexing.h
--- b/src/include/catalog/indexing.h
***************
*** 284,289 **** DECLARE_UNIQUE_INDEX(pg_db_role_setting_databaseid_rol_index, 2965, on pg_db_rol
--- 284,295 ----
  DECLARE_UNIQUE_INDEX(pg_seclabel_object_index, 3597, on pg_seclabel using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops, provider text_ops));
  #define SecLabelObjectIndexId				3597
  
+ DECLARE_UNIQUE_INDEX(pg_extension_oid_index, 3695, on pg_extension using btree(oid oid_ops));
+ #define ExtensionOidIndexId 3695
+ 
+ DECLARE_UNIQUE_INDEX(pg_extension_name_index, 3697, on pg_extension using btree(extname name_ops));
+ #define ExtensionNameIndexId 3697
+ 
  /* last step of initialization script: build the indexes declared above */
  BUILD_INDICES
  
*** /dev/null
--- b/src/include/catalog/pg_extension.h
***************
*** 0 ****
--- 1,61 ----
+ /*-------------------------------------------------------------------------
+  *
+  * pg_extension.h
+  *	  definition of the system "extension" relation (pg_extension)
+  *
+  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * src/include/catalog/pg_extension.h
+  *
+  * NOTES
+  *	  the genbki.pl script reads this file and generates .bki
+  *	  information from the DATA() statements.
+  *
+  *-------------------------------------------------------------------------
+  */
+ #ifndef PG_EXTENSION_H
+ #define PG_EXTENSION_H
+ 
+ #include "catalog/genbki.h"
+ 
+ /* ----------------
+  *		pg_extension definition.  cpp turns this into
+  *		typedef struct FormData_pg_extension
+  * ----------------
+  */
+ #define ExtensionRelationId	3696
+ 
+ CATALOG(pg_extension,3696)
+ {
+ 	NameData	extname;	  /* name of the extension */
+ 	text		extversion;	  /* version "name" of the extension */
+ 	text        custom_class; /* custom class used by the extension */
+ } FormData_pg_extension;
+ 
+ /* ----------------
+  *		Form_pg_extension corresponds to a pointer to a tuple with
+  *		the format of pg_extension relation.
+  * ----------------
+  */
+ typedef FormData_pg_extension *Form_pg_extension;
+ 
+ /* ----------------
+  *		compiler constants for pg_extension
+  * ----------------
+  */
+ 
+ #define Natts_pg_extension					3
+ #define Anum_pg_extension_extname			1
+ #define Anum_pg_extension_extversion		2
+ #define Anum_pg_extension_custom_class		3
+ 
+ /* ----------------
+  *		initial contents of pg_extension
+  * ----------------
+  */
+ 
+ /* btree
+ DATA(insert ("PostgreSQL" PG_VERSION _null_));
+ */
+ #endif   /* PG_EXTENSION_H */
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
***************
*** 3386,3399 **** DESCR("reload configuration files");
  DATA(insert OID = 2622 ( pg_rotate_logfile		PGNSP PGUID 12 1 0 0 f f f t f v 0 0 16 "" _null_ _null_ _null_ _null_ pg_rotate_logfile _null_ _null_ _null_ ));
  DESCR("rotate log file");
  
! DATA(insert OID = 2623 ( pg_stat_file		PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2249 "25" "{25,20,1184,1184,1184,1184,16}" "{i,o,o,o,o,o,o}" "{filename,size,access,modification,change,creation,isdir}" _null_ pg_stat_file _null_ _null_ _null_ ));
  DESCR("return file information");
! DATA(insert OID = 2624 ( pg_read_file		PGNSP PGUID 12 1 0 0 f f f t f v 3 0 25 "25 20 20" _null_ _null_ _null_ _null_ pg_read_file _null_ _null_ _null_ ));
  DESCR("read text from a file");
! DATA(insert OID = 2625 ( pg_ls_dir			PGNSP PGUID 12 1 1000 0 f f f t t v 1 0 25 "25" _null_ _null_ _null_ _null_ pg_ls_dir _null_ _null_ _null_ ));
  DESCR("list all files in a directory");
! DATA(insert OID = 2626 ( pg_sleep			PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "701" _null_ _null_ _null_ _null_ pg_sleep _null_ _null_ _null_ ));
  DESCR("sleep for the specified time in seconds");
  
  DATA(insert OID = 2971 (  text				PGNSP PGUID 12 1 0 0 f f f t f i 1 0 25 "16" _null_ _null_ _null_ _null_ booltext _null_ _null_ _null_ ));
  DESCR("convert boolean to text");
--- 3386,3401 ----
  DATA(insert OID = 2622 ( pg_rotate_logfile		PGNSP PGUID 12 1 0 0 f f f t f v 0 0 16 "" _null_ _null_ _null_ _null_ pg_rotate_logfile _null_ _null_ _null_ ));
  DESCR("rotate log file");
  
! DATA(insert OID = 2623 ( pg_stat_file			PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2249 "25" "{25,20,1184,1184,1184,1184,16}" "{i,o,o,o,o,o,o}" "{filename,size,access,modification,change,creation,isdir}" _null_ pg_stat_file _null_ _null_ _null_ ));
  DESCR("return file information");
! DATA(insert OID = 2624 ( pg_read_file			PGNSP PGUID 12 1 0 0 f f f t f v 3 0 25 "25 20 20" _null_ _null_ _null_ _null_ pg_read_file _null_ _null_ _null_ ));
  DESCR("read text from a file");
! DATA(insert OID = 2625 ( pg_ls_dir				PGNSP PGUID 12 1 1000 0 f f f t t v 1 0 25 "25" _null_ _null_ _null_ _null_ pg_ls_dir _null_ _null_ _null_ ));
  DESCR("list all files in a directory");
! DATA(insert OID = 2626 ( pg_sleep				PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "701" _null_ _null_ _null_ _null_ pg_sleep _null_ _null_ _null_ ));
  DESCR("sleep for the specified time in seconds");
+ DATA(insert OID = 3627 ( pg_execute_from_file	PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "25" _null_ _null_ _null_ _null_ pg_execute_from_file _null_ _null_ _null_ ));
+ DESCR("execute queries read from a file");
  
  DATA(insert OID = 2971 (  text				PGNSP PGUID 12 1 0 0 f f f t f i 1 0 25 "16" _null_ _null_ _null_ _null_ booltext _null_ _null_ _null_ ));
  DESCR("convert boolean to text");
*** a/src/include/catalog/toasting.h
--- b/src/include/catalog/toasting.h
***************
*** 43,48 **** extern void BootstrapToastTable(char *relName,
--- 43,49 ----
  DECLARE_TOAST(pg_attrdef, 2830, 2831);
  DECLARE_TOAST(pg_constraint, 2832, 2833);
  DECLARE_TOAST(pg_description, 2834, 2835);
+ DECLARE_TOAST(pg_extension, 3698, 3699);
  DECLARE_TOAST(pg_proc, 2836, 2837);
  DECLARE_TOAST(pg_rewrite, 2838, 2839);
  DECLARE_TOAST(pg_seclabel, 3598, 3599);
*** /dev/null
--- b/src/include/commands/extension.h
***************
*** 0 ****
--- 1,49 ----
+ /*-------------------------------------------------------------------------
+  *
+  * extension.h
+  *		Extension management commands (create/drop extension).
+  *
+  *
+  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * src/include/commands/extension.h
+  *
+  *-------------------------------------------------------------------------
+  */
+ #ifndef EXTENSION_H
+ #define EXTENSION_H
+ 
+ #include "catalog/objectaddress.h"
+ 
+ /*
+  * create_extension is only set when running a CREATE EXTENSION command, it
+  * allows to register the (INTERNAL) dependancies between the pg_extension
+  * row and the SQL objects created by its installation script.
+  *
+  * For that to work out, all CREATE commands have been modified so that they
+  * will inquire about create_extension and call recordDependencyOn() when
+  * it's set.
+  */
+ extern ObjectAddress *create_extension;
+ 
+ typedef struct ExtensionControlFile
+ {
+ 	char *name;	        /* name of the extension */
+ 	char *version;	    /* version "name" of the extension */
+ 	char *custom_class; /* custom class used by the extension */
+ } ExtensionControlFile;
+ 
+ char *get_extension_install_filename(const char *extname);
+ char *get_extension_control_filename(const char *extname);
+ char * extension_parse_control_line(const char *content, ExtensionControlFile *control);
+ ExtensionControlFile *read_extension_control_file(const char *filename);
+ extern void CreateExtension(CreateExtensionStmt *stmt);
+ extern void DropExtension(DropExtensionStmt *stmt);
+ 
+ Oid get_extension_oid(const char *extname, bool missing_ok);
+ char * get_extension_name(Oid ext_oid);
+ char * RemoveExtensionById(Oid extId);
+ 
+ 
+ #endif   /* EXTENSION_H */
*** a/src/include/nodes/nodes.h
--- b/src/include/nodes/nodes.h
***************
*** 348,353 **** typedef enum NodeTag
--- 348,355 ----
  	T_DropUserMappingStmt,
  	T_AlterTableSpaceOptionsStmt,
  	T_SecLabelStmt,
+ 	T_CreateExtensionStmt,
+ 	T_DropExtensionStmt,
  
  	/*
  	 * TAGS FOR PARSE TREE NODES (parsenodes.h)
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
***************
*** 1053,1058 **** typedef enum ObjectType
--- 1053,1059 ----
  	OBJECT_CONVERSION,
  	OBJECT_DATABASE,
  	OBJECT_DOMAIN,
+ 	OBJECT_EXTENSION,
  	OBJECT_FDW,
  	OBJECT_FOREIGN_SERVER,
  	OBJECT_FUNCTION,
***************
*** 1479,1484 **** typedef struct Constraint
--- 1480,1504 ----
  } Constraint;
  
  /* ----------------------
+  *		Create/Drop Extension Statements
+  * ----------------------
+  */
+ 
+ typedef struct CreateExtensionStmt
+ {
+ 	NodeTag		type;
+ 	char	   *extname;
+ } CreateExtensionStmt;
+ 
+ typedef struct DropExtensionStmt
+ {
+ 	NodeTag		 type;
+ 	char	    *extname;
+ 	bool		 missing_ok;	/* skip error if missing? */
+ 	DropBehavior behavior;		/* drop behavior - cascade/restrict */
+ } DropExtensionStmt;
+ 
+ /* ----------------------
   *		Create/Drop Table Space Statements
   * ----------------------
   */
*** a/src/include/parser/kwlist.h
--- b/src/include/parser/kwlist.h
***************
*** 150,155 **** PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD)
--- 150,156 ----
  PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD)
  PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD)
  PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD)
+ PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD)
  PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD)
  PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD)
  PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD)
*** a/src/include/utils/builtins.h
--- b/src/include/utils/builtins.h
***************
*** 442,447 **** extern Datum pg_relation_filepath(PG_FUNCTION_ARGS);
--- 442,448 ----
  extern Datum pg_stat_file(PG_FUNCTION_ARGS);
  extern Datum pg_read_file(PG_FUNCTION_ARGS);
  extern Datum pg_ls_dir(PG_FUNCTION_ARGS);
+ extern Datum pg_execute_from_file(PG_FUNCTION_ARGS);
  
  /* misc.c */
  extern Datum current_database(PG_FUNCTION_ARGS);
*** /dev/null
--- b/src/include/utils/cfparser.h
***************
*** 0 ****
--- 1,18 ----
+ /*-------------------------------------------------------------------------
+  *
+  * cfparser.h
+  *	  Function for parsing RecoveryCommandFile lines
+  *
+  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * src/include/utils/cfparser.h
+  *
+  *-------------------------------------------------------------------------
+  */
+ #ifndef CFPARSER_H
+ #define CFPARSER_H
+ 
+ bool parseRecoveryCommandFileLine(char *cmdline, char **key_p, char **value_p);
+ 
+ #endif   /* CFPARSER_H */
*** a/src/makefiles/pgxs.mk
--- b/src/makefiles/pgxs.mk
***************
*** 93,102 **** include $(top_srcdir)/src/Makefile.shlib
  all: all-lib
  endif # MODULE_big
  
  
! install: all installdirs
! ifneq (,$(DATA)$(DATA_built))
! 	@for file in $(addprefix $(srcdir)/, $(DATA)) $(DATA_built); do \
  	  echo "$(INSTALL_DATA) $$file '$(DESTDIR)$(datadir)/$(datamoduledir)'"; \
  	  $(INSTALL_DATA) $$file '$(DESTDIR)$(datadir)/$(datamoduledir)'; \
  	done
--- 93,116 ----
  all: all-lib
  endif # MODULE_big
  
+ # create extension support
+ ifndef CONTROL
+ ifdef MODULE_big
+ CONTROL = $(MODULE_big).control
+ EXTENSION = $(MODULE_big)
+ else
+ CONTROL = $(MODULES).control
+ EXTENSION = $(MODULES)
+ endif
+ endif
  
! $(CONTROL):
! 	touch .control
! 	test ! -f $@ && echo "name = '$(EXTENSION)' \nversion = '$(MAJORVERSION)'" > $@
! 
! install: all installdirs $(CONTROL)
! ifneq (,$(DATA)$(DATA_built)$(CONTROL))
! 	@for file in $(addprefix $(srcdir)/, $(DATA)) $(DATA_built) $(CONTROL); do \
  	  echo "$(INSTALL_DATA) $$file '$(DESTDIR)$(datadir)/$(datamoduledir)'"; \
  	  $(INSTALL_DATA) $$file '$(DESTDIR)$(datadir)/$(datamoduledir)'; \
  	done
***************
*** 221,226 **** ifeq ($(PORTNAME), win)
--- 235,241 ----
  	rm -f regress.def
  endif
  endif # REGRESS
+ 	if [ -f .control ]; then rm -f .control $(CONTROL); fi
  
  ifdef MODULE_big
  clean: clean-lib
