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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * nodeNestloop.c
  4.  *   routines to support nest-loop joins
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.11 1999/02/13 23:15:25 momjian Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. /*
  15.  *  INTERFACE ROUTINES
  16.  * ExecNestLoop  - process a nestloop join of two plans
  17.  * ExecInitNestLoop - initialize the join
  18.  * ExecEndNestLoop  - shut down the join
  19.  */
  20. #include "postgres.h"
  21. #include "executor/executor.h"
  22. #include "executor/execdebug.h"
  23. #include "executor/nodeNestloop.h"
  24. #include "executor/nodeIndexscan.h"
  25. /* ----------------------------------------------------------------
  26.  * ExecNestLoop(node)
  27.  *
  28.  * old comments
  29.  * Returns the tuple joined from inner and outer tuples which
  30.  * satisfies the qualification clause.
  31.  *
  32.  * It scans the inner relation to join with current outer tuple.
  33.  *
  34.  * If none is found, next tuple form the outer relation is retrieved
  35.  * and the inner relation is scanned from the beginning again to join
  36.  * with the outer tuple.
  37.  *
  38.  * Nil is returned if all the remaining outer tuples are tried and
  39.  * all fail to join with the inner tuples.
  40.  *
  41.  * Nil is also returned if there is no tuple from inner realtion.
  42.  *
  43.  * Conditions:
  44.  *   -- outerTuple contains current tuple from outer relation and
  45.  *  the right son(inner realtion) maintains "cursor" at the tuple
  46.  *  returned previously.
  47.  * This is achieved by maintaining a scan position on the outer
  48.  * relation.
  49.  *
  50.  * Initial States:
  51.  *   -- the outer child and the inner child
  52.  *    are prepared to return the first tuple.
  53.  * ----------------------------------------------------------------
  54.  */
  55. TupleTableSlot *
  56. ExecNestLoop(NestLoop *node, Plan *parent)
  57. {
  58. NestLoopState *nlstate;
  59. Plan    *innerPlan;
  60. Plan    *outerPlan;
  61. bool needNewOuterTuple;
  62. TupleTableSlot *outerTupleSlot;
  63. TupleTableSlot *innerTupleSlot;
  64. List    *qual;
  65. bool qualResult;
  66. ExprContext *econtext;
  67. /* ----------------
  68.  * get information from the node
  69.  * ----------------
  70.  */
  71. ENL1_printf("getting info from node");
  72. nlstate = node->nlstate;
  73. qual = node->join.qual;
  74. outerPlan = outerPlan(&node->join);
  75. innerPlan = innerPlan(&node->join);
  76. /* ----------------
  77.  * initialize expression context
  78.  * ----------------
  79.  */
  80. econtext = nlstate->jstate.cs_ExprContext;
  81. /* ----------------
  82.  * get the current outer tuple
  83.  * ----------------
  84.  */
  85. outerTupleSlot = nlstate->jstate.cs_OuterTupleSlot;
  86. econtext->ecxt_outertuple = outerTupleSlot;
  87. /* ----------------
  88.  * Ok, everything is setup for the join so now loop until
  89.  * we return a qualifying join tuple..
  90.  * ----------------
  91.  */
  92. if (nlstate->jstate.cs_TupFromTlist)
  93. {
  94. TupleTableSlot *result;
  95. bool isDone;
  96. result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
  97. if (!isDone)
  98. return result;
  99. }
  100. ENL1_printf("entering main loop");
  101. for (;;)
  102. {
  103. /* ----------------
  104.  * The essential idea now is to get the next inner tuple
  105.  * and join it with the current outer tuple.
  106.  * ----------------
  107.  */
  108. needNewOuterTuple = false;
  109. if (!TupIsNull(outerTupleSlot))
  110. ENL1_printf("have outer tuple, deal with it");
  111. else
  112. {
  113. ENL1_printf("outer tuple is nil, need new outer tuple");
  114. needNewOuterTuple = true;
  115. }
  116. /* ----------------
  117.  * if we have an outerTuple, try to get the next inner tuple.
  118.  * ----------------
  119.  */
  120. if (!needNewOuterTuple)
  121. {
  122. ENL1_printf("getting new inner tuple");
  123. innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
  124. econtext->ecxt_innertuple = innerTupleSlot;
  125. if (TupIsNull(innerTupleSlot))
  126. {
  127. ENL1_printf("no inner tuple, need new outer tuple");
  128. needNewOuterTuple = true;
  129. }
  130. }
  131. /* ----------------
  132.  * loop until we have a new outer tuple and a new
  133.  * inner tuple.
  134.  * ----------------
  135.  */
  136. while (needNewOuterTuple)
  137. {
  138. /* ----------------
  139.  * now try to get the next outer tuple
  140.  * ----------------
  141.  */
  142. ENL1_printf("getting new outer tuple");
  143. outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
  144. econtext->ecxt_outertuple = outerTupleSlot;
  145. /* ----------------
  146.  * if there are no more outer tuples, then the join
  147.  * is complete..
  148.  * ----------------
  149.  */
  150. if (TupIsNull(outerTupleSlot))
  151. {
  152. ENL1_printf("no outer tuple, ending join");
  153. return NULL;
  154. }
  155. ENL1_printf("saving new outer tuple information");
  156. nlstate->jstate.cs_OuterTupleSlot = outerTupleSlot;
  157. /* ----------------
  158.  * now rescan the inner plan and get a new inner tuple
  159.  * ----------------
  160.  */
  161. ENL1_printf("rescanning inner plan");
  162. /*
  163.  * The scan key of the inner plan might depend on the current
  164.  * outer tuple (e.g. in index scans), that's why we pass our
  165.  * expr context.
  166.  */
  167. ExecReScan(innerPlan, econtext, parent);
  168. ENL1_printf("getting new inner tuple");
  169. innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
  170. econtext->ecxt_innertuple = innerTupleSlot;
  171. if (TupIsNull(innerTupleSlot))
  172. ENL1_printf("couldn't get inner tuple - need new outer tuple");
  173. else
  174. {
  175. ENL1_printf("got inner and outer tuples");
  176. needNewOuterTuple = false;
  177. }
  178. } /* while (needNewOuterTuple) */
  179. /* ----------------
  180.  *  at this point we have a new pair of inner and outer
  181.  *  tuples so we test the inner and outer tuples to see
  182.  *  if they satisify the node's qualification.
  183.  * ----------------
  184.  */
  185. ENL1_printf("testing qualification");
  186. qualResult = ExecQual((List *) qual, econtext);
  187. if (qualResult)
  188. {
  189. /* ----------------
  190.  * qualification was satisified so we project and
  191.  * return the slot containing the result tuple
  192.  * using ExecProject().
  193.  * ----------------
  194.  */
  195. ProjectionInfo *projInfo;
  196. TupleTableSlot *result;
  197. bool isDone;
  198. ENL1_printf("qualification succeeded, projecting tuple");
  199. projInfo = nlstate->jstate.cs_ProjInfo;
  200. result = ExecProject(projInfo, &isDone);
  201. nlstate->jstate.cs_TupFromTlist = !isDone;
  202. return result;
  203. }
  204. /* ----------------
  205.  * qualification failed so we have to try again..
  206.  * ----------------
  207.  */
  208. ENL1_printf("qualification failed, looping");
  209. }
  210. }
  211. /* ----------------------------------------------------------------
  212.  * ExecInitNestLoop
  213.  *
  214.  * Creates the run-time state information for the nestloop node
  215.  * produced by the planner and initailizes inner and outer relations
  216.  * (child nodes).
  217.  * ----------------------------------------------------------------
  218.  */
  219. bool
  220. ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
  221. {
  222. NestLoopState *nlstate;
  223. NL1_printf("ExecInitNestLoop: %sn",
  224.    "initializing node");
  225. /* ----------------
  226.  * assign execution state to node
  227.  * ----------------
  228.  */
  229. node->join.state = estate;
  230. /* ----------------
  231.  *   create new nest loop state
  232.  * ----------------
  233.  */
  234. nlstate = makeNode(NestLoopState);
  235. nlstate->nl_PortalFlag = false;
  236. node->nlstate = nlstate;
  237. /* ----------------
  238.  * Miscellanious initialization
  239.  *
  240.  *  + assign node's base_id
  241.  *  + assign debugging hooks and
  242.  *  + create expression context for node
  243.  * ----------------
  244.  */
  245. ExecAssignNodeBaseInfo(estate, &nlstate->jstate, parent);
  246. ExecAssignExprContext(estate, &nlstate->jstate);
  247. #define NESTLOOP_NSLOTS 1
  248. /* ----------------
  249.  * tuple table initialization
  250.  * ----------------
  251.  */
  252. ExecInitResultTupleSlot(estate, &nlstate->jstate);
  253. /* ----------------
  254.  *   now initialize children
  255.  * ----------------
  256.  */
  257. ExecInitNode(outerPlan((Plan *) node), estate, (Plan *) node);
  258. ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node);
  259. /* ----------------
  260.  * initialize tuple type and projection info
  261.  * ----------------
  262.  */
  263. ExecAssignResultTypeFromTL((Plan *) node, &nlstate->jstate);
  264. ExecAssignProjectionInfo((Plan *) node, &nlstate->jstate);
  265. /* ----------------
  266.  * finally, wipe the current outer tuple clean.
  267.  * ----------------
  268.  */
  269. nlstate->jstate.cs_OuterTupleSlot = NULL;
  270. nlstate->jstate.cs_TupFromTlist = false;
  271. NL1_printf("ExecInitNestLoop: %sn",
  272.    "node initialized");
  273. return TRUE;
  274. }
  275. int
  276. ExecCountSlotsNestLoop(NestLoop *node)
  277. {
  278. return ExecCountSlotsNode(outerPlan(node)) +
  279. ExecCountSlotsNode(innerPlan(node)) +
  280. NESTLOOP_NSLOTS;
  281. }
  282. /* ----------------------------------------------------------------
  283.  * ExecEndNestLoop
  284.  *
  285.  * closes down scans and frees allocated storage
  286.  * ----------------------------------------------------------------
  287.  */
  288. void
  289. ExecEndNestLoop(NestLoop *node)
  290. {
  291. NestLoopState *nlstate;
  292. NL1_printf("ExecEndNestLoop: %sn",
  293.    "ending node processing");
  294. /* ----------------
  295.  * get info from the node
  296.  * ----------------
  297.  */
  298. nlstate = node->nlstate;
  299. /* ----------------
  300.  * Free the projection info
  301.  *
  302.  * Note: we don't ExecFreeResultType(nlstate)
  303.  *   because the rule manager depends on the tupType
  304.  *   returned by ExecMain().  So for now, this
  305.  *   is freed at end-transaction time.  -cim 6/2/91
  306.  * ----------------
  307.  */
  308. ExecFreeProjectionInfo(&nlstate->jstate);
  309. /* ----------------
  310.  * close down subplans
  311.  * ----------------
  312.  */
  313. ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
  314. ExecEndNode(innerPlan((Plan *) node), (Plan *) node);
  315. /* ----------------
  316.  * clean out the tuple table
  317.  * ----------------
  318.  */
  319. ExecClearTuple(nlstate->jstate.cs_ResultTupleSlot);
  320. NL1_printf("ExecEndNestLoop: %sn",
  321.    "node processing ended");
  322. }
  323. /* ----------------------------------------------------------------
  324.  * ExecReScanNestLoop
  325.  * ----------------------------------------------------------------
  326.  */
  327. void
  328. ExecReScanNestLoop(NestLoop *node, ExprContext *exprCtxt, Plan *parent)
  329. {
  330. NestLoopState *nlstate = node->nlstate;
  331. Plan    *outerPlan = outerPlan((Plan *) node);
  332. /*
  333.  * If outerPlan->chgParam is not null then plan will be automatically
  334.  * re-scanned by first ExecProcNode. innerPlan is re-scanned for each
  335.  * new outer tuple and MUST NOT be re-scanned from here or you'll get
  336.  * troubles from inner index scans when outer Vars are used as
  337.  * run-time keys...
  338.  */
  339. if (outerPlan->chgParam == NULL)
  340. ExecReScan(outerPlan, exprCtxt, (Plan *) node);
  341. /* let outerPlan to free its result typle ... */
  342. nlstate->jstate.cs_OuterTupleSlot = NULL;
  343. nlstate->jstate.cs_TupFromTlist = false;
  344. return;
  345. }