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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * nodeSubplan.c
  4.  *   routines to support subselects
  5.  *
  6.  *-------------------------------------------------------------------------
  7.  */
  8. /*
  9.  *  INTERFACE ROUTINES
  10.  * ExecSubPlan  - process a subselect
  11.  * ExecInitSubPlan - initialize a subselect
  12.  * ExecEndSubPlan - shut down a subselect
  13.  */
  14. #include "postgres.h"
  15. #include "access/heapam.h"
  16. #include "tcop/pquery.h"
  17. #include "executor/executor.h"
  18. #include "executor/execdebug.h"
  19. #include "executor/nodeSubplan.h"
  20. /* ----------------------------------------------------------------
  21.  * ExecSubPlan(node)
  22.  *
  23.  * ----------------------------------------------------------------
  24.  */
  25. Datum
  26. ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
  27. {
  28. Plan    *plan = node->plan;
  29. SubLink    *sublink = node->sublink;
  30. SubLinkType subLinkType = sublink->subLinkType;
  31. TupleTableSlot *slot;
  32. List    *lst;
  33. Datum result = (Datum) false;
  34. bool found = false; /* TRUE if got at least one subplan tuple */
  35. if (node->setParam != NULL)
  36. elog(ERROR, "ExecSubPlan: can't set parent params from subquery");
  37. /*
  38.  * Set Params of this plan from parent plan correlation Vars
  39.  */
  40. if (node->parParam != NULL)
  41. {
  42. foreach(lst, node->parParam)
  43. {
  44. ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]);
  45. prm->value = ExecEvalExpr((Node *) lfirst(pvar),
  46.   econtext,
  47.   &(prm->isnull), NULL);
  48. pvar = lnext(pvar);
  49. }
  50. plan->chgParam = nconc(plan->chgParam, listCopy(node->parParam));
  51. }
  52. ExecReScan(plan, (ExprContext *) NULL, plan);
  53. /*
  54.  * For all sublink types except EXPR_SUBLINK, the result type is
  55.  * boolean, and we have a fairly clear idea of how to combine multiple
  56.  * subitems and deal with NULL values or an empty subplan result.
  57.  *
  58.  * For EXPR_SUBLINK, the result type is whatever the combining operator
  59.  * returns.  We have no way to deal with more than one column in the
  60.  * subplan result --- hopefully the parser forbids that.  More
  61.  * seriously, it's unclear what to do with NULL values or an empty
  62.  * subplan result. For now, we error out, but should something else
  63.  * happen?
  64.  */
  65. for (slot = ExecProcNode(plan, plan);
  66.  !TupIsNull(slot);
  67.  slot = ExecProcNode(plan, plan))
  68. {
  69. HeapTuple tup = slot->val;
  70. TupleDesc tdesc = slot->ttc_tupleDescriptor;
  71. int i = 1;
  72. if (subLinkType == EXPR_SUBLINK && found)
  73. {
  74. elog(ERROR, "ExecSubPlan: more than one tuple returned by expression subselect");
  75. return (Datum) false;
  76. }
  77. if (subLinkType == EXISTS_SUBLINK)
  78. return (Datum) true;
  79. found = true;
  80. foreach(lst, sublink->oper)
  81. {
  82. Expr    *expr = (Expr *) lfirst(lst);
  83. Const    *con = lsecond(expr->args);
  84. bool isnull;
  85. con->constvalue = heap_getattr(tup, i, tdesc, &(con->constisnull));
  86. result = ExecEvalExpr((Node *) expr, econtext, &isnull, (bool *) NULL);
  87. if (isnull)
  88. {
  89. if (subLinkType == EXPR_SUBLINK)
  90. elog(ERROR, "ExecSubPlan: null value returned by expression subselect");
  91. else
  92. result = (Datum) false;
  93. }
  94. if (subLinkType != EXPR_SUBLINK)
  95. {
  96. if ((!(bool) result && !(sublink->useor)) ||
  97. ((bool) result && sublink->useor))
  98. break;
  99. }
  100. i++;
  101. }
  102. if (subLinkType == ALL_SUBLINK && !(bool) result)
  103. break;
  104. if (subLinkType == ANY_SUBLINK && (bool) result)
  105. break;
  106. }
  107. if (!found)
  108. {
  109. /* deal with empty subplan result. Note default result is 'false' */
  110. if (subLinkType == ALL_SUBLINK)
  111. result = (Datum) true;
  112. else if (subLinkType == EXPR_SUBLINK)
  113. elog(ERROR, "ExecSubPlan: no tuples returned by expression subselect");
  114. }
  115. return result;
  116. }
  117. /* ----------------------------------------------------------------
  118.  * ExecInitSubPlan
  119.  *
  120.  * ----------------------------------------------------------------
  121.  */
  122. extern void ExecCheckPerms(CmdType op, int resRel, List *rtable, Query *q);
  123. bool
  124. ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
  125. {
  126. EState    *sp_estate = CreateExecutorState();
  127. ExecCheckPerms(CMD_SELECT, 0, node->rtable, (Query *) NULL);
  128. sp_estate->es_range_table = node->rtable;
  129. sp_estate->es_param_list_info = estate->es_param_list_info;
  130. sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
  131. sp_estate->es_tupleTable =
  132. ExecCreateTupleTable(ExecCountSlotsNode(node->plan) + 10);
  133. pfree(sp_estate->es_refcount);
  134. sp_estate->es_refcount = estate->es_refcount;
  135. sp_estate->es_snapshot = estate->es_snapshot;
  136. if (!ExecInitNode(node->plan, sp_estate, NULL))
  137. return false;
  138. node->shutdown = true;
  139. /*
  140.  * If this plan is un-correlated or undirect correlated one and want
  141.  * to set params for parent plan then prepare parameters.
  142.  */
  143. if (node->setParam != NULL)
  144. {
  145. List    *lst;
  146. foreach(lst, node->setParam)
  147. {
  148. ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
  149. prm->execPlan = node;
  150. }
  151. /*
  152.  * Note that in the case of un-correlated subqueries we don't care
  153.  * about setting parent->chgParam here: indices take care about
  154.  * it, for others - it doesn't matter...
  155.  */
  156. }
  157. return true;
  158. }
  159. /* ----------------------------------------------------------------
  160.  * ExecSetParamPlan
  161.  *
  162.  * Executes plan of node and sets parameters.
  163.  * ----------------------------------------------------------------
  164.  */
  165. void
  166. ExecSetParamPlan(SubPlan *node)
  167. {
  168. Plan    *plan = node->plan;
  169. SubLink    *sublink = node->sublink;
  170. TupleTableSlot *slot;
  171. List    *lst;
  172. bool found = false;
  173. if (sublink->subLinkType == ANY_SUBLINK ||
  174. sublink->subLinkType == ALL_SUBLINK)
  175. elog(ERROR, "ExecSetParamPlan: ANY/ALL subselect unsupported");
  176. if (plan->chgParam != NULL)
  177. ExecReScan(plan, (ExprContext *) NULL, plan);
  178. for (slot = ExecProcNode(plan, plan);
  179.  !TupIsNull(slot);
  180.  slot = ExecProcNode(plan, plan))
  181. {
  182. HeapTuple tup = slot->val;
  183. TupleDesc tdesc = slot->ttc_tupleDescriptor;
  184. int i = 1;
  185. if (sublink->subLinkType == EXPR_SUBLINK && found)
  186. {
  187. elog(ERROR, "ExecSetParamPlan: more than one tuple returned by expression subselect");
  188. return;
  189. }
  190. found = true;
  191. if (sublink->subLinkType == EXISTS_SUBLINK)
  192. {
  193. ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
  194. prm->execPlan = NULL;
  195. prm->value = (Datum) true;
  196. prm->isnull = false;
  197. break;
  198. }
  199. /*
  200.  * If this is uncorrelated subquery then its plan will be closed
  201.  * (see below) and this tuple will be free-ed - bad for not byval
  202.  * types... But is free-ing possible in the next ExecProcNode in
  203.  * this loop ? Who knows... Someday we'll keep track of saved
  204.  * tuples...
  205.  */
  206. tup = heap_copytuple(tup);
  207. foreach(lst, node->setParam)
  208. {
  209. ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
  210. prm->execPlan = NULL;
  211. prm->value = heap_getattr(tup, i, tdesc, &(prm->isnull));
  212. i++;
  213. }
  214. }
  215. if (!found)
  216. {
  217. if (sublink->subLinkType == EXISTS_SUBLINK)
  218. {
  219. ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
  220. prm->execPlan = NULL;
  221. prm->value = (Datum) false;
  222. prm->isnull = false;
  223. }
  224. else
  225. {
  226. foreach(lst, node->setParam)
  227. {
  228. ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
  229. prm->execPlan = NULL;
  230. prm->value = (Datum) NULL;
  231. prm->isnull = true;
  232. }
  233. }
  234. }
  235. if (plan->extParam == NULL) /* un-correlated ... */
  236. {
  237. ExecEndNode(plan, plan);
  238. node->shutdown = false;
  239. }
  240. }
  241. /* ----------------------------------------------------------------
  242.  * ExecEndSubPlan
  243.  * ----------------------------------------------------------------
  244.  */
  245. void
  246. ExecEndSubPlan(SubPlan *node)
  247. {
  248. if (node->shutdown)
  249. {
  250. ExecEndNode(node->plan, node->plan);
  251. node->shutdown = false;
  252. }
  253. }
  254. void
  255. ExecReScanSetParamPlan(SubPlan *node, Plan *parent)
  256. {
  257. Plan    *plan = node->plan;
  258. List    *lst;
  259. if (node->parParam != NULL)
  260. elog(ERROR, "ExecReScanSetParamPlan: direct correlated subquery unsupported, yet");
  261. if (node->setParam == NULL)
  262. elog(ERROR, "ExecReScanSetParamPlan: setParam list is NULL");
  263. if (plan->extParam == NULL)
  264. elog(ERROR, "ExecReScanSetParamPlan: extParam list of plan is NULL");
  265. /*
  266.  * Don't actual re-scan: ExecSetParamPlan does re-scan if
  267.  * node->plan->chgParam is not NULL... ExecReScan (plan, NULL, plan);
  268.  */
  269. foreach(lst, node->setParam)
  270. {
  271. ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
  272. prm->execPlan = node;
  273. }
  274. parent->chgParam = nconc(parent->chgParam, listCopy(node->setParam));
  275. }