Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit beb1ee9

Browse files
committed
Add extension_destdir GUC
Based on a [patch] by Christophe Berg in the Debian Project, add a new GUC, `extension_destdir`, that prepends a directory prefix for extension loading. This directory is prepended to the `SHAREDIR` paths when loading extensions (control and SQL files), and to the `$libdir` directive when loading modules that back functions. Requires a superuser or user with the appropriate SET privilege. Also document the PGXS `DESTDIR` variable, which should be used to install extensions into the proper destination directory. [patch]: https://salsa.debian.org/postgresql/postgresql/-/blob/17/debian/patches/extension_destdir?ref_type=heads
1 parent ed055d2 commit beb1ee9

File tree

7 files changed

+181
-2
lines changed

7 files changed

+181
-2
lines changed

doc/src/sgml/config.sgml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10418,6 +10418,43 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
1041810418
</listitem>
1041910419
</varlistentry>
1042010420

10421+
<varlistentry id="guc-extension-destdir" xreflabel="extension_destdir">
10422+
<term><varname>extension_destdir</varname> (<type>string</type>)
10423+
<indexterm>
10424+
<primary><varname>extension_destdir</varname> configuration parameter</primary>
10425+
</indexterm>
10426+
</term>
10427+
<listitem>
10428+
<para>
10429+
Specifies a directory prefix into which extensions should be
10430+
installed. Only superusers and users with the appropriate
10431+
<literal>SET</literal> privilege can change this setting. When set,
10432+
the postmaster will search this directory for an extension before
10433+
searching the default paths.
10434+
</para>
10435+
10436+
<para>
10437+
For example, this configuration:
10438+
<programlisting>
10439+
extension_destdir = '/mnt/extensions'
10440+
</programlisting>
10441+
will allow <productname>PostgreSQL</productname> to first look for
10442+
extension control files, SQL files, and loadable modules installed in
10443+
<literal>/mnt/extensions</literal> and fall back on the
10444+
default directories if they're not found there.
10445+
</para>
10446+
10447+
<para>
10448+
Note that the files should be installed in their full paths under the
10449+
<varname>extension_destdir</varname> prefix. When using
10450+
<link linkend="extend-pgxs">PGXS</link> to install an extension, pass
10451+
the destination directory via the <varname>DESTDIR</varname> variable
10452+
to install the files in the proper location. For more information see
10453+
<xref linkend="extend-extensions-files-directory"/>.
10454+
</para>
10455+
</listitem>
10456+
</varlistentry>
10457+
1042110458
</variablelist>
1042210459
</sect2>
1042310460
</sect1>

doc/src/sgml/extend.sgml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,8 @@ RETURNS anycompatible AS ...
669669
<para>
670670
The directory containing the extension's <acronym>SQL</acronym> script
671671
file(s). Unless an absolute path is given, the name is relative to
672-
the installation's <literal>SHAREDIR</literal> directory. The
672+
the <literal>SHAREDIR</literal> under the <xref linkend="guc-extension-destdir"/>
673+
prefix and to the installation's <literal>SHAREDIR</literal> directory. The
673674
default behavior is equivalent to specifying
674675
<literal>directory = 'extension'</literal>.
675676
</para>
@@ -1710,6 +1711,15 @@ include $(PGXS)
17101711
</listitem>
17111712
</varlistentry>
17121713

1714+
<varlistentry id="extend-pgxs-destdir">
1715+
<term><varname>DESTDIR</varname></term>
1716+
<listitem>
1717+
<para>
1718+
install all files under this directory prefix
1719+
</para>
1720+
</listitem>
1721+
</varlistentry>
1722+
17131723
<varlistentry id="extend-pgxs-no-installcheck">
17141724
<term><varname>NO_INSTALLCHECK</varname></term>
17151725
<listitem>

src/backend/commands/extension.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,16 @@ get_extension_control_filename(const char *extname)
337337

338338
get_share_path(my_exec_path, sharepath);
339339
result = (char *) palloc(MAXPGPATH);
340+
/*
341+
* If extension_destdir is set, try to find the file there first
342+
*/
343+
if (*extension_destdir != '\0')
344+
{
345+
snprintf(result, MAXPGPATH, "%s%s/extension/%s.control",
346+
extension_destdir, sharepath, extname);
347+
if (pg_file_exists(result))
348+
return result;
349+
}
340350
snprintf(result, MAXPGPATH, "%s/extension/%s.control",
341351
sharepath, extname);
342352

@@ -376,6 +386,16 @@ get_extension_aux_control_filename(ExtensionControlFile *control,
376386
scriptdir = get_extension_script_directory(control);
377387

378388
result = (char *) palloc(MAXPGPATH);
389+
/*
390+
* If extension_destdir is set, try to find the file there first
391+
*/
392+
if (*extension_destdir != '\0')
393+
{
394+
snprintf(result, MAXPGPATH, "%s%s/%s--%s.control",
395+
extension_destdir, scriptdir, control->name, version);
396+
if (pg_file_exists(result))
397+
return result;
398+
}
379399
snprintf(result, MAXPGPATH, "%s/%s--%s.control",
380400
scriptdir, control->name, version);
381401

@@ -394,6 +414,23 @@ get_extension_script_filename(ExtensionControlFile *control,
394414
scriptdir = get_extension_script_directory(control);
395415

396416
result = (char *) palloc(MAXPGPATH);
417+
/*
418+
* If extension_destdir is set, try to find the file there first
419+
*/
420+
if (*extension_destdir != '\0')
421+
{
422+
if (from_version)
423+
snprintf(result, MAXPGPATH, "%s%s/%s--%s--%s.sql",
424+
extension_destdir, scriptdir, control->name, from_version, version);
425+
else
426+
snprintf(result, MAXPGPATH, "%s%s/%s--%s.sql",
427+
extension_destdir, scriptdir, control->name, version);
428+
if (pg_file_exists(result))
429+
{
430+
pfree(scriptdir);
431+
return result;
432+
}
433+
}
397434
if (from_version)
398435
snprintf(result, MAXPGPATH, "%s/%s--%s--%s.sql",
399436
scriptdir, control->name, from_version, version);
@@ -1153,6 +1190,59 @@ get_ext_ver_list(ExtensionControlFile *control)
11531190
DIR *dir;
11541191
struct dirent *de;
11551192

1193+
/*
1194+
* If extension_destdir is set, try to find the files there first
1195+
*/
1196+
if (*extension_destdir != '\0')
1197+
{
1198+
char location[MAXPGPATH];
1199+
1200+
snprintf(location, MAXPGPATH, "%s%s", extension_destdir,
1201+
get_extension_script_directory(control));
1202+
dir = AllocateDir(location);
1203+
while ((de = ReadDir(dir, location)) != NULL)
1204+
{
1205+
char *vername;
1206+
char *vername2;
1207+
ExtensionVersionInfo *evi;
1208+
ExtensionVersionInfo *evi2;
1209+
1210+
/* must be a .sql file ... */
1211+
if (!is_extension_script_filename(de->d_name))
1212+
continue;
1213+
1214+
/* ... matching extension name followed by separator */
1215+
if (strncmp(de->d_name, control->name, extnamelen) != 0 ||
1216+
de->d_name[extnamelen] != '-' ||
1217+
de->d_name[extnamelen + 1] != '-')
1218+
continue;
1219+
1220+
/* extract version name(s) from 'extname--something.sql' filename */
1221+
vername = pstrdup(de->d_name + extnamelen + 2);
1222+
*strrchr(vername, '.') = '\0';
1223+
vername2 = strstr(vername, "--");
1224+
if (!vername2)
1225+
{
1226+
/* It's an install, not update, script; record its version name */
1227+
evi = get_ext_ver_info(vername, &evi_list);
1228+
evi->installable = true;
1229+
continue;
1230+
}
1231+
*vername2 = '\0'; /* terminate first version */
1232+
vername2 += 2; /* and point to second */
1233+
1234+
/* if there's a third --, it's bogus, ignore it */
1235+
if (strstr(vername2, "--"))
1236+
continue;
1237+
1238+
/* Create ExtensionVersionInfos and link them together */
1239+
evi = get_ext_ver_info(vername, &evi_list);
1240+
evi2 = get_ext_ver_info(vername2, &evi_list);
1241+
evi->reachable = lappend(evi->reachable, evi2);
1242+
}
1243+
FreeDir(dir);
1244+
}
1245+
11561246
location = get_extension_script_directory(control);
11571247
dir = AllocateDir(location);
11581248
while ((de = ReadDir(dir, location)) != NULL)

src/backend/utils/fmgr/dfmgr.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "miscadmin.h"
3636
#include "storage/fd.h"
3737
#include "storage/shmem.h"
38+
#include "utils/guc.h"
3839
#include "utils/hsearch.h"
3940

4041

@@ -419,7 +420,7 @@ expand_dynamic_library_name(const char *name)
419420
{
420421
bool have_slash;
421422
char *new;
422-
char *full;
423+
char *full, *full2;
423424

424425
Assert(name);
425426

@@ -434,6 +435,19 @@ expand_dynamic_library_name(const char *name)
434435
else
435436
{
436437
full = substitute_libpath_macro(name);
438+
/*
439+
* If extension_destdir is set, try to find the file there first
440+
*/
441+
if (*extension_destdir != '\0')
442+
{
443+
full2 = psprintf("%s%s", extension_destdir, full);
444+
if (pg_file_exists(full2))
445+
{
446+
pfree(full);
447+
return full2;
448+
}
449+
pfree(full2);
450+
}
437451
if (pg_file_exists(full))
438452
return full;
439453
pfree(full);
@@ -452,6 +466,19 @@ expand_dynamic_library_name(const char *name)
452466
{
453467
full = substitute_libpath_macro(new);
454468
pfree(new);
469+
/*
470+
* If extension_destdir is set, try to find the file there first
471+
*/
472+
if (*extension_destdir != '\0')
473+
{
474+
full2 = psprintf("%s%s", extension_destdir, full);
475+
if (pg_file_exists(full2))
476+
{
477+
pfree(full);
478+
return full2;
479+
}
480+
pfree(full2);
481+
}
455482
if (pg_file_exists(full))
456483
return full;
457484
pfree(full);

src/backend/utils/misc/guc_tables.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,7 @@ char *ConfigFileName;
539539
char *HbaFileName;
540540
char *IdentFileName;
541541
char *external_pid_file;
542+
char *extension_destdir;
542543

543544
char *application_name;
544545

@@ -4554,6 +4555,17 @@ struct config_string ConfigureNamesString[] =
45544555
check_canonical_path, NULL, NULL
45554556
},
45564557

4558+
{
4559+
{"extension_destdir", PGC_SUSET, FILE_LOCATIONS,
4560+
gettext_noop("Path to prepend for extension loading."),
4561+
gettext_noop("This directory is prepended to paths when loading extensions (control and SQL files), and to the '$libdir' directive when loading modules that back functions. The location is made configurable to allow build-time testing of extensions that do not have been installed to their proper location yet."),
4562+
GUC_SUPERUSER_ONLY
4563+
},
4564+
&extension_destdir,
4565+
"",
4566+
NULL, NULL, NULL
4567+
},
4568+
45574569
{
45584570
{"ssl_library", PGC_INTERNAL, PRESET_OPTIONS,
45594571
gettext_noop("Shows the name of the SSL library."),

src/backend/utils/misc/postgresql.conf.sample

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,8 @@
771771
# - Other Defaults -
772772

773773
#dynamic_library_path = '$libdir'
774+
#extension_destdir = '' # prepend path when loading extensions
775+
# and shared objects (added by Debian)
774776
#gin_fuzzy_search_limit = 0
775777

776778

src/include/utils/guc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ extern PGDLLIMPORT char *ConfigFileName;
285285
extern PGDLLIMPORT char *HbaFileName;
286286
extern PGDLLIMPORT char *IdentFileName;
287287
extern PGDLLIMPORT char *external_pid_file;
288+
extern PGDLLIMPORT char *extension_destdir;
288289

289290
extern PGDLLIMPORT char *application_name;
290291

0 commit comments

Comments
 (0)