diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 6ff30ddc0ae67c4b4e92214756156b351ac8dea1..b1673e6549a0ac945d9971d357ad07e559323c40 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1188,7 +1188,6 @@ CreateExtension(CreateExtensionStmt *stmt)
 	List	   *requiredExtensions;
 	List	   *requiredSchemas;
 	Oid			extensionOid;
-	AclResult	aclresult;
 	ListCell   *lc;
 
 	/* Check extension name validity before any filesystem access */
@@ -1393,13 +1392,13 @@ CreateExtension(CreateExtensionStmt *stmt)
 	}
 
 	/*
-	 * Check we have creation rights in target namespace.  Although strictly
-	 * speaking the extension itself isn't in the schema, it will almost
-	 * certainly want to create objects therein, so let's just check now.
+	 * We don't check creation rights on the target namespace here.  If the
+	 * extension script actually creates any objects there, it will fail if
+	 * the user doesn't have such permissions.  But there are cases such as
+	 * procedural languages where it's convenient to set schema = pg_catalog
+	 * yet we don't want to restrict the command to users with ACL_CREATE
+	 * for pg_catalog.
 	 */
-	aclresult = pg_namespace_aclcheck(schemaOid, extowner, ACL_CREATE);
-	if (aclresult != ACLCHECK_OK)
-		aclcheck_error(aclresult, ACL_KIND_NAMESPACE, schemaName);
 
 	/*
 	 * Look up the prerequisite extensions, and build lists of their OIDs
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 98915c4b8914b9fd9a0b85ed45f9790a5328e5a2..ce24d6101d13832e876e002b2d775e11fa94b60b 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -1912,7 +1912,7 @@ load_plpgsql(void)
 
 	PG_CMD_OPEN;
 
-	PG_CMD_PUTS("CREATE LANGUAGE plpgsql;\n");
+	PG_CMD_PUTS("CREATE EXTENSION plpgsql;\n");
 
 	PG_CMD_CLOSE;
 
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index ea1818b1d574d107e93015a14e01f86ade46e2f4..dfbdcadd1453f72815f41c5e91a92ee3a2693afc 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1171,6 +1171,24 @@ selectDumpableDefaultACL(DefaultACLInfo *dinfo)
 		dinfo->dobj.dump = include_everything;
 }
 
+/*
+ * selectDumpableExtension: policy-setting subroutine
+ *		Mark an extension as to be dumped or not
+ *
+ * Normally, we just dump all extensions.  However, in binary-upgrade mode
+ * it's necessary to skip built-in extensions, since we assume those will
+ * already be installed in the target database.  We identify such extensions
+ * by their having OIDs in the range reserved for initdb.
+ */
+static void
+selectDumpableExtension(ExtensionInfo *extinfo)
+{
+	if (binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
+		extinfo->dobj.dump = false;
+	else
+		extinfo->dobj.dump = true;
+}
+
 /*
  * selectDumpableObject: policy-setting subroutine
  *		Mark a generic dumpable object as to be dumped or not
@@ -2730,6 +2748,9 @@ getExtensions(int *numExtensions)
 		extinfo[i].extversion = strdup(PQgetvalue(res, i, i_extversion));
 		extinfo[i].extconfig = strdup(PQgetvalue(res, i, i_extconfig));
 		extinfo[i].extcondition = strdup(PQgetvalue(res, i, i_extcondition));
+
+		/* Decide whether we want to dump it */
+		selectDumpableExtension(&(extinfo[i]));
 	}
 
 	PQclear(res);
@@ -7042,19 +7063,6 @@ dumpExtension(Archive *fout, ExtensionInfo *extinfo)
 	if (!extinfo->dobj.dump || dataOnly)
 		return;
 
-	/*
-	 * In a regular dump, we use IF NOT EXISTS so that there isn't a problem
-	 * if the extension already exists in the target database; this is
-	 * essential for installed-by-default extensions such as plpgsql.
-	 *
-	 * In binary-upgrade mode, that doesn't work well, so instead we skip
-	 * extensions with OIDs less than FirstNormalObjectId; those were
-	 * presumably installed by initdb, and we assume they'll exist in the
-	 * target installation too.
-	 */
-	if (binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		return;
-
 	q = createPQExpBuffer();
 	delq = createPQExpBuffer();
 	labelq = createPQExpBuffer();
@@ -7065,6 +7073,16 @@ dumpExtension(Archive *fout, ExtensionInfo *extinfo)
 
 	if (!binary_upgrade)
 	{
+		/*
+		 * In a regular dump, we use IF NOT EXISTS so that there isn't a
+		 * problem if the extension already exists in the target database;
+		 * this is essential for installed-by-default extensions such as
+		 * plpgsql.
+		 *
+		 * In binary-upgrade mode, that doesn't work well, so instead we skip
+		 * built-in extensions based on their OIDs; see
+		 * selectDumpableExtension.
+		 */
 		appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
 						  qextname, fmtId(extinfo->namespace));
 	}
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index fe7ccf4ba0ba1c3ce7114dcb949bdf29ae32f737..56fb4931ba7c56884d31b9457499c6d51555e182 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	201103041
+#define CATALOG_VERSION_NO	201103042
 
 #endif
diff --git a/src/include/catalog/pg_pltemplate.h b/src/include/catalog/pg_pltemplate.h
index c0578f92c098d7115b1926b4d0088a6387b85ad5..fa086525e7ffe4488a7c66af2eb6c62b63d2c99a 100644
--- a/src/include/catalog/pg_pltemplate.h
+++ b/src/include/catalog/pg_pltemplate.h
@@ -71,9 +71,9 @@ DATA(insert ( "plpgsql"		t t "plpgsql_call_handler" "plpgsql_inline_handler" "pl
 DATA(insert ( "pltcl"		t t "pltcl_call_handler" _null_ _null_ "$libdir/pltcl" _null_ ));
 DATA(insert ( "pltclu"		f f "pltclu_call_handler" _null_ _null_ "$libdir/pltcl" _null_ ));
 DATA(insert ( "plperl"		t t "plperl_call_handler" "plperl_inline_handler" "plperl_validator" "$libdir/plperl" _null_ ));
-DATA(insert ( "plperlu"		f f "plperl_call_handler" "plperl_inline_handler" "plperl_validator" "$libdir/plperl" _null_ ));
+DATA(insert ( "plperlu"		f f "plperlu_call_handler" "plperlu_inline_handler" "plperlu_validator" "$libdir/plperl" _null_ ));
 DATA(insert ( "plpythonu"	f f "plpython_call_handler" "plpython_inline_handler" "plpython_validator" "$libdir/plpython" _null_ ));
-DATA(insert ( "plpython2u"	f f "plpython_call_handler" "plpython_inline_handler" "plpython_validator" "$libdir/plpython2" _null_ ));
+DATA(insert ( "plpython2u"	f f "plpython2_call_handler" "plpython2_inline_handler" "plpython2_validator" "$libdir/plpython2" _null_ ));
 DATA(insert ( "plpython3u"	f f "plpython3_call_handler" "plpython3_inline_handler" "plpython3_validator" "$libdir/plpython3" _null_ ));
 
 #endif   /* PG_PLTEMPLATE_H */
diff --git a/src/pl/plperl/GNUmakefile b/src/pl/plperl/GNUmakefile
index e86cb84dba22734686390c2586b2cb7aa2f873c3..71e2cef4c5ecb553aa5b9b91afa962302f6c247a 100644
--- a/src/pl/plperl/GNUmakefile
+++ b/src/pl/plperl/GNUmakefile
@@ -36,11 +36,14 @@ NAME = plperl
 
 OBJS = plperl.o SPI.o Util.o
 
+DATA = plperl.control plperl--1.0.sql plperl--unpackaged--1.0.sql \
+       plperlu.control plperlu--1.0.sql plperlu--unpackaged--1.0.sql
+
 PERLCHUNKS = plc_perlboot.pl plc_trusted.pl
 
 SHLIB_LINK = $(perl_embed_ldflags)
 
-REGRESS_OPTS = --dbname=$(PL_TESTDB) --load-language=plperl  --load-language=plperlu
+REGRESS_OPTS = --dbname=$(PL_TESTDB) --load-extension=plperl  --load-extension=plperlu
 REGRESS = plperl plperl_trigger plperl_shared plperl_elog plperl_util plperl_init plperlu plperl_array
 # if Perl can support two interpreters in one backend,
 # test plperl-and-plperlu cases
@@ -70,11 +73,25 @@ SPI.c: SPI.xs
 Util.c: Util.xs
 	$(PERL) $(perl_privlibexp)/ExtUtils/xsubpp -typemap $(perl_privlibexp)/ExtUtils/typemap $< >$@
 
-install: all installdirs install-lib
+
+install: all installdirs install-lib install-data
 
 installdirs: installdirs-lib
+	$(MKDIR_P) '$(DESTDIR)$(datadir)/extension'
+
+uninstall: uninstall-lib uninstall-data
+
+install-data:
+	@for file in $(addprefix $(srcdir)/, $(DATA)); do \
+	  echo "$(INSTALL_DATA) $$file '$(DESTDIR)$(datadir)/extension'"; \
+	  $(INSTALL_DATA) $$file '$(DESTDIR)$(datadir)/extension'; \
+	done
+
+uninstall-data:
+	rm -f $(addprefix '$(DESTDIR)$(datadir)/extension'/, $(notdir $(DATA)))
+
+.PHONY: install-data uninstall-data
 
-uninstall: uninstall-lib
 
 check: submake
 	$(pg_regress_check) $(REGRESS_OPTS) $(REGRESS)
diff --git a/src/pl/plperl/plperl--1.0.sql b/src/pl/plperl/plperl--1.0.sql
new file mode 100644
index 0000000000000000000000000000000000000000..befd88274550ce4ca8ef0accfb065e4d7971049a
--- /dev/null
+++ b/src/pl/plperl/plperl--1.0.sql
@@ -0,0 +1,9 @@
+/* src/pl/plperl/plperl--1.0.sql */
+
+/*
+ * Currently, all the interesting stuff is done by CREATE LANGUAGE.
+ * Later we will probably "dumb down" that command and put more of the
+ * knowledge into this script.
+ */
+
+CREATE PROCEDURAL LANGUAGE plperl;
diff --git a/src/pl/plperl/plperl--unpackaged--1.0.sql b/src/pl/plperl/plperl--unpackaged--1.0.sql
new file mode 100644
index 0000000000000000000000000000000000000000..b062bd5d9b3d983c948115f38e946035b567d02f
--- /dev/null
+++ b/src/pl/plperl/plperl--unpackaged--1.0.sql
@@ -0,0 +1,7 @@
+/* src/pl/plperl/plperl--unpackaged--1.0.sql */
+
+ALTER EXTENSION plperl ADD PROCEDURAL LANGUAGE plperl;
+-- ALTER ADD LANGUAGE doesn't pick up the support functions, so we have to.
+ALTER EXTENSION plperl ADD FUNCTION plperl_call_handler();
+ALTER EXTENSION plperl ADD FUNCTION plperl_inline_handler(internal);
+ALTER EXTENSION plperl ADD FUNCTION plperl_validator(oid);
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 72e1e5106a679a463db19c61ae96ef321eb309f2..9a94b3f085236d4333eb1a80a8e1d19dcb891681 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -222,6 +222,9 @@ static plperl_call_data *current_call_data = NULL;
 Datum		plperl_call_handler(PG_FUNCTION_ARGS);
 Datum		plperl_inline_handler(PG_FUNCTION_ARGS);
 Datum		plperl_validator(PG_FUNCTION_ARGS);
+Datum		plperlu_call_handler(PG_FUNCTION_ARGS);
+Datum		plperlu_inline_handler(PG_FUNCTION_ARGS);
+Datum		plperlu_validator(PG_FUNCTION_ARGS);
 void		_PG_init(void);
 
 static PerlInterpreter *plperl_init_interp(void);
@@ -1758,6 +1761,39 @@ plperl_validator(PG_FUNCTION_ARGS)
 }
 
 
+/*
+ * plperlu likewise requires three externally visible functions:
+ * plperlu_call_handler, plperlu_inline_handler, and plperlu_validator.
+ * These are currently just aliases that send control to the plperl
+ * handler functions, and we decide whether a particular function is
+ * trusted or not by inspecting the actual pg_language tuple.
+ */
+
+PG_FUNCTION_INFO_V1(plperlu_call_handler);
+
+Datum
+plperlu_call_handler(PG_FUNCTION_ARGS)
+{
+	return plperl_call_handler(fcinfo);
+}
+
+PG_FUNCTION_INFO_V1(plperlu_inline_handler);
+
+Datum
+plperlu_inline_handler(PG_FUNCTION_ARGS)
+{
+	return plperl_inline_handler(fcinfo);
+}
+
+PG_FUNCTION_INFO_V1(plperlu_validator);
+
+Datum
+plperlu_validator(PG_FUNCTION_ARGS)
+{
+	return plperl_validator(fcinfo);
+}
+
+
 /*
  * Uses mksafefunc/mkunsafefunc to create a subroutine whose text is
  * supplied in s, and returns a reference to it
diff --git a/src/pl/plperl/plperl.control b/src/pl/plperl/plperl.control
new file mode 100644
index 0000000000000000000000000000000000000000..6faace12fa5197b0252869702e43f6002266b4e2
--- /dev/null
+++ b/src/pl/plperl/plperl.control
@@ -0,0 +1,7 @@
+# plperl extension
+comment = 'PL/Perl procedural language'
+default_version = '1.0'
+module_pathname = '$libdir/plperl'
+relocatable = false
+schema = pg_catalog
+superuser = false
diff --git a/src/pl/plperl/plperlu--1.0.sql b/src/pl/plperl/plperlu--1.0.sql
new file mode 100644
index 0000000000000000000000000000000000000000..025f7957c4d8f5a86da88d26418754ea5a411a41
--- /dev/null
+++ b/src/pl/plperl/plperlu--1.0.sql
@@ -0,0 +1,9 @@
+/* src/pl/plperl/plperlu--1.0.sql */
+
+/*
+ * Currently, all the interesting stuff is done by CREATE LANGUAGE.
+ * Later we will probably "dumb down" that command and put more of the
+ * knowledge into this script.
+ */
+
+CREATE PROCEDURAL LANGUAGE plperlu;
diff --git a/src/pl/plperl/plperlu--unpackaged--1.0.sql b/src/pl/plperl/plperlu--unpackaged--1.0.sql
new file mode 100644
index 0000000000000000000000000000000000000000..bc62d36a3d864e6195dfca56b9f72af9d199b103
--- /dev/null
+++ b/src/pl/plperl/plperlu--unpackaged--1.0.sql
@@ -0,0 +1,7 @@
+/* src/pl/plperl/plperlu--unpackaged--1.0.sql */
+
+ALTER EXTENSION plperlu ADD PROCEDURAL LANGUAGE plperlu;
+-- ALTER ADD LANGUAGE doesn't pick up the support functions, so we have to.
+ALTER EXTENSION plperlu ADD FUNCTION plperlu_call_handler();
+ALTER EXTENSION plperlu ADD FUNCTION plperlu_inline_handler(internal);
+ALTER EXTENSION plperlu ADD FUNCTION plperlu_validator(oid);
diff --git a/src/pl/plperl/plperlu.control b/src/pl/plperl/plperlu.control
new file mode 100644
index 0000000000000000000000000000000000000000..69473caed47de76d15315dd0d58aa35ad8037061
--- /dev/null
+++ b/src/pl/plperl/plperlu.control
@@ -0,0 +1,7 @@
+# plperlu extension
+comment = 'PL/PerlU untrusted procedural language'
+default_version = '1.0'
+module_pathname = '$libdir/plperl'
+relocatable = false
+schema = pg_catalog
+superuser = true
diff --git a/src/pl/plpgsql/src/Makefile b/src/pl/plpgsql/src/Makefile
index a5f161dc62d76d706fae7bf36f7b5ba11a6e1b93..d748ef682621f3b5fa2410130aa4e030ff1c08fc 100644
--- a/src/pl/plpgsql/src/Makefile
+++ b/src/pl/plpgsql/src/Makefile
@@ -1,6 +1,6 @@
 #-------------------------------------------------------------------------
 #
-# Makefile for the plpgsql shared object
+# Makefile for the pl/pgsql procedural language
 #
 # src/pl/plpgsql/src/Makefile
 #
@@ -19,17 +19,31 @@ rpath =
 
 OBJS = pl_gram.o pl_handler.o pl_comp.o pl_exec.o pl_funcs.o pl_scanner.o
 
+DATA = plpgsql.control plpgsql--1.0.sql plpgsql--unpackaged--1.0.sql
+
 all: all-lib
 
 # Shared library stuff
 include $(top_srcdir)/src/Makefile.shlib
 
 
-install: installdirs all install-lib
+install: all installdirs install-lib install-data
 
 installdirs: installdirs-lib
+	$(MKDIR_P) '$(DESTDIR)$(datadir)/extension'
+
+uninstall: uninstall-lib uninstall-data
+
+install-data:
+	@for file in $(addprefix $(srcdir)/, $(DATA)); do \
+	  echo "$(INSTALL_DATA) $$file '$(DESTDIR)$(datadir)/extension'"; \
+	  $(INSTALL_DATA) $$file '$(DESTDIR)$(datadir)/extension'; \
+	done
+
+uninstall-data:
+	rm -f $(addprefix '$(DESTDIR)$(datadir)/extension'/, $(notdir $(DATA)))
 
-uninstall: uninstall-lib
+.PHONY: install-data uninstall-data
 
 
 # Force these dependencies to be known even without dependency info built:
diff --git a/src/pl/plpgsql/src/plpgsql--1.0.sql b/src/pl/plpgsql/src/plpgsql--1.0.sql
new file mode 100644
index 0000000000000000000000000000000000000000..514562d70fed83509b6498af28d9ec89aa0e9672
--- /dev/null
+++ b/src/pl/plpgsql/src/plpgsql--1.0.sql
@@ -0,0 +1,9 @@
+/* src/pl/plpgsql/src/plpgsql--1.0.sql */
+
+/*
+ * Currently, all the interesting stuff is done by CREATE LANGUAGE.
+ * Later we will probably "dumb down" that command and put more of the
+ * knowledge into this script.
+ */
+
+CREATE PROCEDURAL LANGUAGE plpgsql;
diff --git a/src/pl/plpgsql/src/plpgsql--unpackaged--1.0.sql b/src/pl/plpgsql/src/plpgsql--unpackaged--1.0.sql
new file mode 100644
index 0000000000000000000000000000000000000000..9de7e8392aae2ea37b0aa8491ec13c63b4d7741a
--- /dev/null
+++ b/src/pl/plpgsql/src/plpgsql--unpackaged--1.0.sql
@@ -0,0 +1,7 @@
+/* src/pl/plpgsql/src/plpgsql--unpackaged--1.0.sql */
+
+ALTER EXTENSION plpgsql ADD PROCEDURAL LANGUAGE plpgsql;
+-- ALTER ADD LANGUAGE doesn't pick up the support functions, so we have to.
+ALTER EXTENSION plpgsql ADD FUNCTION plpgsql_call_handler();
+ALTER EXTENSION plpgsql ADD FUNCTION plpgsql_inline_handler(internal);
+ALTER EXTENSION plpgsql ADD FUNCTION plpgsql_validator(oid);
diff --git a/src/pl/plpgsql/src/plpgsql.control b/src/pl/plpgsql/src/plpgsql.control
new file mode 100644
index 0000000000000000000000000000000000000000..b320227b1202e3586b1617f166523626a64d2f74
--- /dev/null
+++ b/src/pl/plpgsql/src/plpgsql.control
@@ -0,0 +1,7 @@
+# plpgsql extension
+comment = 'PL/pgSQL procedural language'
+default_version = '1.0'
+module_pathname = '$libdir/plpgsql'
+relocatable = false
+schema = pg_catalog
+superuser = false
diff --git a/src/pl/plpython/Makefile b/src/pl/plpython/Makefile
index e6b6ed3ca5262dc3dd9e158b8c10694d77d75618..46e0195142424a8ec594c5202ee46aa6c60941ec 100644
--- a/src/pl/plpython/Makefile
+++ b/src/pl/plpython/Makefile
@@ -37,8 +37,13 @@ override CPPFLAGS := -I. -I$(srcdir) $(python_includespec) $(CPPFLAGS)
 rpathdir = $(python_libdir)
 
 NAME = plpython$(python_majorversion)
+
 OBJS = plpython.o
 
+DATA = plpythonu.control plpythonu--1.0.sql plpythonu--unpackaged--1.0.sql \
+       plpython2u.control plpython2u--1.0.sql plpython2u--unpackaged--1.0.sql \
+       plpython3u.control plpython3u--1.0.sql plpython3u--unpackaged--1.0.sql
+
 
 # Python on win32 ships with import libraries only for Microsoft Visual C++,
 # which are not compatible with mingw gcc. Therefore we need to build a
@@ -60,7 +65,7 @@ REGRESS_OPTS = --dbname=$(PL_TESTDB)
 # Only load plpythonu with Python 2.  The test files themselves load
 # the versioned language plpython(2|3)u.
 ifeq ($(python_majorversion),2)
-REGRESS_OPTS += --load-language=plpythonu
+REGRESS_OPTS += --load-extension=plpythonu
 endif
 REGRESS = \
 	plpython_schema \
@@ -98,18 +103,32 @@ all: all-lib
 
 distprep: spiexceptions.h
 
-install: all installdirs install-lib
+
+install: all installdirs install-lib install-data
 ifeq ($(python_majorversion),2)
 	cd '$(DESTDIR)$(pkglibdir)' && rm -f plpython$(DLSUFFIX) && $(LN_S) $(shlib) plpython$(DLSUFFIX)
 endif
 
 installdirs: installdirs-lib
+	$(MKDIR_P) '$(DESTDIR)$(datadir)/extension'
 
-uninstall: uninstall-lib
+uninstall: uninstall-lib uninstall-data
 ifeq ($(python_majorversion),2)
 	rm -f '$(DESTDIR)$(pkglibdir)/plpython$(DLSUFFIX)'
 endif
 
+install-data:
+	@for file in $(addprefix $(srcdir)/, $(DATA)); do \
+	  echo "$(INSTALL_DATA) $$file '$(DESTDIR)$(datadir)/extension'"; \
+	  $(INSTALL_DATA) $$file '$(DESTDIR)$(datadir)/extension'; \
+	done
+
+uninstall-data:
+	rm -f $(addprefix '$(DESTDIR)$(datadir)/extension'/, $(notdir $(DATA)))
+
+.PHONY: install-data uninstall-data
+
+
 ifeq ($(python_majorversion),3)
 # Adjust regression tests for Python 3 compatibility
 prep3:
@@ -124,6 +143,8 @@ prep3:
 	      -e "s/def next/def __next__/g" \
 	      -e "s/LANGUAGE plpythonu/LANGUAGE plpython3u/g" \
 	      -e "s/LANGUAGE plpython2u/LANGUAGE plpython3u/g" \
+	      -e "s/EXTENSION plpythonu/EXTENSION plpython3u/g" \
+	      -e "s/EXTENSION plpython2u/EXTENSION plpython3u/g" \
 	    $$file >`echo $$file | sed 's,$(srcdir),python3,'`; \
 	done
 
diff --git a/src/pl/plpython/expected/plpython_drop.out b/src/pl/plpython/expected/plpython_drop.out
index fef642f7c06f8655875a82efcfe199191843466f..a0e3b5c4ef64bf8cfaf5adb288971eb6202c536e 100644
--- a/src/pl/plpython/expected/plpython_drop.out
+++ b/src/pl/plpython/expected/plpython_drop.out
@@ -2,4 +2,5 @@
 -- For paranoia's sake, don't leave an untrusted language sitting around
 --
 SET client_min_messages = WARNING;
-DROP PROCEDURAL LANGUAGE plpythonu CASCADE;
+DROP EXTENSION plpythonu CASCADE;
+DROP EXTENSION IF EXISTS plpython2u CASCADE;
diff --git a/src/pl/plpython/expected/plpython_test.out b/src/pl/plpython/expected/plpython_test.out
index 7b2e1703f4bc5ed82a0beddf1fd6696778d0896b..c2358b452d9472e571a71d24681c921cbfeff375 100644
--- a/src/pl/plpython/expected/plpython_test.out
+++ b/src/pl/plpython/expected/plpython_test.out
@@ -1,5 +1,5 @@
 -- first some tests of basic functionality
-CREATE LANGUAGE plpython2u;
+CREATE EXTENSION plpython2u;
 -- really stupid function just to get the module loaded
 CREATE FUNCTION stupid() RETURNS text AS 'return "zarkon"' LANGUAGE plpythonu;
 select stupid();
diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c
index 75f7b5cf57fc371ce4a38e6eb8240d9f4d17155b..e415aa36f41c9a6cccc5f2729c5165bd3addb165 100644
--- a/src/pl/plpython/plpython.c
+++ b/src/pl/plpython/plpython.c
@@ -4652,3 +4652,36 @@ PLyUnicode_FromString(const char *s)
 }
 
 #endif   /* PY_MAJOR_VERSION >= 3 */
+
+#if PY_MAJOR_VERSION < 3
+
+/* Define aliases plpython2_call_handler etc */
+Datum		plpython2_call_handler(PG_FUNCTION_ARGS);
+Datum		plpython2_inline_handler(PG_FUNCTION_ARGS);
+Datum		plpython2_validator(PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(plpython2_call_handler);
+
+Datum
+plpython2_call_handler(PG_FUNCTION_ARGS)
+{
+	return plpython_call_handler(fcinfo);
+}
+
+PG_FUNCTION_INFO_V1(plpython2_inline_handler);
+
+Datum
+plpython2_inline_handler(PG_FUNCTION_ARGS)
+{
+	return plpython_inline_handler(fcinfo);
+}
+
+PG_FUNCTION_INFO_V1(plpython2_validator);
+
+Datum
+plpython2_validator(PG_FUNCTION_ARGS)
+{
+	return plpython_validator(fcinfo);
+}
+
+#endif   /* PY_MAJOR_VERSION < 3 */
diff --git a/src/pl/plpython/plpython2u--1.0.sql b/src/pl/plpython/plpython2u--1.0.sql
new file mode 100644
index 0000000000000000000000000000000000000000..0e4787650207ae6047eb3b787f6726a202d2cee4
--- /dev/null
+++ b/src/pl/plpython/plpython2u--1.0.sql
@@ -0,0 +1,9 @@
+/* src/pl/plpython/plpython2u--1.0.sql */
+
+/*
+ * Currently, all the interesting stuff is done by CREATE LANGUAGE.
+ * Later we will probably "dumb down" that command and put more of the
+ * knowledge into this script.
+ */
+
+CREATE PROCEDURAL LANGUAGE plpython2u;
diff --git a/src/pl/plpython/plpython2u--unpackaged--1.0.sql b/src/pl/plpython/plpython2u--unpackaged--1.0.sql
new file mode 100644
index 0000000000000000000000000000000000000000..a89d8b4d09e77ec37d41471687644b4ac3019d32
--- /dev/null
+++ b/src/pl/plpython/plpython2u--unpackaged--1.0.sql
@@ -0,0 +1,7 @@
+/* src/pl/plpython/plpython2u--unpackaged--1.0.sql */
+
+ALTER EXTENSION plpython2u ADD PROCEDURAL LANGUAGE plpython2u;
+-- ALTER ADD LANGUAGE doesn't pick up the support functions, so we have to.
+ALTER EXTENSION plpython2u ADD FUNCTION plpython2_call_handler();
+ALTER EXTENSION plpython2u ADD FUNCTION plpython2_inline_handler(internal);
+ALTER EXTENSION plpython2u ADD FUNCTION plpython2_validator(oid);
diff --git a/src/pl/plpython/plpython2u.control b/src/pl/plpython/plpython2u.control
new file mode 100644
index 0000000000000000000000000000000000000000..39c2b791efe7524be46f66a2fa513bc2af0d139b
--- /dev/null
+++ b/src/pl/plpython/plpython2u.control
@@ -0,0 +1,7 @@
+# plpython2u extension
+comment = 'PL/Python2U untrusted procedural language'
+default_version = '1.0'
+module_pathname = '$libdir/plpython2'
+relocatable = false
+schema = pg_catalog
+superuser = true
diff --git a/src/pl/plpython/plpython3u--1.0.sql b/src/pl/plpython/plpython3u--1.0.sql
new file mode 100644
index 0000000000000000000000000000000000000000..d5c6e5ab96aef7781c0645c75e87e1186c8fdeee
--- /dev/null
+++ b/src/pl/plpython/plpython3u--1.0.sql
@@ -0,0 +1,9 @@
+/* src/pl/plpython/plpython3u--1.0.sql */
+
+/*
+ * Currently, all the interesting stuff is done by CREATE LANGUAGE.
+ * Later we will probably "dumb down" that command and put more of the
+ * knowledge into this script.
+ */
+
+CREATE PROCEDURAL LANGUAGE plpython3u;
diff --git a/src/pl/plpython/plpython3u--unpackaged--1.0.sql b/src/pl/plpython/plpython3u--unpackaged--1.0.sql
new file mode 100644
index 0000000000000000000000000000000000000000..b1c0d03a3043ab7f13a981b60496685996d9ddb5
--- /dev/null
+++ b/src/pl/plpython/plpython3u--unpackaged--1.0.sql
@@ -0,0 +1,7 @@
+/* src/pl/plpython/plpython3u--unpackaged--1.0.sql */
+
+ALTER EXTENSION plpython3u ADD PROCEDURAL LANGUAGE plpython3u;
+-- ALTER ADD LANGUAGE doesn't pick up the support functions, so we have to.
+ALTER EXTENSION plpython3u ADD FUNCTION plpython3_call_handler();
+ALTER EXTENSION plpython3u ADD FUNCTION plpython3_inline_handler(internal);
+ALTER EXTENSION plpython3u ADD FUNCTION plpython3_validator(oid);
diff --git a/src/pl/plpython/plpython3u.control b/src/pl/plpython/plpython3u.control
new file mode 100644
index 0000000000000000000000000000000000000000..01905ef398b0fdee320ce060c7cf2f513889081e
--- /dev/null
+++ b/src/pl/plpython/plpython3u.control
@@ -0,0 +1,7 @@
+# plpython3u extension
+comment = 'PL/Python3U untrusted procedural language'
+default_version = '1.0'
+module_pathname = '$libdir/plpython3'
+relocatable = false
+schema = pg_catalog
+superuser = true
diff --git a/src/pl/plpython/plpythonu--1.0.sql b/src/pl/plpython/plpythonu--1.0.sql
new file mode 100644
index 0000000000000000000000000000000000000000..beb0aa16457774ee747a3265c8b2001de1baf1e9
--- /dev/null
+++ b/src/pl/plpython/plpythonu--1.0.sql
@@ -0,0 +1,9 @@
+/* src/pl/plpython/plpythonu--1.0.sql */
+
+/*
+ * Currently, all the interesting stuff is done by CREATE LANGUAGE.
+ * Later we will probably "dumb down" that command and put more of the
+ * knowledge into this script.
+ */
+
+CREATE PROCEDURAL LANGUAGE plpythonu;
diff --git a/src/pl/plpython/plpythonu--unpackaged--1.0.sql b/src/pl/plpython/plpythonu--unpackaged--1.0.sql
new file mode 100644
index 0000000000000000000000000000000000000000..7926233250830a3f13deeac003c4bff9a8dfcfd0
--- /dev/null
+++ b/src/pl/plpython/plpythonu--unpackaged--1.0.sql
@@ -0,0 +1,7 @@
+/* src/pl/plpython/plpythonu--unpackaged--1.0.sql */
+
+ALTER EXTENSION plpythonu ADD PROCEDURAL LANGUAGE plpythonu;
+-- ALTER ADD LANGUAGE doesn't pick up the support functions, so we have to.
+ALTER EXTENSION plpythonu ADD FUNCTION plpython_call_handler();
+ALTER EXTENSION plpythonu ADD FUNCTION plpython_inline_handler(internal);
+ALTER EXTENSION plpythonu ADD FUNCTION plpython_validator(oid);
diff --git a/src/pl/plpython/plpythonu.control b/src/pl/plpython/plpythonu.control
new file mode 100644
index 0000000000000000000000000000000000000000..ae91b1c255c665329a15507a53755e6491e532e5
--- /dev/null
+++ b/src/pl/plpython/plpythonu.control
@@ -0,0 +1,7 @@
+# plpythonu extension
+comment = 'PL/PythonU untrusted procedural language'
+default_version = '1.0'
+module_pathname = '$libdir/plpython2'
+relocatable = false
+schema = pg_catalog
+superuser = true
diff --git a/src/pl/plpython/sql/plpython_drop.sql b/src/pl/plpython/sql/plpython_drop.sql
index 319d5e0925d1a405a15aefe980909c7ba9f6245c..72d5d657ec3f593f8b92028116dea70e270a548d 100644
--- a/src/pl/plpython/sql/plpython_drop.sql
+++ b/src/pl/plpython/sql/plpython_drop.sql
@@ -3,4 +3,6 @@
 --
 SET client_min_messages = WARNING;
 
-DROP PROCEDURAL LANGUAGE plpythonu CASCADE;
+DROP EXTENSION plpythonu CASCADE;
+
+DROP EXTENSION IF EXISTS plpython2u CASCADE;
diff --git a/src/pl/plpython/sql/plpython_test.sql b/src/pl/plpython/sql/plpython_test.sql
index 915189847a7cf0fd420da6c6c942dec65e60abbf..c8d5ef5f534613320f857863ade9d39cdb7287e1 100644
--- a/src/pl/plpython/sql/plpython_test.sql
+++ b/src/pl/plpython/sql/plpython_test.sql
@@ -1,5 +1,5 @@
 -- first some tests of basic functionality
-CREATE LANGUAGE plpython2u;
+CREATE EXTENSION plpython2u;
 
 -- really stupid function just to get the module loaded
 CREATE FUNCTION stupid() RETURNS text AS 'return "zarkon"' LANGUAGE plpythonu;
diff --git a/src/pl/tcl/Makefile b/src/pl/tcl/Makefile
index b29478dd6fd135d4b1803bffe1da29d3dc546f0d..c7797c61f5eca6e6fe020831c98fa7e88c8834d9 100644
--- a/src/pl/tcl/Makefile
+++ b/src/pl/tcl/Makefile
@@ -1,6 +1,6 @@
 #-------------------------------------------------------------------------
 #
-# Makefile for the pltcl shared object
+# Makefile for the pl/tcl procedural language
 #
 # src/pl/tcl/Makefile
 #
@@ -35,9 +35,13 @@ SHLIB_LINK += $(TCL_LIBS) -lc
 endif
 
 NAME = pltcl
+
 OBJS = pltcl.o
 
-REGRESS_OPTS = --dbname=$(PL_TESTDB) --load-language=pltcl
+DATA = pltcl.control pltcl--1.0.sql pltcl--unpackaged--1.0.sql \
+       pltclu.control pltclu--1.0.sql pltclu--unpackaged--1.0.sql
+
+REGRESS_OPTS = --dbname=$(PL_TESTDB) --load-extension=pltcl
 REGRESS = pltcl_setup pltcl_queries
 # where to find psql for running the tests
 PSQLDIR = $(bindir)
@@ -49,15 +53,29 @@ ifeq ($(TCL_SHARED_BUILD), 1)
 all: all-lib
 	$(MAKE) -C modules $@
 
-install: all installdirs install-lib
+
+install: all installdirs install-lib install-data
 	$(MAKE) -C modules $@
 
 installdirs: installdirs-lib
+	$(MKDIR_P) '$(DESTDIR)$(datadir)/extension'
 	$(MAKE) -C modules $@
 
-uninstall: uninstall-lib
+uninstall: uninstall-lib uninstall-data
 	$(MAKE) -C modules $@
 
+install-data:
+	@for file in $(addprefix $(srcdir)/, $(DATA)); do \
+	  echo "$(INSTALL_DATA) $$file '$(DESTDIR)$(datadir)/extension'"; \
+	  $(INSTALL_DATA) $$file '$(DESTDIR)$(datadir)/extension'; \
+	done
+
+uninstall-data:
+	rm -f $(addprefix '$(DESTDIR)$(datadir)/extension'/, $(notdir $(DATA)))
+
+.PHONY: install-data uninstall-data
+
+
 check: submake
 	$(pg_regress_check) $(REGRESS_OPTS) $(REGRESS)
 
diff --git a/src/pl/tcl/pltcl--1.0.sql b/src/pl/tcl/pltcl--1.0.sql
new file mode 100644
index 0000000000000000000000000000000000000000..897e1a1fe92974b57770996b95517eda5ca1cd30
--- /dev/null
+++ b/src/pl/tcl/pltcl--1.0.sql
@@ -0,0 +1,9 @@
+/* src/pl/tcl/pltcl--1.0.sql */
+
+/*
+ * Currently, all the interesting stuff is done by CREATE LANGUAGE.
+ * Later we will probably "dumb down" that command and put more of the
+ * knowledge into this script.
+ */
+
+CREATE PROCEDURAL LANGUAGE pltcl;
diff --git a/src/pl/tcl/pltcl--unpackaged--1.0.sql b/src/pl/tcl/pltcl--unpackaged--1.0.sql
new file mode 100644
index 0000000000000000000000000000000000000000..dfad66c268ba93923db5f38831fcbee60a860db5
--- /dev/null
+++ b/src/pl/tcl/pltcl--unpackaged--1.0.sql
@@ -0,0 +1,5 @@
+/* src/pl/tcl/pltcl--unpackaged--1.0.sql */
+
+ALTER EXTENSION pltcl ADD PROCEDURAL LANGUAGE pltcl;
+-- ALTER ADD LANGUAGE doesn't pick up the support functions, so we have to.
+ALTER EXTENSION pltcl ADD FUNCTION pltcl_call_handler();
diff --git a/src/pl/tcl/pltcl.control b/src/pl/tcl/pltcl.control
new file mode 100644
index 0000000000000000000000000000000000000000..b9dc1b8a1381ef9ccbcd6c4989d5aeefb4e8a602
--- /dev/null
+++ b/src/pl/tcl/pltcl.control
@@ -0,0 +1,7 @@
+# pltcl extension
+comment = 'PL/Tcl procedural language'
+default_version = '1.0'
+module_pathname = '$libdir/pltcl'
+relocatable = false
+schema = pg_catalog
+superuser = false
diff --git a/src/pl/tcl/pltclu--1.0.sql b/src/pl/tcl/pltclu--1.0.sql
new file mode 100644
index 0000000000000000000000000000000000000000..e53bb04e6d383e82abb6ae438aac1c16947d1e88
--- /dev/null
+++ b/src/pl/tcl/pltclu--1.0.sql
@@ -0,0 +1,9 @@
+/* src/pl/tcl/pltclu--1.0.sql */
+
+/*
+ * Currently, all the interesting stuff is done by CREATE LANGUAGE.
+ * Later we will probably "dumb down" that command and put more of the
+ * knowledge into this script.
+ */
+
+CREATE PROCEDURAL LANGUAGE pltclu;
diff --git a/src/pl/tcl/pltclu--unpackaged--1.0.sql b/src/pl/tcl/pltclu--unpackaged--1.0.sql
new file mode 100644
index 0000000000000000000000000000000000000000..a5d359fc047327ae800dff0d793fa485bc4d2442
--- /dev/null
+++ b/src/pl/tcl/pltclu--unpackaged--1.0.sql
@@ -0,0 +1,5 @@
+/* src/pl/tcl/pltclu--unpackaged--1.0.sql */
+
+ALTER EXTENSION pltclu ADD PROCEDURAL LANGUAGE pltclu;
+-- ALTER ADD LANGUAGE doesn't pick up the support functions, so we have to.
+ALTER EXTENSION pltclu ADD FUNCTION pltclu_call_handler();
diff --git a/src/pl/tcl/pltclu.control b/src/pl/tcl/pltclu.control
new file mode 100644
index 0000000000000000000000000000000000000000..1418dc5a9ef1c32270024e8f28c3ca1e897a70b7
--- /dev/null
+++ b/src/pl/tcl/pltclu.control
@@ -0,0 +1,7 @@
+# pltclu extension
+comment = 'PL/TclU untrusted procedural language'
+default_version = '1.0'
+module_pathname = '$libdir/pltcl'
+relocatable = false
+schema = pg_catalog
+superuser = true
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index a6160298efb4590708085c8c7347b3033fcb08d0..6ecf78488e01943b912f4d4838f28dac11e2a776 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -86,6 +86,7 @@ char	   *outputdir = ".";
 char	   *psqldir = PGBINDIR;
 char	   *launcher = NULL;
 static _stringlist *loadlanguage = NULL;
+static _stringlist *loadextension = NULL;
 static int	max_connections = 0;
 static char *encoding = NULL;
 static _stringlist *schedulelist = NULL;
@@ -1800,6 +1801,16 @@ create_database(const char *dbname)
 		header(_("installing %s"), sl->str);
 		psql_command(dbname, "CREATE OR REPLACE LANGUAGE \"%s\"", sl->str);
 	}
+
+	/*
+	 * Install any requested extensions.  We use CREATE IF NOT EXISTS
+	 * so that this will work whether or not the extension is preinstalled.
+	 */
+	for (sl = loadextension; sl != NULL; sl = sl->next)
+	{
+		header(_("installing %s"), sl->str);
+		psql_command(dbname, "CREATE EXTENSION IF NOT EXISTS \"%s\"", sl->str);
+	}
 }
 
 static void
@@ -1862,6 +1873,8 @@ help(void)
 	printf(_("  --inputdir=DIR            take input files from DIR (default \".\")\n"));
 	printf(_("  --load-language=lang      load the named language before running the\n"));
 	printf(_("                            tests; can appear multiple times\n"));
+	printf(_("  --load-extension=ext      load the named extension before running the\n"));
+	printf(_("                            tests; can appear multiple times\n"));
 	printf(_("  --create-role=ROLE        create the specified role before testing\n"));
 	printf(_("  --max-connections=N       maximum number of concurrent connections\n"));
 	printf(_("                            (default is 0 meaning unlimited)\n"));
@@ -1925,6 +1938,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 		{"temp-config", required_argument, NULL, 19},
 		{"use-existing", no_argument, NULL, 20},
 		{"launcher", required_argument, NULL, 21},
+		{"load-extension", required_argument, NULL, 22},
 		{NULL, 0, NULL, 0}
 	};
 
@@ -2021,6 +2035,9 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 			case 21:
 				launcher = strdup(optarg);
 				break;
+			case 22:
+				add_stringlist_item(&loadextension, optarg);
+				break;
 			default:
 				/* getopt_long already emitted a complaint */
 				fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
diff --git a/src/tools/msvc/vcregress.pl b/src/tools/msvc/vcregress.pl
index f3024f26ca67ce5597f94bd0dfc6c62ded8c87f6..2fe6b8a05bec82a2464ba3e83ce263170a40f17e 100644
--- a/src/tools/msvc/vcregress.pl
+++ b/src/tools/msvc/vcregress.pl
@@ -146,14 +146,14 @@ sub plcheck
         my $lang = $pl eq 'tcl' ? 'pltcl' : $pl;
         next unless -d "../../$Config/$lang";
         $lang = 'plpythonu' if $lang eq 'plpython';
-        my @lang_args = ("--load-language=$lang");
+        my @lang_args = ("--load-extension=$lang");
         chdir $pl;
         my @tests = fetchTests();
         if ($lang eq 'plperl')
         {
 
             # run both trusted and untrusted perl tests
-            push(@lang_args, "--load-language=plperlu");
+            push(@lang_args, "--load-extension=plperlu");
 
             # assume we're using this perl to built postgres
             # test if we can run two interpreters in one backend, and if so