From 4ecaa7c65dcd1f2f843158fa554e14944096ba81 Mon Sep 17 00:00:00 2001
From: Jakob Egger <jakob@eggerapps.at>
Date: Mon, 1 Jun 2026 15:00:34 +0200
Subject: [PATCH] glob support in extension_search_path and
 dynamic_library_path

---
 src/backend/commands/extension.c | 40 ++++++++++++++++++++++++++++----
 src/backend/utils/fmgr/dfmgr.c   | 37 +++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+), 4 deletions(-)

diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index d073585c421..24348e4dcdc 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -28,6 +28,9 @@
 #include <sys/file.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#ifndef WIN32
+#include <glob.h>
+#endif
 
 #include "access/genam.h"
 #include "access/htup_details.h"
@@ -541,7 +544,13 @@ get_extension_control_directories(void)
 			int			len;
 			char	   *mangled;
 			char	   *piece = first_path_var_separator(ecp);
-			ExtensionLocation *location = palloc_object(ExtensionLocation);
+			char	   *macro;
+#ifndef WIN32
+			glob_t		globres;
+			int			glob_status;
+			int			i;
+#endif
+			ExtensionLocation *location;
 
 			/* Get the length of the next path on ecp */
 			if (piece == NULL)
@@ -559,20 +568,43 @@ get_extension_control_directories(void)
 			 */
 			if (strcmp(piece, EXTENSION_SYSTEM_MACRO) == 0)
 			{
-				location->macro = pstrdup(piece);
+				macro = pstrdup(piece);
 				mangled = substitute_path_macro(piece, EXTENSION_SYSTEM_MACRO, system_dir);
 			}
 			else
 			{
-				location->macro = NULL;
+				macro = NULL;
 				mangled = psprintf("%s/extension", piece);
 			}
 			pfree(piece);
 
-			/* Canonicalize the path based on the OS and add to the list */
+			/* Canonicalize the path based on the OS */
 			canonicalize_path(mangled);
+
+#ifndef WIN32
+			glob_status = glob(mangled, GLOB_BRACE | GLOB_ERR, NULL, &globres);
+			if (glob_status != 0)
+			{
+				if (glob_status == GLOB_NOMATCH)
+					elog(DEBUG3, "extension_search_path: glob(%s) returned no match", mangled);
+				else
+					ereport(ERROR,
+							(errcode(ERRCODE_CONFIG_FILE_ERROR),
+							 errmsg("extension_search_path: glob(%s) returned %d", mangled, glob_status)));
+			}
+			for (i=0;i < globres.gl_pathc; i++) {
+				location = palloc_object(ExtensionLocation);
+				location->macro = macro;
+				location->loc = pstrdup(globres.gl_pathv[i]);
+				paths = lappend(paths, location);
+			}
+			globfree(&globres);
+#else
+			location = palloc_object(ExtensionLocation);
+			location->macro = macro;
 			location->loc = mangled;
 			paths = lappend(paths, location);
+#endif
 
 			/* Break if ecp is empty or move to the next path on ecp */
 			if (ecp[len] == '\0')
diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c
index e636cc81cf8..6d5d072a8aa 100644
--- a/src/backend/utils/fmgr/dfmgr.c
+++ b/src/backend/utils/fmgr/dfmgr.c
@@ -18,6 +18,7 @@
 
 #ifndef WIN32
 #include <dlfcn.h>
+#include <glob.h>
 #endif							/* !WIN32 */
 
 #include "fmgr.h"
@@ -598,6 +599,11 @@ find_in_path(const char *basename, const char *path, const char *path_param,
 		char	   *piece;
 		char	   *mangled;
 		char	   *full;
+#ifndef WIN32
+		glob_t		globres;
+		int			glob_status;
+		int			i;
+#endif
 
 		piece = first_path_var_separator(p);
 		if (piece == p)
@@ -624,6 +630,36 @@ find_in_path(const char *basename, const char *path, const char *path_param,
 					(errcode(ERRCODE_INVALID_NAME),
 					 errmsg("component in parameter \"%s\" is not an absolute path", path_param)));
 
+#ifndef WIN32
+		glob_status = glob(mangled, GLOB_BRACE | GLOB_ERR, NULL, &globres);
+		if (glob_status != 0)
+		{
+			if (glob_status == GLOB_NOMATCH)
+				elog(DEBUG3, "%s: glob(%s) returned no match", path_param, mangled);
+			else
+				ereport(ERROR,
+						(errcode(ERRCODE_CONFIG_FILE_ERROR),
+						 errmsg("%s: glob(%s) returned %d", path_param, mangled, glob_status)));
+		}
+		pfree(mangled);
+		for (i=0;i < globres.gl_pathc; i++)
+		{
+			mangled = globres.gl_pathv[i];
+			full = palloc(strlen(mangled) + 1 + baselen + 1);
+			sprintf(full, "%s/%s", mangled, basename);
+
+			elog(DEBUG3, "%s: trying \"%s\"", __func__, full);
+
+			if (pg_file_exists(full))
+			{
+				globfree(&globres);
+				return full;
+			}
+
+			pfree(full);
+		}
+		globfree(&globres);
+#else
 		full = palloc(strlen(mangled) + 1 + baselen + 1);
 		sprintf(full, "%s/%s", mangled, basename);
 		pfree(mangled);
@@ -634,6 +670,7 @@ find_in_path(const char *basename, const char *path, const char *path_param,
 			return full;
 
 		pfree(full);
+#endif
 
 		if (p[len] == '\0')
 			break;
-- 
2.50.1 (Apple Git-155)

