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:
parent
66541c5aa5
commit
abc3120e9b
@ -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">
|
<chapter Id="runtime-config">
|
||||||
<title>Server Configuration</title>
|
<title>Server Configuration</title>
|
||||||
@ -949,10 +949,10 @@ SET ENABLE_SEQSCAN TO OFF;
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="guc-preload-libraries" xreflabel="preload_libraries">
|
<varlistentry id="guc-shared-preload-libraries" xreflabel="shared_preload_libraries">
|
||||||
<term><varname>preload_libraries</varname> (<type>string</type>)</term>
|
<term><varname>shared_preload_libraries</varname> (<type>string</type>)</term>
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary><varname>preload_libraries</> configuration parameter</primary>
|
<primary><varname>shared_preload_libraries</> configuration parameter</primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
@ -963,6 +963,7 @@ SET ENABLE_SEQSCAN TO OFF;
|
|||||||
<literal>mylib.so</> (or on some platforms,
|
<literal>mylib.so</> (or on some platforms,
|
||||||
<literal>mylib.sl</>) to be preloaded from the installation's
|
<literal>mylib.sl</>) to be preloaded from the installation's
|
||||||
standard library directory.
|
standard library directory.
|
||||||
|
This parameter can only be set at server start.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -3642,6 +3643,60 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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 — <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>
|
</variablelist>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
@ -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">
|
<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
|
shared library file name extension. See <xref linkend="xfunc-c"> for
|
||||||
more information on this topic.
|
more information on this topic.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<indexterm>
|
||||||
|
<primary><filename>$libdir/plugins</></primary>
|
||||||
|
</indexterm>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Non-superusers may only apply <command>LOAD</> to library files
|
||||||
|
located in <filename>$libdir/plugins/</> — 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>
|
||||||
|
|
||||||
<refsect1 id="sql-load-compat">
|
<refsect1 id="sql-load-compat">
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* NOTES
|
||||||
*
|
*
|
||||||
@ -709,7 +709,7 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
/*
|
/*
|
||||||
* process any libraries that should be preloaded at postmaster start
|
* 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
|
* Remove old temporary files. At this point there can be no other
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* NOTES
|
||||||
* this is the "main" module of the postgres backend and
|
* 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)
|
if (IsUnderPostmaster && Log_disconnections)
|
||||||
on_proc_exit(log_disconnections, 0);
|
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.
|
* Send this backend's cancellation info to the frontend.
|
||||||
*/
|
*/
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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;
|
LoadStmt *stmt = (LoadStmt *) parsetree;
|
||||||
|
|
||||||
if (!superuser())
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
||||||
errmsg("must be superuser to do LOAD")));
|
|
||||||
closeAllVfds(); /* probably not necessary... */
|
closeAllVfds(); /* probably not necessary... */
|
||||||
load_file(stmt->filename);
|
/* Allowed names are restricted if you're not superuser */
|
||||||
|
load_file(stmt->filename, !superuser());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
#endif
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "utils/dynamic_loader.h"
|
#include "utils/dynamic_loader.h"
|
||||||
|
#include "utils/hsearch.h"
|
||||||
|
|
||||||
|
|
||||||
/* signatures for PostgreSQL-specific library init/fini functions */
|
/* signatures for PostgreSQL-specific library init/fini functions */
|
||||||
typedef void (*PG_init_t)(void);
|
typedef void (*PG_init_t)(void);
|
||||||
typedef void (*PG_fini_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).
|
* List of dynamically loaded files (kept in malloc'd memory).
|
||||||
*/
|
*/
|
||||||
@ -62,10 +70,13 @@ static DynamicFileList *file_tail = NULL;
|
|||||||
|
|
||||||
char *Dynamic_library_path;
|
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 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 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 *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 */
|
/* Magic structure that module needs to match to be accepted */
|
||||||
static const Pg_magic_struct magic_data = PG_MODULE_MAGIC_DATA;
|
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
|
* 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,
|
* 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
|
* else return (PGFunction) NULL. Note that errors in loading the library
|
||||||
@ -88,37 +99,107 @@ PGFunction
|
|||||||
load_external_function(char *filename, char *funcname,
|
load_external_function(char *filename, char *funcname,
|
||||||
bool signalNotFound, void **filehandle)
|
bool signalNotFound, void **filehandle)
|
||||||
{
|
{
|
||||||
DynamicFileList *file_scanner;
|
char *fullname;
|
||||||
|
void *lib_handle;
|
||||||
PGFunction retval;
|
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;
|
PGModuleMagicFunction magic_func;
|
||||||
char *load_error;
|
char *load_error;
|
||||||
struct stat stat_buf;
|
struct stat stat_buf;
|
||||||
char *fullname;
|
|
||||||
PG_init_t PG_init;
|
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.
|
* Scan the list of loaded FILES to see if the file has been loaded.
|
||||||
*/
|
*/
|
||||||
for (file_scanner = file_list;
|
for (file_scanner = file_list;
|
||||||
file_scanner != NULL &&
|
file_scanner != NULL &&
|
||||||
strcmp(fullname, file_scanner->filename) != 0;
|
strcmp(libname, file_scanner->filename) != 0;
|
||||||
file_scanner = file_scanner->next)
|
file_scanner = file_scanner->next)
|
||||||
;
|
;
|
||||||
|
|
||||||
if (file_scanner == NULL)
|
if (file_scanner == NULL)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Check for same files - different paths (ie, symlink or link)
|
* Check for same files - different paths (ie, symlink or link)
|
||||||
*/
|
*/
|
||||||
if (stat(fullname, &stat_buf) == -1)
|
if (stat(libname, &stat_buf) == -1)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode_for_file_access(),
|
(errcode_for_file_access(),
|
||||||
errmsg("could not access file \"%s\": %m",
|
errmsg("could not access file \"%s\": %m",
|
||||||
fullname)));
|
libname)));
|
||||||
|
|
||||||
for (file_scanner = file_list;
|
for (file_scanner = file_list;
|
||||||
file_scanner != NULL &&
|
file_scanner != NULL &&
|
||||||
@ -133,21 +214,21 @@ load_external_function(char *filename, char *funcname,
|
|||||||
* File not loaded yet.
|
* File not loaded yet.
|
||||||
*/
|
*/
|
||||||
file_scanner = (DynamicFileList *)
|
file_scanner = (DynamicFileList *)
|
||||||
malloc(sizeof(DynamicFileList) + strlen(fullname));
|
malloc(sizeof(DynamicFileList) + strlen(libname));
|
||||||
if (file_scanner == NULL)
|
if (file_scanner == NULL)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||||
errmsg("out of memory")));
|
errmsg("out of memory")));
|
||||||
|
|
||||||
MemSet(file_scanner, 0, sizeof(DynamicFileList));
|
MemSet(file_scanner, 0, sizeof(DynamicFileList));
|
||||||
strcpy(file_scanner->filename, fullname);
|
strcpy(file_scanner->filename, libname);
|
||||||
file_scanner->device = stat_buf.st_dev;
|
file_scanner->device = stat_buf.st_dev;
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
file_scanner->inode = stat_buf.st_ino;
|
file_scanner->inode = stat_buf.st_ino;
|
||||||
#endif
|
#endif
|
||||||
file_scanner->next = NULL;
|
file_scanner->next = NULL;
|
||||||
|
|
||||||
file_scanner->handle = pg_dlopen(fullname);
|
file_scanner->handle = pg_dlopen(file_scanner->filename);
|
||||||
if (file_scanner->handle == NULL)
|
if (file_scanner->handle == NULL)
|
||||||
{
|
{
|
||||||
load_error = (char *) pg_dlerror();
|
load_error = (char *) pg_dlerror();
|
||||||
@ -156,7 +237,7 @@ load_external_function(char *filename, char *funcname,
|
|||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode_for_file_access(),
|
(errcode_for_file_access(),
|
||||||
errmsg("could not load library \"%s\": %s",
|
errmsg("could not load library \"%s\": %s",
|
||||||
fullname, load_error)));
|
libname, load_error)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the magic function to determine compatibility */
|
/* 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)
|
if (module_magic_data.version != magic_data.version)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errmsg("incompatible library \"%s\": version mismatch",
|
(errmsg("incompatible library \"%s\": version mismatch",
|
||||||
fullname),
|
libname),
|
||||||
errdetail("Server is version %d.%d, library is version %d.%d.",
|
errdetail("Server is version %d.%d, library is version %d.%d.",
|
||||||
magic_data.version/100,
|
magic_data.version/100,
|
||||||
magic_data.version % 100,
|
magic_data.version % 100,
|
||||||
@ -192,7 +273,7 @@ load_external_function(char *filename, char *funcname,
|
|||||||
module_magic_data.version % 100)));
|
module_magic_data.version % 100)));
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errmsg("incompatible library \"%s\": magic block mismatch",
|
(errmsg("incompatible library \"%s\": magic block mismatch",
|
||||||
fullname)));
|
libname)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -203,7 +284,7 @@ load_external_function(char *filename, char *funcname,
|
|||||||
/* complain */
|
/* complain */
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errmsg("incompatible library \"%s\": missing magic block",
|
(errmsg("incompatible library \"%s\": missing magic block",
|
||||||
fullname),
|
libname),
|
||||||
errhint("Extension libraries are now required to use the PG_MODULE_MAGIC macro.")));
|
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;
|
file_tail = file_scanner;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return handle if caller wants it. */
|
return file_scanner->handle;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function loads a shlib file without looking up any particular
|
* Unload the specified dynamic-link library file, if it is loaded.
|
||||||
* function in it. If the same shlib has previously been loaded,
|
*
|
||||||
* unload and reload it.
|
* Note: libname is expected to be an exact name for the library file.
|
||||||
*/
|
*/
|
||||||
void
|
static void
|
||||||
load_file(char *filename)
|
internal_unload_library(const char *libname)
|
||||||
{
|
{
|
||||||
DynamicFileList *file_scanner,
|
DynamicFileList *file_scanner,
|
||||||
*prv,
|
*prv,
|
||||||
*nxt;
|
*nxt;
|
||||||
struct stat stat_buf;
|
struct stat stat_buf;
|
||||||
char *fullname;
|
|
||||||
PG_fini_t PG_fini;
|
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
|
* 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
|
* file as a previously loaded file; it's also handy so as to give a good
|
||||||
* error message if bogus file name given.
|
* error message if bogus file name given.
|
||||||
*/
|
*/
|
||||||
if (stat(fullname, &stat_buf) == -1)
|
if (stat(libname, &stat_buf) == -1)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode_for_file_access(),
|
(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
|
* 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;
|
prv = NULL;
|
||||||
for (file_scanner = file_list; file_scanner != NULL; file_scanner = nxt)
|
for (file_scanner = file_list; file_scanner != NULL; file_scanner = nxt)
|
||||||
{
|
{
|
||||||
nxt = file_scanner->next;
|
nxt = file_scanner->next;
|
||||||
if (strcmp(fullname, file_scanner->filename) == 0 ||
|
if (strcmp(libname, file_scanner->filename) == 0 ||
|
||||||
SAME_INODE(stat_buf, *file_scanner))
|
SAME_INODE(stat_buf, *file_scanner))
|
||||||
{
|
{
|
||||||
if (prv)
|
if (prv)
|
||||||
prv->next = nxt;
|
prv->next = nxt;
|
||||||
else
|
else
|
||||||
file_list = nxt;
|
file_list = nxt;
|
||||||
clear_external_function_hash(file_scanner->handle);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the library has a _PG_fini() function, call it.
|
* If the library has a _PG_fini() function, call it.
|
||||||
@ -301,6 +353,7 @@ load_file(char *filename)
|
|||||||
if (PG_fini)
|
if (PG_fini)
|
||||||
(*PG_fini)();
|
(*PG_fini)();
|
||||||
|
|
||||||
|
clear_external_function_hash(file_scanner->handle);
|
||||||
pg_dlclose(file_scanner->handle);
|
pg_dlclose(file_scanner->handle);
|
||||||
free((char *) file_scanner);
|
free((char *) file_scanner);
|
||||||
/* prv does not change */
|
/* prv does not change */
|
||||||
@ -308,23 +361,8 @@ load_file(char *filename)
|
|||||||
else
|
else
|
||||||
prv = file_scanner;
|
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
|
static bool
|
||||||
file_exists(const char *name)
|
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
|
* the name. Else (no slash) try to expand using search path (see
|
||||||
* find_in_dynamic_libpath below); if that works, return the fully
|
* find_in_dynamic_libpath below); if that works, return the fully
|
||||||
* expanded file name. If the previous failed, append DLSUFFIX and
|
* 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 *
|
static char *
|
||||||
expand_dynamic_library_name(const char *name)
|
expand_dynamic_library_name(const char *name)
|
||||||
@ -402,9 +440,28 @@ expand_dynamic_library_name(const char *name)
|
|||||||
pfree(full);
|
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.
|
* Substitute for any macros appearing in the given string.
|
||||||
@ -418,6 +475,7 @@ substitute_libpath_macro(const char *name)
|
|||||||
|
|
||||||
AssertArg(name != NULL);
|
AssertArg(name != NULL);
|
||||||
|
|
||||||
|
/* Currently, we only recognize $libdir at the start of the string */
|
||||||
if (name[0] != '$')
|
if (name[0] != '$')
|
||||||
return pstrdup(name);
|
return pstrdup(name);
|
||||||
|
|
||||||
@ -428,7 +486,8 @@ substitute_libpath_macro(const char *name)
|
|||||||
strncmp(name, "$libdir", strlen("$libdir")) != 0)
|
strncmp(name, "$libdir", strlen("$libdir")) != 0)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_NAME),
|
(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);
|
ret = palloc(strlen(pkglib_path) + strlen(sep_ptr) + 1);
|
||||||
|
|
||||||
@ -513,3 +572,58 @@ find_in_dynamic_libpath(const char *basename)
|
|||||||
|
|
||||||
return NULL;
|
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;
|
||||||
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
static void
|
||||||
process_preload_libraries(void)
|
load_libraries(const char *libraries, const char *gucname, bool restrict)
|
||||||
{
|
{
|
||||||
char *rawstring;
|
char *rawstring;
|
||||||
List *elemlist;
|
List *elemlist;
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
|
|
||||||
if (preload_libraries_string == NULL)
|
if (libraries == NULL || libraries[0] == '\0')
|
||||||
return;
|
return; /* nothing to do */
|
||||||
|
|
||||||
/* Need a modifiable copy of string */
|
/* Need a modifiable copy of string */
|
||||||
rawstring = pstrdup(preload_libraries_string);
|
rawstring = pstrdup(libraries);
|
||||||
|
|
||||||
/* Parse string into list of identifiers */
|
/* Parse string into list of identifiers */
|
||||||
if (!SplitIdentifierString(rawstring, ',', &elemlist))
|
if (!SplitIdentifierString(rawstring, ',', &elemlist))
|
||||||
@ -1124,7 +1131,8 @@ process_preload_libraries(void)
|
|||||||
list_free(elemlist);
|
list_free(elemlist);
|
||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("invalid list syntax for parameter \"preload_libraries\"")));
|
errmsg("invalid list syntax in parameter \"%s\"",
|
||||||
|
gucname)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1135,12 +1143,45 @@ process_preload_libraries(void)
|
|||||||
|
|
||||||
filename = pstrdup(tok);
|
filename = pstrdup(tok);
|
||||||
canonicalize_path(filename);
|
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,
|
ereport(LOG,
|
||||||
(errmsg("preloaded library \"%s\"", filename)));
|
(errmsg("loaded library \"%s\"", filename)));
|
||||||
pfree(filename);
|
pfree(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
pfree(rawstring);
|
pfree(rawstring);
|
||||||
list_free(elemlist);
|
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);
|
||||||
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
* Written by Peter Eisentraut <peter_e@gmx.net>.
|
* Written by Peter Eisentraut <peter_e@gmx.net>.
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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."),
|
gettext_noop("Lists shared libraries to preload into server."),
|
||||||
NULL,
|
NULL,
|
||||||
GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_SUPERUSER_ONLY
|
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
|
"", NULL, NULL
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@
|
|||||||
|
|
||||||
#max_files_per_process = 1000 # min 25
|
#max_files_per_process = 1000 # min 25
|
||||||
# (change requires restart)
|
# (change requires restart)
|
||||||
#preload_libraries = '' # (change requires restart)
|
#shared_preload_libraries = '' # (change requires restart)
|
||||||
|
|
||||||
# - Cost-Based Vacuum Delay -
|
# - Cost-Based Vacuum Delay -
|
||||||
|
|
||||||
@ -419,6 +419,7 @@
|
|||||||
|
|
||||||
#explain_pretty_print = on
|
#explain_pretty_print = on
|
||||||
#dynamic_library_path = '$libdir'
|
#dynamic_library_path = '$libdir'
|
||||||
|
#local_preload_libraries = ''
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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,
|
extern PGFunction load_external_function(char *filename, char *funcname,
|
||||||
bool signalNotFound, void **filehandle);
|
bool signalNotFound, void **filehandle);
|
||||||
extern PGFunction lookup_external_function(void *filehandle, char *funcname);
|
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);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
* NOTES
|
||||||
* some of the information in this file should be moved to other files.
|
* 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 */
|
/* in utils/init/miscinit.c */
|
||||||
extern bool IgnoreSystemIndexes;
|
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 SetReindexProcessing(Oid heapOid, Oid indexOid);
|
||||||
extern void ResetReindexProcessing(void);
|
extern void ResetReindexProcessing(void);
|
||||||
@ -319,6 +320,7 @@ extern void TouchSocketLockFile(void);
|
|||||||
extern void RecordSharedMemoryInLockFile(unsigned long id1,
|
extern void RecordSharedMemoryInLockFile(unsigned long id1,
|
||||||
unsigned long id2);
|
unsigned long id2);
|
||||||
extern void ValidatePgVersion(const char *path);
|
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 */
|
#endif /* MISCADMIN_H */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user