Add server support for "plugin" libraries that can be used for add-on tasks

such as debugging and performance measurement.  This consists of two features:
a table of "rendezvous variables" that allows separately-loaded shared
libraries to communicate, and a new GUC setting "local_preload_libraries"
that allows libraries to be loaded into specific sessions without explicit
cooperation from the client application.  To make local_preload_libraries
as flexible as possible, we do not restrict its use to superusers; instead,
it is restricted to load only libraries stored in $libdir/plugins/.  The
existing LOAD command has also been modified to allow non-superusers to
LOAD libraries stored in this directory.

This patch also renames the existing GUC variable preload_libraries to
shared_preload_libraries (after a suggestion by Simon Riggs) and does some
code refactoring in dfmgr.c to improve clarity.

Korry Douglas, with a little help from Tom Lane.
This commit is contained in:
Tom Lane 2006-08-15 18:26:59 +00:00
parent 66541c5aa5
commit abc3120e9b
11 changed files with 353 additions and 113 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.73 2006/08/08 19:15:07 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.74 2006/08/15 18:26:58 tgl Exp $ -->
<chapter Id="runtime-config">
<title>Server Configuration</title>
@ -949,10 +949,10 @@ SET ENABLE_SEQSCAN TO OFF;
</listitem>
</varlistentry>
<varlistentry id="guc-preload-libraries" xreflabel="preload_libraries">
<term><varname>preload_libraries</varname> (<type>string</type>)</term>
<varlistentry id="guc-shared-preload-libraries" xreflabel="shared_preload_libraries">
<term><varname>shared_preload_libraries</varname> (<type>string</type>)</term>
<indexterm>
<primary><varname>preload_libraries</> configuration parameter</primary>
<primary><varname>shared_preload_libraries</> configuration parameter</primary>
</indexterm>
<listitem>
<para>
@ -963,6 +963,7 @@ SET ENABLE_SEQSCAN TO OFF;
<literal>mylib.so</> (or on some platforms,
<literal>mylib.sl</>) to be preloaded from the installation's
standard library directory.
This parameter can only be set at server start.
</para>
<para>
@ -3642,6 +3643,60 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</para>
</listitem>
</varlistentry>
<varlistentry id="guc-local-preload-libraries" xreflabel="local_preload_libraries">
<term><varname>local_preload_libraries</varname> (<type>string</type>)</term>
<indexterm>
<primary><varname>local_preload_libraries</> configuration parameter</primary>
</indexterm>
<indexterm>
<primary><filename>$libdir/plugins</></primary>
</indexterm>
<listitem>
<para>
This variable specifies one or more shared libraries that are
to be preloaded at connection start. If more than one library
is to be loaded, separate their names with commas.
This parameter cannot be changed after the start of a particular
session.
</para>
<para>
Because this is not a superuser-only option, the libraries
that can be loaded are restricted to those appearing in the
<filename>plugins</> subdirectory of the installation's
standard library directory. (It is the database administrator's
responsibility to ensure that only <quote>safe</> libraries
are installed there.) Entries in <varname>local_preload_libraries</>
can specify this directory explicitly, for example
<literal>$libdir/plugins/mylib</literal>, or just specify
the library name &mdash; <literal>mylib</literal> would have
the same effect as <literal>$libdir/plugins/mylib</literal>.
</para>
<para>
There is no performance advantage to loading a library at session
start rather than when it is first used. Rather, the intent of
this feature is to allow debugging or performance-measurement
libraries to be loaded into specific sessions without an explicit
<command>LOAD</> command being given. For example, debugging could
be enabled for all sessions under a given user name by setting
this parameter with <command>ALTER USER SET</>.
</para>
<para>
If a specified library is not found,
the connection attempt will fail.
</para>
<para>
Every PostgreSQL-supported library has a <quote>magic
block</> that is checked to guarantee compatibility.
For this reason, non-PostgreSQL libraries cannot be
loaded in this way.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/load.sgml,v 1.21 2005/01/04 00:39:53 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/load.sgml,v 1.22 2006/08/15 18:26:58 tgl Exp $
-->
<refentry id="SQL-LOAD">
@ -44,6 +44,19 @@ LOAD '<replaceable class="PARAMETER">filename</replaceable>'
shared library file name extension. See <xref linkend="xfunc-c"> for
more information on this topic.
</para>
<indexterm>
<primary><filename>$libdir/plugins</></primary>
</indexterm>
<para>
Non-superusers may only apply <command>LOAD</> to library files
located in <filename>$libdir/plugins/</> &mdash; the specified
<replaceable class="PARAMETER">filename</replaceable> must begin
with exactly that string. (It is the database administrator's
responsibility to ensure that only <quote>safe</> libraries
are installed there.)
</para>
</refsect1>
<refsect1 id="sql-load-compat">

View File

@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.498 2006/08/08 19:15:07 tgl Exp $
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.499 2006/08/15 18:26:58 tgl Exp $
*
* NOTES
*
@ -709,7 +709,7 @@ PostmasterMain(int argc, char *argv[])
/*
* process any libraries that should be preloaded at postmaster start
*/
process_preload_libraries();
process_shared_preload_libraries();
/*
* Remove old temporary files. At this point there can be no other

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.498 2006/08/13 22:18:08 tgl Exp $
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.499 2006/08/15 18:26:58 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@ -3000,6 +3000,12 @@ PostgresMain(int argc, char *argv[], const char *username)
if (IsUnderPostmaster && Log_disconnections)
on_proc_exit(log_disconnections, 0);
/*
* process any libraries that should be preloaded at backend start
* (this likewise can't be done until GUC settings are complete)
*/
process_local_preload_libraries();
/*
* Send this backend's cancellation info to the frontend.
*/

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.265 2006/08/12 20:05:56 tgl Exp $
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.266 2006/08/15 18:26:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -886,12 +886,9 @@ ProcessUtility(Node *parsetree,
{
LoadStmt *stmt = (LoadStmt *) parsetree;
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to do LOAD")));
closeAllVfds(); /* probably not necessary... */
load_file(stmt->filename);
/* Allowed names are restricted if you're not superuser */
load_file(stmt->filename, !superuser());
}
break;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.87 2006/08/08 19:15:08 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.88 2006/08/15 18:26:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -23,12 +23,20 @@
#endif
#include "miscadmin.h"
#include "utils/dynamic_loader.h"
#include "utils/hsearch.h"
/* signatures for PostgreSQL-specific library init/fini functions */
typedef void (*PG_init_t)(void);
typedef void (*PG_fini_t)(void);
/* hashtable entry for rendezvous variables */
typedef struct
{
char varName[NAMEDATALEN]; /* hash key (must be first) */
void *varValue;
} rendezvousHashEntry;
/*
* List of dynamically loaded files (kept in malloc'd memory).
*/
@ -62,10 +70,13 @@ static DynamicFileList *file_tail = NULL;
char *Dynamic_library_path;
static void *internal_load_library(const char *libname);
static void internal_unload_library(const char *libname);
static bool file_exists(const char *name);
static char *find_in_dynamic_libpath(const char *basename);
static char *expand_dynamic_library_name(const char *name);
static void check_restricted_library_name(const char *name);
static char *substitute_libpath_macro(const char *name);
static char *find_in_dynamic_libpath(const char *basename);
/* Magic structure that module needs to match to be accepted */
static const Pg_magic_struct magic_data = PG_MODULE_MAGIC_DATA;
@ -73,7 +84,7 @@ static const Pg_magic_struct magic_data = PG_MODULE_MAGIC_DATA;
/*
* Load the specified dynamic-link library file, and look for a function
* named funcname in it. (funcname can be NULL to just load the file.)
* named funcname in it.
*
* If the function is not found, we raise an error if signalNotFound is true,
* else return (PGFunction) NULL. Note that errors in loading the library
@ -88,37 +99,107 @@ PGFunction
load_external_function(char *filename, char *funcname,
bool signalNotFound, void **filehandle)
{
DynamicFileList *file_scanner;
char *fullname;
void *lib_handle;
PGFunction retval;
/* Expand the possibly-abbreviated filename to an exact path name */
fullname = expand_dynamic_library_name(filename);
/* Load the shared library, unless we already did */
lib_handle = internal_load_library(fullname);
/* Return handle if caller wants it */
if (filehandle)
*filehandle = lib_handle;
/* Look up the function within the library */
retval = pg_dlsym(lib_handle, funcname);
if (retval == NULL && signalNotFound)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("could not find function \"%s\" in file \"%s\"",
funcname, fullname)));
pfree(fullname);
return retval;
}
/*
* This function loads a shlib file without looking up any particular
* function in it. If the same shlib has previously been loaded,
* unload and reload it.
*
* When 'restrict' is true, only libraries in the presumed-secure
* directory $libdir/plugins may be referenced.
*/
void
load_file(const char *filename, bool restrict)
{
char *fullname;
/* Apply security restriction if requested */
if (restrict)
check_restricted_library_name(filename);
/* Expand the possibly-abbreviated filename to an exact path name */
fullname = expand_dynamic_library_name(filename);
/* Unload the library if currently loaded */
internal_unload_library(fullname);
/* Load the shared library */
(void) internal_load_library(fullname);
pfree(fullname);
}
/*
* Lookup a function whose library file is already loaded.
* Return (PGFunction) NULL if not found.
*/
PGFunction
lookup_external_function(void *filehandle, char *funcname)
{
return pg_dlsym(filehandle, funcname);
}
/*
* Load the specified dynamic-link library file, unless it already is
* loaded. Return the pg_dl* handle for the file.
*
* Note: libname is expected to be an exact name for the library file.
*/
static void *
internal_load_library(const char *libname)
{
DynamicFileList *file_scanner;
PGModuleMagicFunction magic_func;
char *load_error;
struct stat stat_buf;
char *fullname;
PG_init_t PG_init;
fullname = expand_dynamic_library_name(filename);
if (!fullname)
fullname = pstrdup(filename);
/* at this point fullname is always freshly palloc'd */
/*
* Scan the list of loaded FILES to see if the file has been loaded.
*/
for (file_scanner = file_list;
file_scanner != NULL &&
strcmp(fullname, file_scanner->filename) != 0;
strcmp(libname, file_scanner->filename) != 0;
file_scanner = file_scanner->next)
;
if (file_scanner == NULL)
{
/*
* Check for same files - different paths (ie, symlink or link)
*/
if (stat(fullname, &stat_buf) == -1)
if (stat(libname, &stat_buf) == -1)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not access file \"%s\": %m",
fullname)));
libname)));
for (file_scanner = file_list;
file_scanner != NULL &&
@ -133,21 +214,21 @@ load_external_function(char *filename, char *funcname,
* File not loaded yet.
*/
file_scanner = (DynamicFileList *)
malloc(sizeof(DynamicFileList) + strlen(fullname));
malloc(sizeof(DynamicFileList) + strlen(libname));
if (file_scanner == NULL)
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory")));
MemSet(file_scanner, 0, sizeof(DynamicFileList));
strcpy(file_scanner->filename, fullname);
strcpy(file_scanner->filename, libname);
file_scanner->device = stat_buf.st_dev;
#ifndef WIN32
file_scanner->inode = stat_buf.st_ino;
#endif
file_scanner->next = NULL;
file_scanner->handle = pg_dlopen(fullname);
file_scanner->handle = pg_dlopen(file_scanner->filename);
if (file_scanner->handle == NULL)
{
load_error = (char *) pg_dlerror();
@ -156,7 +237,7 @@ load_external_function(char *filename, char *funcname,
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not load library \"%s\": %s",
fullname, load_error)));
libname, load_error)));
}
/* Check the magic function to determine compatibility */
@ -184,7 +265,7 @@ load_external_function(char *filename, char *funcname,
if (module_magic_data.version != magic_data.version)
ereport(ERROR,
(errmsg("incompatible library \"%s\": version mismatch",
fullname),
libname),
errdetail("Server is version %d.%d, library is version %d.%d.",
magic_data.version/100,
magic_data.version % 100,
@ -192,7 +273,7 @@ load_external_function(char *filename, char *funcname,
module_magic_data.version % 100)));
ereport(ERROR,
(errmsg("incompatible library \"%s\": magic block mismatch",
fullname)));
libname)));
}
}
else
@ -203,7 +284,7 @@ load_external_function(char *filename, char *funcname,
/* complain */
ereport(ERROR,
(errmsg("incompatible library \"%s\": missing magic block",
fullname),
libname),
errhint("Extension libraries are now required to use the PG_MODULE_MAGIC macro.")));
}
@ -222,77 +303,48 @@ load_external_function(char *filename, char *funcname,
file_tail = file_scanner;
}
/* Return handle if caller wants it. */
if (filehandle)
*filehandle = file_scanner->handle;
/*
* If funcname is NULL, we only wanted to load the file.
*/
if (funcname == NULL)
{
pfree(fullname);
return NULL;
}
retval = pg_dlsym(file_scanner->handle, funcname);
if (retval == NULL && signalNotFound)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("could not find function \"%s\" in file \"%s\"",
funcname, fullname)));
pfree(fullname);
return retval;
return file_scanner->handle;
}
/*
* This function loads a shlib file without looking up any particular
* function in it. If the same shlib has previously been loaded,
* unload and reload it.
* Unload the specified dynamic-link library file, if it is loaded.
*
* Note: libname is expected to be an exact name for the library file.
*/
void
load_file(char *filename)
static void
internal_unload_library(const char *libname)
{
DynamicFileList *file_scanner,
*prv,
*nxt;
struct stat stat_buf;
char *fullname;
PG_fini_t PG_fini;
fullname = expand_dynamic_library_name(filename);
if (!fullname)
fullname = pstrdup(filename);
/* at this point fullname is always freshly palloc'd */
/*
* We need to do stat() in order to determine whether this is the same
* file as a previously loaded file; it's also handy so as to give a good
* error message if bogus file name given.
*/
if (stat(fullname, &stat_buf) == -1)
if (stat(libname, &stat_buf) == -1)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not access file \"%s\": %m", fullname)));
errmsg("could not access file \"%s\": %m", libname)));
/*
* We have to zap all entries in the list that match on either filename or
* inode, else load_external_function() won't do anything.
* inode, else internal_load_library() will still think it's present.
*/
prv = NULL;
for (file_scanner = file_list; file_scanner != NULL; file_scanner = nxt)
{
nxt = file_scanner->next;
if (strcmp(fullname, file_scanner->filename) == 0 ||
if (strcmp(libname, file_scanner->filename) == 0 ||
SAME_INODE(stat_buf, *file_scanner))
{
if (prv)
prv->next = nxt;
else
file_list = nxt;
clear_external_function_hash(file_scanner->handle);
/*
* If the library has a _PG_fini() function, call it.
@ -301,6 +353,7 @@ load_file(char *filename)
if (PG_fini)
(*PG_fini)();
clear_external_function_hash(file_scanner->handle);
pg_dlclose(file_scanner->handle);
free((char *) file_scanner);
/* prv does not change */
@ -308,23 +361,8 @@ load_file(char *filename)
else
prv = file_scanner;
}
load_external_function(fullname, NULL, false, NULL);
pfree(fullname);
}
/*
* Lookup a function whose library file is already loaded.
* Return (PGFunction) NULL if not found.
*/
PGFunction
lookup_external_function(void *filehandle, char *funcname)
{
return pg_dlsym(filehandle, funcname);
}
static bool
file_exists(const char *name)
{
@ -353,9 +391,9 @@ file_exists(const char *name)
* the name. Else (no slash) try to expand using search path (see
* find_in_dynamic_libpath below); if that works, return the fully
* expanded file name. If the previous failed, append DLSUFFIX and
* try again. If all fails, return NULL.
* try again. If all fails, just return the original name.
*
* A non-NULL result will always be freshly palloc'd.
* The result will always be freshly palloc'd.
*/
static char *
expand_dynamic_library_name(const char *name)
@ -402,9 +440,28 @@ expand_dynamic_library_name(const char *name)
pfree(full);
}
return NULL;
/*
* If we can't find the file, just return the string as-is.
* The ensuing load attempt will fail and report a suitable message.
*/
return pstrdup(name);
}
/*
* Check a restricted library name. It must begin with "$libdir/plugins/"
* and there must not be any directory separators after that (this is
* sufficient to prevent ".." style attacks).
*/
static void
check_restricted_library_name(const char *name)
{
if (strncmp(name, "$libdir/plugins/", 16) != 0 ||
first_dir_separator(name + 16) != NULL)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("access to library \"%s\" is not allowed",
name)));
}
/*
* Substitute for any macros appearing in the given string.
@ -418,6 +475,7 @@ substitute_libpath_macro(const char *name)
AssertArg(name != NULL);
/* Currently, we only recognize $libdir at the start of the string */
if (name[0] != '$')
return pstrdup(name);
@ -428,7 +486,8 @@ substitute_libpath_macro(const char *name)
strncmp(name, "$libdir", strlen("$libdir")) != 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_NAME),
errmsg("invalid macro name in dynamic library path: %s", name)));
errmsg("invalid macro name in dynamic library path: %s",
name)));
ret = palloc(strlen(pkglib_path) + strlen(sep_ptr) + 1);
@ -513,3 +572,58 @@ find_in_dynamic_libpath(const char *basename)
return NULL;
}
/*
* Find (or create) a rendezvous variable that one dynamically
* loaded library can use to meet up with another.
*
* On the first call of this function for a particular varName,
* a "rendezvous variable" is created with the given name.
* The value of the variable is a void pointer (initially set to NULL).
* Subsequent calls with the same varName just return the address of
* the existing variable. Once created, a rendezvous variable lasts
* for the life of the process.
*
* Dynamically loaded libraries can use rendezvous variables
* to find each other and share information: they just need to agree
* on the variable name and the data it will point to.
*/
void **
find_rendezvous_variable(const char *varName)
{
static HTAB *rendezvousHash = NULL;
char key[NAMEDATALEN];
rendezvousHashEntry *hentry;
bool found;
/* Create a hashtable if we haven't already done so in this process */
if (rendezvousHash == NULL)
{
HASHCTL ctl;
MemSet(&ctl, 0, sizeof(ctl));
ctl.keysize = NAMEDATALEN;
ctl.entrysize = sizeof(rendezvousHashEntry);
rendezvousHash = hash_create("Rendezvous variable hash",
16,
&ctl,
HASH_ELEM);
}
/* Turn the varName into a fixed-size string */
StrNCpy(key, varName, sizeof(key));
/* Find or create the hashtable entry for this varName */
hentry = (rendezvousHashEntry *) hash_search(rendezvousHash,
key,
HASH_ENTER,
&found);
/* Initialize to NULL if first time */
if (!found)
hentry->varValue = NULL;
return &hentry->varValue;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.156 2006/08/08 19:15:08 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.157 2006/08/15 18:26:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1097,24 +1097,31 @@ ValidatePgVersion(const char *path)
*-------------------------------------------------------------------------
*/
/* GUC variable: list of library names to be preloaded */
char *preload_libraries_string = NULL;
/*
* GUC variables: lists of library names to be preloaded at postmaster
* start and at backend start
*/
char *shared_preload_libraries_string = NULL;
char *local_preload_libraries_string = NULL;
/*
* process any libraries that should be preloaded at postmaster start
* load the shared libraries listed in 'libraries'
*
* 'gucname': name of GUC variable, for error reports
* 'restrict': if true, force libraries to be in $libdir/plugins/
*/
void
process_preload_libraries(void)
static void
load_libraries(const char *libraries, const char *gucname, bool restrict)
{
char *rawstring;
List *elemlist;
ListCell *l;
if (preload_libraries_string == NULL)
return;
if (libraries == NULL || libraries[0] == '\0')
return; /* nothing to do */
/* Need a modifiable copy of string */
rawstring = pstrdup(preload_libraries_string);
rawstring = pstrdup(libraries);
/* Parse string into list of identifiers */
if (!SplitIdentifierString(rawstring, ',', &elemlist))
@ -1124,7 +1131,8 @@ process_preload_libraries(void)
list_free(elemlist);
ereport(LOG,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("invalid list syntax for parameter \"preload_libraries\"")));
errmsg("invalid list syntax in parameter \"%s\"",
gucname)));
return;
}
@ -1135,12 +1143,45 @@ process_preload_libraries(void)
filename = pstrdup(tok);
canonicalize_path(filename);
(void) load_external_function(filename, NULL, true, NULL);
/* If restricting, insert $libdir/plugins if not mentioned already */
if (restrict && first_dir_separator(filename) == NULL)
{
char *expanded;
expanded = palloc(strlen("$libdir/plugins/") + strlen(filename) + 1);
strcpy(expanded, "$libdir/plugins/");
strcat(expanded, filename);
pfree(filename);
filename = expanded;
}
load_file(filename, restrict);
ereport(LOG,
(errmsg("preloaded library \"%s\"", filename)));
(errmsg("loaded library \"%s\"", filename)));
pfree(filename);
}
pfree(rawstring);
list_free(elemlist);
}
/*
* process any libraries that should be preloaded at postmaster start
*/
void
process_shared_preload_libraries(void)
{
load_libraries(shared_preload_libraries_string,
"shared_preload_libraries",
false);
}
/*
* process any libraries that should be preloaded at backend start
*/
void
process_local_preload_libraries(void)
{
load_libraries(local_preload_libraries_string,
"local_preload_libraries",
true);
}

View File

@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.341 2006/08/14 02:27:26 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.342 2006/08/15 18:26:59 tgl Exp $
*
*--------------------------------------------------------------------
*/
@ -1964,12 +1964,22 @@ static struct config_string ConfigureNamesString[] =
},
{
{"preload_libraries", PGC_POSTMASTER, RESOURCES_KERNEL,
{"shared_preload_libraries", PGC_POSTMASTER, RESOURCES_KERNEL,
gettext_noop("Lists shared libraries to preload into server."),
NULL,
GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_SUPERUSER_ONLY
},
&preload_libraries_string,
&shared_preload_libraries_string,
"", NULL, NULL
},
{
{"local_preload_libraries", PGC_BACKEND, CLIENT_CONN_OTHER,
gettext_noop("Lists shared libraries to preload into each backend."),
NULL,
GUC_LIST_INPUT | GUC_LIST_QUOTE
},
&local_preload_libraries_string,
"", NULL, NULL
},

View File

@ -120,7 +120,7 @@
#max_files_per_process = 1000 # min 25
# (change requires restart)
#preload_libraries = '' # (change requires restart)
#shared_preload_libraries = '' # (change requires restart)
# - Cost-Based Vacuum Delay -
@ -419,6 +419,7 @@
#explain_pretty_print = on
#dynamic_library_path = '$libdir'
#local_preload_libraries = ''
#---------------------------------------------------------------------------

View File

@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/fmgr.h,v 1.45 2006/05/31 20:58:09 tgl Exp $
* $PostgreSQL: pgsql/src/include/fmgr.h,v 1.46 2006/08/15 18:26:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -488,7 +488,8 @@ extern char *Dynamic_library_path;
extern PGFunction load_external_function(char *filename, char *funcname,
bool signalNotFound, void **filehandle);
extern PGFunction lookup_external_function(void *filehandle, char *funcname);
extern void load_file(char *filename);
extern void load_file(const char *filename, bool restrict);
extern void **find_rendezvous_variable(const char *varName);
/*

View File

@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.187 2006/08/08 19:15:08 tgl Exp $
* $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.188 2006/08/15 18:26:59 tgl Exp $
*
* NOTES
* some of the information in this file should be moved to other files.
@ -307,7 +307,8 @@ extern void BaseInit(void);
/* in utils/init/miscinit.c */
extern bool IgnoreSystemIndexes;
extern char *preload_libraries_string;
extern char *shared_preload_libraries_string;
extern char *local_preload_libraries_string;
extern void SetReindexProcessing(Oid heapOid, Oid indexOid);
extern void ResetReindexProcessing(void);
@ -319,6 +320,7 @@ extern void TouchSocketLockFile(void);
extern void RecordSharedMemoryInLockFile(unsigned long id1,
unsigned long id2);
extern void ValidatePgVersion(const char *path);
extern void process_preload_libraries(void);
extern void process_shared_preload_libraries(void);
extern void process_local_preload_libraries(void);
#endif /* MISCADMIN_H */