diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml index bc7a86dba1def93d415e554cd6aaea0c437a5878..f5ed95be5d4648dbe88312f09cfcea12edf10773 100644 --- a/doc/src/sgml/runtime.sgml +++ b/doc/src/sgml/runtime.sgml @@ -1,5 +1,5 @@ <!-- -$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.66 2001/05/12 22:51:35 petere Exp $ +$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.67 2001/05/17 17:44:17 petere Exp $ --> <Chapter Id="runtime"> @@ -996,6 +996,49 @@ env PGOPTIONS='-c geqo=off' psql </listitem> </varlistentry> + <varlistentry> + <term>DYNAMIC_LIBRARY_PATH (<type>string</type>)</term> + <listitem> + <para> + If a dynamically loadable module needs to be opened and the + specified name does not have a directory component (i.e., the + name does not contain a slash), the system will search this + path for the specified file. (The name that is used is the + name specified in the <command>CREATE FUNCTION</command> or + <command>LOAD</command> command.) + </para> + + <para> + The value for dynamic_library_path has to be a colon-separated + list of absolute directory names. If a directory name starts + with the special value <literal>$libdir</literal>, the + compiled-in PostgreSQL library directory, which is where the + modules provided by the PostgreSQL distribution are installed, + is substituted. An example value: + <informalexample> +<programlisting> +dynamic_library_path = '/usr/local/lib:/home/my_project/lib:$libdir:$libdir/contrib' +</programlisting> + </informalexample> + </para> + + <para> + The default value for this parameter is + <literal>$libdir</literal>. If the value is set to the empty + string, the automatic path search is turned off. + </para> + + <para> + This parameter can be changed at run time by superusers, but + note that a setting done that way will only persist till the + end of the client connection, so this method should be + reserved for development purposes. The recommended way to set + this parameter is in the <filename>postgresql.conf</filename> + configuration file. + </para> + </listitem> + </varlistentry> + <varlistentry> <indexterm> <primary>fsync</primary> diff --git a/src/backend/utils/fmgr/Makefile b/src/backend/utils/fmgr/Makefile index 1e7c19db3319f1193ce555ea95874ef3cbeb4b61..a449b80942b2694ca5aa382a6183ae53f960f9bb 100644 --- a/src/backend/utils/fmgr/Makefile +++ b/src/backend/utils/fmgr/Makefile @@ -4,7 +4,7 @@ # Makefile for utils/fmgr # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/utils/fmgr/Makefile,v 1.10 2000/08/31 16:10:50 petere Exp $ +# $Header: /cvsroot/pgsql/src/backend/utils/fmgr/Makefile,v 1.11 2001/05/17 17:44:18 petere Exp $ # #------------------------------------------------------------------------- @@ -14,6 +14,9 @@ include $(top_builddir)/src/Makefile.global OBJS = dfmgr.o fmgr.o +override CPPFLAGS += -DLIBDIR=\"$(libdir)\" -DDLSUFFIX=\"$(DLSUFFIX)\" + + all: SUBSYS.o SUBSYS.o: $(OBJS) diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c index 49be6b37903bd2619b3847059b1e18e7f6a6b142..695fb1ed76e8c769d9bf72d4411bbd1f7122f350 100644 --- a/src/backend/utils/fmgr/dfmgr.c +++ b/src/backend/utils/fmgr/dfmgr.c @@ -8,16 +8,18 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.48 2001/03/22 03:59:58 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.49 2001/05/17 17:44:18 petere Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" +#include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include "dynloader.h" +#include "miscadmin.h" #include "utils/dynamic_loader.h" @@ -44,6 +46,12 @@ static DynamicFileList *file_tail = (DynamicFileList *) NULL; #define SAME_INODE(A,B) ((A).st_ino == (B).inode && (A).st_dev == (B).device) +char * Dynamic_library_path; + +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); + /* * Load the specified dynamic-link library file, and look for a function @@ -60,6 +68,11 @@ load_external_function(char *filename, char *funcname, PGFunction retval; char *load_error; struct stat stat_buf; + char *fullname; + + fullname = expand_dynamic_library_name(filename); + if (fullname) + filename = fullname; /* * Scan the list of loaded FILES to see if the file has been loaded. @@ -143,6 +156,11 @@ load_file(char *filename) DynamicFileList *file_scanner, *p; struct stat stat_buf; + char *fullname; + + fullname = expand_dynamic_library_name(filename); + if (fullname) + filename = fullname; /* * We need to do stat() in order to determine whether this is the same @@ -181,3 +199,181 @@ load_file(char *filename) load_external_function(filename, (char *) NULL, false); } + + + +static bool +file_exists(const char *name) +{ + struct stat st; + + AssertArg(name != NULL); + + if (stat(name, &st) == 0) + return true; + else if (!(errno == ENOENT || errno == ENOTDIR || errno == EACCES)) + elog(ERROR, "stat failed on %s: %s", name, strerror(errno)); + + return false; +} + + +/* Example format: ".so" */ +#ifndef DLSUFFIX +#error "DLSUFFIX must be defined to compile this file." +#endif + +/* Example format: "/usr/local/pgsql/lib" */ +#ifndef LIBDIR +#error "LIBDIR needs to be defined to compile this file." +#endif + + +/* + * If name contains a slash, check if the file exists, if so return + * 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. The return value is + * palloc'ed. + */ +static char * +expand_dynamic_library_name(const char *name) +{ + bool have_slash; + char * new; + size_t len; + + AssertArg(name); + + have_slash = (strchr(name, '/') != NULL); + + if (!have_slash) + { + char * full; + + full = find_in_dynamic_libpath(name); + if (full) + return full; + } + else + { + if (file_exists(name)) + return pstrdup(name); + } + + len = strlen(name); + + new = palloc(len + strlen(DLSUFFIX) + 1); + strcpy(new, name); + strcpy(new + len, DLSUFFIX); + + if (!have_slash) + { + char * full; + + full = find_in_dynamic_libpath(new); + pfree(new); + if (full) + return full; + } + else + { + if (file_exists(new)) + return new; + } + + return NULL; +} + + + +/* + * Search for a file called 'basename' in the colon-separated search + * path 'path'. If the file is found, the full file name is returned + * in palloced memory. The the file is not found, return NULL. + */ +static char * +find_in_dynamic_libpath(const char * basename) +{ + const char *p; + char *full; + size_t len; + size_t baselen; + + AssertArg(basename != NULL); + AssertArg(strchr(basename, '/') == NULL); + AssertState(Dynamic_library_path != NULL); + + p = Dynamic_library_path; + if (strlen(p) == 0) + return NULL; + + baselen = strlen(basename); + + do { + len = strcspn(p, ":"); + + if (len == 0) + elog(ERROR, "zero length dynamic_library_path component"); + + /* substitute special value */ + if (p[0] == '$') + { + size_t varname_len = strcspn(p + 1, "/") + 1; + const char * replacement = NULL; + size_t repl_len; + + if (strncmp(p, "$libdir", varname_len)==0) + replacement = LIBDIR; + else + elog(ERROR, "invalid dynamic_library_path specification"); + + repl_len = strlen(replacement); + + if (p[varname_len] == '\0') + { + full = palloc(repl_len + 1 + baselen + 1); + snprintf(full, repl_len + 1 + baselen + 1, + "%s/%s", replacement, basename); + } + else + { + full = palloc(repl_len + (len - varname_len) + 1 + baselen + 1); + + strcpy(full, replacement); + strncat(full, p + varname_len, len - varname_len); + full[repl_len + (len - varname_len)] = '\0'; + strcat(full, "/"); + strcat(full, basename); + } + } + + /* regular case */ + else + { + /* only absolute paths */ + if (p[0] != '/') + elog(ERROR, "dynamic_library_path component is not absolute"); + + full = palloc(len + 1 + baselen + 1); + strncpy(full, p, len); + full[len] = '/'; + strcpy(full + len + 1, basename); + } + + if (DebugLvl > 1) + elog(DEBUG, "find_in_dynamic_libpath: trying %s", full); + + if (file_exists(full)) + return full; + + pfree(full); + if (p[len] == '\0') + break; + else + p += len + 1; + } while(1); + + return NULL; +} diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 1d779979a194f92584d2597d3abccf3d97ad22fc..6e080594f8b6662891da9be5b2bb5a0c566f22d2 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -4,7 +4,7 @@ * Support for grand unified configuration scheme, including SET * command, configuration file, and command line options. * - * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.35 2001/03/22 17:41:47 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.36 2001/05/17 17:44:18 petere Exp $ * * Copyright 2000 by PostgreSQL Global Development Group * Written by Peter Eisentraut <peter_e@gmx.net>. @@ -22,6 +22,7 @@ #include "access/xlog.h" #include "commands/async.h" +#include "fmgr.h" #include "libpq/auth.h" #include "libpq/pqcomm.h" #include "miscadmin.h" @@ -328,6 +329,9 @@ static struct config_real static struct config_string ConfigureNamesString[] = { + {"dynamic_library_path", PGC_SUSET, &Dynamic_library_path, + "$libdir", NULL, NULL}, + {"krb_server_keyfile", PGC_POSTMASTER, &pg_krb_server_keyfile, PG_KRB_SRVTAB, NULL, NULL}, diff --git a/src/include/fmgr.h b/src/include/fmgr.h index 3ccd1c39c615e7fe8659bcf04e4618676703de6d..44641bdcb1829dab3f070500a4cb2655a51ebf5c 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -11,7 +11,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: fmgr.h,v 1.13 2001/03/22 04:00:25 momjian Exp $ + * $Id: fmgr.h,v 1.14 2001/05/17 17:44:18 petere Exp $ * *------------------------------------------------------------------------- */ @@ -350,6 +350,7 @@ extern Oid fmgr_internal_function(const char *proname); extern PGFunction load_external_function(char *filename, char *funcname, bool signalNotFound); extern void load_file(char *filename); +extern char * Dynamic_library_path; /*