From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Date: Fri, 5 Jun 2026 12:00:00 +0530
Subject: [PATCH v1] dfmgr: let extension-script LOAD use dynamic_library_path

Commit f777d773878 (fix for bug #18920) restricted the simple "$libdir/"
prefix stripping to load_external_function() so that a user-issued
LOAD '$libdir/foo' would keep the literal "$libdir/" prefix and not
consult dynamic_library_path.

A side effect is that a LOAD '$libdir/foo' executed *inside* an
extension script also keeps the literal prefix, so a hardcoded
"$libdir/" library reference in an extension's SQL script can no
longer be resolved through dynamic_library_path.  This breaks
extensions installed via extension_control_path /
dynamic_library_path (for example PostGIS, whose upgrade scripts do
LOAD '$libdir/postgis-3').

A LOAD running inside an extension script should behave like the
extension's function loads: strip the simple "$libdir/" prefix and
let dynamic_library_path be consulted.  A LOAD issued directly by a
user should keep the literal prefix.  The two are distinguished by
creating_extension.

Factor the existing prefix stripping into a small helper and use it
from load_external_function() unchanged and from load_file() only
while an extension script is being executed.

Reported-by: Gabriele Bartolini
Discussion: https://postgr.es/m/19506-9478f3012ecc2328@postgresql.org
---
 src/backend/utils/fmgr/dfmgr.c | 38 ++++++++++++++++++++++------------
 1 file changed, 25 insertions(+), 13 deletions(-)

diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c
index e636cc81cf8..14b6e5b5c4c 100644
--- a/src/backend/utils/fmgr/dfmgr.c
+++ b/src/backend/utils/fmgr/dfmgr.c
@@ -20,6 +20,7 @@
 #include <dlfcn.h>
 #endif							/* !WIN32 */
 
+#include "commands/extension.h"
 #include "fmgr.h"
 #include "lib/stringinfo.h"
 #include "miscadmin.h"
@@ -71,6 +72,7 @@ char	   *Dynamic_library_path;
 static void *internal_load_library(const char *libname);
 pg_noreturn static void incompatible_module_error(const char *libname,
 												  const Pg_abi_values *module_magic_data);
+static const char *strip_libdir_prefix(const char *filename);
 static char *expand_dynamic_library_name(const char *name);
 static void check_restricted_library_name(const char *name);
 
@@ -99,20 +101,7 @@ load_external_function(const char *filename, const char *funcname,
 	void	   *lib_handle;
 	void	   *retval;
 
-	/*
-	 * For extensions with hardcoded '$libdir/' library names, we strip the
-	 * prefix to allow the library search path to be used. This is done only
-	 * for simple names (e.g., "$libdir/foo"), not for nested paths (e.g.,
-	 * "$libdir/foo/bar").
-	 *
-	 * For nested paths, 'expand_dynamic_library_name' directly expands the
-	 * '$libdir' macro, so we leave them untouched.
-	 */
-	if (strncmp(filename, "$libdir/", 8) == 0)
-	{
-		if (first_dir_separator(filename + 8) == NULL)
-			filename += 8;
-	}
+	filename = strip_libdir_prefix(filename);
 
 	/* Expand the possibly-abbreviated filename to an exact path name */
 	fullname = expand_dynamic_library_name(filename);
@@ -150,6 +139,9 @@ load_file(const char *filename, bool restricted)
 {
 	char	   *fullname;
 
+	if (creating_extension)
+		filename = strip_libdir_prefix(filename);
+
 	/* Apply security restriction if requested */
 	if (restricted)
 		check_restricted_library_name(filename);
@@ -309,6 +301,24 @@ internal_load_library(const char *libname)
 	return file_scanner->handle;
 }
 
+/*
+ * For extensions with hardcoded '$libdir/' library names, strip the prefix to
+ * allow the library search path to be used. This is done only for simple names
+ * (e.g., "$libdir/foo"), not for nested paths (e.g., "$libdir/foo/bar").
+ *
+ * For nested paths, expand_dynamic_library_name() directly expands the
+ * '$libdir' macro, so leave them untouched.
+ */
+static const char *
+strip_libdir_prefix(const char *filename)
+{
+	if (strncmp(filename, "$libdir/", 8) == 0 &&
+		first_dir_separator(filename + 8) == NULL)
+		filename += 8;
+
+	return filename;
+}
+
 /*
  * Report a suitable error for an incompatible magic block.
  */
-- 
2.43.0

base-commit: 7598b5383b16a562bd7e7732eda7d783b34f4615
