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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * functions.c
  4.  *   Routines to handle functions called from the executor
  5.  *   Putting this stuff in fmgr makes the postmaster a mess....
  6.  *
  7.  * Copyright (c) 1994, Regents of the University of California
  8.  *
  9.  *
  10.  * IDENTIFICATION
  11.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/executor/functions.c,v 1.26 1999/05/25 16:08:39 momjian Exp $
  12.  *
  13.  *-------------------------------------------------------------------------
  14.  */
  15. #include <string.h>
  16. #include "postgres.h"
  17. #include "nodes/primnodes.h"
  18. #include "nodes/relation.h"
  19. #include "nodes/execnodes.h"
  20. #include "nodes/plannodes.h"
  21. #include "catalog/pg_proc.h"
  22. #include "tcop/pquery.h"
  23. #include "tcop/tcopprot.h"
  24. #include "tcop/utility.h"
  25. #include "nodes/params.h"
  26. #include "fmgr.h"
  27. #include "utils/fcache.h"
  28. #include "utils/datum.h"
  29. #include "utils/elog.h"
  30. #include "utils/palloc.h"
  31. #include "utils/syscache.h"
  32. #include "catalog/pg_language.h"
  33. #include "access/heapam.h"
  34. #include "access/xact.h"
  35. #include "executor/executor.h"
  36. #include "executor/execdefs.h"
  37. #include "executor/functions.h"
  38. #undef new
  39. typedef enum
  40. {
  41. F_EXEC_START, F_EXEC_RUN, F_EXEC_DONE
  42. } ExecStatus;
  43. typedef struct local_es
  44. {
  45. QueryDesc  *qd;
  46. EState    *estate;
  47. struct local_es *next;
  48. ExecStatus status;
  49. } execution_state;
  50. #define LAST_POSTQUEL_COMMAND(es) ((es)->next == (execution_state *)NULL)
  51. /* non-export function prototypes */
  52. static TupleDesc postquel_start(execution_state *es);
  53. static execution_state *init_execution_state(FunctionCachePtr fcache,
  54.  char *args[]);
  55. static TupleTableSlot *postquel_getnext(execution_state *es);
  56. static void postquel_end(execution_state *es);
  57. static void postquel_sub_params(execution_state *es, int nargs,
  58. char *args[], bool *nullV);
  59. static Datum postquel_execute(execution_state *es, FunctionCachePtr fcache,
  60.  List *fTlist, char **args, bool *isNull);
  61. Datum
  62. ProjectAttribute(TupleDesc TD,
  63.  TargetEntry *tlist,
  64.  HeapTuple tup,
  65.  bool *isnullP)
  66. {
  67. Datum val,
  68. valueP;
  69. Var    *attrVar = (Var *) tlist->expr;
  70. AttrNumber attrno = attrVar->varattno;
  71. val = heap_getattr(tup, attrno, TD, isnullP);
  72. if (*isnullP)
  73. return (Datum) NULL;
  74. valueP = datumCopy(val,
  75.    TD->attrs[attrno - 1]->atttypid,
  76.    TD->attrs[attrno - 1]->attbyval,
  77.    (Size) TD->attrs[attrno - 1]->attlen);
  78. return valueP;
  79. }
  80. static execution_state *
  81. init_execution_state(FunctionCachePtr fcache,
  82.  char *args[])
  83. {
  84. execution_state *newes;
  85. execution_state *nextes;
  86. execution_state *preves;
  87. List    *queryTree_list,
  88.    *planTree_list,
  89.    *qtl_item;
  90. int nargs = fcache->nargs;
  91. newes = (execution_state *) palloc(sizeof(execution_state));
  92. nextes = newes;
  93. preves = (execution_state *) NULL;
  94. planTree_list = pg_parse_and_plan(fcache->src, fcache->argOidVect,
  95. nargs, &queryTree_list, None, FALSE);
  96. foreach(qtl_item, queryTree_list)
  97. {
  98. Query    *queryTree = lfirst(qtl_item);
  99. Plan    *planTree = lfirst(planTree_list);
  100. EState    *estate;
  101. if (!nextes)
  102. nextes = (execution_state *) palloc(sizeof(execution_state));
  103. if (preves)
  104. preves->next = nextes;
  105. nextes->next = NULL;
  106. nextes->status = F_EXEC_START;
  107. nextes->qd = CreateQueryDesc(queryTree,
  108.  planTree,
  109.  None);
  110. estate = CreateExecutorState();
  111. if (queryTree->limitOffset != NULL || queryTree->limitCount != NULL)
  112. elog(ERROR, "LIMIT clause from SQL functions not yet implemented");
  113. if (nargs > 0)
  114. {
  115. int i;
  116. ParamListInfo paramLI;
  117. paramLI = (ParamListInfo) palloc((nargs + 1) * sizeof(ParamListInfoData));
  118. MemSet(paramLI, 0, nargs * sizeof(ParamListInfoData));
  119. estate->es_param_list_info = paramLI;
  120. for (i = 0; i < nargs; paramLI++, i++)
  121. {
  122. paramLI->kind = PARAM_NUM;
  123. paramLI->id = i + 1;
  124. paramLI->isnull = false;
  125. paramLI->value = (Datum) NULL;
  126. }
  127. paramLI->kind = PARAM_INVALID;
  128. }
  129. else
  130. estate->es_param_list_info = (ParamListInfo) NULL;
  131. nextes->estate = estate;
  132. preves = nextes;
  133. nextes = (execution_state *) NULL;
  134. planTree_list = lnext(planTree_list);
  135. }
  136. return newes;
  137. }
  138. static TupleDesc
  139. postquel_start(execution_state *es)
  140. {
  141. #ifdef FUNC_UTIL_PATCH
  142. /*
  143.  * Do nothing for utility commands. (create, destroy...)  DZ -
  144.  * 30-8-1996
  145.  */
  146. if (es->qd->operation == CMD_UTILITY)
  147. return (TupleDesc) NULL;
  148. #endif
  149. return ExecutorStart(es->qd, es->estate);
  150. }
  151. static TupleTableSlot *
  152. postquel_getnext(execution_state *es)
  153. {
  154. int feature;
  155. #ifdef FUNC_UTIL_PATCH
  156. if (es->qd->operation == CMD_UTILITY)
  157. {
  158. /*
  159.  * Process an utility command. (create, destroy...)  DZ -
  160.  * 30-8-1996
  161.  */
  162. ProcessUtility(es->qd->parsetree->utilityStmt, es->qd->dest);
  163. if (!LAST_POSTQUEL_COMMAND(es))
  164. CommandCounterIncrement();
  165. return (TupleTableSlot *) NULL;
  166. }
  167. #endif
  168. feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
  169. return ExecutorRun(es->qd, es->estate, feature, (Node *) NULL, (Node *) NULL);
  170. }
  171. static void
  172. postquel_end(execution_state *es)
  173. {
  174. #ifdef FUNC_UTIL_PATCH
  175. /*
  176.  * Do nothing for utility commands. (create, destroy...)  DZ -
  177.  * 30-8-1996
  178.  */
  179. if (es->qd->operation == CMD_UTILITY)
  180. return;
  181. #endif
  182. ExecutorEnd(es->qd, es->estate);
  183. }
  184. static void
  185. postquel_sub_params(execution_state *es,
  186. int nargs,
  187. char *args[],
  188. bool *nullV)
  189. {
  190. ParamListInfo paramLI;
  191. EState    *estate;
  192. estate = es->estate;
  193. paramLI = estate->es_param_list_info;
  194. while (paramLI->kind != PARAM_INVALID)
  195. {
  196. if (paramLI->kind == PARAM_NUM)
  197. {
  198. Assert(paramLI->id <= nargs);
  199. paramLI->value = (Datum) args[(paramLI->id - 1)];
  200. paramLI->isnull = nullV[(paramLI->id - 1)];
  201. }
  202. paramLI++;
  203. }
  204. }
  205. static TupleTableSlot *
  206. copy_function_result(FunctionCachePtr fcache,
  207.  TupleTableSlot *resultSlot)
  208. {
  209. TupleTableSlot *funcSlot;
  210. TupleDesc resultTd;
  211. HeapTuple newTuple;
  212. HeapTuple oldTuple;
  213. Assert(!TupIsNull(resultSlot));
  214. oldTuple = resultSlot->val;
  215. funcSlot = (TupleTableSlot *) fcache->funcSlot;
  216. if (funcSlot == (TupleTableSlot *) NULL)
  217. return resultSlot;
  218. resultTd = resultSlot->ttc_tupleDescriptor;
  219. /*
  220.  * When the funcSlot is NULL we have to initialize the funcSlot's
  221.  * tuple descriptor.
  222.  */
  223. if (TupIsNull(funcSlot))
  224. {
  225. int i = 0;
  226. TupleDesc funcTd = funcSlot->ttc_tupleDescriptor;
  227. while (i < oldTuple->t_data->t_natts)
  228. {
  229. funcTd->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
  230. memmove(funcTd->attrs[i],
  231. resultTd->attrs[i],
  232. ATTRIBUTE_TUPLE_SIZE);
  233. i++;
  234. }
  235. }
  236. newTuple = heap_copytuple(oldTuple);
  237. return ExecStoreTuple(newTuple, funcSlot, InvalidBuffer, true);
  238. }
  239. static Datum
  240. postquel_execute(execution_state *es,
  241.  FunctionCachePtr fcache,
  242.  List *fTlist,
  243.  char **args,
  244.  bool *isNull)
  245. {
  246. TupleTableSlot *slot;
  247. Datum value;
  248. /*
  249.  * It's more right place to do it (before
  250.  * postquel_start->ExecutorStart). Now
  251.  * ExecutorStart->ExecInitIndexScan->ExecEvalParam works ok. (But
  252.  * note: I HOPE we can do it here). - vadim 01/22/97
  253.  */
  254. if (fcache->nargs > 0)
  255. postquel_sub_params(es, fcache->nargs, args, fcache->nullVect);
  256. if (es->status == F_EXEC_START)
  257. {
  258. postquel_start(es);
  259. es->status = F_EXEC_RUN;
  260. }
  261. slot = postquel_getnext(es);
  262. if (TupIsNull(slot))
  263. {
  264. postquel_end(es);
  265. es->status = F_EXEC_DONE;
  266. *isNull = true;
  267. /*
  268.  * If this isn't the last command for the function we have to
  269.  * increment the command counter so that subsequent commands can
  270.  * see changes made by previous ones.
  271.  */
  272. if (!LAST_POSTQUEL_COMMAND(es))
  273. CommandCounterIncrement();
  274. return (Datum) NULL;
  275. }
  276. if (LAST_POSTQUEL_COMMAND(es))
  277. {
  278. TupleTableSlot *resSlot;
  279. /*
  280.  * Copy the result.  copy_function_result is smart enough to do
  281.  * nothing when no action is called for.  This helps reduce the
  282.  * logic and code redundancy here.
  283.  */
  284. resSlot = copy_function_result(fcache, slot);
  285. if (fTlist != NIL)
  286. {
  287. TargetEntry *tle = lfirst(fTlist);
  288. value = ProjectAttribute(resSlot->ttc_tupleDescriptor,
  289.  tle,
  290.  resSlot->val,
  291.  isNull);
  292. }
  293. else
  294. {
  295. value = (Datum) resSlot;
  296. *isNull = false;
  297. }
  298. /*
  299.  * If this is a single valued function we have to end the function
  300.  * execution now.
  301.  */
  302. if (fcache->oneResult)
  303. {
  304. postquel_end(es);
  305. es->status = F_EXEC_DONE;
  306. }
  307. return value;
  308. }
  309. /*
  310.  * If this isn't the last command for the function, we don't return
  311.  * any results, but we have to increment the command counter so that
  312.  * subsequent commands can see changes made by previous ones.
  313.  */
  314. CommandCounterIncrement();
  315. return (Datum) NULL;
  316. }
  317. Datum
  318. postquel_function(Func *funcNode, char **args, bool *isNull, bool *isDone)
  319. {
  320. execution_state *es;
  321. Datum result = 0;
  322. FunctionCachePtr fcache = funcNode->func_fcache;
  323. CommandId savedId;
  324. /*
  325.  * Before we start do anything we must save CurrentScanCommandId to
  326.  * restore it before return to upper Executor. Also, we have to set
  327.  * CurrentScanCommandId equal to CurrentCommandId. - vadim 08/29/97
  328.  */
  329. savedId = GetScanCommandId();
  330. SetScanCommandId(GetCurrentCommandId());
  331. es = (execution_state *) fcache->func_state;
  332. if (es == NULL)
  333. {
  334. es = init_execution_state(fcache, args);
  335. fcache->func_state = (char *) es;
  336. }
  337. while (es && es->status == F_EXEC_DONE)
  338. es = es->next;
  339. Assert(es);
  340. /*
  341.  * Execute each command in the function one after another until we're
  342.  * executing the final command and get a result or we run out of
  343.  * commands.
  344.  */
  345. while (es != (execution_state *) NULL)
  346. {
  347. result = postquel_execute(es,
  348.   fcache,
  349.   funcNode->func_tlist,
  350.   args,
  351.   isNull);
  352. if (es->status != F_EXEC_DONE)
  353. break;
  354. es = es->next;
  355. }
  356. /*
  357.  * If we've gone through every command in this function, we are done.
  358.  */
  359. if (es == (execution_state *) NULL)
  360. {
  361. /*
  362.  * Reset the execution states to start over again
  363.  */
  364. es = (execution_state *) fcache->func_state;
  365. while (es)
  366. {
  367. es->status = F_EXEC_START;
  368. es = es->next;
  369. }
  370. /*
  371.  * Let caller know we're finished.
  372.  */
  373. *isDone = true;
  374. SetScanCommandId(savedId);
  375. return (fcache->oneResult) ? result : (Datum) NULL;
  376. }
  377. /*
  378.  * If we got a result from a command within the function it has to be
  379.  * the final command.  All others shouldn't be returing anything.
  380.  */
  381. Assert(LAST_POSTQUEL_COMMAND(es));
  382. *isDone = false;
  383. SetScanCommandId(savedId);
  384. return result;
  385. }