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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * nodeUnique.c
  4.  *   Routines to handle unique'ing of queries where appropriate
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.20 1999/02/13 23:15:29 momjian Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. /*
  15.  * INTERFACE ROUTINES
  16.  * ExecUnique - generate a unique'd temporary relation
  17.  * ExecInitUnique - initialize node and subnodes..
  18.  * ExecEndUnique - shutdown node and subnodes
  19.  *
  20.  * NOTES
  21.  * Assumes tuples returned from subplan arrive in
  22.  * sorted order.
  23.  *
  24.  */
  25. #include <string.h>
  26. #include "postgres.h"
  27. #include "fmgr.h"
  28. #include "executor/executor.h"
  29. #include "executor/nodeUnique.h"
  30. #include "optimizer/clauses.h"
  31. #include "access/heapam.h"
  32. #include "access/printtup.h" /* for getTypeOutAndElem() */
  33. #include "utils/builtins.h" /* for namecpy() */
  34. /* ----------------------------------------------------------------
  35.  * ExecIdenticalTuples
  36.  *
  37.  * This is a hack function used by ExecUnique to see if
  38.  * two tuples are identical.  This should be provided
  39.  * by the heap tuple code but isn't.  The real problem
  40.  * is that we assume we can byte compare tuples to determine
  41.  * if they are "equal".  In fact, if we have user defined
  42.  * types there may be problems because it's possible that
  43.  * an ADT may have multiple representations with the
  44.  * same ADT value. -cim
  45.  * ----------------------------------------------------------------
  46.  */
  47. static bool /* true if tuples are identical, false
  48.  * otherwise */
  49. ExecIdenticalTuples(TupleTableSlot *t1, TupleTableSlot *t2)
  50. {
  51. HeapTuple h1;
  52. HeapTuple h2;
  53. char    *d1;
  54. char    *d2;
  55. int len;
  56. h1 = t1->val;
  57. h2 = t2->val;
  58. /* ----------------
  59.  * if tuples aren't the same length then they are
  60.  * obviously different (one may have null attributes).
  61.  * ----------------
  62.  */
  63. if (h1->t_len != h2->t_len)
  64. return false;
  65. /* ----------------
  66.  * if the tuples have different header offsets then
  67.  * they are different.  This will prevent us from returning
  68.  * true when comparing tuples of one attribute where one of
  69.  * two we're looking at is null (t_len - t_hoff == 0).
  70.  * THE t_len FIELDS CAN BE THE SAME IN THIS CASE!!
  71.  * ----------------
  72.  */
  73. if (h1->t_data->t_hoff != h2->t_data->t_hoff)
  74. return false;
  75. /* ----------------
  76.  * ok, now get the pointers to the data and the
  77.  * size of the attribute portion of the tuple.
  78.  * ----------------
  79.  */
  80. d1 = (char *) GETSTRUCT(h1);
  81. d2 = (char *) GETSTRUCT(h2);
  82. len = (int) h1->t_len - (int) h1->t_data->t_hoff;
  83. /* ----------------
  84.  * byte compare the data areas and return the result.
  85.  * ----------------
  86.  */
  87. if (memcmp(d1, d2, len) != 0)
  88. return false;
  89. return true;
  90. }
  91. /* ----------------------------------------------------------------
  92.  * ExecUnique
  93.  *
  94.  * This is a very simple node which filters out duplicate
  95.  * tuples from a stream of sorted tuples from a subplan.
  96.  *
  97.  * XXX see comments below regarding freeing tuples.
  98.  * ----------------------------------------------------------------
  99.  */
  100. TupleTableSlot * /* return: a tuple or NULL */
  101. ExecUnique(Unique *node)
  102. {
  103. UniqueState *uniquestate;
  104. TupleTableSlot *resultTupleSlot;
  105. TupleTableSlot *slot;
  106. Plan    *outerPlan;
  107. char    *uniqueAttr;
  108. AttrNumber uniqueAttrNum;
  109. TupleDesc tupDesc;
  110. Oid typoutput,
  111. typelem;
  112. /* ----------------
  113.  * get information from the node
  114.  * ----------------
  115.  */
  116. uniquestate = node->uniquestate;
  117. outerPlan = outerPlan((Plan *) node);
  118. resultTupleSlot = uniquestate->cs_ResultTupleSlot;
  119. uniqueAttr = node->uniqueAttr;
  120. uniqueAttrNum = node->uniqueAttrNum;
  121. if (uniqueAttr)
  122. {
  123. tupDesc = ExecGetResultType(uniquestate);
  124. getTypeOutAndElem((Oid) tupDesc->attrs[uniqueAttrNum - 1]->atttypid,
  125.   &typoutput, &typelem);
  126. }
  127. else
  128. { /* keep compiler quiet */
  129. tupDesc = NULL;
  130. typoutput = InvalidOid;
  131. typelem = InvalidOid;
  132. }
  133. /* ----------------
  134.  * now loop, returning only non-duplicate tuples.
  135.  * We assume that the tuples arrive in sorted order
  136.  * so we can detect duplicates easily.
  137.  * ----------------
  138.  */
  139. for (;;)
  140. {
  141. /* ----------------
  142.  *  fetch a tuple from the outer subplan
  143.  * ----------------
  144.  */
  145. slot = ExecProcNode(outerPlan, (Plan *) node);
  146. if (TupIsNull(slot))
  147. return NULL;
  148. /* ----------------
  149.  *  we use the result tuple slot to hold our saved tuples.
  150.  *  if we haven't a saved tuple to compare our new tuple with,
  151.  *  then we exit the loop. This new tuple as the saved tuple
  152.  *  the next time we get here.
  153.  * ----------------
  154.  */
  155. if (TupIsNull(resultTupleSlot))
  156. break;
  157. /* ----------------
  158.  *  now test if the new tuple and the previous
  159.  *  tuple match.  If so then we loop back and fetch
  160.  *  another new tuple from the subplan.
  161.  * ----------------
  162.  */
  163. if (uniqueAttr)
  164. {
  165. /*
  166.  * to check equality, we check to see if the typoutput of the
  167.  * attributes are equal
  168.  */
  169. bool isNull1,
  170. isNull2;
  171. Datum attr1,
  172. attr2;
  173. char    *val1,
  174.    *val2;
  175. attr1 = heap_getattr(slot->val,
  176.  uniqueAttrNum, tupDesc, &isNull1);
  177. attr2 = heap_getattr(resultTupleSlot->val,
  178.  uniqueAttrNum, tupDesc, &isNull2);
  179. if (isNull1 == isNull2)
  180. {
  181. if (isNull1) /* both are null, they are equal */
  182. continue;
  183. val1 = fmgr(typoutput, attr1, typelem,
  184. tupDesc->attrs[uniqueAttrNum - 1]->atttypmod);
  185. val2 = fmgr(typoutput, attr2, typelem,
  186. tupDesc->attrs[uniqueAttrNum - 1]->atttypmod);
  187. /*
  188.  * now, val1 and val2 are ascii representations so we can
  189.  * use strcmp for comparison
  190.  */
  191. if (strcmp(val1, val2) == 0) /* they are equal */
  192. {
  193. pfree(val1);
  194. pfree(val2);
  195. continue;
  196. }
  197. pfree(val1);
  198. pfree(val2);
  199. break;
  200. }
  201. else
  202. /* one is null and the other isn't, they aren't equal */
  203. break;
  204. }
  205. else
  206. {
  207. if (!ExecIdenticalTuples(slot, resultTupleSlot))
  208. break;
  209. }
  210. }
  211. /* ----------------
  212.  * we have a new tuple different from the previous saved tuple
  213.  * so we save it in the saved tuple slot. We copy the tuple
  214.  * so we don't increment the buffer ref count.
  215.  * ----------------
  216.  */
  217. ExecStoreTuple(heap_copytuple(slot->val),
  218.    resultTupleSlot,
  219.    InvalidBuffer,
  220.    true);
  221. return resultTupleSlot;
  222. }
  223. /* ----------------------------------------------------------------
  224.  * ExecInitUnique
  225.  *
  226.  * This initializes the unique node state structures and
  227.  * the node's subplan.
  228.  * ----------------------------------------------------------------
  229.  */
  230. bool /* return: initialization status */
  231. ExecInitUnique(Unique *node, EState *estate, Plan *parent)
  232. {
  233. UniqueState *uniquestate;
  234. Plan    *outerPlan;
  235. char    *uniqueAttr;
  236. /* ----------------
  237.  * assign execution state to node
  238.  * ----------------
  239.  */
  240. node->plan.state = estate;
  241. /* ----------------
  242.  * create new UniqueState for node
  243.  * ----------------
  244.  */
  245. uniquestate = makeNode(UniqueState);
  246. node->uniquestate = uniquestate;
  247. uniqueAttr = node->uniqueAttr;
  248. /* ----------------
  249.  * Miscellanious initialization
  250.  *
  251.  *  + assign node's base_id
  252.  *  + assign debugging hooks and
  253.  *
  254.  * Unique nodes have no ExprContext initialization because
  255.  * they never call ExecQual or ExecTargetList.
  256.  * ----------------
  257.  */
  258. ExecAssignNodeBaseInfo(estate, uniquestate, parent);
  259. #define UNIQUE_NSLOTS 1
  260. /* ------------
  261.  * Tuple table initialization
  262.  * ------------
  263.  */
  264. ExecInitResultTupleSlot(estate, uniquestate);
  265. /* ----------------
  266.  * then initialize outer plan
  267.  * ----------------
  268.  */
  269. outerPlan = outerPlan((Plan *) node);
  270. ExecInitNode(outerPlan, estate, (Plan *) node);
  271. /* ----------------
  272.  * unique nodes do no projections, so initialize
  273.  * projection info for this node appropriately
  274.  * ----------------
  275.  */
  276. ExecAssignResultTypeFromOuterPlan((Plan *) node, uniquestate);
  277. uniquestate->cs_ProjInfo = NULL;
  278. if (uniqueAttr)
  279. {
  280. TupleDesc tupDesc;
  281. int i = 0;
  282. tupDesc = ExecGetResultType(uniquestate);
  283. /*
  284.  * the parser should have ensured that uniqueAttr is a legal
  285.  * attribute name
  286.  */
  287. while (strcmp((tupDesc->attrs[i]->attname).data, uniqueAttr) != 0)
  288. i++;
  289. node->uniqueAttrNum = i + 1; /* attribute numbers start from 1 */
  290. }
  291. else
  292. node->uniqueAttrNum = InvalidAttrNumber;
  293. /* ----------------
  294.  * all done.
  295.  * ----------------
  296.  */
  297. return TRUE;
  298. }
  299. int
  300. ExecCountSlotsUnique(Unique *node)
  301. {
  302. return ExecCountSlotsNode(outerPlan(node)) +
  303. ExecCountSlotsNode(innerPlan(node)) +
  304. UNIQUE_NSLOTS;
  305. }
  306. /* ----------------------------------------------------------------
  307.  * ExecEndUnique
  308.  *
  309.  * This shuts down the subplan and frees resources allocated
  310.  * to this node.
  311.  * ----------------------------------------------------------------
  312.  */
  313. void
  314. ExecEndUnique(Unique *node)
  315. {
  316. UniqueState *uniquestate;
  317. uniquestate = node->uniquestate;
  318. ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
  319. ExecClearTuple(uniquestate->cs_ResultTupleSlot);
  320. }
  321. void
  322. ExecReScanUnique(Unique *node, ExprContext *exprCtxt, Plan *parent)
  323. {
  324. UniqueState *uniquestate = node->uniquestate;
  325. ExecClearTuple(uniquestate->cs_ResultTupleSlot);
  326. /*
  327.  * if chgParam of subnode is not null then plan will be re-scanned by
  328.  * first ExecProcNode.
  329.  */
  330. if (((Plan *) node)->lefttree->chgParam == NULL)
  331. ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
  332. }