On Mon, Mar 13, 2023 at 02:48:56PM -0400, Regina Obe wrote: > > I still see the main use-case as for those that micro version and for this > use case, they would need a way, not necessarily to have a single upgrade > script, but a script for each minor. > > So something like > > 3.2.%--3.4.0 = 3.2--3.4.0
I could implement this too if there's an agreement about it. For now I'm attaching an updated patch with conflicts resolved. --strk;
>From a10a1a7200f76bbc6e2def8d4684b647a99316cd Mon Sep 17 00:00:00 2001 From: Sandro Santilli <s...@kbt.io> Date: Wed, 14 Sep 2022 11:10:10 +0200 Subject: [PATCH v2] Allow wildcard (%) in extension upgrade paths A wildcard character "%" will be accepted in the "source" side of the upgrade script and be considered usable to upgrade any version to the "target" side. Includes regression test and documentation. --- doc/src/sgml/extend.sgml | 8 ++++ src/backend/commands/extension.c | 42 ++++++++++++++++--- src/test/modules/test_extensions/Makefile | 7 ++-- .../expected/test_extensions.out | 16 +++++++ src/test/modules/test_extensions/meson.build | 3 ++ .../test_extensions/sql/test_extensions.sql | 9 ++++ .../test_ext_wildcard1--%--2.0.sql | 6 +++ .../test_ext_wildcard1--1.0.sql | 6 +++ .../test_ext_wildcard1.control | 3 ++ 9 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 src/test/modules/test_extensions/test_ext_wildcard1--%--2.0.sql create mode 100644 src/test/modules/test_extensions/test_ext_wildcard1--1.0.sql create mode 100644 src/test/modules/test_extensions/test_ext_wildcard1.control diff --git a/doc/src/sgml/extend.sgml b/doc/src/sgml/extend.sgml index 218940ee5c..bdd463b81f 100644 --- a/doc/src/sgml/extend.sgml +++ b/doc/src/sgml/extend.sgml @@ -1120,6 +1120,14 @@ SELECT pg_catalog.pg_extension_config_dump('my_config', 'WHERE NOT standard_entr <literal>1.1</literal>). </para> + <para> + The literal value <literal>%</literal> can be used as the + <replaceable>old_version</replaceable> component in an extension + update script for it to match any version. Such wildcard update + scripts will only be used when no explicit path is found from + old to target version. + </para> + <para> Given that a suitable update script is available, the command <command>ALTER EXTENSION UPDATE</command> will update an installed extension diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index 0eabe18335..36b6d7e01a 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -132,6 +132,7 @@ static void ApplyExtensionUpdates(Oid extensionOid, bool cascade, bool is_create); static char *read_whole_file(const char *filename, int *length); +static bool file_exists(const char *name); /* @@ -913,7 +914,14 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control, if (from_version == NULL) elog(DEBUG1, "executing extension script for \"%s\" version '%s'", control->name, version); else + { + if ( ! file_exists(filename) ) + { + /* if filename does not exist, try wildcard */ + filename = get_extension_script_filename(control, "%", version); + } elog(DEBUG1, "executing extension script for \"%s\" update from version '%s' to '%s'", control->name, from_version, version); + } /* * If installing a trusted extension on behalf of a non-superuser, become @@ -1258,14 +1266,19 @@ identify_update_path(ExtensionControlFile *control, /* Find shortest path */ result = find_update_path(evi_list, evi_start, evi_target, false, false); + if (result != NIL) + return result; - if (result == NIL) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"", - control->name, oldVersion, newVersion))); + /* Find wildcard path, if no explicit path was found */ + evi_start = get_ext_ver_info("%", &evi_list); + result = find_update_path(evi_list, evi_start, evi_target, false, false); + if (result != NIL) + return result; - return result; + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"", + control->name, oldVersion, newVersion))); } /* @@ -3470,3 +3483,20 @@ read_whole_file(const char *filename, int *length) buf[*length] = '\0'; return buf; } + +static bool +file_exists(const char *name) +{ + struct stat st; + + Assert(name != NULL); + + if (stat(name, &st) == 0) + return !S_ISDIR(st.st_mode); + else if (!(errno == ENOENT || errno == ENOTDIR || errno == EACCES)) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not access file \"%s\": %m", name))); + + return false; +} diff --git a/src/test/modules/test_extensions/Makefile b/src/test/modules/test_extensions/Makefile index 70fc0c8e66..beec04eea3 100644 --- a/src/test/modules/test_extensions/Makefile +++ b/src/test/modules/test_extensions/Makefile @@ -7,8 +7,8 @@ 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_evttrig \ - test_ext_req_schema1 test_ext_req_schema2 test_ext_req_schema3 - + test_ext_req_schema1 test_ext_req_schema2 test_ext_req_schema3 \ + test_ext_evttrig test_ext_wildcard1 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 \ @@ -18,7 +18,8 @@ DATA = test_ext1--1.0.sql test_ext2--1.0.sql test_ext3--1.0.sql \ test_ext_evttrig--1.0.sql test_ext_evttrig--1.0--2.0.sql \ test_ext_req_schema1--1.0.sql \ test_ext_req_schema2--1.0.sql \ - test_ext_req_schema3--1.0.sql + test_ext_req_schema3--1.0.sql \ + test_ext_wildcard1--1.0.sql test_ext_wildcard1--%--2.0.sql \ REGRESS = test_extensions test_extdepend diff --git a/src/test/modules/test_extensions/expected/test_extensions.out b/src/test/modules/test_extensions/expected/test_extensions.out index a31775a260..790b9b9368 100644 --- a/src/test/modules/test_extensions/expected/test_extensions.out +++ b/src/test/modules/test_extensions/expected/test_extensions.out @@ -389,3 +389,19 @@ SELECT test_s_dep.dep_req2(); DROP EXTENSION test_ext_req_schema1 CASCADE; NOTICE: drop cascades to extension test_ext_req_schema2 + +CREATE EXTENSION test_ext_wildcard1; +SELECT ext_wildcard1_version(); + ext_wildcard1_version +----------------------- + 1.0 +(1 row) + +ALTER EXTENSION test_ext_wildcard1 UPDATE TO '2.0'; +SELECT ext_wildcard1_version(); + ext_wildcard1_version +----------------------- + 2.0 +(1 row) + +DROP EXTENSION test_ext_wildcard1; diff --git a/src/test/modules/test_extensions/meson.build b/src/test/modules/test_extensions/meson.build index 29e5bb2fb5..7b14d65545 100644 --- a/src/test/modules/test_extensions/meson.build +++ b/src/test/modules/test_extensions/meson.build @@ -36,6 +36,9 @@ test_install_data += files( 'test_ext_req_schema2.control', 'test_ext_req_schema3--1.0.sql', 'test_ext_req_schema3.control', + 'test_ext_wildcard1--1.0.sql', + 'test_ext_wildcard1--%--2.0.sql', + 'test_ext_wildcard1.control', ) tests += { diff --git a/src/test/modules/test_extensions/sql/test_extensions.sql b/src/test/modules/test_extensions/sql/test_extensions.sql index f4947e7da6..676face363 100644 --- a/src/test/modules/test_extensions/sql/test_extensions.sql +++ b/src/test/modules/test_extensions/sql/test_extensions.sql @@ -232,3 +232,12 @@ ALTER EXTENSION test_ext_req_schema1 SET SCHEMA test_s_dep2; -- now ok SELECT test_s_dep2.dep_req1(); SELECT test_s_dep.dep_req2(); DROP EXTENSION test_ext_req_schema1 CASCADE; + +-- +-- Test wildcard upgrade +-- +CREATE EXTENSION test_ext_wildcard1; +SELECT ext_wildcard1_version(); +ALTER EXTENSION test_ext_wildcard1 UPDATE TO '2.0'; +SELECT ext_wildcard1_version(); +DROP EXTENSION test_ext_wildcard1; diff --git a/src/test/modules/test_extensions/test_ext_wildcard1--%--2.0.sql b/src/test/modules/test_extensions/test_ext_wildcard1--%--2.0.sql new file mode 100644 index 0000000000..75154e5c55 --- /dev/null +++ b/src/test/modules/test_extensions/test_ext_wildcard1--%--2.0.sql @@ -0,0 +1,6 @@ +/* src/test/modules/test_extensions/test_ext_wildcard1--%--2.0.sql */ +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION test_ext_wildcard1 UPDATE TO '2.0'" to load this file. \quit + +CREATE OR REPLACE FUNCTION ext_wildcard1_version() returns TEXT +AS 'SELECT 2.0' LANGUAGE 'sql'; diff --git a/src/test/modules/test_extensions/test_ext_wildcard1--1.0.sql b/src/test/modules/test_extensions/test_ext_wildcard1--1.0.sql new file mode 100644 index 0000000000..a69e791fda --- /dev/null +++ b/src/test/modules/test_extensions/test_ext_wildcard1--1.0.sql @@ -0,0 +1,6 @@ +/* src/test/modules/test_extensions/test_ext_wildcard1--1.0.sql */ +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "CREATE EXTENSION test_ext_wildcard1" to load this file. \quit + +CREATE FUNCTION ext_wildcard1_version() returns TEXT +AS 'SELECT 1.0' LANGUAGE 'sql'; diff --git a/src/test/modules/test_extensions/test_ext_wildcard1.control b/src/test/modules/test_extensions/test_ext_wildcard1.control new file mode 100644 index 0000000000..0c2fc6fca6 --- /dev/null +++ b/src/test/modules/test_extensions/test_ext_wildcard1.control @@ -0,0 +1,3 @@ +comment = 'Test extension wildcard 1' +default_version = '1.0' +relocatable = true -- 2.34.1