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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * fcache.c
  4.  *   Code for the 'function cache' used in Oper and Func nodes....
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/utils/cache/fcache.c,v 1.22 1999/05/10 00:46:06 momjian Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include "postgres.h"
  15. #include <nodes/parsenodes.h>
  16. #include <fmgr.h>
  17. #include "access/htup.h"
  18. #include "utils/catcache.h"
  19. #include "utils/syscache.h"
  20. #include "catalog/pg_type.h"
  21. #include "catalog/pg_proc.h"
  22. #include "catalog/pg_language.h"
  23. #include "catalog/pg_class.h"
  24. #include "parser/parsetree.h" /* for getrelname() */
  25. #include "utils/builtins.h"
  26. #include "utils/fcache.h"
  27. #include "utils/fcache2.h"
  28. #include "nodes/primnodes.h"
  29. #include "nodes/execnodes.h"
  30. #ifndef HAVE_MEMMOVE
  31. #include <regex/utils.h>
  32. #else
  33. #include <string.h>
  34. #endif
  35. static Oid GetDynamicFuncArgType(Var *arg, ExprContext *econtext);
  36. static FunctionCachePtr init_fcache(Oid foid,
  37. bool use_syscache,
  38. List *argList,
  39. ExprContext *econtext);
  40. /*-----------------------------------------------------------------
  41.  *
  42.  * Initialize the 'FunctionCache' given the PG_PROC oid.
  43.  *
  44.  *
  45.  * NOTE:  This function can be called when the system cache is being
  46.  *   initialized. Therefore, use_syscache should ONLY be true
  47.  *   when the function return type is interesting (ie: set_fcache).
  48.  *-----------------------------------------------------------------
  49.  */
  50. #define FuncArgTypeIsDynamic(arg) 
  51. (IsA(arg,Var) && ((Var*)arg)->varattno == InvalidAttrNumber)
  52. static Oid
  53. GetDynamicFuncArgType(Var *arg, ExprContext *econtext)
  54. {
  55. char    *relname;
  56. int rtid;
  57. HeapTuple tup;
  58. Assert(IsA(arg, Var));
  59. rtid = ((Var *) arg)->varno;
  60. relname = (char *) getrelname(rtid, econtext->ecxt_range_table);
  61. tup = SearchSysCacheTuple(TYPNAME,
  62.   PointerGetDatum(relname),
  63.   0, 0, 0);
  64. if (!tup)
  65. elog(ERROR, "Lookup failed on type tuple for class %s",
  66.  relname);
  67. return tup->t_data->t_oid;
  68. }
  69. static FunctionCachePtr
  70. init_fcache(Oid foid,
  71. bool use_syscache,
  72. List *argList,
  73. ExprContext *econtext)
  74. {
  75. HeapTuple procedureTuple;
  76. HeapTuple typeTuple;
  77. Form_pg_proc procedureStruct;
  78. Form_pg_type typeStruct;
  79. FunctionCachePtr retval;
  80. text    *tmp;
  81. int nargs;
  82. /* ----------------
  83.  *  get the procedure tuple corresponding to the given
  84.  *  functionOid.  If this fails, returnValue has been
  85.  *  pre-initialized to "null" so we just return it.
  86.  * ----------------
  87.  */
  88. retval = (FunctionCachePtr) palloc(sizeof(FunctionCache));
  89. memset(retval, 0, sizeof(FunctionCache));
  90. if (!use_syscache)
  91. elog(ERROR, "what the ????, init the fcache without the catalogs?");
  92. procedureTuple = SearchSysCacheTuple(PROOID,
  93.  ObjectIdGetDatum(foid),
  94.  0, 0, 0);
  95. if (!HeapTupleIsValid(procedureTuple))
  96. elog(ERROR,
  97.  "init_fcache: %s %u",
  98.  "Cache lookup failed for procedure", foid);
  99. /* ----------------
  100.  *  get the return type from the procedure tuple
  101.  * ----------------
  102.  */
  103. procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
  104. /* ----------------
  105.  *  get the type tuple corresponding to the return type
  106.  *  If this fails, returnValue has been pre-initialized
  107.  *  to "null" so we just return it.
  108.  * ----------------
  109.  */
  110. typeTuple = SearchSysCacheTuple(TYPOID,
  111.    ObjectIdGetDatum(procedureStruct->prorettype),
  112. 0, 0, 0);
  113. if (!HeapTupleIsValid(typeTuple))
  114. elog(ERROR,
  115.  "init_fcache: %s %u",
  116.  "Cache lookup failed for type",
  117.  (procedureStruct)->prorettype);
  118. /* ----------------
  119.  *  get the type length and by-value from the type tuple and
  120.  *  save the information in our one element cache.
  121.  * ----------------
  122.  */
  123. typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
  124. retval->typlen = (typeStruct)->typlen;
  125. if ((typeStruct)->typrelid == InvalidOid)
  126. {
  127. /* The return type is not a relation, so just use byval */
  128. retval->typbyval = (typeStruct)->typbyval ? true : false;
  129. }
  130. else
  131. {
  132. /*
  133.  * This is a hack. We assume here that any function returning a
  134.  * relation returns it by reference.  This needs to be fixed.
  135.  */
  136. retval->typbyval = false;
  137. }
  138. retval->foid = foid;
  139. retval->language = procedureStruct->prolang;
  140. retval->func_state = (char *) NULL;
  141. retval->setArg = NULL;
  142. retval->hasSetArg = false;
  143. retval->oneResult = !procedureStruct->proretset;
  144. retval->istrusted = procedureStruct->proistrusted;
  145. /*
  146.  * If we are returning exactly one result then we have to copy tuples
  147.  * and by reference results because we have to end the execution
  148.  * before we return the results.  When you do this everything
  149.  * allocated by the executor (i.e. slots and tuples) is freed.
  150.  */
  151. if ((retval->language == SQLlanguageId) &&
  152. (retval->oneResult) &&
  153. !(retval->typbyval))
  154. {
  155. Form_pg_class relationStruct;
  156. HeapTuple relationTuple;
  157. TupleDesc td;
  158. TupleTableSlot *slot;
  159. slot = makeNode(TupleTableSlot);
  160. slot->ttc_shouldFree = true;
  161. slot->ttc_descIsNew = true;
  162. slot->ttc_tupleDescriptor = (TupleDesc) NULL;
  163. slot->ttc_buffer = InvalidBuffer;
  164. slot->ttc_whichplan = -1;
  165. retval->funcSlot = (Pointer) slot;
  166. relationTuple = (HeapTuple)
  167. SearchSysCacheTuple(RELNAME,
  168. PointerGetDatum(&typeStruct->typname),
  169. 0, 0, 0);
  170. if (relationTuple)
  171. {
  172. relationStruct = (Form_pg_class) GETSTRUCT(relationTuple);
  173. td = CreateTemplateTupleDesc(relationStruct->relnatts);
  174. }
  175. else
  176. td = CreateTemplateTupleDesc(1);
  177. ((TupleTableSlot *) retval->funcSlot)->ttc_tupleDescriptor = td;
  178. }
  179. else
  180. retval->funcSlot = (char *) NULL;
  181. nargs = procedureStruct->pronargs;
  182. retval->nargs = nargs;
  183. if (nargs > 0)
  184. {
  185. Oid    *argTypes;
  186. retval->nullVect = (bool *) palloc((retval->nargs) * sizeof(bool));
  187. if (retval->language == SQLlanguageId)
  188. {
  189. int i;
  190. List    *oneArg;
  191. retval->argOidVect = (Oid *) palloc(retval->nargs * sizeof(Oid));
  192. argTypes = procedureStruct->proargtypes;
  193. memmove(retval->argOidVect,
  194. argTypes,
  195. (retval->nargs) * sizeof(Oid));
  196. for (i = 0;
  197.  argList;
  198.  i++, argList = lnext(argList))
  199. {
  200. oneArg = lfirst(argList);
  201. if (FuncArgTypeIsDynamic(oneArg))
  202. retval->argOidVect[i] = GetDynamicFuncArgType((Var *) oneArg,
  203.    econtext);
  204. }
  205. }
  206. else
  207. retval->argOidVect = (Oid *) NULL;
  208. }
  209. else
  210. {
  211. retval->argOidVect = (Oid *) NULL;
  212. retval->nullVect = (BoolPtr) NULL;
  213. }
  214. /*
  215.  * XXX this is the first varlena in the struct.  If the order changes
  216.  * for some reason this will fail.
  217.  */
  218. if (procedureStruct->prolang == SQLlanguageId)
  219. {
  220. retval->src = textout(&(procedureStruct->prosrc));
  221. retval->bin = (char *) NULL;
  222. }
  223. else
  224. {
  225. /*
  226.  * I'm not sure that we even need to do this at all.
  227.  */
  228. /*
  229.  * We do for untrusted functions.
  230.  */
  231. if (procedureStruct->proistrusted)
  232. retval->bin = (char *) NULL;
  233. else
  234. {
  235. tmp = (text *)
  236. SearchSysCacheGetAttribute(PROOID,
  237.    Anum_pg_proc_probin,
  238.    ObjectIdGetDatum(foid),
  239.    0, 0, 0);
  240. retval->bin = textout(tmp);
  241. }
  242. retval->src = (char *) NULL;
  243. }
  244. if (retval->language != SQLlanguageId)
  245. {
  246. fmgr_info(foid, &(retval->func));
  247. retval->nargs = retval->func.fn_nargs;
  248. }
  249. else
  250. retval->func.fn_addr = (func_ptr) NULL;
  251. return retval;
  252. }
  253. void
  254. setFcache(Node *node, Oid foid, List *argList, ExprContext *econtext)
  255. {
  256. Func    *fnode;
  257. Oper    *onode;
  258. FunctionCachePtr fcache;
  259. fcache = init_fcache(foid, true, argList, econtext);
  260. if (IsA(node, Oper))
  261. {
  262. onode = (Oper *) node;
  263. onode->op_fcache = fcache;
  264. }
  265. else if (IsA(node, Func))
  266. {
  267. fnode = (Func *) node;
  268. fnode->func_fcache = fcache;
  269. }
  270. else
  271. elog(ERROR, "init_fcache: node must be Oper or Func!");
  272. }