diff --git a/contrib/hstore_plperl/expected/hstore_plperl.out b/contrib/hstore_plperl/expected/hstore_plperl.out index cf384eba64..25fc506c23 100644 --- a/contrib/hstore_plperl/expected/hstore_plperl.out +++ b/contrib/hstore_plperl/expected/hstore_plperl.out @@ -1,6 +1,6 @@ -CREATE EXTENSION hstore; -CREATE EXTENSION plperl; -CREATE EXTENSION hstore_plperl; +CREATE EXTENSION hstore_plperl CASCADE; +NOTICE: installing required extension "hstore" +NOTICE: installing required extension "plperl" SELECT transforms.udt_schema, transforms.udt_name, routine_schema, routine_name, group_name, transform_type diff --git a/contrib/hstore_plperl/expected/hstore_plperlu.out b/contrib/hstore_plperl/expected/hstore_plperlu.out index c97fd3fae2..b09fb78af9 100644 --- a/contrib/hstore_plperl/expected/hstore_plperlu.out +++ b/contrib/hstore_plperl/expected/hstore_plperlu.out @@ -1,6 +1,6 @@ -CREATE EXTENSION hstore; -CREATE EXTENSION plperlu; -CREATE EXTENSION hstore_plperlu; +CREATE EXTENSION hstore_plperlu CASCADE; +NOTICE: installing required extension "hstore" +NOTICE: installing required extension "plperlu" SELECT transforms.udt_schema, transforms.udt_name, routine_schema, routine_name, group_name, transform_type diff --git a/contrib/hstore_plperl/sql/hstore_plperl.sql b/contrib/hstore_plperl/sql/hstore_plperl.sql index 0f70f149f5..9398aedfbb 100644 --- a/contrib/hstore_plperl/sql/hstore_plperl.sql +++ b/contrib/hstore_plperl/sql/hstore_plperl.sql @@ -1,6 +1,4 @@ -CREATE EXTENSION hstore; -CREATE EXTENSION plperl; -CREATE EXTENSION hstore_plperl; +CREATE EXTENSION hstore_plperl CASCADE; SELECT transforms.udt_schema, transforms.udt_name, routine_schema, routine_name, diff --git a/contrib/hstore_plperl/sql/hstore_plperlu.sql b/contrib/hstore_plperl/sql/hstore_plperlu.sql index 3cfb2fdd77..8d8508cf29 100644 --- a/contrib/hstore_plperl/sql/hstore_plperlu.sql +++ b/contrib/hstore_plperl/sql/hstore_plperlu.sql @@ -1,6 +1,4 @@ -CREATE EXTENSION hstore; -CREATE EXTENSION plperlu; -CREATE EXTENSION hstore_plperlu; +CREATE EXTENSION hstore_plperlu CASCADE; SELECT transforms.udt_schema, transforms.udt_name, routine_schema, routine_name, diff --git a/contrib/hstore_plpython/expected/hstore_plpython.out b/contrib/hstore_plpython/expected/hstore_plpython.out index 23091d3729..b0025c04a8 100644 --- a/contrib/hstore_plpython/expected/hstore_plpython.out +++ b/contrib/hstore_plpython/expected/hstore_plpython.out @@ -1,5 +1,5 @@ -CREATE EXTENSION plpython2u; -CREATE EXTENSION hstore_plpython2u; +CREATE EXTENSION hstore_plpython2u CASCADE; +NOTICE: installing required extension "plpython2u" -- test hstore -> python CREATE FUNCTION test1(val hstore) RETURNS int LANGUAGE plpythonu diff --git a/contrib/hstore_plpython/sql/hstore_plpython.sql b/contrib/hstore_plpython/sql/hstore_plpython.sql index 9ff2ebcd83..d55bedaf50 100644 --- a/contrib/hstore_plpython/sql/hstore_plpython.sql +++ b/contrib/hstore_plpython/sql/hstore_plpython.sql @@ -1,5 +1,4 @@ -CREATE EXTENSION plpython2u; -CREATE EXTENSION hstore_plpython2u; +CREATE EXTENSION hstore_plpython2u CASCADE; -- test hstore -> python diff --git a/contrib/ltree_plpython/expected/ltree_plpython.out b/contrib/ltree_plpython/expected/ltree_plpython.out index c6e8a7c087..4779755fc8 100644 --- a/contrib/ltree_plpython/expected/ltree_plpython.out +++ b/contrib/ltree_plpython/expected/ltree_plpython.out @@ -1,5 +1,5 @@ -CREATE EXTENSION plpython2u; -CREATE EXTENSION ltree_plpython2u; +CREATE EXTENSION ltree_plpython2u CASCADE; +NOTICE: installing required extension "plpython2u" CREATE FUNCTION test1(val ltree) RETURNS int LANGUAGE plpythonu TRANSFORM FOR TYPE ltree diff --git a/contrib/ltree_plpython/sql/ltree_plpython.sql b/contrib/ltree_plpython/sql/ltree_plpython.sql index f08ff6a3f0..210f5428a5 100644 --- a/contrib/ltree_plpython/sql/ltree_plpython.sql +++ b/contrib/ltree_plpython/sql/ltree_plpython.sql @@ -1,5 +1,4 @@ -CREATE EXTENSION plpython2u; -CREATE EXTENSION ltree_plpython2u; +CREATE EXTENSION ltree_plpython2u CASCADE; CREATE FUNCTION test1(val ltree) RETURNS int diff --git a/doc/src/sgml/ref/create_extension.sgml b/doc/src/sgml/ref/create_extension.sgml index a1e7e4f812..d4cc310918 100644 --- a/doc/src/sgml/ref/create_extension.sgml +++ b/doc/src/sgml/ref/create_extension.sgml @@ -25,6 +25,7 @@ CREATE EXTENSION [ IF NOT EXISTS ] extension_name [ WITH ] [ SCHEMA schema_name ] [ VERSION version ] [ FROM old_version ] + [ CASCADE ] @@ -94,6 +95,35 @@ CREATE EXTENSION [ IF NOT EXISTS ] extension_name If not specified, and the extension's control file does not specify a schema either, the current default object creation schema is used. + + If the extension specifies schema in its control file, + the schema cannot be overriden with SCHEMA clause. + The SCHEMA clause in this case works as follows: + + + + If schema_name matches + the schema in control file, it will be used normally as there is no + conflict. + + + + + If the CASCADE clause is given, the + schema_name will only + be used for the missing required extensions which do not specify + schema in their control files. + + + + + If schema_name is not + the same as the one in extension's control file and the + CASCADE clause is not given, error will be thrown. + + + + Remember that the extension itself is not considered to be within any schema: extensions have unqualified names that must be unique @@ -139,6 +169,18 @@ CREATE EXTENSION [ IF NOT EXISTS ] extension_name + + + CASCADE + + + Try to install extension including the required dependencies + recursively. The SCHEMA option will be propagated + to the required extensions. Other options are not recursively + applied when using this clause. + + + diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index 6b92bdc5e0..67b16a7a68 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -43,11 +43,13 @@ #include "catalog/pg_type.h" #include "commands/alter.h" #include "commands/comment.h" +#include "commands/defrem.h" #include "commands/extension.h" #include "commands/schemacmds.h" #include "funcapi.h" #include "mb/pg_wchar.h" #include "miscadmin.h" +#include "nodes/makefuncs.h" #include "storage/fd.h" #include "tcop/utility.h" #include "utils/builtins.h" @@ -1165,18 +1167,25 @@ find_update_path(List *evi_list, } /* - * CREATE EXTENSION + * CREATE EXTENSION worker + * + * When CASCADE is specified CreateExtensionInternal() recurses if required + * extensions need to be installed. To sanely handle cyclic dependencies + * cascade_parent contains the dependency chain leading to the current + * invocation; thus allowing to error out if there's a cyclic dependency. */ -ObjectAddress -CreateExtension(CreateExtensionStmt *stmt) +static ObjectAddress +CreateExtensionInternal(CreateExtensionStmt *stmt, List *parents) { DefElem *d_schema = NULL; DefElem *d_new_version = NULL; DefElem *d_old_version = NULL; - char *schemaName; - Oid schemaOid; + DefElem *d_cascade = NULL; + char *schemaName = NULL; + Oid schemaOid = InvalidOid; char *versionName; char *oldVersionName; + bool cascade = false; Oid extowner = GetUserId(); ExtensionControlFile *pcontrol; ExtensionControlFile *control; @@ -1187,41 +1196,6 @@ CreateExtension(CreateExtensionStmt *stmt) ListCell *lc; ObjectAddress address; - /* Check extension name validity before any filesystem access */ - check_valid_extension_name(stmt->extname); - - /* - * Check for duplicate extension name. The unique index on - * pg_extension.extname would catch this anyway, and serves as a backstop - * in case of race conditions; but this is a friendlier error message, and - * besides we need a check to support IF NOT EXISTS. - */ - if (get_extension_oid(stmt->extname, true) != InvalidOid) - { - if (stmt->if_not_exists) - { - ereport(NOTICE, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("extension \"%s\" already exists, skipping", - stmt->extname))); - return InvalidObjectAddress; - } - else - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("extension \"%s\" already exists", - stmt->extname))); - } - - /* - * We use global variables to track the extension being created, so we can - * create only one extension at the same time. - */ - if (creating_extension) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("nested CREATE EXTENSION is not supported"))); - /* * Read the primary control file. Note we assume that it does not contain * any non-ASCII data, so there is no need to worry about encoding at this @@ -1260,6 +1234,15 @@ CreateExtension(CreateExtensionStmt *stmt) errmsg("conflicting or redundant options"))); d_old_version = defel; } + else if (strcmp(defel->defname, "cascade") == 0) + { + if (d_cascade) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + d_cascade = defel; + cascade = defGetBoolean(d_cascade); + } else elog(ERROR, "unrecognized option: %s", defel->defname); } @@ -1337,33 +1320,37 @@ CreateExtension(CreateExtensionStmt *stmt) { /* * User given schema, CREATE EXTENSION ... WITH SCHEMA ... - * - * It's an error to give a schema different from control->schema if - * control->schema is specified. */ schemaName = strVal(d_schema->arg); - if (control->schema != NULL && - strcmp(control->schema, schemaName) != 0) + /* If the user is giving us the schema name, it must exist already. */ + schemaOid = get_namespace_oid(schemaName, false); + } + + if (control->schema != NULL) + { + /* + * The extension is not relocatable and the author gave us a schema + * for it. + * + * Unless CASCADE parameter was given, it's an error to give a schema + * different from control->schema if control->schema is specified. + */ + if (schemaName && strcmp(control->schema, schemaName) != 0 && + !cascade) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("extension \"%s\" must be installed in schema \"%s\"", control->name, control->schema))); - /* If the user is giving us the schema name, it must exist already */ - schemaOid = get_namespace_oid(schemaName, false); - } - else if (control->schema != NULL) - { - /* - * The extension is not relocatable and the author gave us a schema - * for it. We create the schema here if it does not already exist. - */ + /* Always use the schema from control file for current extension. */ schemaName = control->schema; + + /* Find or create the schema in case it does not exist. */ schemaOid = get_namespace_oid(schemaName, true); - if (schemaOid == InvalidOid) + if (!OidIsValid(schemaOid)) { CreateSchemaStmt *csstmt = makeNode(CreateSchemaStmt); @@ -1375,16 +1362,17 @@ CreateExtension(CreateExtensionStmt *stmt) /* * CreateSchemaCommand includes CommandCounterIncrement, so new - * schema is now visible + * schema is now visible. */ schemaOid = get_namespace_oid(schemaName, false); } } - else + else if (!OidIsValid(schemaOid)) { /* - * Else, use the current default creation namespace, which is the - * first explicit entry in the search_path. + * Neither user nor author of the extension specified schema, use the + * current default creation namespace, which is the first explicit + * entry in the search_path. */ List *search_path = fetch_search_path(false); @@ -1423,16 +1411,65 @@ CreateExtension(CreateExtensionStmt *stmt) Oid reqext; Oid reqschema; - /* - * We intentionally don't use get_extension_oid's default error - * message here, because it would be confusing in this context. - */ reqext = get_extension_oid(curreq, true); if (!OidIsValid(reqext)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("required extension \"%s\" is not installed", - curreq))); + { + if (cascade) + { + CreateExtensionStmt *ces; + ListCell *lc; + ObjectAddress addr; + List *cascade_parents; + + /* Check extension name validity before trying to cascade */ + check_valid_extension_name(curreq); + + /* Check for cyclic dependency between extensions. */ + foreach(lc, parents) + { + char *pname = (char *) lfirst(lc); + + if (strcmp(pname, curreq) == 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_RECURSION), + errmsg("cyclic dependency detected between extensions \"%s\" and \"%s\"", + curreq, stmt->extname))); + } + + ereport(NOTICE, + (errmsg("installing required extension \"%s\"", + curreq))); + + /* Create and execute new CREATE EXTENSION statement. */ + ces = makeNode(CreateExtensionStmt); + ces->extname = curreq; + + /* Propagate the CASCADE option */ + ces->options = list_make1(d_cascade); + + /* Propagate the SCHEMA option if given. */ + if (d_schema && d_schema->arg) + ces->options = lappend(ces->options, d_schema); + + /* + * Pass the current list of parents + the current extension to + * the "child" CreateExtensionInternal(). + */ + cascade_parents = + lappend(list_copy(parents), stmt->extname); + + /* Create the required extension. */ + addr = CreateExtensionInternal(ces, cascade_parents); + reqext = addr.objectId; + } + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("required extension \"%s\" is not installed", + curreq), + errhint("Use CREATE EXTENSION CASCADE to install required extensions too."))); + } + reqschema = get_extension_schema(reqext); requiredExtensions = lappend_oid(requiredExtensions, reqext); requiredSchemas = lappend_oid(requiredSchemas, reqschema); @@ -1473,6 +1510,52 @@ CreateExtension(CreateExtensionStmt *stmt) return address; } +/* + * CREATE EXTENSION + */ +ObjectAddress +CreateExtension(CreateExtensionStmt *stmt) +{ + /* Check extension name validity before any filesystem access */ + check_valid_extension_name(stmt->extname); + + /* + * Check for duplicate extension name. The unique index on + * pg_extension.extname would catch this anyway, and serves as a backstop + * in case of race conditions; but this is a friendlier error message, and + * besides we need a check to support IF NOT EXISTS. + */ + if (get_extension_oid(stmt->extname, true) != InvalidOid) + { + if (stmt->if_not_exists) + { + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("extension \"%s\" already exists, skipping", + stmt->extname))); + return InvalidObjectAddress; + } + else + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("extension \"%s\" already exists", + stmt->extname))); + } + + /* + * We use global variables to track the extension being created, so we can + * create only one extension at the same time. + */ + if (creating_extension) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("nested CREATE EXTENSION is not supported"))); + + + /* Finally create the extension. */ + return CreateExtensionInternal(stmt, NIL); +} + /* * InsertExtensionTuple * diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index fb84937b62..417fb55bc4 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -3876,6 +3876,10 @@ create_extension_opt_item: { $$ = makeDefElem("old_version", (Node *)makeString($2)); } + | CASCADE + { + $$ = makeDefElem("cascade", (Node *)makeInteger(TRUE)); + } ; /***************************************************************************** diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 4294ffd052..1619de52ae 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -2264,7 +2264,12 @@ psql_completion(const char *text, int start, int end) /* CREATE EXTENSION */ else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 && pg_strcasecmp(prev2_wd, "EXTENSION") == 0) - COMPLETE_WITH_CONST("WITH SCHEMA"); + { + static const char *const list_CREATE_EXTENSION[] = + {"WITH SCHEMA", "CASCADE", NULL}; + + COMPLETE_WITH_LIST(list_CREATE_EXTENSION); + } /* CREATE FOREIGN */ else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 && diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile index 9b96654279..6167ec1344 100644 --- a/src/test/modules/Makefile +++ b/src/test/modules/Makefile @@ -9,6 +9,7 @@ SUBDIRS = \ commit_ts \ dummy_seclabel \ test_ddl_deparse \ + test_extensions \ test_parser \ test_rls_hooks \ test_shm_mq \ diff --git a/src/test/modules/test_extensions/.gitignore b/src/test/modules/test_extensions/.gitignore new file mode 100644 index 0000000000..5dcb3ff972 --- /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 0000000000..5691357c07 --- /dev/null +++ b/src/test/modules/test_extensions/Makefile @@ -0,0 +1,23 @@ +# 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_ext_cyclic1 test_ext_cyclic2 +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_ext_cyclic1--1.0.sql \ + test_ext_cyclic2--1.0.sql + +REGRESS = test_extensions + +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_extensions.out b/src/test/modules/test_extensions/expected/test_extensions.out new file mode 100644 index 0000000000..a57bb4b7ff --- /dev/null +++ b/src/test/modules/test_extensions/expected/test_extensions.out @@ -0,0 +1,37 @@ +-- 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 SCHEMA test_ext; +CREATE EXTENSION test_ext1 SCHEMA test_ext; +ERROR: extension "test_ext1" must be installed in schema "test_ext1" +-- finally success +CREATE EXTENSION test_ext1 SCHEMA test_ext 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 | test_ext | 1.0 | t + test_ext3 | test_ext | 1.0 | t + test_ext4 | test_ext | 1.0 | t + test_ext5 | test_ext | 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 test_ext 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 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 0000000000..9076c02807 --- /dev/null +++ b/src/test/modules/test_extensions/sql/test_extensions.sql @@ -0,0 +1,15 @@ +-- test some errors +CREATE EXTENSION test_ext1; +CREATE EXTENSION test_ext1 SCHEMA test_ext1; +CREATE EXTENSION test_ext1 SCHEMA test_ext; +CREATE SCHEMA test_ext; +CREATE EXTENSION test_ext1 SCHEMA test_ext; + +-- finally success +CREATE EXTENSION test_ext1 SCHEMA test_ext 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 test_ext CASCADE; 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 0000000000..9a4bb1be78 --- /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 0000000000..9c069dfcaf --- /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 0000000000..0f6d4ec2fb --- /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 0000000000..946b7d58fe --- /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 0000000000..7dec684dcb --- /dev/null +++ b/src/test/modules/test_extensions/test_ext3--1.0.sql @@ -0,0 +1,3 @@ +/* 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 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 0000000000..5f1afe72fc --- /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 0000000000..19f051f6f7 --- /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 0000000000..fc62591950 --- /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 0000000000..baf6ef85dd --- /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 0000000000..51bc57efea --- /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_ext_cyclic1--1.0.sql b/src/test/modules/test_extensions/test_ext_cyclic1--1.0.sql new file mode 100644 index 0000000000..81bdaf48d2 --- /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 0000000000..aaab403463 --- /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 0000000000..ae2b3e9a96 --- /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 0000000000..1e28f96391 --- /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/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 3abbb4caf4..c122f0259c 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -41,7 +41,8 @@ my $contrib_extrasource = { 'seg' => [ 'contrib/seg/segscan.l', 'contrib/seg/segparse.y' ], }; my @contrib_excludes = ( 'commit_ts', 'hstore_plperl', 'hstore_plpython', 'intagg', - 'ltree_plpython', 'pgcrypto', 'sepgsql', 'brin'); + 'ltree_plpython', 'pgcrypto', 'sepgsql', 'brin', + 'test_extensions'); # Set of variables for frontend modules my $frontend_defines = { 'initdb' => 'FRONTEND' };