Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wVMGb-001u7G-0L for pgsql-bugs@arkaria.postgresql.org; Fri, 05 Jun 2026 04:34:45 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wVMGZ-009zzs-2g for pgsql-bugs@arkaria.postgresql.org; Fri, 05 Jun 2026 04:34:43 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wVMGZ-009zzh-1N for pgsql-bugs@lists.postgresql.org; Fri, 05 Jun 2026 04:34:43 +0000 Received: from mail-pj1-x1030.google.com ([2607:f8b0:4864:20::1030]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wVMGW-00000001BB5-1C9E for pgsql-bugs@lists.postgresql.org; Fri, 05 Jun 2026 04:34:41 +0000 Received: by mail-pj1-x1030.google.com with SMTP id 98e67ed59e1d1-36b8d414666so927761a91.3 for ; Thu, 04 Jun 2026 21:34:39 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1780634078; cv=none; d=google.com; s=arc-20240605; b=IZhd2L1z9jyEjSKaedIW/rUQcI3zwk664NR2Ex/6dmoo1YT4prhz/BEIjDa0BGCD4k 4PiNg/u/MtfIV+tY6SEEyT/93XZ1UpaX9uYOCilmkwGPBeQzkJFV4jZtdeFa3JwjTcvR P8gwZNmrIzsbotJgbQE1SEiBZTm3VSoPyDy0rOp4PQoDBgqIPJPvwda6T+alR76uKxRt IXJMXu2ubYPsx0//IBsdcvXP0r8++Q+E1r6nQQfdDe0LfnHDRIutFCaCFyiZRPeXPt4S qy72xM68HulXo3xDmtekNdzbdPjqiOoyxASUUk/859goJyCBciauISleFHpRkWpEj9oP wZdg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:dkim-signature; bh=F4naHJz36JivwV8jNrQlkgvS5QvWbnzjHENdCYwp/N8=; fh=MxmWx+OuaxKPr69X7jrCv7AUETQVBmZSsJBlPoOEk18=; b=CiRoaoPYAHf9Cb9G7LbvnwgtKFDSPI9jVg3bLFEgJupNmu64j/NcjVOxsrL2KS1JEb ypjZjXVn10O76e1AxaxDlRGjuHTuXYrhSUvDixEqDzR/Amag2A8mRQ208FDjYBtjMBoR 2juLv69/DFX2Yr7/lHt/zDhUohgRtps1G9YHPcK6jJt6lHQ3gT0GmyKec2fwbbJdQJY2 VLF/pQY9fLdAgGFOlICp3/MmxLzxZ9pe5j1smqmRcRQl4HKDk3HzKkTqfyg4yKO26jTk 9ad+jq4NuGEIXBdPCFESccw8kM0SfVP814kH83ERwqdPByMS4iUNxoUE8ThcMXVmz0Nr q/pA==; darn=lists.postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=enterprisedb.com; s=google; t=1780634078; x=1781238878; darn=lists.postgresql.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=F4naHJz36JivwV8jNrQlkgvS5QvWbnzjHENdCYwp/N8=; b=UCPYGlhWOL5V0iGKb4yopeHfofBEayS1aea49h3lCltQyPvonA79xjxltpFBw4Efg5 I2W8WCuAYYQjnKy5EgPhd4C1ESgesePnpFT/dJwyTLPLzQwgskt94xCftaC9b1kEbaZd C3A4+JyhBKvsNnP/zy5k3myYezeFtfu9l6rIkxr7KdlLEbkqAGGRRLD1jE2hl/Y+zssA HdEzO4SgSjnD4YBpjIdKau7twRXLB2k28lj6u9qXAnzixqtnl36+sxjBi23r/mI0Mljk 8LwI34o4MWyU99Ja1WhIokBTTx9bBta1An2Sw77RANHqCCYj43NKYv7YEW7HMy3r7Xcu XZ9Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780634078; x=1781238878; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=F4naHJz36JivwV8jNrQlkgvS5QvWbnzjHENdCYwp/N8=; b=TpIftujx6gsy4vgtQx+oEdaqWhCK0rC2QQXFLsQp+C+JhXatKNjsPyMNlravdBzhMv QLSu9OZSD38xeVFqG9sIJZAvhtLn/j6nncmdKN6Zm2BdZ+l7qK2GU9zXL03kIm3NQ9X0 MXdOEd3eIcWu9SdLmS8PNTP3p5Gvb5iHXYmPJvq8XhDKI08B3qwaLpr2L8EQYQkd6sNS oh8X1Jqepyi6+Q4cno9K+ZDeCw52wQRXplsz5ACcdms/DxMx4DWRZ4GWtXFs5GebcwkA zSAYhEQMaTUHSHmTV3lrAR0Y84YcyxszIAwHCymDyPWs39jioUehyJKlqbFWTt9+DZMZ wDkA== X-Forwarded-Encrypted: i=1; AFNElJ+KJ7OVNV1XCc1B5xKZdblaYq9GBNDPWZzRbAkAKnA40PIA3sGO/k+1jMUBjY8bKOduQu4FAuFvNrj9@lists.postgresql.org X-Gm-Message-State: AOJu0Yz50Ydfn6WUAFJmeit0fhX9EqFOgmKhnfFraxGrgKxED8qcucoF Haoo0GBHR1ydtxW9i8DXRXIzcrozw/aI2v4an+WU1cPIWzAHH9ZcczIj3TphJcYXAORw9r+fgkz UxPPq31yBcAtdfBVJCYrRybXqr2ByFQysJfNotdrM X-Gm-Gg: Acq92OEMCbH5Ry0mfTRCATj1I3UM9VjHEOKY5WwUTgBvRfO8HqDOJX+DordsF8X4GgA yn2vqISpvNhk0PEZkl4sWZx/S2tsgzB6WujqYsSKEwaHIrhX48U6iFR6Q5WhHR5qbSVgCUsRhec OyTI3MVBN4nxYORoxAR2ODakLFoRmy3zAGQAwNGxVk1KXIQLitU/Ou8R1E1guEsGbEYyu6wACNM VNgLm0PCzh77nvTk9ILSYvrRtr/R08cZ5P5OEWpB8dL5BV3HB8CX8NSNxPScAhZy3tCVvcWu+0e v5ZWJjmD3fYpZrbWy44= X-Received: by 2002:a17:90a:dfcd:b0:36d:b12f:6143 with SMTP id 98e67ed59e1d1-370f1b09906mr2354241a91.25.1780634078323; Thu, 04 Jun 2026 21:34:38 -0700 (PDT) MIME-Version: 1.0 References: <19506-9478f3012ecc2328@postgresql.org> In-Reply-To: From: Gabriele Bartolini Date: Fri, 5 Jun 2026 14:34:27 +1000 X-Gm-Features: AVHnY4Jra-G25sU1CS0PVS5JxTSlclcv1xtdjRAtdMYawXQcIBOoglWp4JJQRWM Message-ID: Subject: Re: BUG #19506: LOAD '$libdir/...' inside extension scripts ignores dynamic_library_path with extension_control_path To: Ayush Tiwari Cc: gabriele.bartolini@gmail.com, pgsql-bugs@lists.postgresql.org, Peter Eisentraut Content-Type: multipart/alternative; boundary="000000000000b6b6c706537a2df4" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --000000000000b6b6c706537a2df4 Content-Type: text/plain; charset="UTF-8" Hi Ayush, I was about to draft an email to hackers about this. I had already done a patch: https://github.com/gbartolini/postgres/pull/1 Thanks for your reply. I will verify yours later. Cheers, Gabriele On Fri, 5 Jun 2026 at 14:27, Ayush Tiwari wrote: > Hi, > > On Thu, 4 Jun 2026 at 21:23, PG Bug reporting form > wrote: > >> The following bug has been logged on the website: >> >> Bug reference: 19506 >> Logged by: Gabriele Bartolini >> Email address: gabriele.bartolini@gmail.com >> PostgreSQL version: 18.4 >> Operating system: Linux (reproduced under CloudNativePG/Kubernetes) >> Description: >> >> When an extension is installed in a location reached via >> `extension_control_path` / `dynamic_library_path` (rather than the >> compiled-in package library directory), a LOAD '$libdir/foo' hardcoded >> inside an extension's SQL script fails to find the library. PostGIS does >> this in its upgrade scripts, so a PostGIS upgrade fails: >> >> ``` >> app=# SELECT postgis_extensions_upgrade(); >> NOTICE: Updating extension postgis 3.6.1 >> ERROR: could not access file "$libdir/postgis-3": No such file or >> directory >> CONTEXT: SQL statement "LOAD '$libdir/postgis-3'" >> extension script file "postgis--ANY--3.6.3.sql", near line 1530 >> ``` >> >> This is a side effect of the fix for bug #18920 (commit f777d773878). >> Commit >> 4f7f7b03758 (`extension_control_path`) made the feature work by stripping >> the '$libdir/' prefix so that dynamic_library_path is consulted. #18920 >> then >> restricted that stripping to the function-load path so that a user-issued >> `LOAD` keeps the literal '$libdir/' prefix. As a result, a `LOAD` inside >> an >> extension script now also keeps the literal prefix, so >> `dynamic_library_path` is never consulted, and the library cannot be >> found. >> >> A `LOAD` running inside an extension script should behave like the >> extension's function loads (strip '$libdir/'), while a LOAD issued >> directly >> by a user should keep it (the #18920 behaviour). The two can be >> distinguished by `creating_extension`. >> >> Reproduced with the CloudNativePG operator on Kubernetes, but it applies >> to >> any setup using `extension_control_path` / `dynamic_library_path`. >> > > Thanks for the report and the very clear diagnosis, I could > reproduce the issue and your analysis matches what I see. > > The attached patch implements exactly what you suggested: a > LOAD running while creating_extension is true strips the simple > "$libdir/" prefix (so dynamic_library_path is consulted, like > the extension's own function loads do), while a user-issued > LOAD keeps the literal prefix and therefore preserves the > #18920 behaviour. > > To avoid duplicating the existing prefix-stripping logic in > load_external_function(), I factored it out into a small > static helper and reused it from load_file(). Nested paths > (e.g. "$libdir/foo/bar") are still left untouched and continue > to be expanded by expand_dynamic_library_name() as before. > > Verified locally that the PostGIS-style reproducer now succeeds > when the extension is installed via extension_control_path / > dynamic_library_path, that a plain user-issued > LOAD '$libdir/foo' still behaves as on HEAD, and that the > existing extension regression suites still pass. > > Regards, > Ayush > -- Gabriele Bartolini VP, Chief Architect, Kubernetes enterprisedb.com / Melbourne, Australia --000000000000b6b6c706537a2df4 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi Ayush,

I was about to draft an email to hackers = about this. I had already done a patch:=C2=A0https://github.com/gbartolini/postgres/pull/1

Thanks for your reply. I will verify yours later.

Cheers,
Gabriele

Hi,

On Thu, 4 Jun 2026 at 21:23, PG Bug reporting form <noreply@postgresql.org= > wrote:
The = following bug has been logged on the website:

Bug reference:=C2=A0 =C2=A0 =C2=A0 19506
Logged by:=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Gabriele Bartolini
Email address:=C2=A0 =C2=A0 =C2=A0 gabriele.bartolini@gmail.com
PostgreSQL version: 18.4
Operating system:=C2=A0 =C2=A0Linux (reproduced under CloudNativePG/Kuberne= tes)
Description:=C2=A0 =C2=A0 =C2=A0 =C2=A0

When an extension is installed in a location reached via
`extension_control_path` / `dynamic_library_path` (rather than the
compiled-in package library directory), a LOAD '$libdir/foo' hardco= ded
inside an extension's SQL script fails to find the library. PostGIS doe= s
this in its upgrade scripts, so a PostGIS upgrade fails:

```
app=3D# SELECT postgis_extensions_upgrade();
NOTICE:=C2=A0 Updating extension postgis 3.6.1
ERROR:=C2=A0 could not access file "$libdir/postgis-3": No such f= ile or directory
CONTEXT:=C2=A0 SQL statement "LOAD '$libdir/postgis-3'" extension script file "postgis--ANY--3.6.3.sql", near line 1530 ```

This is a side effect of the fix for bug #18920 (commit f777d773878). Commi= t
4f7f7b03758 (`extension_control_path`) made the feature work by stripping the '$libdir/' prefix so that dynamic_library_path is consulted. #1= 8920 then
restricted that stripping to the function-load path so that a user-issued `LOAD` keeps the literal '$libdir/' prefix. As a result, a `LOAD` i= nside an
extension script now also keeps the literal prefix, so
`dynamic_library_path` is never consulted, and the library cannot be found.=

A `LOAD` running inside an extension script should behave like the
extension's function loads (strip '$libdir/'), while a LOAD iss= ued directly
by a user should keep it (the #18920 behaviour). The two can be
distinguished by `creating_extension`.

Reproduced with the CloudNativePG operator on Kubernetes, but it applies to=
any setup using `extension_control_path` / `dynamic_library_path`.

Thanks for the report and the very clear diagnosis, = I could
reproduce the issue and your analysis matches what I see.
The attached patch implements exactly what you suggested: a
LOAD runnin= g while creating_extension is true strips the simple
"$libdir/"= ; prefix (so dynamic_library_path is consulted, like
the extension's= own function loads do), while a user-issued
LOAD keeps the literal pref= ix and therefore preserves the
#18920 behaviour.

To avoid duplica= ting the existing prefix-stripping logic in
load_external_function(), I = factored it out into a small
static helper and reused it from load_file(= ).=C2=A0 Nested paths
(e.g. "$libdir/foo/bar") are still left = untouched and continue
to be expanded by expand_dynamic_library_name() a= s before.

Verified locally that the PostGIS-style reproducer now suc= ceeds
when the extension is installed via extension_control_path /
dy= namic_library_path, that a plain user-issued
LOAD '$libdir/foo' = still behaves as on HEAD, and that the
existing extension regression sui= tes still pass.

Regards,
Ayush


--
Gabriele Bartolini
VP, Chief Arch= itect, Kubernetes
enterprisedb.com=C2=A0/ Melbourne, Australia
--000000000000b6b6c706537a2df4--