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 1pOybE-0002H3-EK for pgsql-hackers@arkaria.postgresql.org; Mon, 06 Feb 2023 10:19:48 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1pOybD-0001CE-2y for pgsql-hackers@arkaria.postgresql.org; Mon, 06 Feb 2023 10:19:47 +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 1pOybC-0001C5-Hb for pgsql-hackers@lists.postgresql.org; Mon, 06 Feb 2023 10:19:46 +0000 Received: from mail-il1-x135.google.com ([2607:f8b0:4864:20::135]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1pOybA-0006yA-52 for pgsql-hackers@postgresql.org; Mon, 06 Feb 2023 10:19:46 +0000 Received: by mail-il1-x135.google.com with SMTP id k17so1750323ilq.12 for ; Mon, 06 Feb 2023 02:19:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pcorp-us.20210112.gappssmtp.com; s=20210112; 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=6qM8P2P6utbTP/T8meVkQYjlbisk80bGl17r4wHCxh8=; b=AvVKj1p88qOaMxOIZEFBNg6eOUC+yPLkYX5K8w8OGNdAX8RP4kHPh2an0OT7NyWJNb sN9OL2Tb/EQQPPgQ5Y69LNo7LBDPbeWlf5ig32ivOUDTGH87E/In2NNYlfJuYnRc/pku WFLQE0mIC9bMGJrhFK4yVfNxCZ2iowBw6GLuBkb8mC8AmT1GoK03JxSb6GJTxopjd1X7 OYNkkbOQiW1cG1pSnAL6PGp5Uliz8NB5W0CCR/adx1hgoak2XU00rOdRLAT2/g5yxOGr mb0QfrUgcM7yNrq49P1EkaXBLMgVf6lsSu0F2oTgEV+jUZvZDWdXmSJ2zGh6M36gOGPG srJw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=6qM8P2P6utbTP/T8meVkQYjlbisk80bGl17r4wHCxh8=; b=JArUwEYaI1XlO7/UXJT+xPHw+nEiB+874RQu9bR4DbRaJ2A+qK/y38yTSDeZLd1SHj KrPAvQqtZG8pkNy9Pgxby3nmhNt6w5mDLZY3/Y0w4hipB8074ZMB2Dp8ZJKe3K5coDqv NUjInC7URyV46s3ubONC9/7KGRf0QNFXCieWVXKTG5ZZOrmKYMUrzURrdlHeWoXcCvFV DT8UGH27JjDk8HguPymZYnSrw35nsQcKQ4jFy0TitSjqFyAGc3G8zn4N9WTBedJjU9IV 1QiLskU07H4dH/bPpRTtJ2h5BPLpF1WVPofNcXZ/2mCTAJ2NUOUQ90icJ/DCn8P1hKyH FFrw== X-Gm-Message-State: AO0yUKV4vAebs3kSb8P/jw2ssuqYYyoDagtb5rPqpz7iwuARGzsk56gV kbBR88b3WxUlB2EqOSWp9wQWUbM+hFz4ImTv X-Google-Smtp-Source: AK7set8cF3WKWmmO7AebzwUgrtoM9fHnkYNSTroYqqdacyxhDPrVhQjzd4ONBu59VHODE1nfd/eXBA== X-Received: by 2002:a05:6e02:1c8f:b0:313:859e:1e0a with SMTP id w15-20020a056e021c8f00b00313859e1e0amr14361636ill.10.1675678782116; Mon, 06 Feb 2023 02:19:42 -0800 (PST) Received: from F (50-78-240-110-static.hfc.comcastbusiness.net. [50.78.240.110]) by smtp.gmail.com with ESMTPSA id p8-20020a02c808000000b003a9cab5c5e3sm3304421jao.116.2023.02.06.02.19.41 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 06 Feb 2023 02:19:41 -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> In-Reply-To: Subject: RE: Ability to reference other extensions by schema in extension scripts Date: Mon, 6 Feb 2023 05:19:39 -0500 Message-ID: <000401d93a14$8647f540$92d7dfc0$@pcorp.us> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_0005_01D939EA.9D721450" X-Mailer: Microsoft Outlook 15.0 Thread-Index: AQFgXZxpr0yOB+9uS1Xwc1lFBKthIAHDgsBQATMNnPQCHx2JfQJ9+hXQAio5JzGvEl9twIBTFrBw 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_01D939EA.9D721450 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit > > > Here is first version of my patch using the > > > @extschema:extensionname@ syntax you proposed. > > > > > > This patch includes: > > > 1) Changes to replace references of @extschema:extensionname@ with > > > the schema of the required extension > > > 2) Documentation for the feature > > > 3) Tests for the feature. > > > Attached is a revised version of the original patch. It is revised to prevent ALTER EXTENSION .. SET SCHEMA if there is a dependent extension that references the extension in their scripts using @extschema:extensionname@ It also adds additional tests to verify that new feature. In going thru the code base, I was tempted to add a new dependency type instead of using the existing DEPENDENCY_AUTO. I think this would be cleaner, but I felt that was overstepping the area a bit, since it requires making changes to dependency.h and dependency.c My main concern with using DEPENDENCY_AUTO is because it was designed for cases where an object can be dropped without need for CASCADE. In this case, we don't want a dependent extension to be dropped if it's required is dropped. However since there will already exist a DEPENDENCY_NORMAL between the 2 extensions, I figure we are protected against that issue already. The issue I ran into is there doesn't seem to be an easy way of checking if a pg_depend record is already in place, so I ended up dropping it first with deleteDependencyRecordsForSpecific so I wouldn't need to check and then reading it. The reason for that is during CREATE EXTENSION it would need to create the dependency. It would also need to do so with ALTER EXTENSION .. UPDATE, since extension could later on add it in their upgrade scripts and so there end up being dupes after many ALTER EXTENSION UPDATE calls. pg_depends getAutoExtensionsOfObject seemed suited to that check, as is done in alter.c ExecAlterObjectDependsStmt /* Avoid duplicates */ currexts = getAutoExtensionsOfObject(address.classId, address.objectId); if (!list_member_oid(currexts, refAddr.objectId)) recordDependencyOn(&address, &refAddr, DEPENDENCY_AUTO_EXTENSION); but it is hard-coded to only check DEPENDENCY_AUTO_EXTENSION Why isn't there a variant getAutoExtensionsOfObject take a DEPENDENCY type as an option so it would be more useful or is there functionality for that I missed? Thanks, Regina ------=_NextPart_000_0005_01D939EA.9D721450 Content-Type: application/octet-stream; name="0002-Allow-use-of-extschema-reqextname-to-reference.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="0002-Allow-use-of-extschema-reqextname-to-reference.patch" From 92019e9015d7c6a536a580b92569d67fee2127e7 Mon Sep 17 00:00:00 2001=0A= From: Regina Obe =0A= Date: Sun, 5 Feb 2023 01:35:29 -0500=0A= Subject: [PATCH 2/2] 1. Changes to extension execute logic to allow=0A= referencing required extension schemas by variable 2. Extension tests = both=0A= Makefile and meson.build 3. Documentation of the new feature 4. Add a=0A= DEPENDENCY_AUTO dependency whenever currently created extension = references a=0A= required schema by variable name in its scripts 5. Prevent an extension = from=0A= being relocated if there is a DEPENDENCY_AUTO depend to it=0A= =0A= ---=0A= doc/src/sgml/extend.sgml | 17 +++++=0A= src/backend/commands/extension.c | 71 ++++++++++++++++++-=0A= src/test/modules/test_extensions/Makefile | 9 ++-=0A= .../expected/test_extensions.out | 66 +++++++++++++++++=0A= src/test/modules/test_extensions/meson.build | 7 ++=0A= .../test_extensions/sql/test_extensions.sql | 25 +++++++=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, 238 insertions(+), 3 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..0fc87c96d3 100644=0A= --- a/src/backend/commands/extension.c=0A= +++ b/src/backend/commands/extension.c=0A= @@ -1030,6 +1030,70 @@ 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 it's schema=0A= + * is referenced by @extschema:reqextname@ syntax=0A= + */=0A= + if (control->requires)=0A= + {=0A= + ObjectAddresses *addrs;=0A= + addrs =3D new_object_addresses();=0A= + ObjectAddress depender;=0A= + ObjectAddressSet(depender, ExtensionRelationId, = CurrentExtensionObject);=0A= + foreach(lc, control->requires)=0A= + {=0A= + char *curreq =3D (char *) lfirst(lc);=0A= + Oid reqext;=0A= + Oid reqschema;=0A= + reqext =3D get_required_extension(curreq,=0A= + control->name,=0A= + schemaName,=0A= + false,=0A= + NIL,=0A= + false);=0A= + reqschema =3D get_extension_schema(reqext);=0A= + char *reqname;=0A= + reqname =3D get_namespace_name(reqschema);=0A= + StringInfoData rToken;=0A= + initStringInfo(&rToken);=0A= + appendStringInfo(&rToken, "%s%s%s", "@extschema:", curreq, "@");=0A= + if (strstr(c_sql,rToken.data) !=3D NULL){=0A= + /*=0A= + * If the required extension's schema is referenced by variable = name, =0A= + * add a dependency that the current extension =0A= + * references the schema of the required extension =0A= + **/=0A= + =0A= + ObjectAddress referenced;=0A= + ObjectAddressSet(referenced, ExtensionRelationId, reqext);=0A= +=0A= + /*=0A= + * Deleting the dependency if it exists, because it will be added = again=0A= + * and no easy check to determine if the dependency already exists=0A= + */=0A= + deleteDependencyRecordsForSpecific(depender.classId, = depender.objectId,=0A= + DEPENDENCY_AUTO,=0A= + referenced.classId, referenced.objectId);=0A= +=0A= + add_exact_object_address(&referenced, addrs);=0A= + /*=0A= + * Replace each occurence of @extschema:reqextname@=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= + /* Record all required schemas that have their schema referenced in = script by this one=0A= + * with a DEPENDENCY_AUTO in pg_depend =0A= + */ =0A= + record_object_address_dependencies(&depender, addrs, = DEPENDENCY_AUTO);=0A= + free_object_addresses(addrs); =0A= + }=0A= /*=0A= * If module_pathname was set in the control file, substitute its=0A= * value for occurrences of MODULE_PATHNAME.=0A= @@ -2816,12 +2880,17 @@ AlterExtensionNamespace(const char = *extensionName, const char *newschema, Oid *o=0A= ObjectAddress dep;=0A= Oid dep_oldNspOid;=0A= =0A= + /* If a dependent object scripts =0A= + * reference the variable schema name of this extension=0A= + * do not allow relocation */=0A= + if (pg_depend->deptype =3D=3D DEPENDENCY_AUTO && pg_depend->classid = =3D=3D ExtensionRelationId )=0A= + elog(ERROR, "Extension can not be relocated because dependent = extension references it's location");=0A= /*=0A= * Ignore non-membership dependencies. (Currently, the only other=0A= * case we could see here is a normal dependency from another=0A= * extension.)=0A= */=0A= - if (pg_depend->deptype !=3D DEPENDENCY_EXTENSION)=0A= + if (pg_depend->deptype !=3D DEPENDENCY_EXTENSION )=0A= continue;=0A= =0A= dep.classId =3D pg_depend->classid;=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..fc1f69c098 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,69 @@ 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= +SELECT count(*) =0A= + FROM pg_depend AS d =0A= +WHERE d.deptype=3D'a' AND d.refclassid::regclass::text =3D = 'pg_extension' AND d.classid::regclass::text =3D 'pg_extension';=0A= + count =0A= +-------=0A= + 3=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: Extension can not be relocated because dependent extension = references it's location=0A= +SELECT dep_req();=0A= + dep_req =0A= +---------=0A= + 1update=0A= +(1 row)=0A= +=0A= +SELECT count(*) =0A= + FROM pg_depend AS d =0A= +WHERE d.deptype=3D'a' AND d.refclassid::regclass::text =3D = 'pg_extension' AND d.classid::regclass::text =3D 'pg_extension';=0A= + count =0A= +-------=0A= + 3=0A= +(1 row)=0A= +=0A= +DROP EXTENSION test_ext_req_schema3;=0A= +SELECT count(*) =0A= + FROM pg_depend AS d =0A= +WHERE d.deptype=3D'a' AND d.refclassid::regclass::text =3D = 'pg_extension' AND d.classid::regclass::text =3D 'pg_extension';=0A= + count =0A= +-------=0A= + 1=0A= +(1 row)=0A= +=0A= +DROP EXTENSION test_ext_req_schema2;=0A= +SELECT count(*) =0A= + FROM pg_depend AS d =0A= +WHERE d.deptype=3D'a' AND d.refclassid::regclass::text =3D = 'pg_extension' AND d.classid::regclass::text =3D 'pg_extension';=0A= + count =0A= +-------=0A= + 0=0A= +(1 row)=0A= +=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..41f8e6739d 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,28 @@ 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= +SELECT count(*) =0A= + FROM pg_depend AS d =0A= +WHERE d.deptype=3D'a' AND d.refclassid::regclass::text =3D = 'pg_extension' AND d.classid::regclass::text =3D 'pg_extension';=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= +SELECT count(*) =0A= + FROM pg_depend AS d =0A= +WHERE d.deptype=3D'a' AND d.refclassid::regclass::text =3D = 'pg_extension' AND d.classid::regclass::text =3D 'pg_extension';=0A= +DROP EXTENSION test_ext_req_schema3;=0A= +SELECT count(*) =0A= + FROM pg_depend AS d =0A= +WHERE d.deptype=3D'a' AND d.refclassid::regclass::text =3D = 'pg_extension' AND d.classid::regclass::text =3D 'pg_extension';=0A= +DROP EXTENSION test_ext_req_schema2;=0A= +SELECT count(*) =0A= + FROM pg_depend AS d =0A= +WHERE d.deptype=3D'a' AND d.refclassid::regclass::text =3D = 'pg_extension' AND d.classid::regclass::text =3D 'pg_extension';=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_01D939EA.9D721450--