From bb12060e42c2b62bdd71d87099d3919d25f0c5da Mon Sep 17 00:00:00 2001 From: "Chao Li (Evan)" Date: Tue, 3 Nov 2026 09:55:18 +0800 Subject: [PATCH v1 1/2] Ignore empty elements in extension_control_path Skip empty elements before appending the extension directory suffix, so leading, trailing, and repeated separators do not add /extension to the search path. Preserve the documented system-directory default for an entirely empty setting. Document the behavior and cover empty elements in the extension control path TAP tests. Author: Chao Li --- doc/src/sgml/config.sgml | 2 ++ src/backend/commands/extension.c | 16 ++++++++++++- .../t/001_extension_control_path.pl | 24 +++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index f7db2995c3e..eb9574e3dbc 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -11736,6 +11736,8 @@ extension_control_path = 'C:\tools\postgresql;H:\my_project\share;$system' The default value for this parameter is '$system'. If the value is set to an empty string, the default '$system' is also assumed. + Empty elements within a nonempty value are ignored. A value consisting + only of separators searches no directories. diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index 5855668c5ca..6ef4bdb3faf 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -541,7 +541,7 @@ get_extension_control_directories(void) int len; char *mangled; char *piece = first_path_var_separator(ecp); - ExtensionLocation *location = palloc_object(ExtensionLocation); + ExtensionLocation *location; /* Get the length of the next path on ecp */ if (piece == NULL) @@ -549,6 +549,17 @@ get_extension_control_directories(void) else len = piece - ecp; + /* Ignore empty path elements, including a trailing one. */ + if (len == 0) + { + if (ecp[len] == '\0') + break; + ecp += len + 1; + continue; + } + + location = palloc_object(ExtensionLocation); + /* Copy the next path found on ecp */ piece = palloc(len + 1); strlcpy(piece, ecp, len + 1); @@ -582,6 +593,9 @@ get_extension_control_directories(void) } } + foreach_ptr(ExtensionLocation, location, paths) + elog(DEBUG3, "%s: path \"%s\"", __func__, location->loc); + return paths; #undef EXTENSION_SYSTEM_MACRO } diff --git a/src/test/modules/test_extensions/t/001_extension_control_path.pl b/src/test/modules/test_extensions/t/001_extension_control_path.pl index 4a013a7da4b..7c42561f5bc 100644 --- a/src/test/modules/test_extensions/t/001_extension_control_path.pl +++ b/src/test/modules/test_extensions/t/001_extension_control_path.pl @@ -115,6 +115,30 @@ is($ret, "\$system", "\$system location is shown correctly in pg_available_extensions with empty extension_control_path" ); +# Empty path elements must not add /extension to the search path. +my $path_message = qr/get_extension_control_directories: path/; +for my $path ( + "$sep$ext_dir_canonicalized", + "$ext_dir_canonicalized$sep", + $sep) +{ + my $stderr; + $node->psql( + 'postgres', + "set client_min_messages = debug3; + set extension_control_path = '$path'; + select count(*) from pg_available_extensions", + stderr => \$stderr, + on_error_die => 1); + if ($path ne $sep) + { + like($stderr, qr{$path_message "\Q$ext_dir_canonicalized\E/extension"}, + "custom directory is searched with path '$path'"); + } + unlike($stderr, qr{$path_message "/extension"}, + "empty elements should not search /extension with path '$path'"); +} + # Test with an extension that does not exists my ($code, $stdout, $stderr) = $node->psql('postgres', "CREATE EXTENSION invalid"); -- 2.50.1 (Apple Git-155)