Hide duplicate names from extension views

If extensions of equal names were installed in different directories
in the path, the views pg_available_extensions and
pg_available_extension_versions would show all of them, even though
only the first one was actually reachable by CREATE EXTENSION.  To
fix, have those views skip extensions found later in the path if they
have names already found earlier.

Also add a bit of documentation that only the first extension in the
path can be used.

Reported-by: Pierrick <pierrick.chovelon@dalibo.com>
Discussion: https://www.postgresql.org/message-id/flat/8f5a0517-1cb8-4085-ae89-77e7454e27ba%40dalibo.com
This commit is contained in:
Peter Eisentraut 2025-09-15 07:25:22 +02:00
parent 454c046094
commit bf5da5d6ca
3 changed files with 36 additions and 3 deletions

View File

@ -11065,6 +11065,12 @@ extension_control_path = 'C:\tools\postgresql;H:\my_project\share;$system'
string, the default <literal>'$system'</literal> is also assumed.
</para>
<para>
If extensions with equal names are present in multiple directories in
the configured path, only the instance found first in the path will be
used.
</para>
<para>
This parameter can be changed at run time by superusers and users
with the appropriate <literal>SET</literal> privilege, but a

View File

@ -2208,6 +2208,7 @@ pg_available_extensions(PG_FUNCTION_ARGS)
List *locations;
DIR *dir;
struct dirent *de;
List *found_ext = NIL;
/* Build tuplestore to hold the result rows */
InitMaterializedSRF(fcinfo, 0);
@ -2232,6 +2233,7 @@ pg_available_extensions(PG_FUNCTION_ARGS)
{
ExtensionControlFile *control;
char *extname;
String *extname_str;
Datum values[3];
bool nulls[3];
@ -2246,6 +2248,16 @@ pg_available_extensions(PG_FUNCTION_ARGS)
if (strstr(extname, "--"))
continue;
/*
* Ignore already-found names. They are not reachable by the
* path search, so don't shown them.
*/
extname_str = makeString(extname);
if (list_member(found_ext, extname_str))
continue;
else
found_ext = lappend(found_ext, extname_str);
control = new_ExtensionControlFile(extname);
control->control_dir = pstrdup(location);
parse_extension_control_file(control, NULL);
@ -2294,6 +2306,7 @@ pg_available_extension_versions(PG_FUNCTION_ARGS)
List *locations;
DIR *dir;
struct dirent *de;
List *found_ext = NIL;
/* Build tuplestore to hold the result rows */
InitMaterializedSRF(fcinfo, 0);
@ -2318,6 +2331,7 @@ pg_available_extension_versions(PG_FUNCTION_ARGS)
{
ExtensionControlFile *control;
char *extname;
String *extname_str;
if (!is_extension_control_filename(de->d_name))
continue;
@ -2330,6 +2344,16 @@ pg_available_extension_versions(PG_FUNCTION_ARGS)
if (strstr(extname, "--"))
continue;
/*
* Ignore already-found names. They are not reachable by the
* path search, so don't shown them.
*/
extname_str = makeString(extname);
if (list_member(found_ext, extname_str))
continue;
else
found_ext = lappend(found_ext, extname_str);
/* read the control file */
control = new_ExtensionControlFile(extname);
control->control_dir = pstrdup(location);

View File

@ -11,12 +11,15 @@ my $node = PostgreSQL::Test::Cluster->new('node');
$node->init;
# Create a temporary directory for the extension control file
# Create temporary directories for the extension control files
my $ext_dir = PostgreSQL::Test::Utils::tempdir();
mkpath("$ext_dir/extension");
my $ext_dir2 = PostgreSQL::Test::Utils::tempdir();
mkpath("$ext_dir2/extension");
my $ext_name = "test_custom_ext_paths";
create_extension($ext_name, $ext_dir);
create_extension($ext_name, $ext_dir2);
my $ext_name2 = "test_custom_ext_paths_using_directory";
mkpath("$ext_dir/$ext_name2");
@ -26,7 +29,7 @@ create_extension($ext_name2, $ext_dir, $ext_name2);
my $sep = $windows_os ? ";" : ":";
$node->append_conf(
'postgresql.conf', qq{
extension_control_path = '\$system$sep@{[ $windows_os ? ($ext_dir =~ s/\\/\\\\/gr) : $ext_dir ]}'
extension_control_path = '\$system$sep@{[ $windows_os ? ($ext_dir =~ s/\\/\\\\/gr) : $ext_dir ]}$sep@{[ $windows_os ? ($ext_dir2 =~ s/\\/\\\\/gr) : $ext_dir2 ]}'
});
# Start node
@ -34,7 +37,7 @@ $node->start;
my $ecp = $node->safe_psql('postgres', 'show extension_control_path;');
is($ecp, "\$system$sep$ext_dir",
is($ecp, "\$system$sep$ext_dir$sep$ext_dir2",
"custom extension control directory path configured");
$node->safe_psql('postgres', "CREATE EXTENSION $ext_name");