dfmgr.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:7k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * dfmgr.c
  4.  *   Dynamic function manager code.
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.26.2.1 1999/08/02 05:25:06 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include "postgres.h"
  17. #include "utils/dynamic_loader.h"
  18. #include "access/heapam.h"
  19. #include "catalog/catname.h"
  20. #include "catalog/pg_proc.h"
  21. #include "dynloader.h"
  22. #include "utils/builtins.h"
  23. #include "utils/syscache.h"
  24. static DynamicFileList *file_list = (DynamicFileList *) NULL;
  25. static DynamicFileList *file_tail = (DynamicFileList *) NULL;
  26. #define NOT_EQUAL(A, B) (((A).st_ino != (B).inode) 
  27.   || ((A).st_dev != (B).device))
  28. static Oid procedureId_save = -1;
  29. static int pronargs_save;
  30. static func_ptr user_fn_save = (func_ptr) NULL;
  31. static func_ptr handle_load(char *filename, char *funcname);
  32. func_ptr
  33. fmgr_dynamic(Oid procedureId, int *pronargs)
  34. {
  35. HeapTuple procedureTuple;
  36. Form_pg_proc procedureStruct;
  37. char    *proname,
  38.    *probinstring;
  39. Datum probinattr;
  40. func_ptr user_fn;
  41. Relation rel;
  42. bool isnull;
  43. if (procedureId == procedureId_save)
  44. {
  45. *pronargs = pronargs_save;
  46. return user_fn_save;
  47. }
  48. /*
  49.  * The procedure isn't a builtin, so we'll have to do a catalog lookup
  50.  * to find its pg_proc entry.
  51.  */
  52. procedureTuple = SearchSysCacheTuple(PROOID,
  53.  ObjectIdGetDatum(procedureId),
  54.  0, 0, 0);
  55. if (!HeapTupleIsValid(procedureTuple))
  56. {
  57. elog(ERROR, "fmgr: Cache lookup failed for procedure %un",
  58.  procedureId);
  59. return (func_ptr) NULL;
  60. }
  61. procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
  62. proname = procedureStruct->proname.data;
  63. pronargs_save = *pronargs = procedureStruct->pronargs;
  64. /*
  65.  * Extract the procedure info from the pg_proc tuple. Since probin is
  66.  * varlena, do a amgetattr() on the procedure tuple.  To do that, we
  67.  * need the rel for the procedure relation, so...
  68.  */
  69. /* open pg_procedure */
  70. rel = heap_openr(ProcedureRelationName);
  71. if (!RelationIsValid(rel))
  72. {
  73. elog(ERROR, "fmgr: Could not open relation %s",
  74.  ProcedureRelationName);
  75. return (func_ptr) NULL;
  76. }
  77. probinattr = heap_getattr(procedureTuple,
  78.   Anum_pg_proc_probin,
  79.   RelationGetDescr(rel), &isnull);
  80. if (!PointerIsValid(probinattr) /* || isnull */ )
  81. {
  82. heap_close(rel);
  83. elog(ERROR, "fmgr: Could not extract probin for %u from %s",
  84.  procedureId, ProcedureRelationName);
  85. return (func_ptr) NULL;
  86. }
  87. probinstring = textout((struct varlena *) probinattr);
  88. user_fn = handle_load(probinstring, proname);
  89. procedureId_save = procedureId;
  90. user_fn_save = user_fn;
  91. return user_fn;
  92. }
  93. static func_ptr
  94. handle_load(char *filename, char *funcname)
  95. {
  96. DynamicFileList *file_scanner = (DynamicFileList *) NULL;
  97. func_ptr retval = (func_ptr) NULL;
  98. char    *load_error;
  99. struct stat stat_buf;
  100. /*
  101.  * Do this because loading files may screw up the dynamic function
  102.  * manager otherwise.
  103.  */
  104. procedureId_save = -1;
  105. /*
  106.  * Scan the list of loaded FILES to see if the function has been
  107.  * loaded.
  108.  */
  109. if (filename != (char *) NULL)
  110. {
  111. for (file_scanner = file_list;
  112.  file_scanner != (DynamicFileList *) NULL
  113.  && file_scanner->filename != (char *) NULL
  114.  && strcmp(filename, file_scanner->filename) != 0;
  115.  file_scanner = file_scanner->next)
  116. ;
  117. if (file_scanner == (DynamicFileList *) NULL)
  118. {
  119. if (stat(filename, &stat_buf) == -1)
  120. elog(ERROR, "stat failed on file '%s': %m", filename);
  121. for (file_scanner = file_list;
  122.  file_scanner != (DynamicFileList *) NULL
  123.  && (NOT_EQUAL(stat_buf, *file_scanner));
  124.  file_scanner = file_scanner->next)
  125. ;
  126. /*
  127.  * Same files - different paths (ie, symlink or link)
  128.  */
  129. if (file_scanner != (DynamicFileList *) NULL)
  130. strcpy(file_scanner->filename, filename);
  131. }
  132. }
  133. else
  134. file_scanner = (DynamicFileList *) NULL;
  135. /*
  136.  * File not loaded yet.
  137.  */
  138. if (file_scanner == (DynamicFileList *) NULL)
  139. {
  140. if (file_list == (DynamicFileList *) NULL)
  141. {
  142. file_list = (DynamicFileList *)
  143. malloc(sizeof(DynamicFileList));
  144. file_scanner = file_list;
  145. }
  146. else
  147. {
  148. file_tail->next = (DynamicFileList *)
  149. malloc(sizeof(DynamicFileList));
  150. file_scanner = file_tail->next;
  151. }
  152. MemSet((char *) file_scanner, 0, sizeof(DynamicFileList));
  153. strcpy(file_scanner->filename, filename);
  154. file_scanner->device = stat_buf.st_dev;
  155. file_scanner->inode = stat_buf.st_ino;
  156. file_scanner->next = (DynamicFileList *) NULL;
  157. file_scanner->handle = pg_dlopen(filename);
  158. if (file_scanner->handle == (void *) NULL)
  159. {
  160. load_error = (char *) pg_dlerror();
  161. if (file_scanner == file_list)
  162. file_list = (DynamicFileList *) NULL;
  163. else
  164. file_tail->next = (DynamicFileList *) NULL;
  165. free((char *) file_scanner);
  166. elog(ERROR, "Load of file %s failed: %s", filename, load_error);
  167. }
  168. /*
  169.  * Just load the file - we are done with that so return.
  170.  */
  171. file_tail = file_scanner;
  172. if (funcname == (char *) NULL)
  173. return (func_ptr) NULL;
  174. }
  175. retval = (func_ptr) pg_dlsym(file_scanner->handle, funcname);
  176. if (retval == (func_ptr) NULL)
  177. elog(ERROR, "Can't find function %s in file %s", funcname, filename);
  178. return retval;
  179. }
  180. /*
  181.  * This function loads files by the following:
  182.  *
  183.  * If the file is already loaded:
  184.  * o  Zero out that file's loaded space (so it doesn't screw up linking)
  185.  * o  Free all space associated with that file
  186.  * o  Free that file's descriptor.
  187.  *
  188.  * Now load the file by calling handle_load with a NULL argument as the
  189.  * function.
  190.  */
  191. void
  192. load_file(char *filename)
  193. {
  194. DynamicFileList *file_scanner,
  195.    *p;
  196. struct stat stat_buf;
  197. int done = 0;
  198. /*
  199.  * We need to do stat() in order to determine whether this is the same
  200.  * file as a previously loaded file; it's also handy so as to give a
  201.  * good error message if bogus file name given.
  202.  */
  203. if (stat(filename, &stat_buf) == -1)
  204. elog(ERROR, "LOAD: could not open file '%s': %m", filename);
  205. if (file_list != (DynamicFileList *) NULL
  206. && !NOT_EQUAL(stat_buf, *file_list))
  207. {
  208. file_scanner = file_list;
  209. file_list = file_list->next;
  210. pg_dlclose(file_scanner->handle);
  211. free((char *) file_scanner);
  212. }
  213. else if (file_list != (DynamicFileList *) NULL)
  214. {
  215. file_scanner = file_list;
  216. while (!done)
  217. {
  218. if (file_scanner->next == (DynamicFileList *) NULL)
  219. done = 1;
  220. else if (!NOT_EQUAL(stat_buf, *(file_scanner->next)))
  221. done = 1;
  222. else
  223. file_scanner = file_scanner->next;
  224. }
  225. if (file_scanner->next != (DynamicFileList *) NULL)
  226. {
  227. p = file_scanner->next;
  228. file_scanner->next = file_scanner->next->next;
  229. pg_dlclose(file_scanner->handle);
  230. free((char *) p);
  231. }
  232. }
  233. handle_load(filename, (char *) NULL);
  234. }
  235. /* Is this used? bjm 1998/10/08   No. tgl 1999/02/07 */
  236. #ifdef NOT_USED
  237. func_ptr
  238. trigger_dynamic(char *filename, char *funcname)
  239. {
  240. func_ptr trigger_fn;
  241. trigger_fn = handle_load(filename, funcname);
  242. return trigger_fn;
  243. }
  244. #endif