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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * nodeGroup.c
  4.  *   Routines to handle group nodes (used for queries with GROUP BY clause).
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * DESCRIPTION
  10.  *   The Group node is designed for handling queries with a GROUP BY clause.
  11.  *   It's outer plan must be a sort node. It assumes that the tuples it gets
  12.  *   back from the outer plan is sorted in the order specified by the group
  13.  *   columns. (ie. tuples from the same group are consecutive)
  14.  *
  15.  * IDENTIFICATION
  16.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.27 1999/07/11 01:57:32 tgl Exp $
  17.  *
  18.  *-------------------------------------------------------------------------
  19.  */
  20. #include <string.h>
  21. #include "postgres.h"
  22. #include "fmgr.h"
  23. #include "access/heapam.h"
  24. #include "catalog/catalog.h"
  25. #include "access/printtup.h"
  26. #include "executor/executor.h"
  27. #include "executor/nodeGroup.h"
  28. static TupleTableSlot *ExecGroupEveryTuple(Group *node);
  29. static TupleTableSlot *ExecGroupOneTuple(Group *node);
  30. static bool sameGroup(HeapTuple oldslot, HeapTuple newslot,
  31.   int numCols, AttrNumber *grpColIdx, TupleDesc tupdesc);
  32. /* ---------------------------------------
  33.  *  ExecGroup -
  34.  *
  35.  * There are two modes in which tuples are returned by ExecGroup. If
  36.  * tuplePerGroup is TRUE, every tuple from the same group will be
  37.  * returned, followed by a NULL at the end of each group. This is
  38.  * useful for Agg node which needs to aggregate over tuples of the same
  39.  * group. (eg. SELECT salary, count{*} FROM emp GROUP BY salary)
  40.  *
  41.  * If tuplePerGroup is FALSE, only one tuple per group is returned. The
  42.  * tuple returned contains only the group columns. NULL is returned only
  43.  * at the end when no more groups is present. This is useful when
  44.  * the query does not involve aggregates. (eg. SELECT salary FROM emp
  45.  * GROUP BY salary)
  46.  * ------------------------------------------
  47.  */
  48. TupleTableSlot *
  49. ExecGroup(Group *node)
  50. {
  51. if (node->tuplePerGroup)
  52. return ExecGroupEveryTuple(node);
  53. else
  54. return ExecGroupOneTuple(node);
  55. }
  56. /*
  57.  * ExecGroupEveryTuple -
  58.  *  return every tuple with a NULL between each group
  59.  */
  60. static TupleTableSlot *
  61. ExecGroupEveryTuple(Group *node)
  62. {
  63. GroupState *grpstate;
  64. EState    *estate;
  65. ExprContext *econtext;
  66. HeapTuple outerTuple = NULL;
  67. HeapTuple firsttuple;
  68. TupleTableSlot *outerslot;
  69. ProjectionInfo *projInfo;
  70. TupleTableSlot *resultSlot;
  71. bool isDone;
  72. /* ---------------------
  73.  * get state info from node
  74.  * ---------------------
  75.  */
  76. grpstate = node->grpstate;
  77. if (grpstate->grp_done)
  78. return NULL;
  79. estate = node->plan.state;
  80. econtext = grpstate->csstate.cstate.cs_ExprContext;
  81. /* if we haven't returned first tuple of new group yet ... */
  82. if (grpstate->grp_useFirstTuple)
  83. {
  84. grpstate->grp_useFirstTuple = FALSE;
  85. ExecStoreTuple(grpstate->grp_firstTuple,
  86.    grpstate->csstate.css_ScanTupleSlot,
  87.    InvalidBuffer,
  88.    false);
  89. }
  90. else
  91. {
  92. outerslot = ExecProcNode(outerPlan(node), (Plan *) node);
  93. if (TupIsNull(outerslot))
  94. {
  95. grpstate->grp_done = TRUE;
  96. return NULL;
  97. }
  98. outerTuple = outerslot->val;
  99. firsttuple = grpstate->grp_firstTuple;
  100. /* this should occur on the first call only */
  101. if (firsttuple == NULL)
  102. grpstate->grp_firstTuple = heap_copytuple(outerTuple);
  103. else
  104. {
  105. /*
  106.  * Compare with first tuple and see if this tuple is of the
  107.  * same group.
  108.  */
  109. if (!sameGroup(firsttuple, outerTuple,
  110.    node->numCols, node->grpColIdx,
  111.    ExecGetScanType(&grpstate->csstate)))
  112. {
  113. grpstate->grp_useFirstTuple = TRUE;
  114. pfree(firsttuple);
  115. grpstate->grp_firstTuple = heap_copytuple(outerTuple);
  116. return NULL; /* signifies the end of the group */
  117. }
  118. }
  119. ExecStoreTuple(outerTuple,
  120.    grpstate->csstate.css_ScanTupleSlot,
  121.    outerslot->ttc_buffer,
  122.    false);
  123. }
  124. /* ----------------
  125.  * form a projection tuple, store it in the result tuple
  126.  * slot and return it.
  127.  * ----------------
  128.  */
  129. projInfo = grpstate->csstate.cstate.cs_ProjInfo;
  130. econtext->ecxt_scantuple = grpstate->csstate.css_ScanTupleSlot;
  131. resultSlot = ExecProject(projInfo, &isDone);
  132. return resultSlot;
  133. }
  134. /*
  135.  * ExecGroupOneTuple -
  136.  *   returns one tuple per group, a NULL at the end when there are no more
  137.  *   tuples.
  138.  */
  139. static TupleTableSlot *
  140. ExecGroupOneTuple(Group *node)
  141. {
  142. GroupState *grpstate;
  143. EState    *estate;
  144. ExprContext *econtext;
  145. HeapTuple outerTuple = NULL;
  146. HeapTuple firsttuple;
  147. TupleTableSlot *outerslot;
  148. ProjectionInfo *projInfo;
  149. TupleTableSlot *resultSlot;
  150. bool isDone;
  151. /* ---------------------
  152.  * get state info from node
  153.  * ---------------------
  154.  */
  155. grpstate = node->grpstate;
  156. if (grpstate->grp_done)
  157. return NULL;
  158. estate = node->plan.state;
  159. econtext = node->grpstate->csstate.cstate.cs_ExprContext;
  160. firsttuple = grpstate->grp_firstTuple;
  161. /* this should occur on the first call only */
  162. if (firsttuple == NULL)
  163. {
  164. outerslot = ExecProcNode(outerPlan(node), (Plan *) node);
  165. if (TupIsNull(outerslot))
  166. {
  167. grpstate->grp_done = TRUE;
  168. return NULL;
  169. }
  170. grpstate->grp_firstTuple = firsttuple =
  171. heap_copytuple(outerslot->val);
  172. }
  173. /*
  174.  * find all tuples that belong to a group
  175.  */
  176. for (;;)
  177. {
  178. outerslot = ExecProcNode(outerPlan(node), (Plan *) node);
  179. if (TupIsNull(outerslot))
  180. {
  181. grpstate->grp_done = TRUE;
  182. outerTuple = NULL;
  183. break;
  184. }
  185. outerTuple = outerslot->val;
  186. /* ----------------
  187.  * Compare with first tuple and see if this tuple is of
  188.  * the same group.
  189.  * ----------------
  190.  */
  191. if ((!sameGroup(firsttuple, outerTuple,
  192. node->numCols, node->grpColIdx,
  193. ExecGetScanType(&grpstate->csstate))))
  194. break;
  195. }
  196. /* ----------------
  197.  * form a projection tuple, store it in the result tuple
  198.  * slot and return it.
  199.  * ----------------
  200.  */
  201. projInfo = grpstate->csstate.cstate.cs_ProjInfo;
  202. ExecStoreTuple(firsttuple,
  203.    grpstate->csstate.css_ScanTupleSlot,
  204.    InvalidBuffer,
  205.    false);
  206. econtext->ecxt_scantuple = grpstate->csstate.css_ScanTupleSlot;
  207. resultSlot = ExecProject(projInfo, &isDone);
  208. /* save outerTuple if we are not done yet */
  209. if (!grpstate->grp_done)
  210. {
  211. pfree(firsttuple);
  212. grpstate->grp_firstTuple = heap_copytuple(outerTuple);
  213. }
  214. return resultSlot;
  215. }
  216. /* -----------------
  217.  * ExecInitGroup
  218.  *
  219.  * Creates the run-time information for the group node produced by the
  220.  * planner and initializes its outer subtree
  221.  * -----------------
  222.  */
  223. bool
  224. ExecInitGroup(Group *node, EState *estate, Plan *parent)
  225. {
  226. GroupState *grpstate;
  227. Plan    *outerPlan;
  228. /*
  229.  * assign the node's execution state
  230.  */
  231. node->plan.state = estate;
  232. /*
  233.  * create state structure
  234.  */
  235. grpstate = makeNode(GroupState);
  236. node->grpstate = grpstate;
  237. grpstate->grp_useFirstTuple = FALSE;
  238. grpstate->grp_done = FALSE;
  239. grpstate->grp_firstTuple = NULL;
  240. /*
  241.  * assign node's base id and create expression context
  242.  */
  243. ExecAssignNodeBaseInfo(estate, &grpstate->csstate.cstate,
  244.    (Plan *) parent);
  245. ExecAssignExprContext(estate, &grpstate->csstate.cstate);
  246. #define GROUP_NSLOTS 2
  247. /*
  248.  * tuple table initialization
  249.  */
  250. ExecInitScanTupleSlot(estate, &grpstate->csstate);
  251. ExecInitResultTupleSlot(estate, &grpstate->csstate.cstate);
  252. /*
  253.  * initializes child nodes
  254.  */
  255. outerPlan = outerPlan(node);
  256. ExecInitNode(outerPlan, estate, (Plan *) node);
  257. /* ----------------
  258.  * initialize tuple type.
  259.  * ----------------
  260.  */
  261. ExecAssignScanTypeFromOuterPlan((Plan *) node, &grpstate->csstate);
  262. /*
  263.  * Initialize tuple type for both result and scan. This node does no
  264.  * projection
  265.  */
  266. ExecAssignResultTypeFromTL((Plan *) node, &grpstate->csstate.cstate);
  267. ExecAssignProjectionInfo((Plan *) node, &grpstate->csstate.cstate);
  268. return TRUE;
  269. }
  270. int
  271. ExecCountSlotsGroup(Group *node)
  272. {
  273. return ExecCountSlotsNode(outerPlan(node)) + GROUP_NSLOTS;
  274. }
  275. /* ------------------------
  276.  * ExecEndGroup(node)
  277.  *
  278.  * -----------------------
  279.  */
  280. void
  281. ExecEndGroup(Group *node)
  282. {
  283. GroupState *grpstate;
  284. Plan    *outerPlan;
  285. grpstate = node->grpstate;
  286. ExecFreeProjectionInfo(&grpstate->csstate.cstate);
  287. outerPlan = outerPlan(node);
  288. ExecEndNode(outerPlan, (Plan *) node);
  289. /* clean up tuple table */
  290. ExecClearTuple(grpstate->csstate.css_ScanTupleSlot);
  291. if (grpstate->grp_firstTuple != NULL)
  292. {
  293. pfree(grpstate->grp_firstTuple);
  294. grpstate->grp_firstTuple = NULL;
  295. }
  296. }
  297. /*****************************************************************************
  298.  *
  299.  *****************************************************************************/
  300. /*
  301.  * code swiped from nodeUnique.c
  302.  */
  303. static bool
  304. sameGroup(HeapTuple oldtuple,
  305.   HeapTuple newtuple,
  306.   int numCols,
  307.   AttrNumber *grpColIdx,
  308.   TupleDesc tupdesc)
  309. {
  310. bool isNull1,
  311. isNull2;
  312. Datum attr1,
  313. attr2;
  314. char    *val1,
  315.    *val2;
  316. int i;
  317. AttrNumber att;
  318. Oid typoutput,
  319. typelem;
  320. for (i = 0; i < numCols; i++)
  321. {
  322. att = grpColIdx[i];
  323. getTypeOutAndElem((Oid) tupdesc->attrs[att - 1]->atttypid,
  324.   &typoutput, &typelem);
  325. attr1 = heap_getattr(oldtuple,
  326.  att,
  327.  tupdesc,
  328.  &isNull1);
  329. attr2 = heap_getattr(newtuple,
  330.  att,
  331.  tupdesc,
  332.  &isNull2);
  333. if (isNull1 == isNull2)
  334. {
  335. if (isNull1) /* both are null, they are equal */
  336. continue;
  337. val1 = fmgr(typoutput, attr1, typelem,
  338. tupdesc->attrs[att - 1]->atttypmod);
  339. val2 = fmgr(typoutput, attr2, typelem,
  340. tupdesc->attrs[att - 1]->atttypmod);
  341. /*
  342.  * now, val1 and val2 are ascii representations so we can use
  343.  * strcmp for comparison
  344.  */
  345. if (strcmp(val1, val2) != 0)
  346. {
  347. pfree(val1);
  348. pfree(val2);
  349. return FALSE;
  350. }
  351. pfree(val1);
  352. pfree(val2);
  353. }
  354. else
  355. {
  356. /* one is null and the other isn't, they aren't equal */
  357. return FALSE;
  358. }
  359. }
  360. return TRUE;
  361. }
  362. void
  363. ExecReScanGroup(Group *node, ExprContext *exprCtxt, Plan *parent)
  364. {
  365. GroupState *grpstate = node->grpstate;
  366. grpstate->grp_useFirstTuple = FALSE;
  367. grpstate->grp_done = FALSE;
  368. if (grpstate->grp_firstTuple != NULL)
  369. {
  370. pfree(grpstate->grp_firstTuple);
  371. grpstate->grp_firstTuple = NULL;
  372. }
  373. if (((Plan *) node)->lefttree &&
  374. ((Plan *) node)->lefttree->chgParam == NULL)
  375. ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
  376. }