Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pX8wR-0007XP-Ph for pgsql-hackers@arkaria.postgresql.org; Tue, 28 Feb 2023 22:59:28 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1pX8wQ-00077U-91 for pgsql-hackers@arkaria.postgresql.org; Tue, 28 Feb 2023 22:59:26 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pX8wP-00075B-PI for pgsql-hackers@lists.postgresql.org; Tue, 28 Feb 2023 22:59:25 +0000 Received: from mail-qt1-x834.google.com ([2607:f8b0:4864:20::834]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1pX8wK-0007Sx-WB for pgsql-hackers@postgresql.org; Tue, 28 Feb 2023 22:59:25 +0000 Received: by mail-qt1-x834.google.com with SMTP id y10so7772978qtj.2 for ; Tue, 28 Feb 2023 14:59:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pcorp-us.20210112.gappssmtp.com; s=20210112; t=1677625159; h=content-language:thread-index:mime-version:message-id:date:subject :in-reply-to:references:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=CgvFGMcWXnUYgpffbK/ifg/pogmJZZLmzqGZs8uXR8I=; b=MNUOH3/7tWqA3Wh244lL9nnyWdefyo9ty1Qb3++exhdIoMD+dQVqV0qE2d9gxORLzp rq+mCfbkfBNf/GrFavVRwGKZHrYKjxViG19l+G1uCYbY3PDY5/xGnGBiH4DhP57Q/4ow dG0WEeXz/74KdaBB01TZV4vI9kNULj9JDDnzBJmPond/YUWnCap73RNnw9zlHKjdoKf8 3wKe3nv1JXqRy8+02MScmfteHuQL9ZGFcHGd197xEsaJ6eAkISfoFculKEQvA5WtKGaV ReFJLKgN7g6Bn92UNrgSPuJ6wJwrb5o7whjlSZ/5pjmlHHh+3rheQKMmPcPoQUNUmlfh 3GfA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1677625159; h=content-language:thread-index:mime-version:message-id:date:subject :in-reply-to:references:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=CgvFGMcWXnUYgpffbK/ifg/pogmJZZLmzqGZs8uXR8I=; b=DOgULNDTSWPFYXPYPqcEpj/O8xoZ1BEXtXZ5UT/GoSvXvUvREIb66UCDw+MU8TlN7r wbH/7sPP1dTJNg+xHl786mHCS/IsBK5J1b9v/VSjyzQQRRHgNr6ATzrp3aAZi9asuMbh VwSC3VUqwnNc2rXcdfuWUmw42CTERPvWqweBq+EZRjyWCgtSBkZ2qZgL9NW2li9sMzi/ c3sWzBGmB/kzzXGL+dwrKfVl3/AqFgFwmr2aJMdp+2jUGjzJNk56499bvHA5EuGQ0Jdo 0c62Wb/pYyCvHjTTuHU8x9Wsacqk2JN26qDVqGKi+ePD0vgIgRggpwEvtngn35lmMcqC IUdw== X-Gm-Message-State: AO0yUKXOQhp/lmsAyfMQ5duEqOz3Rm69a9xhVI7uk7etFzoaQeU5ex9X atELusjGNK6iQFGr6z2jdC7IyoVY42Jsez4a X-Google-Smtp-Source: AK7set+VuiDPzuGuVLAA2smJzaIPv+71zRra1bAaje660BIx6SDPpvZO+HCdmRqWpnCV9RxIITM7Xg== X-Received: by 2002:ac8:5894:0:b0:3bf:b707:e889 with SMTP id t20-20020ac85894000000b003bfb707e889mr8652946qta.34.1677625158711; Tue, 28 Feb 2023 14:59:18 -0800 (PST) Received: from F ([208.127.183.82]) by smtp.gmail.com with ESMTPSA id w30-20020a05620a095e00b007422fd3009esm7559468qkw.20.2023.02.28.14.59.17 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 28 Feb 2023 14:59:18 -0800 (PST) From: "Regina Obe" To: Cc: "'Tom Lane'" , References: <003001d8f4ae$402282c0$c0678840$@pcorp.us> <79300.1668052170@sss.pgh.pa.us> <004501d8f4bf$1213fba0$363bf2e0$@pcorp.us> <175298.1668101858@sss.pgh.pa.us> <004b01d8fef3$752dbf30$5f893d90$@pcorp.us> <20221215085234.rpjzlm7hmsmbanqv@c19> <000401d93a14$8647f540$92d7dfc0$@pcorp.us> <20230223183906.6rhtybwdpe37sri7@c19> <000001d949ad$1159adc0$340d0940$@pcorp.us> <20230228224608.ak7br5shev4wic5a@c19> In-Reply-To: <20230228224608.ak7br5shev4wic5a@c19> Subject: RE: Ability to reference other extensions by schema in extension scripts Date: Tue, 28 Feb 2023 17:59:16 -0500 Message-ID: <000401d94bc8$48dff700$da9fe500$@pcorp.us> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_0005_01D94B9E.600B4E90" X-Mailer: Microsoft Outlook 15.0 Thread-Index: AQFgXZxpr0yOB+9uS1Xwc1lFBKthIAHDgsBQATMNnPQCHx2JfQJ9+hXQAio5JzEC/Q8E0gI4X7GsAa+Q4ksB7Zpnba9CULRQ Content-Language: en-us List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk This is a multipart message in MIME format. ------=_NextPart_000_0005_01D94B9E.600B4E90 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit > On Sun, Feb 26, 2023 at 01:39:24AM -0500, Regina Obe wrote: > > > > 1) Just don't allow any extensions referenced by other > > > extensions to be relocatable. > > > > Attached is my revision 3 patch, which follows the proposed #1. > > Don't allow schema relocation of an extension if another extension > > requires it. > > I've built a version of PostgreSQL with this patch applied and I confirm it > works as expected. > > The "ext1" is relocatable and creates a function ext1log(): > > =# create extension ext1 schema n1; > CREATE EXTENSION > > The "ext2" is relocatable and creates a function ext2log() relying on the > ext1log() function from "ext1" extension, referencing it via > @extschema:ext1@: > > =# create extension ext2 schema n2; > CREATE EXTENSION > =# select n2.ext2log('hello'); -- things work here > ext1: ext2: hello > > By creating "ext2", "ext1" becomes effectively non-relocatable: > > =# alter extension ext1 set schema n2; > ERROR: cannot SET SCHEMA of extension ext1 because other extensions > require it > DETAIL: extension ext2 requires extension ext1 > > Drop "ext2" makes "ext1" relocatable again: > > =# drop extension ext2; > DROP EXTENSION > =# alter extension ext1 set schema n2; > ALTER EXTENSION > > Upon re-creating "ext2" the referenced ext1 schema will be the correct one: > > =# create extension ext2 schema n1; > CREATE EXTENSION > =# select n1.ext2log('hello'); > ext1: ext2: hello > > The code itself builds w/out warnings with: > > mkdir build > cd build > ../configure > make 2> ERR # ERR is empty > > The testsuite reports all successes: > > make check > [...] > ======================= > All 213 tests passed. > ======================= > > Since I didn't see the tests for extension in there, I've also explicitly run that > portion: > > make -C src/test/modules/test_extensions/ check > [...] > test test_extensions ... ok 32 ms > test test_extdepend ... ok 12 ms > [...] > ===================== > All 2 tests passed. > ===================== > > > As mentioned already the downside of this patch is that it would not be > possibile to change the schema of an otherwise relocatable extension once > other extension depend on it, but I can't think of any good reason to allow > that, as it would mean dependent code would need to always dynamically > determine the install location of the objects in that extension, which sounds > dangerous, security wise. > > --strk; > > Libre GIS consultant/developer > https://strk.kbt.io/services.html Oops I had forgotten to submit the updated patch strk was testing against in my fork. He had asked me to clean up the warnings off list and the description. Attached is the revised. Thanks strk for the patient help and guidance. Thanks, Regina ------=_NextPart_000_0005_01D94B9E.600B4E90 Content-Type: application/octet-stream; name="0004-Allow-use-of-extschema-reqextname-to-reference.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="0004-Allow-use-of-extschema-reqextname-to-reference.patch" From 5279686f1338f31d974f7bb749a201e0d0b280fc Mon Sep 17 00:00:00 2001=0A= From: Regina Obe =0A= Date: Sun, 5 Feb 2023 01:35:29 -0500=0A= Subject: [PATCH 4/4] Allow @extschema:@ in extension scripts=0A= =0A= This feature allows an extension author to reference=0A= extension schemas of extensions in the requires variable=0A= of the control file using variable syntax=0A= @extschema:@ where is the=0A= name of any of the listed required extensions.=0A= =0A= This feature is needed particularly in cases=0A= when another extension packages a function=0A= which references an object from one of its=0A= required extensions and this function is used to back=0A= indexes, constraints, and materialized views.=0A= =0A= Without this feature, because pg_restore removes the paths,=0A= these indexes, constraints, materialized views are not restored=0A= because when the function is called, the function call fails=0A= because items it depends on cannot be schema qualified.=0A= =0A= This feature will allow extension authors to schema qualify=0A= references to required extension objects to prevent this issue.=0A= Aside from this issue, schema qualifying all these references will=0A= improve security by preventing a rogue version of a function from being=0A= used.=0A= =0A= - Extension tests both Makefile and meson.build=0A= - Documentation of the new feature=0A= - Prevent an extension from being relocated if=0A= another extension requires it=0A= =0A= Discussion: = https://postgr.es/m/000801d94959%2463a9f520%242afddf60%24%40pcorp.us=0A= ---=0A= doc/src/sgml/extend.sgml | 17 +++++++=0A= src/backend/commands/extension.c | 49 +++++++++++++++++++=0A= src/test/modules/test_extensions/Makefile | 9 +++-=0A= .../expected/test_extensions.out | 40 +++++++++++++++=0A= src/test/modules/test_extensions/meson.build | 7 +++=0A= .../test_extensions/sql/test_extensions.sql | 14 ++++++=0A= .../test_ext_req_schema1--1.0.sql | 6 +++=0A= .../test_ext_req_schema1.control | 3 ++=0A= .../test_ext_req_schema2--1.0--2.0.sql | 7 +++=0A= .../test_ext_req_schema2--1.0.sql | 9 ++++=0A= .../test_ext_req_schema2.control | 4 ++=0A= .../test_ext_req_schema3--1.0.sql | 13 +++++=0A= .../test_ext_req_schema3.control | 4 ++=0A= 13 files changed, 180 insertions(+), 2 deletions(-)=0A= create mode 100644 = src/test/modules/test_extensions/test_ext_req_schema1--1.0.sql=0A= create mode 100644 = src/test/modules/test_extensions/test_ext_req_schema1.control=0A= create mode 100644 = src/test/modules/test_extensions/test_ext_req_schema2--1.0--2.0.sql=0A= create mode 100644 = src/test/modules/test_extensions/test_ext_req_schema2--1.0.sql=0A= create mode 100644 = src/test/modules/test_extensions/test_ext_req_schema2.control=0A= create mode 100644 = src/test/modules/test_extensions/test_ext_req_schema3--1.0.sql=0A= create mode 100644 = src/test/modules/test_extensions/test_ext_req_schema3.control=0A= =0A= diff --git a/doc/src/sgml/extend.sgml b/doc/src/sgml/extend.sgml=0A= index b70cbe83ae..6c93bddb36 100644=0A= --- a/doc/src/sgml/extend.sgml=0A= +++ b/doc/src/sgml/extend.sgml=0A= @@ -908,6 +908,23 @@ RETURNS anycompatible AS ...=0A= =0A= =0A= =0A= + =0A= + =0A= + An extension might depend on other extensions.=0A= + It is useful to schema qualify calls to dependent extension to = minimize reliance on search_path.=0A= + This is critical for cases such as functions used in indexes, = materialized views, or check constraints.=0A= + To reference a required extension's schema, you must first have = requires=0A= + variable specifying the list of extensions your extension = requires.=0A= + In your extension sql scripts,=0A= + you can reference a required extension's schema with syntax=0A= + @extschema:reqextname@ where = reqextname=0A= + is the name of an extension in your requires = list.=0A= + All occurrences of this string will be=0A= + replaced by the schema the required extension is installed in = before the script is=0A= + executed.=0A= + =0A= + =0A= +=0A= =0A= =0A= If the extension does not support relocation at all, set=0A= diff --git a/src/backend/commands/extension.c = b/src/backend/commands/extension.c=0A= index b1509cc505..17ebb1a4fc 100644=0A= --- a/src/backend/commands/extension.c=0A= +++ b/src/backend/commands/extension.c=0A= @@ -1030,6 +1030,41 @@ execute_extension_script(Oid extensionOid, = ExtensionControlFile *control,=0A= CStringGetTextDatum(qSchemaName));=0A= }=0A= =0A= + /*=0A= + * If this extension requires other extensions=0A= + * Check each required extension to see if its schema=0A= + * is referenced by @extschema:reqextname@ syntax=0A= + */=0A= + foreach(lc, control->requires)=0A= + {=0A= + char *curreq =3D (char *) lfirst(lc);=0A= + Oid reqext;=0A= + Oid reqschema;=0A= + StringInfoData rToken;=0A= + char *reqname;=0A= + reqext =3D get_required_extension(curreq,=0A= + control->name,=0A= + (char *) schemaName,=0A= + false,=0A= + NIL,=0A= + false);=0A= + reqschema =3D get_extension_schema(reqext);=0A= + reqname =3D get_namespace_name(reqschema);=0A= + initStringInfo(&rToken);=0A= + appendStringInfo(&rToken, "%s%s%s", "@extschema:", curreq, "@");=0A= +=0A= + /*=0A= + * If the required extension's schema is referenced=0A= + * by variable name,=0A= + * Replace each occurence of @extschema:@=0A= + * with the required extension's schema=0A= + */=0A= + t_sql =3D DirectFunctionCall3Coll(replace_text,=0A= + C_COLLATION_OID,=0A= + t_sql,=0A= + CStringGetTextDatum(rToken.data),=0A= + CStringGetTextDatum(quote_identifier(reqname)));=0A= + }=0A= /*=0A= * If module_pathname was set in the control file, substitute its=0A= * value for occurrences of MODULE_PATHNAME.=0A= @@ -2816,6 +2851,20 @@ AlterExtensionNamespace(const char = *extensionName, const char *newschema, Oid *o=0A= ObjectAddress dep;=0A= Oid dep_oldNspOid;=0A= =0A= + /* If an extension requires this extension=0A= + * do not allow relocation */=0A= + if (pg_depend->deptype =3D=3D DEPENDENCY_NORMAL && pg_depend->classid = =3D=3D ExtensionRelationId){=0A= + dep.classId =3D pg_depend->classid;=0A= + dep.objectId =3D pg_depend->objid;=0A= + dep.objectSubId =3D pg_depend->objsubid;=0A= + ereport(ERROR,=0A= + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),=0A= + errmsg("cannot SET SCHEMA of extension %s because other = extensions require it",=0A= + NameStr(extForm->extname)),=0A= + errdetail("%s requires extension %s",=0A= + getObjectDescription(&dep, false), = NameStr(extForm->extname))));=0A= +=0A= + }=0A= /*=0A= * Ignore non-membership dependencies. (Currently, the only other=0A= * case we could see here is a normal dependency from another=0A= diff --git a/src/test/modules/test_extensions/Makefile = b/src/test/modules/test_extensions/Makefile=0A= index c3139ab0fc..c073df963c 100644=0A= --- a/src/test/modules/test_extensions/Makefile=0A= +++ b/src/test/modules/test_extensions/Makefile=0A= @@ -6,14 +6,19 @@ PGFILEDESC =3D "test_extensions - regression testing = for EXTENSION support"=0A= EXTENSION =3D test_ext1 test_ext2 test_ext3 test_ext4 test_ext5 = test_ext6 \=0A= test_ext7 test_ext8 test_ext_cine test_ext_cor \=0A= test_ext_cyclic1 test_ext_cyclic2 \=0A= - test_ext_evttrig=0A= + test_ext_evttrig \=0A= + test_ext_req_schema1 test_ext_req_schema2 = test_ext_req_schema3=0A= +=0A= DATA =3D test_ext1--1.0.sql test_ext2--1.0.sql test_ext3--1.0.sql \=0A= test_ext4--1.0.sql test_ext5--1.0.sql test_ext6--1.0.sql \=0A= test_ext7--1.0.sql test_ext7--1.0--2.0.sql test_ext8--1.0.sql \=0A= test_ext_cine--1.0.sql test_ext_cine--1.0--1.1.sql \=0A= test_ext_cor--1.0.sql \=0A= test_ext_cyclic1--1.0.sql test_ext_cyclic2--1.0.sql \=0A= - test_ext_evttrig--1.0.sql test_ext_evttrig--1.0--2.0.sql=0A= + test_ext_evttrig--1.0.sql test_ext_evttrig--1.0--2.0.sql \=0A= + test_ext_req_schema1--1.0.sql \=0A= + test_ext_req_schema2--1.0.sql test_ext_req_schema2--1.0--2.0.sql = \=0A= + test_ext_req_schema3--1.0.sql=0A= =0A= REGRESS =3D test_extensions test_extdepend=0A= =0A= diff --git = a/src/test/modules/test_extensions/expected/test_extensions.out = b/src/test/modules/test_extensions/expected/test_extensions.out=0A= index 821fed38d1..21dfd05982 100644=0A= --- a/src/test/modules/test_extensions/expected/test_extensions.out=0A= +++ b/src/test/modules/test_extensions/expected/test_extensions.out=0A= @@ -312,3 +312,43 @@ Objects in extension "test_ext_cine"=0A= table ext_cine_tab3=0A= (9 rows)=0A= =0A= +CREATE SCHEMA test_s_dep;=0A= +CREATE EXTENSION test_ext_req_schema1 SCHEMA test_s_dep;=0A= +CREATE EXTENSION test_ext_req_schema3 CASCADE;=0A= +NOTICE: installing required extension "test_ext_req_schema2"=0A= +SELECT dep_req();=0A= + dep_req =0A= +---------=0A= + 1032w=0A= +(1 row)=0A= +=0A= +SELECT dep_req2();=0A= + dep_req2 =0A= +----------=0A= + 1032w=0A= +(1 row)=0A= +=0A= +SELECT dep_req3();=0A= + dep_req3 =0A= +----------=0A= + 2032w=0A= +(1 row)=0A= +=0A= +ALTER EXTENSION test_ext_req_schema2 UPDATE TO '2.0';=0A= +CREATE SCHEMA test_s_dep2;=0A= +ALTER EXTENSION test_ext_req_schema1 SET SCHEMA test_s_dep2;=0A= +ERROR: cannot SET SCHEMA of extension test_ext_req_schema1 because = other extensions require it=0A= +DETAIL: extension test_ext_req_schema3 requires extension = test_ext_req_schema1=0A= +SELECT dep_req();=0A= + dep_req =0A= +---------=0A= + 1update=0A= +(1 row)=0A= +=0A= +DROP EXTENSION test_ext_req_schema1;=0A= +ERROR: cannot drop extension test_ext_req_schema1 because other = objects depend on it=0A= +DETAIL: extension test_ext_req_schema2 depends on extension = test_ext_req_schema1=0A= +extension test_ext_req_schema3 depends on extension test_ext_req_schema1=0A= +HINT: Use DROP ... CASCADE to drop the dependent objects too.=0A= +DROP EXTENSION test_ext_req_schema3;=0A= +DROP EXTENSION test_ext_req_schema2;=0A= diff --git a/src/test/modules/test_extensions/meson.build = b/src/test/modules/test_extensions/meson.build=0A= index 45597ddc23..7519f6e28e 100644=0A= --- a/src/test/modules/test_extensions/meson.build=0A= +++ b/src/test/modules/test_extensions/meson.build=0A= @@ -31,6 +31,13 @@ install_data(=0A= 'test_ext_evttrig--1.0--2.0.sql',=0A= 'test_ext_evttrig--1.0.sql',=0A= 'test_ext_evttrig.control',=0A= + 'test_ext_req_schema1--1.0.sql',=0A= + 'test_ext_req_schema1.control',=0A= + 'test_ext_req_schema2--1.0.sql',=0A= + 'test_ext_req_schema2.control',=0A= + 'test_ext_req_schema2--1.0--2.0.sql',=0A= + 'test_ext_req_schema3.control',=0A= + 'test_ext_req_schema3--1.0.sql',=0A= kwargs: contrib_data_args,=0A= )=0A= =0A= diff --git a/src/test/modules/test_extensions/sql/test_extensions.sql = b/src/test/modules/test_extensions/sql/test_extensions.sql=0A= index 41b6cddf0b..81ecd13736 100644=0A= --- a/src/test/modules/test_extensions/sql/test_extensions.sql=0A= +++ b/src/test/modules/test_extensions/sql/test_extensions.sql=0A= @@ -209,3 +209,17 @@ CREATE EXTENSION test_ext_cine;=0A= ALTER EXTENSION test_ext_cine UPDATE TO '1.1';=0A= =0A= \dx+ test_ext_cine=0A= +=0A= +CREATE SCHEMA test_s_dep;=0A= +CREATE EXTENSION test_ext_req_schema1 SCHEMA test_s_dep;=0A= +CREATE EXTENSION test_ext_req_schema3 CASCADE;=0A= +SELECT dep_req();=0A= +SELECT dep_req2();=0A= +SELECT dep_req3();=0A= +ALTER EXTENSION test_ext_req_schema2 UPDATE TO '2.0';=0A= +CREATE SCHEMA test_s_dep2;=0A= +ALTER EXTENSION test_ext_req_schema1 SET SCHEMA test_s_dep2;=0A= +SELECT dep_req();=0A= +DROP EXTENSION test_ext_req_schema1;=0A= +DROP EXTENSION test_ext_req_schema3;=0A= +DROP EXTENSION test_ext_req_schema2;=0A= \ No newline at end of file=0A= 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=0A= new file mode 100644=0A= index 0000000000..462fb52145=0A= --- /dev/null=0A= +++ b/src/test/modules/test_extensions/test_ext_req_schema1--1.0.sql=0A= @@ -0,0 +1,6 @@=0A= +/* src/test/modules/test_extensions/test_ext_req_schema1--1.0.sql */=0A= +-- complain if script is sourced in psql, rather than via CREATE = EXTENSION=0A= +\echo Use "CREATE EXTENSION test_ext_req_schema1" to load this file. = \quit=0A= +=0A= +CREATE DOMAIN req AS text=0A= + CONSTRAINT starts_with_1 check(pg_catalog.left(value,1) = OPERATOR(pg_catalog.=3D) '1');=0A= diff --git = a/src/test/modules/test_extensions/test_ext_req_schema1.control = b/src/test/modules/test_extensions/test_ext_req_schema1.control=0A= new file mode 100644=0A= index 0000000000..9ea4558a90=0A= --- /dev/null=0A= +++ b/src/test/modules/test_extensions/test_ext_req_schema1.control=0A= @@ -0,0 +1,3 @@=0A= +comment =3D 'Create required extension to be referenced'=0A= +default_version =3D '1.0'=0A= +relocatable =3D true=0A= 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=0A= new file mode 100644=0A= index 0000000000..73a44a25e5=0A= --- /dev/null=0A= +++ b/src/test/modules/test_extensions/test_ext_req_schema2--1.0--2.0.sql=0A= @@ -0,0 +1,7 @@=0A= +/* src/test/modules/test_extensions/test_ext_req_schema2--1.0.sql */=0A= +-- complain if script is sourced in psql, rather than via CREATE = EXTENSION=0A= +\echo Use "CREATE EXTENSION test_ext_req_schema2" to load this file. = \quit=0A= +=0A= +CREATE OR REPLACE FUNCTION dep_req() RETURNS = @extschema:test_ext_req_schema1@.req=0A= +LANGUAGE SQL IMMUTABLE PARALLEL SAFE=0A= +AS 'SELECT ''1update''::@extschema:test_ext_req_schema1@.req';=0A= 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=0A= new file mode 100644=0A= index 0000000000..9fe25d48a1=0A= --- /dev/null=0A= +++ b/src/test/modules/test_extensions/test_ext_req_schema2--1.0.sql=0A= @@ -0,0 +1,9 @@=0A= +/* src/test/modules/test_extensions/test_ext_req_schema2--1.0.sql */=0A= +-- complain if script is sourced in psql, rather than via CREATE = EXTENSION=0A= +\echo Use "CREATE EXTENSION test_ext_req_schema2" to load this file. = \quit=0A= +CREATE DOMAIN dreq AS text=0A= + CONSTRAINT starts_with_2 check(pg_catalog.left(value,1) = OPERATOR(pg_catalog.=3D) '2');=0A= +=0A= +CREATE FUNCTION dep_req() RETURNS @extschema:test_ext_req_schema1@.req=0A= +LANGUAGE SQL IMMUTABLE PARALLEL SAFE=0A= +AS 'SELECT ''1032w''::@extschema:test_ext_req_schema1@.req';=0A= diff --git = a/src/test/modules/test_extensions/test_ext_req_schema2.control = b/src/test/modules/test_extensions/test_ext_req_schema2.control=0A= new file mode 100644=0A= index 0000000000..d2ba5add97=0A= --- /dev/null=0A= +++ b/src/test/modules/test_extensions/test_ext_req_schema2.control=0A= @@ -0,0 +1,4 @@=0A= +comment =3D 'Test schema referencing of required extensions'=0A= +default_version =3D '1.0'=0A= +relocatable =3D true=0A= +requires =3D 'test_ext_req_schema1'=0A= 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=0A= new file mode 100644=0A= index 0000000000..bd05669097=0A= --- /dev/null=0A= +++ b/src/test/modules/test_extensions/test_ext_req_schema3--1.0.sql=0A= @@ -0,0 +1,13 @@=0A= +/* src/test/modules/test_extensions/test_ext_req_schema2--1.0.sql */=0A= +-- complain if script is sourced in psql, rather than via CREATE = EXTENSION=0A= +\echo Use "CREATE EXTENSION test_ext_req_schema2" to load this file. = \quit=0A= +CREATE DOMAIN req2 AS text=0A= + CONSTRAINT starts_with_2 check(pg_catalog.left(value,1) = OPERATOR(pg_catalog.=3D) '2');=0A= +=0A= +CREATE FUNCTION dep_req2() RETURNS @extschema:test_ext_req_schema1@.req=0A= +LANGUAGE SQL IMMUTABLE PARALLEL SAFE=0A= +AS 'SELECT ''1032w''::@extschema:test_ext_req_schema1@.req';=0A= +=0A= +CREATE FUNCTION dep_req3() RETURNS @extschema:test_ext_req_schema2@.dreq=0A= +LANGUAGE SQL IMMUTABLE PARALLEL SAFE=0A= +AS 'SELECT ''2032w''::@extschema:test_ext_req_schema2@.dreq';=0A= diff --git = a/src/test/modules/test_extensions/test_ext_req_schema3.control = b/src/test/modules/test_extensions/test_ext_req_schema3.control=0A= new file mode 100644=0A= index 0000000000..b052fad785=0A= --- /dev/null=0A= +++ b/src/test/modules/test_extensions/test_ext_req_schema3.control=0A= @@ -0,0 +1,4 @@=0A= +comment =3D 'Test schema referencing of 2 required extensions'=0A= +default_version =3D '1.0'=0A= +relocatable =3D true=0A= +requires =3D 'test_ext_req_schema1,test_ext_req_schema2'=0A= -- =0A= 2.21.0.windows.1=0A= =0A= ------=_NextPart_000_0005_01D94B9E.600B4E90--