📄 dfmgr.c
字号:
/*------------------------------------------------------------------------- * * dfmgr.c * Dynamic function manager code. * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.26.2.1 1999/08/02 05:25:06 scrappy Exp $ * *------------------------------------------------------------------------- */#include <sys/types.h>#include <sys/stat.h>#include "postgres.h"#include "utils/dynamic_loader.h"#include "access/heapam.h"#include "catalog/catname.h"#include "catalog/pg_proc.h"#include "dynloader.h"#include "utils/builtins.h"#include "utils/syscache.h"static DynamicFileList *file_list = (DynamicFileList *) NULL;static DynamicFileList *file_tail = (DynamicFileList *) NULL;#define NOT_EQUAL(A, B) (((A).st_ino != (B).inode) \ || ((A).st_dev != (B).device))static Oid procedureId_save = -1;static int pronargs_save;static func_ptr user_fn_save = (func_ptr) NULL;static func_ptr handle_load(char *filename, char *funcname);func_ptrfmgr_dynamic(Oid procedureId, int *pronargs){ HeapTuple procedureTuple; Form_pg_proc procedureStruct; char *proname, *probinstring; Datum probinattr; func_ptr user_fn; Relation rel; bool isnull; if (procedureId == procedureId_save) { *pronargs = pronargs_save; return user_fn_save; } /* * The procedure isn't a builtin, so we'll have to do a catalog lookup * to find its pg_proc entry. */ procedureTuple = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(procedureId), 0, 0, 0); if (!HeapTupleIsValid(procedureTuple)) { elog(ERROR, "fmgr: Cache lookup failed for procedure %u\n", procedureId); return (func_ptr) NULL; } procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple); proname = procedureStruct->proname.data; pronargs_save = *pronargs = procedureStruct->pronargs; /* * Extract the procedure info from the pg_proc tuple. Since probin is * varlena, do a amgetattr() on the procedure tuple. To do that, we * need the rel for the procedure relation, so... */ /* open pg_procedure */ rel = heap_openr(ProcedureRelationName); if (!RelationIsValid(rel)) { elog(ERROR, "fmgr: Could not open relation %s", ProcedureRelationName); return (func_ptr) NULL; } probinattr = heap_getattr(procedureTuple, Anum_pg_proc_probin, RelationGetDescr(rel), &isnull); if (!PointerIsValid(probinattr) /* || isnull */ ) { heap_close(rel); elog(ERROR, "fmgr: Could not extract probin for %u from %s", procedureId, ProcedureRelationName); return (func_ptr) NULL; } probinstring = textout((struct varlena *) probinattr); user_fn = handle_load(probinstring, proname); procedureId_save = procedureId; user_fn_save = user_fn; return user_fn;}static func_ptrhandle_load(char *filename, char *funcname){ DynamicFileList *file_scanner = (DynamicFileList *) NULL; func_ptr retval = (func_ptr) NULL; char *load_error; struct stat stat_buf; /* * Do this because loading files may screw up the dynamic function * manager otherwise. */ procedureId_save = -1; /* * Scan the list of loaded FILES to see if the function has been * loaded. */ if (filename != (char *) NULL) { for (file_scanner = file_list; file_scanner != (DynamicFileList *) NULL && file_scanner->filename != (char *) NULL && strcmp(filename, file_scanner->filename) != 0; file_scanner = file_scanner->next) ; if (file_scanner == (DynamicFileList *) NULL) { if (stat(filename, &stat_buf) == -1) elog(ERROR, "stat failed on file '%s': %m", filename); for (file_scanner = file_list; file_scanner != (DynamicFileList *) NULL && (NOT_EQUAL(stat_buf, *file_scanner)); file_scanner = file_scanner->next) ; /* * Same files - different paths (ie, symlink or link) */ if (file_scanner != (DynamicFileList *) NULL) strcpy(file_scanner->filename, filename); } } else file_scanner = (DynamicFileList *) NULL; /* * File not loaded yet. */ if (file_scanner == (DynamicFileList *) NULL) { if (file_list == (DynamicFileList *) NULL) { file_list = (DynamicFileList *) malloc(sizeof(DynamicFileList)); file_scanner = file_list; } else { file_tail->next = (DynamicFileList *) malloc(sizeof(DynamicFileList)); file_scanner = file_tail->next; } MemSet((char *) file_scanner, 0, sizeof(DynamicFileList)); strcpy(file_scanner->filename, filename); file_scanner->device = stat_buf.st_dev; file_scanner->inode = stat_buf.st_ino; file_scanner->next = (DynamicFileList *) NULL; file_scanner->handle = pg_dlopen(filename); if (file_scanner->handle == (void *) NULL) { load_error = (char *) pg_dlerror(); if (file_scanner == file_list) file_list = (DynamicFileList *) NULL; else file_tail->next = (DynamicFileList *) NULL; free((char *) file_scanner); elog(ERROR, "Load of file %s failed: %s", filename, load_error); } /* * Just load the file - we are done with that so return. */ file_tail = file_scanner; if (funcname == (char *) NULL) return (func_ptr) NULL; } retval = (func_ptr) pg_dlsym(file_scanner->handle, funcname); if (retval == (func_ptr) NULL) elog(ERROR, "Can't find function %s in file %s", funcname, filename); return retval;}/* * This function loads files by the following: * * If the file is already loaded: * o Zero out that file's loaded space (so it doesn't screw up linking) * o Free all space associated with that file * o Free that file's descriptor. * * Now load the file by calling handle_load with a NULL argument as the * function. */voidload_file(char *filename){ DynamicFileList *file_scanner, *p; struct stat stat_buf; int done = 0; /* * 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(filename, &stat_buf) == -1) elog(ERROR, "LOAD: could not open file '%s': %m", filename); if (file_list != (DynamicFileList *) NULL && !NOT_EQUAL(stat_buf, *file_list)) { file_scanner = file_list; file_list = file_list->next; pg_dlclose(file_scanner->handle); free((char *) file_scanner); } else if (file_list != (DynamicFileList *) NULL) { file_scanner = file_list; while (!done) { if (file_scanner->next == (DynamicFileList *) NULL) done = 1; else if (!NOT_EQUAL(stat_buf, *(file_scanner->next))) done = 1; else file_scanner = file_scanner->next; } if (file_scanner->next != (DynamicFileList *) NULL) { p = file_scanner->next; file_scanner->next = file_scanner->next->next; pg_dlclose(file_scanner->handle); free((char *) p); } } handle_load(filename, (char *) NULL);}/* Is this used? bjm 1998/10/08 No. tgl 1999/02/07 */#ifdef NOT_USEDfunc_ptrtrigger_dynamic(char *filename, char *funcname){ func_ptr trigger_fn; trigger_fn = handle_load(filename, funcname); return trigger_fn;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -