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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * nodeAppend.c
  4.  *   routines to handle append nodes.
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.19 1999/05/25 16:08:40 momjian Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. /* INTERFACE ROUTINES
  15.  * ExecInitAppend - initialize the append node
  16.  * ExecProcAppend - retrieve the next tuple from the node
  17.  * ExecEndAppend - shut down the append node
  18.  * ExecReScanAppend - rescan the append node
  19.  *
  20.  *  NOTES
  21.  * Each append node contains a list of one or more subplans which
  22.  * must be iteratively processed (forwards or backwards).
  23.  * Tuples are retrieved by executing the 'whichplan'th subplan
  24.  * until the subplan stops returning tuples, at which point that
  25.  * plan is shut down and the next started up.
  26.  *
  27.  * Append nodes don't make use of their left and right
  28.  * subtrees, rather they maintain a list of subplans so
  29.  * a typical append node looks like this in the plan tree:
  30.  *
  31.  *    ...
  32.  *    /
  33.  * Append -------+------+------+--- nil
  34.  * /   |  | |
  35.  *   nil nil  ... ...    ...
  36.  *  subplans
  37.  *
  38.  * Append nodes are currently used for unions, and to support inheritance
  39.  * queries, where several relations need to be scanned.
  40.  * For example, in our standard person/student/employee/student-emp
  41.  * example, where student and employee inherit from person
  42.  * and student-emp inherits from student and employee, the
  43.  * query:
  44.  *
  45.  * retrieve (e.name) from e in person*
  46.  *
  47.  * generates the plan:
  48.  *
  49.  *   |
  50.  * Append -------+-------+--------+--------+
  51.  * /   |   |    | |
  52.  *   nil nil  Scan  Scan   Scan    Scan
  53.  *   |   |    | |
  54.  * person employee student student-emp
  55.  */
  56. #include "postgres.h"
  57. #include "access/heapam.h"
  58. #include "executor/executor.h"
  59. #include "executor/execdebug.h"
  60. #include "executor/nodeAppend.h"
  61. #include "executor/nodeIndexscan.h"
  62. #include "utils/palloc.h"
  63. #include "utils/mcxt.h"
  64. #include "parser/parsetree.h" /* for rt_store() macro */
  65. static bool exec_append_initialize_next(Append *node);
  66. /* ----------------------------------------------------------------
  67.  * exec_append_initialize_next
  68.  *
  69.  * Sets up the append node state (i.e. the append state node)
  70.  * for the "next" scan.
  71.  *
  72.  * Returns t iff there is a "next" scan to process.
  73.  * ----------------------------------------------------------------
  74.  */
  75. static bool
  76. exec_append_initialize_next(Append *node)
  77. {
  78. EState    *estate;
  79. AppendState *appendstate;
  80. TupleTableSlot *result_slot;
  81. List    *rangeTable;
  82. int whichplan;
  83. int nplans;
  84. List    *rtables;
  85. List    *rtable;
  86. ResTarget  *rtentry;
  87. /* ----------------
  88.  * get information from the append node
  89.  * ----------------
  90.  */
  91. estate = node->plan.state;
  92. appendstate = node->appendstate;
  93. result_slot = appendstate->cstate.cs_ResultTupleSlot;
  94. rangeTable = estate->es_range_table;
  95. whichplan = appendstate->as_whichplan;
  96. nplans = appendstate->as_nplans;
  97. rtables = node->unionrtables;
  98. rtable = node->inheritrtable;
  99. if (whichplan < 0)
  100. {
  101. /* ----------------
  102.  * if scanning in reverse, we start at
  103.  * the last scan in the list and then
  104.  * proceed back to the first.. in any case
  105.  * we inform ExecProcAppend that we are
  106.  * at the end of the line by returning FALSE
  107.  * ----------------
  108.  */
  109. appendstate->as_whichplan = 0;
  110. return FALSE;
  111. }
  112. else if (whichplan >= nplans)
  113. {
  114. /* ----------------
  115.  * as above, end the scan if we go beyond
  116.  * the last scan in our list..
  117.  * ----------------
  118.  */
  119. appendstate->as_whichplan = nplans - 1;
  120. return FALSE;
  121. }
  122. else
  123. {
  124. /* ----------------
  125.  * initialize the scan
  126.  * (and update the range table appropriately)
  127.  *   (doesn't this leave the range table hosed for anybody upstream
  128.  *    of the Append node??? - jolly )
  129.  * ----------------
  130.  */
  131. if (node->inheritrelid > 0)
  132. {
  133. rtentry = nth(whichplan, rtable);
  134. Assert(rtentry != NULL);
  135. rt_store(node->inheritrelid, rangeTable, rtentry);
  136. }
  137. else
  138. estate->es_range_table = nth(whichplan, rtables);
  139. if (appendstate->as_junkFilter_list)
  140. {
  141. estate->es_junkFilter = (JunkFilter *) nth(whichplan,
  142. appendstate->as_junkFilter_list);
  143. }
  144. if (appendstate->as_result_relation_info_list)
  145. {
  146. estate->es_result_relation_info = (RelationInfo *) nth(whichplan,
  147.   appendstate->as_result_relation_info_list);
  148. }
  149. result_slot->ttc_whichplan = whichplan;
  150. return TRUE;
  151. }
  152. }
  153. /* ----------------------------------------------------------------
  154.  * ExecInitAppend
  155.  *
  156.  * Begins all of the subscans of the append node, storing the
  157.  * scan structures in the 'initialized' vector of the append-state
  158.  * structure.
  159.  *
  160.  *    (This is potentially wasteful, since the entire result of the
  161.  * append node may not be scanned, but this way all of the
  162.  * structures get allocated in the executor's top level memory
  163.  * block instead of that of the call to ExecProcAppend.)
  164.  *
  165.  * Returns the scan result of the first scan.
  166.  * ----------------------------------------------------------------
  167.  */
  168. bool
  169. ExecInitAppend(Append *node, EState *estate, Plan *parent)
  170. {
  171. AppendState *appendstate;
  172. int nplans;
  173. List    *resultList = NULL;
  174. List    *rtable;
  175. List    *appendplans;
  176. bool    *initialized;
  177. int i;
  178. Plan    *initNode;
  179. List    *junkList;
  180. RelationInfo *es_rri = estate->es_result_relation_info;
  181. /* ----------------
  182.  * assign execution state to node and get information
  183.  * for append state
  184.  * ----------------
  185.  */
  186. node->plan.state = estate;
  187. appendplans = node->appendplans;
  188. nplans = length(appendplans);
  189. rtable = node->inheritrtable;
  190. CXT1_printf("ExecInitAppend: context is %dn", CurrentMemoryContext);
  191. initialized = (bool *) palloc(nplans * sizeof(bool));
  192. /* ----------------
  193.  * create new AppendState for our append node
  194.  * ----------------
  195.  */
  196. appendstate = makeNode(AppendState);
  197. appendstate->as_whichplan = 0;
  198. appendstate->as_nplans = nplans;
  199. appendstate->as_initialized = initialized;
  200. appendstate->as_rtentries = rtable;
  201. node->appendstate = appendstate;
  202. /* ----------------
  203.  * Miscellanious initialization
  204.  *
  205.  *  + assign node's base_id
  206.  *  + assign debugging hooks
  207.  *
  208.  * Append plans don't have expression contexts because they
  209.  * never call ExecQual or ExecTargetList.
  210.  * ----------------
  211.  */
  212. ExecAssignNodeBaseInfo(estate, &appendstate->cstate, parent);
  213. #define APPEND_NSLOTS 1
  214. /* ----------------
  215.  * append nodes still have Result slots, which hold pointers
  216.  * to tuples, so we have to initialize them..
  217.  * ----------------
  218.  */
  219. ExecInitResultTupleSlot(estate, &appendstate->cstate);
  220. /*
  221.  * If the inherits rtentry is the result relation, we have to make a
  222.  * result relation info list for all inheritors so we can update their
  223.  * indices and put the result tuples in the right place etc.
  224.  *
  225.  * e.g. replace p (age = p.age + 1) from p in person*
  226.  */
  227. if ((es_rri != (RelationInfo *) NULL) &&
  228. (node->inheritrelid == es_rri->ri_RangeTableIndex))
  229. {
  230. RelationInfo *rri;
  231. List    *rtentryP;
  232. foreach(rtentryP, rtable)
  233. {
  234. Oid reloid;
  235. RangeTblEntry *rtentry = lfirst(rtentryP);
  236. reloid = rtentry->relid;
  237. rri = makeNode(RelationInfo);
  238. rri->ri_RangeTableIndex = es_rri->ri_RangeTableIndex;
  239. rri->ri_RelationDesc = heap_open(reloid);
  240. rri->ri_NumIndices = 0;
  241. rri->ri_IndexRelationDescs = NULL; /* index descs */
  242. rri->ri_IndexRelationInfo = NULL; /* index key info */
  243. resultList = lcons(rri, resultList);
  244. ExecOpenIndices(reloid, rri);
  245. }
  246. appendstate->as_result_relation_info_list = resultList;
  247. }
  248. /* ----------------
  249.  * call ExecInitNode on each of the plans in our list
  250.  * and save the results into the array "initialized"
  251.  * ----------------
  252.  */
  253. junkList = NIL;
  254. for (i = 0; i < nplans; i++)
  255. {
  256. JunkFilter *j;
  257. List    *targetList;
  258. /* ----------------
  259.  * NOTE: we first modify range table in
  260.  *   exec_append_initialize_next() and
  261.  *   then initialize the subnode,
  262.  *   since it may use the range table.
  263.  * ----------------
  264.  */
  265. appendstate->as_whichplan = i;
  266. exec_append_initialize_next(node);
  267. initNode = (Plan *) nth(i, appendplans);
  268. initialized[i] = ExecInitNode(initNode, estate, (Plan *) node);
  269. /* ---------------
  270.  * Each targetlist in the subplan may need its own junk filter
  271.  *
  272.  * This is true only when the reln being replaced/deleted is
  273.  * the one that we're looking at the subclasses of
  274.  * ---------------
  275.  */
  276. if ((es_rri != (RelationInfo *) NULL) &&
  277. (node->inheritrelid == es_rri->ri_RangeTableIndex))
  278. {
  279. targetList = initNode->targetlist;
  280. j = (JunkFilter *) ExecInitJunkFilter(targetList);
  281. junkList = lappend(junkList, j);
  282. }
  283. }
  284. appendstate->as_junkFilter_list = junkList;
  285. if (junkList != NIL)
  286. estate->es_junkFilter = (JunkFilter *) lfirst(junkList);
  287. /* ----------------
  288.  * initialize the return type from the appropriate subplan.
  289.  * ----------------
  290.  */
  291. initNode = (Plan *) nth(0, appendplans);
  292. ExecAssignResultType(&appendstate->cstate,
  293. /*  ExecGetExecTupDesc(initNode), */
  294.  ExecGetTupType(initNode));
  295. appendstate->cstate.cs_ProjInfo = NULL;
  296. /* ----------------
  297.  * return the result from the first subplan's initialization
  298.  * ----------------
  299.  */
  300. appendstate->as_whichplan = 0;
  301. exec_append_initialize_next(node);
  302. #ifdef NOT_USED
  303. result = (List *) initialized[0];
  304. #endif
  305. return TRUE;
  306. }
  307. int
  308. ExecCountSlotsAppend(Append *node)
  309. {
  310. List    *plan;
  311. List    *appendplans = node->appendplans;
  312. int nSlots = 0;
  313. foreach(plan, appendplans)
  314. nSlots += ExecCountSlotsNode((Plan *) lfirst(plan));
  315. return nSlots + APPEND_NSLOTS;
  316. }
  317. /* ----------------------------------------------------------------
  318.  *    ExecProcAppend
  319.  *
  320.  * Handles the iteration over the multiple scans.
  321.  *
  322.  *    NOTE: Can't call this ExecAppend, that name is used in execMain.l
  323.  * ----------------------------------------------------------------
  324.  */
  325. TupleTableSlot *
  326. ExecProcAppend(Append *node)
  327. {
  328. EState    *estate;
  329. AppendState *appendstate;
  330. int whichplan;
  331. List    *appendplans;
  332. Plan    *subnode;
  333. TupleTableSlot *result;
  334. TupleTableSlot *result_slot;
  335. ScanDirection direction;
  336. /* ----------------
  337.  * get information from the node
  338.  * ----------------
  339.  */
  340. appendstate = node->appendstate;
  341. estate = node->plan.state;
  342. direction = estate->es_direction;
  343. appendplans = node->appendplans;
  344. whichplan = appendstate->as_whichplan;
  345. result_slot = appendstate->cstate.cs_ResultTupleSlot;
  346. /* ----------------
  347.  * figure out which subplan we are currently processing
  348.  * ----------------
  349.  */
  350. subnode = (Plan *) nth(whichplan, appendplans);
  351. if (subnode == NULL)
  352. elog(DEBUG, "ExecProcAppend: subnode is NULL");
  353. /* ----------------
  354.  * get a tuple from the subplan
  355.  * ----------------
  356.  */
  357. result = ExecProcNode(subnode, (Plan *) node);
  358. if (!TupIsNull(result))
  359. {
  360. /* ----------------
  361.  * if the subplan gave us something then place a copy of
  362.  * whatever we get into our result slot and return it, else..
  363.  * ----------------
  364.  */
  365. return ExecStoreTuple(result->val,
  366.   result_slot, result->ttc_buffer, false);
  367. }
  368. else
  369. {
  370. /* ----------------
  371.  * .. go on to the "next" subplan in the appropriate
  372.  * direction and try processing again (recursively)
  373.  * ----------------
  374.  */
  375. whichplan = appendstate->as_whichplan;
  376. if (ScanDirectionIsForward(direction))
  377. appendstate->as_whichplan = whichplan + 1;
  378. else
  379. appendstate->as_whichplan = whichplan - 1;
  380. /* ----------------
  381.  * return something from next node or an empty slot
  382.  * all of our subplans have been exhausted.
  383.  * ----------------
  384.  */
  385. if (exec_append_initialize_next(node))
  386. {
  387. ExecSetSlotDescriptorIsNew(result_slot, true);
  388. return ExecProcAppend(node);
  389. }
  390. else
  391. return ExecClearTuple(result_slot);
  392. }
  393. }
  394. /* ----------------------------------------------------------------
  395.  * ExecEndAppend
  396.  *
  397.  * Shuts down the subscans of the append node.
  398.  *
  399.  * Returns nothing of interest.
  400.  * ----------------------------------------------------------------
  401.  */
  402. void
  403. ExecEndAppend(Append *node)
  404. {
  405. AppendState *appendstate;
  406. int nplans;
  407. List    *appendplans;
  408. bool    *initialized;
  409. int i;
  410. List    *resultRelationInfoList;
  411. RelationInfo *resultRelationInfo;
  412. /* ----------------
  413.  * get information from the node
  414.  * ----------------
  415.  */
  416. appendstate = node->appendstate;
  417. appendplans = node->appendplans;
  418. nplans = appendstate->as_nplans;
  419. initialized = appendstate->as_initialized;
  420. /* ----------------
  421.  * shut down each of the subscans
  422.  * ----------------
  423.  */
  424. for (i = 0; i < nplans; i++)
  425. {
  426. if (initialized[i] == TRUE)
  427. ExecEndNode((Plan *) nth(i, appendplans), (Plan *) node);
  428. }
  429. /* ----------------
  430.  * close out the different result relations
  431.  * ----------------
  432.  */
  433. resultRelationInfoList = appendstate->as_result_relation_info_list;
  434. while (resultRelationInfoList != NIL)
  435. {
  436. Relation resultRelationDesc;
  437. resultRelationInfo = (RelationInfo *) lfirst(resultRelationInfoList);
  438. resultRelationDesc = resultRelationInfo->ri_RelationDesc;
  439. heap_close(resultRelationDesc);
  440. pfree(resultRelationInfo);
  441. resultRelationInfoList = lnext(resultRelationInfoList);
  442. }
  443. if (appendstate->as_result_relation_info_list)
  444. pfree(appendstate->as_result_relation_info_list);
  445. /*
  446.  * XXX should free appendstate->as_rtentries  and
  447.  * appendstate->as_junkfilter_list here
  448.  */
  449. }
  450. void
  451. ExecReScanAppend(Append *node, ExprContext *exprCtxt, Plan *parent)
  452. {
  453. AppendState *appendstate = node->appendstate;
  454. int nplans = length(node->appendplans);
  455. int i;
  456. for (i = 0; i < nplans; i++)
  457. {
  458. Plan    *rescanNode;
  459. appendstate->as_whichplan = i;
  460. rescanNode = (Plan *) nth(i, node->appendplans);
  461. if (rescanNode->chgParam == NULL)
  462. {
  463. exec_append_initialize_next(node);
  464. ExecReScan((Plan *) rescanNode, exprCtxt, (Plan *) node);
  465. }
  466. }
  467. appendstate->as_whichplan = 0;
  468. exec_append_initialize_next(node);
  469. }