summaryrefslogtreecommitdiffstats
path: root/src/test/modules/test_extensions
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:17:33 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:17:33 +0000
commit5e45211a64149b3c659b90ff2de6fa982a5a93ed (patch)
tree739caf8c461053357daa9f162bef34516c7bf452 /src/test/modules/test_extensions
parentInitial commit. (diff)
downloadpostgresql-15-5e45211a64149b3c659b90ff2de6fa982a5a93ed.tar.xz
postgresql-15-5e45211a64149b3c659b90ff2de6fa982a5a93ed.zip
Adding upstream version 15.5.upstream/15.5
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/test/modules/test_extensions')
-rw-r--r--src/test/modules/test_extensions/.gitignore4
-rw-r--r--src/test/modules/test_extensions/Makefile34
-rw-r--r--src/test/modules/test_extensions/expected/test_extdepend.out188
-rw-r--r--src/test/modules/test_extensions/expected/test_extensions.out322
-rw-r--r--src/test/modules/test_extensions/sql/test_extdepend.sql90
-rw-r--r--src/test/modules/test_extensions/sql/test_extensions.sql220
-rw-r--r--src/test/modules/test_extensions/test_ext1--1.0.sql3
-rw-r--r--src/test/modules/test_extensions/test_ext1.control5
-rw-r--r--src/test/modules/test_extensions/test_ext2--1.0.sql3
-rw-r--r--src/test/modules/test_extensions/test_ext2.control4
-rw-r--r--src/test/modules/test_extensions/test_ext3--1.0.sql9
-rw-r--r--src/test/modules/test_extensions/test_ext3.control3
-rw-r--r--src/test/modules/test_extensions/test_ext4--1.0.sql3
-rw-r--r--src/test/modules/test_extensions/test_ext4.control4
-rw-r--r--src/test/modules/test_extensions/test_ext5--1.0.sql3
-rw-r--r--src/test/modules/test_extensions/test_ext5.control3
-rw-r--r--src/test/modules/test_extensions/test_ext6--1.0.sql1
-rw-r--r--src/test/modules/test_extensions/test_ext6.control5
-rw-r--r--src/test/modules/test_extensions/test_ext7--1.0--2.0.sql8
-rw-r--r--src/test/modules/test_extensions/test_ext7--1.0.sql13
-rw-r--r--src/test/modules/test_extensions/test_ext7.control4
-rw-r--r--src/test/modules/test_extensions/test_ext8--1.0.sql21
-rw-r--r--src/test/modules/test_extensions/test_ext8.control4
-rw-r--r--src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql26
-rw-r--r--src/test/modules/test_extensions/test_ext_cine--1.0.sql25
-rw-r--r--src/test/modules/test_extensions/test_ext_cine.control3
-rw-r--r--src/test/modules/test_extensions/test_ext_cor--1.0.sql20
-rw-r--r--src/test/modules/test_extensions/test_ext_cor.control3
-rw-r--r--src/test/modules/test_extensions/test_ext_cyclic1--1.0.sql3
-rw-r--r--src/test/modules/test_extensions/test_ext_cyclic1.control4
-rw-r--r--src/test/modules/test_extensions/test_ext_cyclic2--1.0.sql3
-rw-r--r--src/test/modules/test_extensions/test_ext_cyclic2.control4
-rw-r--r--src/test/modules/test_extensions/test_ext_evttrig--1.0--2.0.sql7
-rw-r--r--src/test/modules/test_extensions/test_ext_evttrig--1.0.sql16
-rw-r--r--src/test/modules/test_extensions/test_ext_evttrig.control3
-rw-r--r--src/test/modules/test_extensions/test_ext_extschema--1.0.sql5
-rw-r--r--src/test/modules/test_extensions/test_ext_extschema.control3
37 files changed, 1079 insertions, 0 deletions
diff --git a/src/test/modules/test_extensions/.gitignore b/src/test/modules/test_extensions/.gitignore
new file mode 100644
index 0000000..5dcb3ff
--- /dev/null
+++ b/src/test/modules/test_extensions/.gitignore
@@ -0,0 +1,4 @@
+# Generated subdirectories
+/log/
+/results/
+/tmp_check/
diff --git a/src/test/modules/test_extensions/Makefile b/src/test/modules/test_extensions/Makefile
new file mode 100644
index 0000000..6796c6b
--- /dev/null
+++ b/src/test/modules/test_extensions/Makefile
@@ -0,0 +1,34 @@
+# src/test/modules/test_extensions/Makefile
+
+MODULE = test_extensions
+PGFILEDESC = "test_extensions - regression testing for EXTENSION support"
+
+EXTENSION = test_ext1 test_ext2 test_ext3 test_ext4 test_ext5 test_ext6 \
+ test_ext7 test_ext8 test_ext_cine test_ext_cor \
+ test_ext_cyclic1 test_ext_cyclic2 \
+ test_ext_extschema \
+ test_ext_evttrig
+DATA = test_ext1--1.0.sql test_ext2--1.0.sql test_ext3--1.0.sql \
+ test_ext4--1.0.sql test_ext5--1.0.sql test_ext6--1.0.sql \
+ test_ext7--1.0.sql test_ext7--1.0--2.0.sql test_ext8--1.0.sql \
+ test_ext_cine--1.0.sql test_ext_cine--1.0--1.1.sql \
+ test_ext_cor--1.0.sql \
+ test_ext_cyclic1--1.0.sql test_ext_cyclic2--1.0.sql \
+ test_ext_extschema--1.0.sql \
+ test_ext_evttrig--1.0.sql test_ext_evttrig--1.0--2.0.sql
+
+REGRESS = test_extensions test_extdepend
+
+# force C locale for output stability
+NO_LOCALE = 1
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = src/test/modules/test_extensions
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/src/test/modules/test_extensions/expected/test_extdepend.out b/src/test/modules/test_extensions/expected/test_extdepend.out
new file mode 100644
index 0000000..0b62015
--- /dev/null
+++ b/src/test/modules/test_extensions/expected/test_extdepend.out
@@ -0,0 +1,188 @@
+--
+-- test ALTER THING name DEPENDS ON EXTENSION
+--
+-- Common setup for all tests
+CREATE TABLE test_extdep_commands (command text);
+COPY test_extdep_commands FROM stdin;
+SELECT * FROM test_extdep_commands;
+ command
+-------------------------------------------------------------------------
+ CREATE SCHEMA test_ext
+ CREATE EXTENSION test_ext5 SCHEMA test_ext
+ SET search_path TO test_ext
+ CREATE TABLE a (a1 int)
+
+ CREATE FUNCTION b() RETURNS TRIGGER LANGUAGE plpgsql AS +
+ $$ BEGIN NEW.a1 := NEW.a1 + 42; RETURN NEW; END; $$
+ ALTER FUNCTION b() DEPENDS ON EXTENSION test_ext5
+
+ CREATE TRIGGER c BEFORE INSERT ON a FOR EACH ROW EXECUTE PROCEDURE b()
+ ALTER TRIGGER c ON a DEPENDS ON EXTENSION test_ext5
+
+ CREATE MATERIALIZED VIEW d AS SELECT * FROM a
+ ALTER MATERIALIZED VIEW d DEPENDS ON EXTENSION test_ext5
+
+ CREATE INDEX e ON a (a1)
+ ALTER INDEX e DEPENDS ON EXTENSION test_ext5
+ RESET search_path
+(17 rows)
+
+-- First, test that dependent objects go away when the extension is dropped.
+SELECT * FROM test_extdep_commands \gexec
+ CREATE SCHEMA test_ext
+ CREATE EXTENSION test_ext5 SCHEMA test_ext
+ SET search_path TO test_ext
+ CREATE TABLE a (a1 int)
+
+ CREATE FUNCTION b() RETURNS TRIGGER LANGUAGE plpgsql AS
+ $$ BEGIN NEW.a1 := NEW.a1 + 42; RETURN NEW; END; $$
+ ALTER FUNCTION b() DEPENDS ON EXTENSION test_ext5
+
+ CREATE TRIGGER c BEFORE INSERT ON a FOR EACH ROW EXECUTE PROCEDURE b()
+ ALTER TRIGGER c ON a DEPENDS ON EXTENSION test_ext5
+
+ CREATE MATERIALIZED VIEW d AS SELECT * FROM a
+ ALTER MATERIALIZED VIEW d DEPENDS ON EXTENSION test_ext5
+
+ CREATE INDEX e ON a (a1)
+ ALTER INDEX e DEPENDS ON EXTENSION test_ext5
+ RESET search_path
+-- A dependent object made dependent again has no effect
+ALTER FUNCTION test_ext.b() DEPENDS ON EXTENSION test_ext5;
+-- make sure we have the right dependencies on the extension
+SELECT deptype, p.*
+ FROM pg_depend, pg_identify_object(classid, objid, objsubid) AS p
+ WHERE refclassid = 'pg_extension'::regclass AND
+ refobjid = (SELECT oid FROM pg_extension WHERE extname = 'test_ext5')
+ORDER BY type;
+ deptype | type | schema | name | identity
+---------+-------------------+----------+------+-----------------
+ x | function | test_ext | | test_ext.b()
+ x | index | test_ext | e | test_ext.e
+ x | materialized view | test_ext | d | test_ext.d
+ x | trigger | | | c on test_ext.a
+(4 rows)
+
+DROP EXTENSION test_ext5;
+-- anything still depending on the table?
+SELECT deptype, i.*
+ FROM pg_catalog.pg_depend, pg_identify_object(classid, objid, objsubid) i
+WHERE refclassid='pg_class'::regclass AND
+ refobjid='test_ext.a'::regclass AND NOT deptype IN ('i', 'a');
+ deptype | type | schema | name | identity
+---------+------+--------+------+----------
+(0 rows)
+
+DROP SCHEMA test_ext CASCADE;
+NOTICE: drop cascades to table test_ext.a
+-- Second test: If we drop the table, the objects are dropped too and no
+-- vestige remains in pg_depend.
+SELECT * FROM test_extdep_commands \gexec
+ CREATE SCHEMA test_ext
+ CREATE EXTENSION test_ext5 SCHEMA test_ext
+ SET search_path TO test_ext
+ CREATE TABLE a (a1 int)
+
+ CREATE FUNCTION b() RETURNS TRIGGER LANGUAGE plpgsql AS
+ $$ BEGIN NEW.a1 := NEW.a1 + 42; RETURN NEW; END; $$
+ ALTER FUNCTION b() DEPENDS ON EXTENSION test_ext5
+
+ CREATE TRIGGER c BEFORE INSERT ON a FOR EACH ROW EXECUTE PROCEDURE b()
+ ALTER TRIGGER c ON a DEPENDS ON EXTENSION test_ext5
+
+ CREATE MATERIALIZED VIEW d AS SELECT * FROM a
+ ALTER MATERIALIZED VIEW d DEPENDS ON EXTENSION test_ext5
+
+ CREATE INDEX e ON a (a1)
+ ALTER INDEX e DEPENDS ON EXTENSION test_ext5
+ RESET search_path
+DROP TABLE test_ext.a; -- should fail, require cascade
+ERROR: cannot drop table test_ext.a because other objects depend on it
+DETAIL: materialized view test_ext.d depends on table test_ext.a
+HINT: Use DROP ... CASCADE to drop the dependent objects too.
+DROP TABLE test_ext.a CASCADE;
+NOTICE: drop cascades to materialized view test_ext.d
+-- anything still depending on the extension? Should be only function b()
+SELECT deptype, i.*
+ FROM pg_catalog.pg_depend, pg_identify_object(classid, objid, objsubid) i
+ WHERE refclassid='pg_extension'::regclass AND
+ refobjid=(SELECT oid FROM pg_extension WHERE extname='test_ext5');
+ deptype | type | schema | name | identity
+---------+----------+----------+------+--------------
+ x | function | test_ext | | test_ext.b()
+(1 row)
+
+DROP EXTENSION test_ext5;
+DROP SCHEMA test_ext CASCADE;
+-- Third test: we can drop the objects individually
+SELECT * FROM test_extdep_commands \gexec
+ CREATE SCHEMA test_ext
+ CREATE EXTENSION test_ext5 SCHEMA test_ext
+ SET search_path TO test_ext
+ CREATE TABLE a (a1 int)
+
+ CREATE FUNCTION b() RETURNS TRIGGER LANGUAGE plpgsql AS
+ $$ BEGIN NEW.a1 := NEW.a1 + 42; RETURN NEW; END; $$
+ ALTER FUNCTION b() DEPENDS ON EXTENSION test_ext5
+
+ CREATE TRIGGER c BEFORE INSERT ON a FOR EACH ROW EXECUTE PROCEDURE b()
+ ALTER TRIGGER c ON a DEPENDS ON EXTENSION test_ext5
+
+ CREATE MATERIALIZED VIEW d AS SELECT * FROM a
+ ALTER MATERIALIZED VIEW d DEPENDS ON EXTENSION test_ext5
+
+ CREATE INDEX e ON a (a1)
+ ALTER INDEX e DEPENDS ON EXTENSION test_ext5
+ RESET search_path
+SET search_path TO test_ext;
+DROP TRIGGER c ON a;
+DROP FUNCTION b();
+DROP MATERIALIZED VIEW d;
+DROP INDEX e;
+SELECT deptype, i.*
+ FROM pg_catalog.pg_depend, pg_identify_object(classid, objid, objsubid) i
+ WHERE (refclassid='pg_extension'::regclass AND
+ refobjid=(SELECT oid FROM pg_extension WHERE extname='test_ext5'))
+ OR (refclassid='pg_class'::regclass AND refobjid='test_ext.a'::regclass)
+ AND NOT deptype IN ('i', 'a');
+ deptype | type | schema | name | identity
+---------+------+--------+------+----------
+(0 rows)
+
+DROP TABLE a;
+RESET search_path;
+DROP SCHEMA test_ext CASCADE;
+NOTICE: drop cascades to extension test_ext5
+-- Fourth test: we can mark the objects as dependent, then unmark; then the
+-- drop of the extension does nothing
+SELECT * FROM test_extdep_commands \gexec
+ CREATE SCHEMA test_ext
+ CREATE EXTENSION test_ext5 SCHEMA test_ext
+ SET search_path TO test_ext
+ CREATE TABLE a (a1 int)
+
+ CREATE FUNCTION b() RETURNS TRIGGER LANGUAGE plpgsql AS
+ $$ BEGIN NEW.a1 := NEW.a1 + 42; RETURN NEW; END; $$
+ ALTER FUNCTION b() DEPENDS ON EXTENSION test_ext5
+
+ CREATE TRIGGER c BEFORE INSERT ON a FOR EACH ROW EXECUTE PROCEDURE b()
+ ALTER TRIGGER c ON a DEPENDS ON EXTENSION test_ext5
+
+ CREATE MATERIALIZED VIEW d AS SELECT * FROM a
+ ALTER MATERIALIZED VIEW d DEPENDS ON EXTENSION test_ext5
+
+ CREATE INDEX e ON a (a1)
+ ALTER INDEX e DEPENDS ON EXTENSION test_ext5
+ RESET search_path
+SET search_path TO test_ext;
+ALTER FUNCTION b() NO DEPENDS ON EXTENSION test_ext5;
+ALTER TRIGGER c ON a NO DEPENDS ON EXTENSION test_ext5;
+ALTER MATERIALIZED VIEW d NO DEPENDS ON EXTENSION test_ext5;
+ALTER INDEX e NO DEPENDS ON EXTENSION test_ext5;
+DROP EXTENSION test_ext5;
+DROP TRIGGER c ON a;
+DROP FUNCTION b();
+DROP MATERIALIZED VIEW d;
+DROP INDEX e;
+DROP SCHEMA test_ext CASCADE;
+NOTICE: drop cascades to table a
diff --git a/src/test/modules/test_extensions/expected/test_extensions.out b/src/test/modules/test_extensions/expected/test_extensions.out
new file mode 100644
index 0000000..4ed9eba
--- /dev/null
+++ b/src/test/modules/test_extensions/expected/test_extensions.out
@@ -0,0 +1,322 @@
+CREATE SCHEMA has$dollar;
+-- test some errors
+CREATE EXTENSION test_ext1;
+ERROR: required extension "test_ext2" is not installed
+HINT: Use CREATE EXTENSION ... CASCADE to install required extensions too.
+CREATE EXTENSION test_ext1 SCHEMA test_ext1;
+ERROR: schema "test_ext1" does not exist
+CREATE EXTENSION test_ext1 SCHEMA test_ext;
+ERROR: schema "test_ext" does not exist
+CREATE EXTENSION test_ext1 SCHEMA has$dollar;
+ERROR: extension "test_ext1" must be installed in schema "test_ext1"
+-- finally success
+CREATE EXTENSION test_ext1 SCHEMA has$dollar CASCADE;
+NOTICE: installing required extension "test_ext2"
+NOTICE: installing required extension "test_ext3"
+NOTICE: installing required extension "test_ext5"
+NOTICE: installing required extension "test_ext4"
+SELECT extname, nspname, extversion, extrelocatable FROM pg_extension e, pg_namespace n WHERE extname LIKE 'test_ext%' AND e.extnamespace = n.oid ORDER BY 1;
+ extname | nspname | extversion | extrelocatable
+-----------+------------+------------+----------------
+ test_ext1 | test_ext1 | 1.0 | f
+ test_ext2 | has$dollar | 1.0 | t
+ test_ext3 | has$dollar | 1.0 | t
+ test_ext4 | has$dollar | 1.0 | t
+ test_ext5 | has$dollar | 1.0 | t
+(5 rows)
+
+CREATE EXTENSION test_ext_cyclic1 CASCADE;
+NOTICE: installing required extension "test_ext_cyclic2"
+ERROR: cyclic dependency detected between extensions "test_ext_cyclic1" and "test_ext_cyclic2"
+DROP SCHEMA has$dollar CASCADE;
+NOTICE: drop cascades to 5 other objects
+DETAIL: drop cascades to extension test_ext3
+drop cascades to extension test_ext5
+drop cascades to extension test_ext2
+drop cascades to extension test_ext4
+drop cascades to extension test_ext1
+CREATE SCHEMA has$dollar;
+CREATE EXTENSION test_ext6;
+DROP EXTENSION test_ext6;
+CREATE EXTENSION test_ext6;
+-- test dropping of member tables that own extensions:
+-- this table will be absorbed into test_ext7
+create table old_table1 (col1 serial primary key);
+create extension test_ext7;
+\dx+ test_ext7
+Objects in extension "test_ext7"
+ Object description
+-------------------------------
+ sequence ext7_table1_col1_seq
+ sequence ext7_table2_col2_seq
+ sequence old_table1_col1_seq
+ table ext7_table1
+ table ext7_table2
+ table old_table1
+(6 rows)
+
+alter extension test_ext7 update to '2.0';
+\dx+ test_ext7
+Objects in extension "test_ext7"
+ Object description
+-------------------------------
+ sequence ext7_table2_col2_seq
+ table ext7_table2
+(2 rows)
+
+-- test handling of temp objects created by extensions
+create extension test_ext8;
+-- \dx+ would expose a variable pg_temp_nn schema name, so we can't use it here
+select regexp_replace(pg_describe_object(classid, objid, objsubid),
+ 'pg_temp_\d+', 'pg_temp', 'g') as "Object description"
+from pg_depend
+where refclassid = 'pg_extension'::regclass and deptype = 'e' and
+ refobjid = (select oid from pg_extension where extname = 'test_ext8')
+order by 1;
+ Object description
+-----------------------------------------
+ function ext8_even(posint)
+ function pg_temp.ext8_temp_even(posint)
+ table ext8_table1
+ table ext8_temp_table1
+ type posint
+(5 rows)
+
+-- Should be possible to drop and recreate this extension
+drop extension test_ext8;
+create extension test_ext8;
+select regexp_replace(pg_describe_object(classid, objid, objsubid),
+ 'pg_temp_\d+', 'pg_temp', 'g') as "Object description"
+from pg_depend
+where refclassid = 'pg_extension'::regclass and deptype = 'e' and
+ refobjid = (select oid from pg_extension where extname = 'test_ext8')
+order by 1;
+ Object description
+-----------------------------------------
+ function ext8_even(posint)
+ function pg_temp.ext8_temp_even(posint)
+ table ext8_table1
+ table ext8_temp_table1
+ type posint
+(5 rows)
+
+-- here we want to start a new session and wait till old one is gone
+select pg_backend_pid() as oldpid \gset
+\c -
+do 'declare c int = 0;
+begin
+ while (select count(*) from pg_stat_activity where pid = '
+ :'oldpid'
+ ') > 0 loop c := c + 1; perform pg_stat_clear_snapshot(); end loop;
+ raise log ''test_extensions looped % times'', c;
+end';
+-- extension should now contain no temp objects
+\dx+ test_ext8
+Objects in extension "test_ext8"
+ Object description
+----------------------------
+ function ext8_even(posint)
+ table ext8_table1
+ type posint
+(3 rows)
+
+-- dropping it should still work
+drop extension test_ext8;
+-- Test creation of extension in temporary schema with two-phase commit,
+-- which should not work. This function wrapper is useful for portability.
+-- Avoid noise caused by CONTEXT and NOTICE messages including the temporary
+-- schema name.
+\set SHOW_CONTEXT never
+SET client_min_messages TO 'warning';
+-- First enforce presence of temporary schema.
+CREATE TEMP TABLE test_ext4_tab ();
+CREATE OR REPLACE FUNCTION create_extension_with_temp_schema()
+ RETURNS VOID AS $$
+ DECLARE
+ tmpschema text;
+ query text;
+ BEGIN
+ SELECT INTO tmpschema pg_my_temp_schema()::regnamespace;
+ query := 'CREATE EXTENSION test_ext4 SCHEMA ' || tmpschema || ' CASCADE;';
+ RAISE NOTICE 'query %', query;
+ EXECUTE query;
+ END; $$ LANGUAGE plpgsql;
+BEGIN;
+SELECT create_extension_with_temp_schema();
+ create_extension_with_temp_schema
+-----------------------------------
+
+(1 row)
+
+PREPARE TRANSACTION 'twophase_extension';
+ERROR: cannot PREPARE a transaction that has operated on temporary objects
+-- Clean up
+DROP TABLE test_ext4_tab;
+DROP FUNCTION create_extension_with_temp_schema();
+RESET client_min_messages;
+\unset SHOW_CONTEXT
+-- Test case of an event trigger run in an extension upgrade script.
+-- See: https://postgr.es/m/20200902193715.6e0269d4@firost
+CREATE EXTENSION test_ext_evttrig;
+ALTER EXTENSION test_ext_evttrig UPDATE TO '2.0';
+DROP EXTENSION test_ext_evttrig;
+-- It's generally bad style to use CREATE OR REPLACE unnecessarily.
+-- Test what happens if an extension does it anyway.
+-- Replacing a shell type or operator is sort of like CREATE OR REPLACE;
+-- check that too.
+CREATE FUNCTION ext_cor_func() RETURNS text
+ AS $$ SELECT 'ext_cor_func: original'::text $$ LANGUAGE sql;
+CREATE EXTENSION test_ext_cor; -- fail
+ERROR: function ext_cor_func() is not a member of extension "test_ext_cor"
+DETAIL: An extension is not allowed to replace an object that it does not own.
+SELECT ext_cor_func();
+ ext_cor_func
+------------------------
+ ext_cor_func: original
+(1 row)
+
+DROP FUNCTION ext_cor_func();
+CREATE VIEW ext_cor_view AS
+ SELECT 'ext_cor_view: original'::text AS col;
+CREATE EXTENSION test_ext_cor; -- fail
+ERROR: view ext_cor_view is not a member of extension "test_ext_cor"
+DETAIL: An extension is not allowed to replace an object that it does not own.
+SELECT ext_cor_func();
+ERROR: function ext_cor_func() does not exist
+LINE 1: SELECT ext_cor_func();
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+SELECT * FROM ext_cor_view;
+ col
+------------------------
+ ext_cor_view: original
+(1 row)
+
+DROP VIEW ext_cor_view;
+CREATE TYPE test_ext_type;
+CREATE EXTENSION test_ext_cor; -- fail
+ERROR: type test_ext_type is not a member of extension "test_ext_cor"
+DETAIL: An extension is not allowed to replace an object that it does not own.
+DROP TYPE test_ext_type;
+-- this makes a shell "point <<@@ polygon" operator too
+CREATE OPERATOR @@>> ( PROCEDURE = poly_contain_pt,
+ LEFTARG = polygon, RIGHTARG = point,
+ COMMUTATOR = <<@@ );
+CREATE EXTENSION test_ext_cor; -- fail
+ERROR: operator <<@@(point,polygon) is not a member of extension "test_ext_cor"
+DETAIL: An extension is not allowed to replace an object that it does not own.
+DROP OPERATOR <<@@ (point, polygon);
+CREATE EXTENSION test_ext_cor; -- now it should work
+SELECT ext_cor_func();
+ ext_cor_func
+------------------------------
+ ext_cor_func: from extension
+(1 row)
+
+SELECT * FROM ext_cor_view;
+ col
+------------------------------
+ ext_cor_view: from extension
+(1 row)
+
+SELECT 'x'::test_ext_type;
+ test_ext_type
+---------------
+ x
+(1 row)
+
+SELECT point(0,0) <<@@ polygon(circle(point(0,0),1));
+ ?column?
+----------
+ t
+(1 row)
+
+\dx+ test_ext_cor
+Objects in extension "test_ext_cor"
+ Object description
+------------------------------
+ function ext_cor_func()
+ operator <<@@(point,polygon)
+ type test_ext_type
+ view ext_cor_view
+(4 rows)
+
+--
+-- CREATE IF NOT EXISTS is an entirely unsound thing for an extension
+-- to be doing, but let's at least plug the major security hole in it.
+--
+CREATE COLLATION ext_cine_coll
+ ( LC_COLLATE = "C", LC_CTYPE = "C" );
+CREATE EXTENSION test_ext_cine; -- fail
+ERROR: collation ext_cine_coll is not a member of extension "test_ext_cine"
+DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.
+DROP COLLATION ext_cine_coll;
+CREATE MATERIALIZED VIEW ext_cine_mv AS SELECT 11 AS f1;
+CREATE EXTENSION test_ext_cine; -- fail
+ERROR: materialized view ext_cine_mv is not a member of extension "test_ext_cine"
+DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.
+DROP MATERIALIZED VIEW ext_cine_mv;
+CREATE FOREIGN DATA WRAPPER dummy;
+CREATE SERVER ext_cine_srv FOREIGN DATA WRAPPER dummy;
+CREATE EXTENSION test_ext_cine; -- fail
+ERROR: server ext_cine_srv is not a member of extension "test_ext_cine"
+DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.
+DROP SERVER ext_cine_srv;
+CREATE SCHEMA ext_cine_schema;
+CREATE EXTENSION test_ext_cine; -- fail
+ERROR: schema ext_cine_schema is not a member of extension "test_ext_cine"
+DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.
+DROP SCHEMA ext_cine_schema;
+CREATE SEQUENCE ext_cine_seq;
+CREATE EXTENSION test_ext_cine; -- fail
+ERROR: sequence ext_cine_seq is not a member of extension "test_ext_cine"
+DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.
+DROP SEQUENCE ext_cine_seq;
+CREATE TABLE ext_cine_tab1 (x int);
+CREATE EXTENSION test_ext_cine; -- fail
+ERROR: table ext_cine_tab1 is not a member of extension "test_ext_cine"
+DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.
+DROP TABLE ext_cine_tab1;
+CREATE TABLE ext_cine_tab2 AS SELECT 42 AS y;
+CREATE EXTENSION test_ext_cine; -- fail
+ERROR: table ext_cine_tab2 is not a member of extension "test_ext_cine"
+DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns.
+DROP TABLE ext_cine_tab2;
+CREATE EXTENSION test_ext_cine;
+\dx+ test_ext_cine
+Objects in extension "test_ext_cine"
+ Object description
+-----------------------------------
+ collation ext_cine_coll
+ foreign-data wrapper ext_cine_fdw
+ materialized view ext_cine_mv
+ schema ext_cine_schema
+ sequence ext_cine_seq
+ server ext_cine_srv
+ table ext_cine_tab1
+ table ext_cine_tab2
+(8 rows)
+
+ALTER EXTENSION test_ext_cine UPDATE TO '1.1';
+\dx+ test_ext_cine
+Objects in extension "test_ext_cine"
+ Object description
+-----------------------------------
+ collation ext_cine_coll
+ foreign-data wrapper ext_cine_fdw
+ materialized view ext_cine_mv
+ schema ext_cine_schema
+ sequence ext_cine_seq
+ server ext_cine_srv
+ table ext_cine_tab1
+ table ext_cine_tab2
+ table ext_cine_tab3
+(9 rows)
+
+--
+-- Test @extschema@ syntax.
+--
+CREATE SCHEMA "has space";
+CREATE EXTENSION test_ext_extschema SCHEMA has$dollar;
+ERROR: invalid character in extension "test_ext_extschema" schema: must not contain any of ""$'\"
+CREATE EXTENSION test_ext_extschema SCHEMA "has space";
diff --git a/src/test/modules/test_extensions/sql/test_extdepend.sql b/src/test/modules/test_extensions/sql/test_extdepend.sql
new file mode 100644
index 0000000..63240a1
--- /dev/null
+++ b/src/test/modules/test_extensions/sql/test_extdepend.sql
@@ -0,0 +1,90 @@
+--
+-- test ALTER THING name DEPENDS ON EXTENSION
+--
+
+-- Common setup for all tests
+CREATE TABLE test_extdep_commands (command text);
+COPY test_extdep_commands FROM stdin;
+ CREATE SCHEMA test_ext
+ CREATE EXTENSION test_ext5 SCHEMA test_ext
+ SET search_path TO test_ext
+ CREATE TABLE a (a1 int)
+
+ CREATE FUNCTION b() RETURNS TRIGGER LANGUAGE plpgsql AS\n $$ BEGIN NEW.a1 := NEW.a1 + 42; RETURN NEW; END; $$
+ ALTER FUNCTION b() DEPENDS ON EXTENSION test_ext5
+
+ CREATE TRIGGER c BEFORE INSERT ON a FOR EACH ROW EXECUTE PROCEDURE b()
+ ALTER TRIGGER c ON a DEPENDS ON EXTENSION test_ext5
+
+ CREATE MATERIALIZED VIEW d AS SELECT * FROM a
+ ALTER MATERIALIZED VIEW d DEPENDS ON EXTENSION test_ext5
+
+ CREATE INDEX e ON a (a1)
+ ALTER INDEX e DEPENDS ON EXTENSION test_ext5
+ RESET search_path
+\.
+
+SELECT * FROM test_extdep_commands;
+-- First, test that dependent objects go away when the extension is dropped.
+SELECT * FROM test_extdep_commands \gexec
+-- A dependent object made dependent again has no effect
+ALTER FUNCTION test_ext.b() DEPENDS ON EXTENSION test_ext5;
+-- make sure we have the right dependencies on the extension
+SELECT deptype, p.*
+ FROM pg_depend, pg_identify_object(classid, objid, objsubid) AS p
+ WHERE refclassid = 'pg_extension'::regclass AND
+ refobjid = (SELECT oid FROM pg_extension WHERE extname = 'test_ext5')
+ORDER BY type;
+DROP EXTENSION test_ext5;
+-- anything still depending on the table?
+SELECT deptype, i.*
+ FROM pg_catalog.pg_depend, pg_identify_object(classid, objid, objsubid) i
+WHERE refclassid='pg_class'::regclass AND
+ refobjid='test_ext.a'::regclass AND NOT deptype IN ('i', 'a');
+DROP SCHEMA test_ext CASCADE;
+
+-- Second test: If we drop the table, the objects are dropped too and no
+-- vestige remains in pg_depend.
+SELECT * FROM test_extdep_commands \gexec
+DROP TABLE test_ext.a; -- should fail, require cascade
+DROP TABLE test_ext.a CASCADE;
+-- anything still depending on the extension? Should be only function b()
+SELECT deptype, i.*
+ FROM pg_catalog.pg_depend, pg_identify_object(classid, objid, objsubid) i
+ WHERE refclassid='pg_extension'::regclass AND
+ refobjid=(SELECT oid FROM pg_extension WHERE extname='test_ext5');
+DROP EXTENSION test_ext5;
+DROP SCHEMA test_ext CASCADE;
+
+-- Third test: we can drop the objects individually
+SELECT * FROM test_extdep_commands \gexec
+SET search_path TO test_ext;
+DROP TRIGGER c ON a;
+DROP FUNCTION b();
+DROP MATERIALIZED VIEW d;
+DROP INDEX e;
+
+SELECT deptype, i.*
+ FROM pg_catalog.pg_depend, pg_identify_object(classid, objid, objsubid) i
+ WHERE (refclassid='pg_extension'::regclass AND
+ refobjid=(SELECT oid FROM pg_extension WHERE extname='test_ext5'))
+ OR (refclassid='pg_class'::regclass AND refobjid='test_ext.a'::regclass)
+ AND NOT deptype IN ('i', 'a');
+DROP TABLE a;
+RESET search_path;
+DROP SCHEMA test_ext CASCADE;
+
+-- Fourth test: we can mark the objects as dependent, then unmark; then the
+-- drop of the extension does nothing
+SELECT * FROM test_extdep_commands \gexec
+SET search_path TO test_ext;
+ALTER FUNCTION b() NO DEPENDS ON EXTENSION test_ext5;
+ALTER TRIGGER c ON a NO DEPENDS ON EXTENSION test_ext5;
+ALTER MATERIALIZED VIEW d NO DEPENDS ON EXTENSION test_ext5;
+ALTER INDEX e NO DEPENDS ON EXTENSION test_ext5;
+DROP EXTENSION test_ext5;
+DROP TRIGGER c ON a;
+DROP FUNCTION b();
+DROP MATERIALIZED VIEW d;
+DROP INDEX e;
+DROP SCHEMA test_ext CASCADE;
diff --git a/src/test/modules/test_extensions/sql/test_extensions.sql b/src/test/modules/test_extensions/sql/test_extensions.sql
new file mode 100644
index 0000000..212fd9b
--- /dev/null
+++ b/src/test/modules/test_extensions/sql/test_extensions.sql
@@ -0,0 +1,220 @@
+CREATE SCHEMA has$dollar;
+
+-- test some errors
+CREATE EXTENSION test_ext1;
+CREATE EXTENSION test_ext1 SCHEMA test_ext1;
+CREATE EXTENSION test_ext1 SCHEMA test_ext;
+CREATE EXTENSION test_ext1 SCHEMA has$dollar;
+
+-- finally success
+CREATE EXTENSION test_ext1 SCHEMA has$dollar CASCADE;
+
+SELECT extname, nspname, extversion, extrelocatable FROM pg_extension e, pg_namespace n WHERE extname LIKE 'test_ext%' AND e.extnamespace = n.oid ORDER BY 1;
+
+CREATE EXTENSION test_ext_cyclic1 CASCADE;
+
+DROP SCHEMA has$dollar CASCADE;
+CREATE SCHEMA has$dollar;
+
+CREATE EXTENSION test_ext6;
+DROP EXTENSION test_ext6;
+CREATE EXTENSION test_ext6;
+
+-- test dropping of member tables that own extensions:
+-- this table will be absorbed into test_ext7
+create table old_table1 (col1 serial primary key);
+create extension test_ext7;
+\dx+ test_ext7
+alter extension test_ext7 update to '2.0';
+\dx+ test_ext7
+
+-- test handling of temp objects created by extensions
+create extension test_ext8;
+
+-- \dx+ would expose a variable pg_temp_nn schema name, so we can't use it here
+select regexp_replace(pg_describe_object(classid, objid, objsubid),
+ 'pg_temp_\d+', 'pg_temp', 'g') as "Object description"
+from pg_depend
+where refclassid = 'pg_extension'::regclass and deptype = 'e' and
+ refobjid = (select oid from pg_extension where extname = 'test_ext8')
+order by 1;
+
+-- Should be possible to drop and recreate this extension
+drop extension test_ext8;
+create extension test_ext8;
+
+select regexp_replace(pg_describe_object(classid, objid, objsubid),
+ 'pg_temp_\d+', 'pg_temp', 'g') as "Object description"
+from pg_depend
+where refclassid = 'pg_extension'::regclass and deptype = 'e' and
+ refobjid = (select oid from pg_extension where extname = 'test_ext8')
+order by 1;
+
+-- here we want to start a new session and wait till old one is gone
+select pg_backend_pid() as oldpid \gset
+\c -
+do 'declare c int = 0;
+begin
+ while (select count(*) from pg_stat_activity where pid = '
+ :'oldpid'
+ ') > 0 loop c := c + 1; perform pg_stat_clear_snapshot(); end loop;
+ raise log ''test_extensions looped % times'', c;
+end';
+
+-- extension should now contain no temp objects
+\dx+ test_ext8
+
+-- dropping it should still work
+drop extension test_ext8;
+
+-- Test creation of extension in temporary schema with two-phase commit,
+-- which should not work. This function wrapper is useful for portability.
+
+-- Avoid noise caused by CONTEXT and NOTICE messages including the temporary
+-- schema name.
+\set SHOW_CONTEXT never
+SET client_min_messages TO 'warning';
+-- First enforce presence of temporary schema.
+CREATE TEMP TABLE test_ext4_tab ();
+CREATE OR REPLACE FUNCTION create_extension_with_temp_schema()
+ RETURNS VOID AS $$
+ DECLARE
+ tmpschema text;
+ query text;
+ BEGIN
+ SELECT INTO tmpschema pg_my_temp_schema()::regnamespace;
+ query := 'CREATE EXTENSION test_ext4 SCHEMA ' || tmpschema || ' CASCADE;';
+ RAISE NOTICE 'query %', query;
+ EXECUTE query;
+ END; $$ LANGUAGE plpgsql;
+BEGIN;
+SELECT create_extension_with_temp_schema();
+PREPARE TRANSACTION 'twophase_extension';
+-- Clean up
+DROP TABLE test_ext4_tab;
+DROP FUNCTION create_extension_with_temp_schema();
+RESET client_min_messages;
+\unset SHOW_CONTEXT
+
+-- Test case of an event trigger run in an extension upgrade script.
+-- See: https://postgr.es/m/20200902193715.6e0269d4@firost
+CREATE EXTENSION test_ext_evttrig;
+ALTER EXTENSION test_ext_evttrig UPDATE TO '2.0';
+DROP EXTENSION test_ext_evttrig;
+
+-- It's generally bad style to use CREATE OR REPLACE unnecessarily.
+-- Test what happens if an extension does it anyway.
+-- Replacing a shell type or operator is sort of like CREATE OR REPLACE;
+-- check that too.
+
+CREATE FUNCTION ext_cor_func() RETURNS text
+ AS $$ SELECT 'ext_cor_func: original'::text $$ LANGUAGE sql;
+
+CREATE EXTENSION test_ext_cor; -- fail
+
+SELECT ext_cor_func();
+
+DROP FUNCTION ext_cor_func();
+
+CREATE VIEW ext_cor_view AS
+ SELECT 'ext_cor_view: original'::text AS col;
+
+CREATE EXTENSION test_ext_cor; -- fail
+
+SELECT ext_cor_func();
+
+SELECT * FROM ext_cor_view;
+
+DROP VIEW ext_cor_view;
+
+CREATE TYPE test_ext_type;
+
+CREATE EXTENSION test_ext_cor; -- fail
+
+DROP TYPE test_ext_type;
+
+-- this makes a shell "point <<@@ polygon" operator too
+CREATE OPERATOR @@>> ( PROCEDURE = poly_contain_pt,
+ LEFTARG = polygon, RIGHTARG = point,
+ COMMUTATOR = <<@@ );
+
+CREATE EXTENSION test_ext_cor; -- fail
+
+DROP OPERATOR <<@@ (point, polygon);
+
+CREATE EXTENSION test_ext_cor; -- now it should work
+
+SELECT ext_cor_func();
+
+SELECT * FROM ext_cor_view;
+
+SELECT 'x'::test_ext_type;
+
+SELECT point(0,0) <<@@ polygon(circle(point(0,0),1));
+
+\dx+ test_ext_cor
+
+--
+-- CREATE IF NOT EXISTS is an entirely unsound thing for an extension
+-- to be doing, but let's at least plug the major security hole in it.
+--
+
+CREATE COLLATION ext_cine_coll
+ ( LC_COLLATE = "C", LC_CTYPE = "C" );
+
+CREATE EXTENSION test_ext_cine; -- fail
+
+DROP COLLATION ext_cine_coll;
+
+CREATE MATERIALIZED VIEW ext_cine_mv AS SELECT 11 AS f1;
+
+CREATE EXTENSION test_ext_cine; -- fail
+
+DROP MATERIALIZED VIEW ext_cine_mv;
+
+CREATE FOREIGN DATA WRAPPER dummy;
+
+CREATE SERVER ext_cine_srv FOREIGN DATA WRAPPER dummy;
+
+CREATE EXTENSION test_ext_cine; -- fail
+
+DROP SERVER ext_cine_srv;
+
+CREATE SCHEMA ext_cine_schema;
+
+CREATE EXTENSION test_ext_cine; -- fail
+
+DROP SCHEMA ext_cine_schema;
+
+CREATE SEQUENCE ext_cine_seq;
+
+CREATE EXTENSION test_ext_cine; -- fail
+
+DROP SEQUENCE ext_cine_seq;
+
+CREATE TABLE ext_cine_tab1 (x int);
+
+CREATE EXTENSION test_ext_cine; -- fail
+
+DROP TABLE ext_cine_tab1;
+
+CREATE TABLE ext_cine_tab2 AS SELECT 42 AS y;
+
+CREATE EXTENSION test_ext_cine; -- fail
+
+DROP TABLE ext_cine_tab2;
+
+CREATE EXTENSION test_ext_cine;
+
+\dx+ test_ext_cine
+
+ALTER EXTENSION test_ext_cine UPDATE TO '1.1';
+
+\dx+ test_ext_cine
+
+--
+-- Test @extschema@ syntax.
+--
+CREATE SCHEMA "has space";
+CREATE EXTENSION test_ext_extschema SCHEMA has$dollar;
+CREATE EXTENSION test_ext_extschema SCHEMA "has space";
diff --git a/src/test/modules/test_extensions/test_ext1--1.0.sql b/src/test/modules/test_extensions/test_ext1--1.0.sql
new file mode 100644
index 0000000..9a4bb1b
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext1--1.0.sql
@@ -0,0 +1,3 @@
+/* src/test/modules/test_extensions/test_ext1--1.0.sql */
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_ext1" to load this file. \quit
diff --git a/src/test/modules/test_extensions/test_ext1.control b/src/test/modules/test_extensions/test_ext1.control
new file mode 100644
index 0000000..9c069df
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext1.control
@@ -0,0 +1,5 @@
+comment = 'Test extension 1'
+default_version = '1.0'
+schema = 'test_ext1'
+relocatable = false
+requires = 'test_ext2,test_ext4'
diff --git a/src/test/modules/test_extensions/test_ext2--1.0.sql b/src/test/modules/test_extensions/test_ext2--1.0.sql
new file mode 100644
index 0000000..0f6d4ec
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext2--1.0.sql
@@ -0,0 +1,3 @@
+/* src/test/modules/test_extensions/test_ext2--1.0.sql */
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_ext2" to load this file. \quit
diff --git a/src/test/modules/test_extensions/test_ext2.control b/src/test/modules/test_extensions/test_ext2.control
new file mode 100644
index 0000000..946b7d5
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext2.control
@@ -0,0 +1,4 @@
+comment = 'Test extension 2'
+default_version = '1.0'
+relocatable = true
+requires = 'test_ext3,test_ext5'
diff --git a/src/test/modules/test_extensions/test_ext3--1.0.sql b/src/test/modules/test_extensions/test_ext3--1.0.sql
new file mode 100644
index 0000000..4fcb63d
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext3--1.0.sql
@@ -0,0 +1,9 @@
+/* src/test/modules/test_extensions/test_ext3--1.0.sql */
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_ext3" to load this file. \quit
+
+CREATE TABLE test_ext3_table (col_old INT);
+
+ALTER TABLE test_ext3_table RENAME col_old TO col_new;
+
+UPDATE test_ext3_table SET col_new = 0;
diff --git a/src/test/modules/test_extensions/test_ext3.control b/src/test/modules/test_extensions/test_ext3.control
new file mode 100644
index 0000000..5f1afe7
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext3.control
@@ -0,0 +1,3 @@
+comment = 'Test extension 3'
+default_version = '1.0'
+relocatable = true
diff --git a/src/test/modules/test_extensions/test_ext4--1.0.sql b/src/test/modules/test_extensions/test_ext4--1.0.sql
new file mode 100644
index 0000000..19f051f
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext4--1.0.sql
@@ -0,0 +1,3 @@
+/* src/test/modules/test_extensions/test_ext4--1.0.sql */
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_ext4" to load this file. \quit
diff --git a/src/test/modules/test_extensions/test_ext4.control b/src/test/modules/test_extensions/test_ext4.control
new file mode 100644
index 0000000..fc62591
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext4.control
@@ -0,0 +1,4 @@
+comment = 'Test extension 4'
+default_version = '1.0'
+relocatable = true
+requires = 'test_ext5'
diff --git a/src/test/modules/test_extensions/test_ext5--1.0.sql b/src/test/modules/test_extensions/test_ext5--1.0.sql
new file mode 100644
index 0000000..baf6ef8
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext5--1.0.sql
@@ -0,0 +1,3 @@
+/* src/test/modules/test_extensions/test_ext5--1.0.sql */
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_ext5" to load this file. \quit
diff --git a/src/test/modules/test_extensions/test_ext5.control b/src/test/modules/test_extensions/test_ext5.control
new file mode 100644
index 0000000..51bc57e
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext5.control
@@ -0,0 +1,3 @@
+comment = 'Test extension 5'
+default_version = '1.0'
+relocatable = true
diff --git a/src/test/modules/test_extensions/test_ext6--1.0.sql b/src/test/modules/test_extensions/test_ext6--1.0.sql
new file mode 100644
index 0000000..65a4fc5
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext6--1.0.sql
@@ -0,0 +1 @@
+grant usage on schema @extschema@ to public;
diff --git a/src/test/modules/test_extensions/test_ext6.control b/src/test/modules/test_extensions/test_ext6.control
new file mode 100644
index 0000000..04b2146
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext6.control
@@ -0,0 +1,5 @@
+comment = 'test_ext6'
+default_version = '1.0'
+relocatable = false
+superuser = true
+schema = 'test_ext6'
diff --git a/src/test/modules/test_extensions/test_ext7--1.0--2.0.sql b/src/test/modules/test_extensions/test_ext7--1.0--2.0.sql
new file mode 100644
index 0000000..50e3dca
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext7--1.0--2.0.sql
@@ -0,0 +1,8 @@
+/* src/test/modules/test_extensions/test_ext7--1.0--2.0.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION test_ext7 UPDATE TO '2.0'" to load this file. \quit
+
+-- drop some tables with serial columns
+drop table ext7_table1;
+drop table old_table1;
diff --git a/src/test/modules/test_extensions/test_ext7--1.0.sql b/src/test/modules/test_extensions/test_ext7--1.0.sql
new file mode 100644
index 0000000..0c2d72a
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext7--1.0.sql
@@ -0,0 +1,13 @@
+/* src/test/modules/test_extensions/test_ext7--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_ext7" to load this file. \quit
+
+-- link some existing serial-owning table to the extension
+alter extension test_ext7 add table old_table1;
+alter extension test_ext7 add sequence old_table1_col1_seq;
+
+-- ordinary member tables with serial columns
+create table ext7_table1 (col1 serial primary key);
+
+create table ext7_table2 (col2 serial primary key);
diff --git a/src/test/modules/test_extensions/test_ext7.control b/src/test/modules/test_extensions/test_ext7.control
new file mode 100644
index 0000000..b58df53
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext7.control
@@ -0,0 +1,4 @@
+comment = 'Test extension 7'
+default_version = '1.0'
+schema = 'public'
+relocatable = false
diff --git a/src/test/modules/test_extensions/test_ext8--1.0.sql b/src/test/modules/test_extensions/test_ext8--1.0.sql
new file mode 100644
index 0000000..1561ffe
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext8--1.0.sql
@@ -0,0 +1,21 @@
+/* src/test/modules/test_extensions/test_ext8--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_ext8" to load this file. \quit
+
+-- create some random data type
+create domain posint as int check (value > 0);
+
+-- use it in regular and temporary tables and functions
+
+create table ext8_table1 (f1 posint);
+
+create temp table ext8_temp_table1 (f1 posint);
+
+create function ext8_even (posint) returns bool as
+ 'select ($1 % 2) = 0' language sql;
+
+create function pg_temp.ext8_temp_even (posint) returns bool as
+ 'select ($1 % 2) = 0' language sql;
+
+-- we intentionally don't drop the temp objects before exiting
diff --git a/src/test/modules/test_extensions/test_ext8.control b/src/test/modules/test_extensions/test_ext8.control
new file mode 100644
index 0000000..70f8caa
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext8.control
@@ -0,0 +1,4 @@
+comment = 'Test extension 8'
+default_version = '1.0'
+schema = 'public'
+relocatable = false
diff --git a/src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql b/src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql
new file mode 100644
index 0000000..6dadfd2
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql
@@ -0,0 +1,26 @@
+/* src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql */
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION test_ext_cine UPDATE TO '1.1'" to load this file. \quit
+
+--
+-- These are the same commands as in the 1.0 script; we expect them
+-- to do nothing.
+--
+
+CREATE COLLATION IF NOT EXISTS ext_cine_coll
+ ( LC_COLLATE = "POSIX", LC_CTYPE = "POSIX" );
+
+CREATE MATERIALIZED VIEW IF NOT EXISTS ext_cine_mv AS SELECT 42 AS f1;
+
+CREATE SERVER IF NOT EXISTS ext_cine_srv FOREIGN DATA WRAPPER ext_cine_fdw;
+
+CREATE SCHEMA IF NOT EXISTS ext_cine_schema;
+
+CREATE SEQUENCE IF NOT EXISTS ext_cine_seq;
+
+CREATE TABLE IF NOT EXISTS ext_cine_tab1 (x int);
+
+CREATE TABLE IF NOT EXISTS ext_cine_tab2 AS SELECT 42 AS y;
+
+-- just to verify the script ran
+CREATE TABLE ext_cine_tab3 (z int);
diff --git a/src/test/modules/test_extensions/test_ext_cine--1.0.sql b/src/test/modules/test_extensions/test_ext_cine--1.0.sql
new file mode 100644
index 0000000..01408ff
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext_cine--1.0.sql
@@ -0,0 +1,25 @@
+/* src/test/modules/test_extensions/test_ext_cine--1.0.sql */
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_ext_cine" to load this file. \quit
+
+--
+-- CREATE IF NOT EXISTS is an entirely unsound thing for an extension
+-- to be doing, but let's at least plug the major security hole in it.
+--
+
+CREATE COLLATION IF NOT EXISTS ext_cine_coll
+ ( LC_COLLATE = "POSIX", LC_CTYPE = "POSIX" );
+
+CREATE MATERIALIZED VIEW IF NOT EXISTS ext_cine_mv AS SELECT 42 AS f1;
+
+CREATE FOREIGN DATA WRAPPER ext_cine_fdw;
+
+CREATE SERVER IF NOT EXISTS ext_cine_srv FOREIGN DATA WRAPPER ext_cine_fdw;
+
+CREATE SCHEMA IF NOT EXISTS ext_cine_schema;
+
+CREATE SEQUENCE IF NOT EXISTS ext_cine_seq;
+
+CREATE TABLE IF NOT EXISTS ext_cine_tab1 (x int);
+
+CREATE TABLE IF NOT EXISTS ext_cine_tab2 AS SELECT 42 AS y;
diff --git a/src/test/modules/test_extensions/test_ext_cine.control b/src/test/modules/test_extensions/test_ext_cine.control
new file mode 100644
index 0000000..ced713b
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext_cine.control
@@ -0,0 +1,3 @@
+comment = 'Test extension using CREATE IF NOT EXISTS'
+default_version = '1.0'
+relocatable = true
diff --git a/src/test/modules/test_extensions/test_ext_cor--1.0.sql b/src/test/modules/test_extensions/test_ext_cor--1.0.sql
new file mode 100644
index 0000000..2e8d89c
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext_cor--1.0.sql
@@ -0,0 +1,20 @@
+/* src/test/modules/test_extensions/test_ext_cor--1.0.sql */
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_ext_cor" to load this file. \quit
+
+-- It's generally bad style to use CREATE OR REPLACE unnecessarily.
+-- Test what happens if an extension does it anyway.
+
+CREATE OR REPLACE FUNCTION ext_cor_func() RETURNS text
+ AS $$ SELECT 'ext_cor_func: from extension'::text $$ LANGUAGE sql;
+
+CREATE OR REPLACE VIEW ext_cor_view AS
+ SELECT 'ext_cor_view: from extension'::text AS col;
+
+-- These are for testing replacement of a shell type/operator, which works
+-- enough like an implicit OR REPLACE to be important to check.
+
+CREATE TYPE test_ext_type AS ENUM('x', 'y');
+
+CREATE OPERATOR <<@@ ( PROCEDURE = pt_contained_poly,
+ LEFTARG = point, RIGHTARG = polygon );
diff --git a/src/test/modules/test_extensions/test_ext_cor.control b/src/test/modules/test_extensions/test_ext_cor.control
new file mode 100644
index 0000000..0e972e5
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext_cor.control
@@ -0,0 +1,3 @@
+comment = 'Test extension using CREATE OR REPLACE'
+default_version = '1.0'
+relocatable = true
diff --git a/src/test/modules/test_extensions/test_ext_cyclic1--1.0.sql b/src/test/modules/test_extensions/test_ext_cyclic1--1.0.sql
new file mode 100644
index 0000000..81bdaf4
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext_cyclic1--1.0.sql
@@ -0,0 +1,3 @@
+/* src/test/modules/test_extensions/test_ext_cyclic1--1.0.sql */
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_ext_cyclic1" to load this file. \quit
diff --git a/src/test/modules/test_extensions/test_ext_cyclic1.control b/src/test/modules/test_extensions/test_ext_cyclic1.control
new file mode 100644
index 0000000..aaab403
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext_cyclic1.control
@@ -0,0 +1,4 @@
+comment = 'Test extension cyclic 1'
+default_version = '1.0'
+relocatable = true
+requires = 'test_ext_cyclic2'
diff --git a/src/test/modules/test_extensions/test_ext_cyclic2--1.0.sql b/src/test/modules/test_extensions/test_ext_cyclic2--1.0.sql
new file mode 100644
index 0000000..ae2b3e9
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext_cyclic2--1.0.sql
@@ -0,0 +1,3 @@
+/* src/test/modules/test_extensions/test_ext_cyclic2--1.0.sql */
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_ext_cyclic2" to load this file. \quit
diff --git a/src/test/modules/test_extensions/test_ext_cyclic2.control b/src/test/modules/test_extensions/test_ext_cyclic2.control
new file mode 100644
index 0000000..1e28f96
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext_cyclic2.control
@@ -0,0 +1,4 @@
+comment = 'Test extension cyclic 2'
+default_version = '1.0'
+relocatable = true
+requires = 'test_ext_cyclic1'
diff --git a/src/test/modules/test_extensions/test_ext_evttrig--1.0--2.0.sql b/src/test/modules/test_extensions/test_ext_evttrig--1.0--2.0.sql
new file mode 100644
index 0000000..fdd2f35
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext_evttrig--1.0--2.0.sql
@@ -0,0 +1,7 @@
+/* src/test/modules/test_extensions/test_event_trigger--1.0--2.0.sql */
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION test_event_trigger UPDATE TO '2.0'" to load this file. \quit
+
+-- Test extension upgrade with event trigger.
+ALTER EVENT TRIGGER table_rewrite_trg DISABLE;
+ALTER TABLE t DROP COLUMN id;
diff --git a/src/test/modules/test_extensions/test_ext_evttrig--1.0.sql b/src/test/modules/test_extensions/test_ext_evttrig--1.0.sql
new file mode 100644
index 0000000..0071712
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext_evttrig--1.0.sql
@@ -0,0 +1,16 @@
+/* src/test/modules/test_extensions/test_event_trigger--1.0.sql */
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_event_trigger" to load this file. \quit
+
+-- Base table with event trigger, used in a regression test involving
+-- extension upgrades.
+CREATE TABLE t (id text);
+CREATE OR REPLACE FUNCTION _evt_table_rewrite_fnct()
+RETURNS EVENT_TRIGGER LANGUAGE plpgsql AS
+$$
+ BEGIN
+ END;
+$$;
+CREATE EVENT TRIGGER table_rewrite_trg
+ ON table_rewrite
+ EXECUTE PROCEDURE _evt_table_rewrite_fnct();
diff --git a/src/test/modules/test_extensions/test_ext_evttrig.control b/src/test/modules/test_extensions/test_ext_evttrig.control
new file mode 100644
index 0000000..915fae6
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext_evttrig.control
@@ -0,0 +1,3 @@
+comment = 'Test extension - event trigger'
+default_version = '1.0'
+relocatable = true
diff --git a/src/test/modules/test_extensions/test_ext_extschema--1.0.sql b/src/test/modules/test_extensions/test_ext_extschema--1.0.sql
new file mode 100644
index 0000000..aed5383
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext_extschema--1.0.sql
@@ -0,0 +1,5 @@
+/* src/test/modules/test_extensions/test_ext_extschema--1.0.sql */
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_ext_extschema" to load this file. \quit
+
+SELECT 1 AS @extschema@;
diff --git a/src/test/modules/test_extensions/test_ext_extschema.control b/src/test/modules/test_extensions/test_ext_extschema.control
new file mode 100644
index 0000000..b124d49
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext_extschema.control
@@ -0,0 +1,3 @@
+comment = 'test @extschema@'
+default_version = '1.0'
+relocatable = false