From 52d7f06a6663d2f6c8577bd5b60ba937b0565ac0 Mon Sep 17 00:00:00 2001 From: Regina Obe Date: Fri, 11 Nov 2022 00:58:46 -0500 Subject: [PATCH] Allow use of @extschema:reqextname@ to reference the schema of a required extension called reqextname. This patch includes 1. Changes to extension execute logic 2. Extension tests both Makefile and meson.build 3. Documentation of the new feature --- doc/src/sgml/extend.sgml | 17 ++++++++++ src/backend/commands/extension.c | 33 +++++++++++++++++++ src/test/modules/test_extensions/Makefile | 9 +++-- .../expected/test_extensions.out | 29 ++++++++++++++++ src/test/modules/test_extensions/meson.build | 7 ++++ .../test_extensions/sql/test_extensions.sql | 9 +++++ .../test_ext_req_schema1--1.0.sql | 6 ++++ .../test_ext_req_schema1.control | 3 ++ .../test_ext_req_schema2--1.0--2.0.sql | 7 ++++ .../test_ext_req_schema2--1.0.sql | 10 ++++++ .../test_ext_req_schema2.control | 4 +++ .../test_ext_req_schema3--1.0.sql | 14 ++++++++ .../test_ext_req_schema3.control | 4 +++ 13 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 src/test/modules/test_extensions/test_ext_req_schema1--1.0.sql create mode 100644 src/test/modules/test_extensions/test_ext_req_schema1.control create mode 100644 src/test/modules/test_extensions/test_ext_req_schema2--1.0--2.0.sql create mode 100644 src/test/modules/test_extensions/test_ext_req_schema2--1.0.sql create mode 100644 src/test/modules/test_extensions/test_ext_req_schema2.control create mode 100644 src/test/modules/test_extensions/test_ext_req_schema3--1.0.sql create mode 100644 src/test/modules/test_extensions/test_ext_req_schema3.control diff --git a/doc/src/sgml/extend.sgml b/doc/src/sgml/extend.sgml index 46e873a166..62fdd9b919 100644 --- a/doc/src/sgml/extend.sgml +++ b/doc/src/sgml/extend.sgml @@ -908,6 +908,23 @@ RETURNS anycompatible AS ... + + + An extension might depend on other extensions. + It is useful to schema qualify calls to dependent extension to minimize reliance on search_path. + This is critical for cases such as functions used in indexes, materialized views, or check constraints. + To reference a required extension's schema, you must first have requires + variable specifying the list of extensions your extension requires. + In your extension sql scripts, + you can reference a required extension's schema with syntax + @extschema:reqextname@ where reqextname + is the name of an extension in your requires list. + All occurrences of this string will be + replaced by the schema the required extension is installed in before the script is + executed. + + + If the extension does not support relocation at all, set diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index 806d6056ab..15945fd432 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -1028,6 +1028,39 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control, CStringGetTextDatum(qSchemaName)); } + /* + * If an extension requires other extensions + * Replace each occurence of @extschema:extname@ + * where extname is the name of the required extension + * with the schema name that extname is located in. + */ + if (control->requires) + { + foreach(lc, control->requires) + { + char *curreq = (char *) lfirst(lc); + Oid reqext; + Oid reqschema; + reqext = get_required_extension(curreq, + control->name, + schemaName, + false, + NIL, + false); + reqschema = get_extension_schema(reqext); + char *reqname; + reqname = get_namespace_name(reqschema); + StringInfoData rToken; + initStringInfo(&rToken); + appendStringInfo(&rToken, "%s%s%s", "@extschema:", curreq, "@"); + + t_sql = DirectFunctionCall3Coll(replace_text, + C_COLLATION_OID, + t_sql, + CStringGetTextDatum(rToken.data), + CStringGetTextDatum(quote_identifier(reqname))); + } + } /* * If module_pathname was set in the control file, substitute its * value for occurrences of MODULE_PATHNAME. diff --git a/src/test/modules/test_extensions/Makefile b/src/test/modules/test_extensions/Makefile index c3139ab0fc..c073df963c 100644 --- a/src/test/modules/test_extensions/Makefile +++ b/src/test/modules/test_extensions/Makefile @@ -6,14 +6,19 @@ 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_evttrig + test_ext_evttrig \ + test_ext_req_schema1 test_ext_req_schema2 test_ext_req_schema3 + 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_evttrig--1.0.sql test_ext_evttrig--1.0--2.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_schema2--1.0--2.0.sql \ + test_ext_req_schema3--1.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 821fed38d1..022504f1ec 100644 --- a/src/test/modules/test_extensions/expected/test_extensions.out +++ b/src/test/modules/test_extensions/expected/test_extensions.out @@ -312,3 +312,32 @@ Objects in extension "test_ext_cine" table ext_cine_tab3 (9 rows) +CREATE SCHEMA test_s_dep; +CREATE EXTENSION test_ext_req_schema1 SCHEMA test_s_dep; +CREATE EXTENSION test_ext_req_schema3 CASCADE; +NOTICE: installing required extension "test_ext_req_schema2" +SELECT dep_req(); + dep_req +--------- + 1032w +(1 row) + +SELECT dep_req2(); + dep_req2 +---------- + 1032w +(1 row) + +SELECT dep_req3(); + dep_req3 +---------- + 2032w +(1 row) + +ALTER EXTENSION test_ext_req_schema2 UPDATE TO '2.0'; +SELECT dep_req(); + dep_req +--------- + 1update +(1 row) + diff --git a/src/test/modules/test_extensions/meson.build b/src/test/modules/test_extensions/meson.build index e95a9f2e7e..20bee210b8 100644 --- a/src/test/modules/test_extensions/meson.build +++ b/src/test/modules/test_extensions/meson.build @@ -29,6 +29,13 @@ install_data( 'test_ext_evttrig--1.0--2.0.sql', 'test_ext_evttrig--1.0.sql', 'test_ext_evttrig.control', + 'test_ext_req_schema1--1.0.sql', + 'test_ext_req_schema1.control', + 'test_ext_req_schema2--1.0.sql', + 'test_ext_req_schema2.control', + 'test_ext_req_schema2--1.0--2.0.sql', + 'test_ext_req_schema3.control', + 'test_ext_req_schema3--1.0.sql', kwargs: contrib_data_args, ) diff --git a/src/test/modules/test_extensions/sql/test_extensions.sql b/src/test/modules/test_extensions/sql/test_extensions.sql index 41b6cddf0b..ba087c26a1 100644 --- a/src/test/modules/test_extensions/sql/test_extensions.sql +++ b/src/test/modules/test_extensions/sql/test_extensions.sql @@ -209,3 +209,12 @@ CREATE EXTENSION test_ext_cine; ALTER EXTENSION test_ext_cine UPDATE TO '1.1'; \dx+ test_ext_cine + +CREATE SCHEMA test_s_dep; +CREATE EXTENSION test_ext_req_schema1 SCHEMA test_s_dep; +CREATE EXTENSION test_ext_req_schema3 CASCADE; +SELECT dep_req(); +SELECT dep_req2(); +SELECT dep_req3(); +ALTER EXTENSION test_ext_req_schema2 UPDATE TO '2.0'; +SELECT dep_req(); diff --git a/src/test/modules/test_extensions/test_ext_req_schema1--1.0.sql b/src/test/modules/test_extensions/test_ext_req_schema1--1.0.sql new file mode 100644 index 0000000000..462fb52145 --- /dev/null +++ b/src/test/modules/test_extensions/test_ext_req_schema1--1.0.sql @@ -0,0 +1,6 @@ +/* src/test/modules/test_extensions/test_ext_req_schema1--1.0.sql */ +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION test_ext_req_schema1" to load this file. \quit + +CREATE DOMAIN req AS text + CONSTRAINT starts_with_1 check(pg_catalog.left(value,1) OPERATOR(pg_catalog.=) '1'); diff --git a/src/test/modules/test_extensions/test_ext_req_schema1.control b/src/test/modules/test_extensions/test_ext_req_schema1.control new file mode 100644 index 0000000000..9ea4558a90 --- /dev/null +++ b/src/test/modules/test_extensions/test_ext_req_schema1.control @@ -0,0 +1,3 @@ +comment = 'Create required extension to be referenced' +default_version = '1.0' +relocatable = true diff --git a/src/test/modules/test_extensions/test_ext_req_schema2--1.0--2.0.sql b/src/test/modules/test_extensions/test_ext_req_schema2--1.0--2.0.sql new file mode 100644 index 0000000000..73a44a25e5 --- /dev/null +++ b/src/test/modules/test_extensions/test_ext_req_schema2--1.0--2.0.sql @@ -0,0 +1,7 @@ +/* src/test/modules/test_extensions/test_ext_req_schema2--1.0.sql */ +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION test_ext_req_schema2" to load this file. \quit + +CREATE OR REPLACE FUNCTION dep_req() RETURNS @extschema:test_ext_req_schema1@.req +LANGUAGE SQL IMMUTABLE PARALLEL SAFE +AS 'SELECT ''1update''::@extschema:test_ext_req_schema1@.req'; diff --git a/src/test/modules/test_extensions/test_ext_req_schema2--1.0.sql b/src/test/modules/test_extensions/test_ext_req_schema2--1.0.sql new file mode 100644 index 0000000000..05b0eb24e1 --- /dev/null +++ b/src/test/modules/test_extensions/test_ext_req_schema2--1.0.sql @@ -0,0 +1,10 @@ +/* src/test/modules/test_extensions/test_ext_req_schema2--1.0.sql */ +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION test_ext_req_schema2" to load this file. \quit +CREATE DOMAIN dreq AS text + CONSTRAINT starts_with_2 check(pg_catalog.left(value,1) OPERATOR(pg_catalog.=) '2'); + +CREATE FUNCTION dep_req() RETURNS @extschema:test_ext_req_schema1@.req +LANGUAGE SQL IMMUTABLE PARALLEL SAFE +AS 'SELECT ''1032w''::@extschema:test_ext_req_schema1@.req'; + diff --git a/src/test/modules/test_extensions/test_ext_req_schema2.control b/src/test/modules/test_extensions/test_ext_req_schema2.control new file mode 100644 index 0000000000..d2ba5add97 --- /dev/null +++ b/src/test/modules/test_extensions/test_ext_req_schema2.control @@ -0,0 +1,4 @@ +comment = 'Test schema referencing of required extensions' +default_version = '1.0' +relocatable = true +requires = 'test_ext_req_schema1' diff --git a/src/test/modules/test_extensions/test_ext_req_schema3--1.0.sql b/src/test/modules/test_extensions/test_ext_req_schema3--1.0.sql new file mode 100644 index 0000000000..f28be6c82d --- /dev/null +++ b/src/test/modules/test_extensions/test_ext_req_schema3--1.0.sql @@ -0,0 +1,14 @@ +/* src/test/modules/test_extensions/test_ext_req_schema2--1.0.sql */ +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION test_ext_req_schema2" to load this file. \quit +CREATE DOMAIN req2 AS text + CONSTRAINT starts_with_2 check(pg_catalog.left(value,1) OPERATOR(pg_catalog.=) '2'); + +CREATE FUNCTION dep_req2() RETURNS @extschema:test_ext_req_schema1@.req +LANGUAGE SQL IMMUTABLE PARALLEL SAFE +AS 'SELECT ''1032w''::@extschema:test_ext_req_schema1@.req'; + +CREATE FUNCTION dep_req3() RETURNS @extschema:test_ext_req_schema2@.dreq +LANGUAGE SQL IMMUTABLE PARALLEL SAFE +AS 'SELECT ''2032w''::@extschema:test_ext_req_schema2@.dreq'; + diff --git a/src/test/modules/test_extensions/test_ext_req_schema3.control b/src/test/modules/test_extensions/test_ext_req_schema3.control new file mode 100644 index 0000000000..b052fad785 --- /dev/null +++ b/src/test/modules/test_extensions/test_ext_req_schema3.control @@ -0,0 +1,4 @@ +comment = 'Test schema referencing of 2 required extensions' +default_version = '1.0' +relocatable = true +requires = 'test_ext_req_schema1,test_ext_req_schema2' -- 2.21.0.windows.1