1 /*-------------------------------------------------------------------------
4 * Dynamic function manager code.
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.23 1999/02/13 23:19:51 momjian Exp $
12 *-------------------------------------------------------------------------
14 #include <sys/types.h>
21 #include "config.h" /* for MAXPATHLEN */
22 #include "fmgr.h" /* generated by Gen_fmgrtab.sh */
23 #include "utils/dynamic_loader.h"
24 #include "utils/elog.h"
25 #include "utils/builtins.h"
26 #include "access/heapam.h"
27 #include "nodes/pg_list.h"
29 #include "dynloader.h"
35 #include "catalog/catname.h"
36 #include "utils/syscache.h"
37 #include "catalog/pg_proc.h"
39 static DynamicFileList *file_list = (DynamicFileList *) NULL;
40 static DynamicFileList *file_tail = (DynamicFileList *) NULL;
42 #define NOT_EQUAL(A, B) (((A).st_ino != (B).inode) \
43 || ((A).st_dev != (B).device))
45 static Oid procedureId_save = -1;
46 static int pronargs_save;
47 static func_ptr user_fn_save = (func_ptr) NULL;
48 static func_ptr handle_load(char *filename, char *funcname);
51 fmgr_dynamic(Oid procedureId, int *pronargs)
53 HeapTuple procedureTuple;
54 Form_pg_proc procedureStruct;
62 if (procedureId == procedureId_save)
64 *pronargs = pronargs_save;
69 * The procedure isn't a builtin, so we'll have to do a catalog lookup
70 * to find its pg_proc entry.
72 procedureTuple = SearchSysCacheTuple(PROOID,
73 ObjectIdGetDatum(procedureId),
75 if (!HeapTupleIsValid(procedureTuple))
77 elog(ERROR, "fmgr: Cache lookup failed for procedure %d\n",
79 return (func_ptr) NULL;
82 procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
83 proname = procedureStruct->proname.data;
84 pronargs_save = *pronargs = procedureStruct->pronargs;
87 * Extract the procedure info from the pg_proc tuple. Since probin is
88 * varlena, do a amgetattr() on the procedure tuple. To do that, we
89 * need the rel for the procedure relation, so...
92 /* open pg_procedure */
94 rel = heap_openr(ProcedureRelationName);
95 if (!RelationIsValid(rel))
97 elog(ERROR, "fmgr: Could not open relation %s",
98 ProcedureRelationName);
99 return (func_ptr) NULL;
101 probinattr = heap_getattr(procedureTuple,
103 RelationGetDescr(rel), &isnull);
104 if (!PointerIsValid(probinattr) /* || isnull */ )
107 elog(ERROR, "fmgr: Could not extract probin for %d from %s",
108 procedureId, ProcedureRelationName);
109 return (func_ptr) NULL;
111 probinstring = textout((struct varlena *) probinattr);
113 user_fn = handle_load(probinstring, proname);
115 procedureId_save = procedureId;
116 user_fn_save = user_fn;
122 handle_load(char *filename, char *funcname)
124 DynamicFileList *file_scanner = (DynamicFileList *) NULL;
125 func_ptr retval = (func_ptr) NULL;
127 struct stat stat_buf;
130 * Do this because loading files may screw up the dynamic function
133 procedureId_save = -1;
136 * Scan the list of loaded FILES to see if the function has been
140 if (filename != (char *) NULL)
142 for (file_scanner = file_list;
143 file_scanner != (DynamicFileList *) NULL
144 && file_scanner->filename != (char *) NULL
145 && strcmp(filename, file_scanner->filename) != 0;
146 file_scanner = file_scanner->next)
148 if (file_scanner == (DynamicFileList *) NULL)
150 if (stat(filename, &stat_buf) == -1)
151 elog(ERROR, "stat failed on file %s", filename);
153 for (file_scanner = file_list;
154 file_scanner != (DynamicFileList *) NULL
155 && (NOT_EQUAL(stat_buf, *file_scanner));
156 file_scanner = file_scanner->next)
160 * Same files - different paths (ie, symlink or link)
162 if (file_scanner != (DynamicFileList *) NULL)
163 strcpy(file_scanner->filename, filename);
168 file_scanner = (DynamicFileList *) NULL;
171 * File not loaded yet.
174 if (file_scanner == (DynamicFileList *) NULL)
176 if (file_list == (DynamicFileList *) NULL)
178 file_list = (DynamicFileList *)
179 malloc(sizeof(DynamicFileList));
180 file_scanner = file_list;
184 file_tail->next = (DynamicFileList *)
185 malloc(sizeof(DynamicFileList));
186 file_scanner = file_tail->next;
188 MemSet((char *) file_scanner, 0, sizeof(DynamicFileList));
190 strcpy(file_scanner->filename, filename);
191 file_scanner->device = stat_buf.st_dev;
192 file_scanner->inode = stat_buf.st_ino;
193 file_scanner->next = (DynamicFileList *) NULL;
195 file_scanner->handle = pg_dlopen(filename);
196 if (file_scanner->handle == (void *) NULL)
198 load_error = (char *) pg_dlerror();
199 if (file_scanner == file_list)
200 file_list = (DynamicFileList *) NULL;
202 file_tail->next = (DynamicFileList *) NULL;
204 free((char *) file_scanner);
205 elog(ERROR, "Load of file %s failed: %s", filename, load_error);
209 * Just load the file - we are done with that so return.
211 file_tail = file_scanner;
213 if (funcname == (char *) NULL)
214 return (func_ptr) NULL;
217 retval = (func_ptr) pg_dlsym(file_scanner->handle, funcname);
219 if (retval == (func_ptr) NULL)
220 elog(ERROR, "Can't find function %s in file %s", funcname, filename);
226 * This function loads files by the following:
228 * If the file is already loaded:
229 * o Zero out that file's loaded space (so it doesn't screw up linking)
230 * o Free all space associated with that file
231 * o Free that file's descriptor.
233 * Now load the file by calling handle_load with a NULL argument as the
237 load_file(char *filename)
239 DynamicFileList *file_scanner,
241 struct stat stat_buf;
245 if (stat(filename, &stat_buf) == -1)
246 elog(ERROR, "stat failed on file %s", filename);
248 if (file_list != (DynamicFileList *) NULL
249 && !NOT_EQUAL(stat_buf, *file_list))
251 file_scanner = file_list;
252 file_list = file_list->next;
253 pg_dlclose(file_scanner->handle);
254 free((char *) file_scanner);
256 else if (file_list != (DynamicFileList *) NULL)
258 file_scanner = file_list;
261 if (file_scanner->next == (DynamicFileList *) NULL)
263 else if (!NOT_EQUAL(stat_buf, *(file_scanner->next)))
266 file_scanner = file_scanner->next;
269 if (file_scanner->next != (DynamicFileList *) NULL)
271 p = file_scanner->next;
272 file_scanner->next = file_scanner->next->next;
273 pg_dlclose(file_scanner->handle);
277 handle_load(filename, (char *) NULL);
280 /* Is this used? bjm 1998/10/08 No. tgl 1999/02/07 */
283 trigger_dynamic(char *filename, char *funcname)
287 trigger_fn = handle_load(filename, funcname);