PostgreSQL Source Code  git master
nodeSetOp.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "executor/executor.h"
#include "executor/nodeSetOp.h"
#include "miscadmin.h"
#include "utils/memutils.h"
Include dependency graph for nodeSetOp.c:

Go to the source code of this file.

Data Structures

struct  SetOpStatePerGroupData
 

Typedefs

typedef struct SetOpStatePerGroupData SetOpStatePerGroupData
 

Functions

static TupleTableSlotsetop_retrieve_direct (SetOpState *setopstate)
 
static void setop_fill_hash_table (SetOpState *setopstate)
 
static TupleTableSlotsetop_retrieve_hash_table (SetOpState *setopstate)
 
static void initialize_counts (SetOpStatePerGroup pergroup)
 
static void advance_counts (SetOpStatePerGroup pergroup, int flag)
 
static int fetch_tuple_flag (SetOpState *setopstate, TupleTableSlot *inputslot)
 
static void build_hash_table (SetOpState *setopstate)
 
static void set_output_count (SetOpState *setopstate, SetOpStatePerGroup pergroup)
 
static TupleTableSlotExecSetOp (PlanState *pstate)
 
SetOpStateExecInitSetOp (SetOp *node, EState *estate, int eflags)
 
void ExecEndSetOp (SetOpState *node)
 
void ExecReScanSetOp (SetOpState *node)
 

Typedef Documentation

◆ SetOpStatePerGroupData

Function Documentation

◆ advance_counts()

static void advance_counts ( SetOpStatePerGroup  pergroup,
int  flag 
)
inlinestatic

Definition at line 89 of file nodeSetOp.c.

90 {
91  if (flag)
92  pergroup->numRight++;
93  else
94  pergroup->numLeft++;
95 }
char * flag(int b)
Definition: test-ctype.c:33

References flag(), SetOpStatePerGroupData::numLeft, and SetOpStatePerGroupData::numRight.

Referenced by setop_fill_hash_table(), and setop_retrieve_direct().

◆ build_hash_table()

static void build_hash_table ( SetOpState setopstate)
static

Definition at line 120 of file nodeSetOp.c.

121 {
122  SetOp *node = (SetOp *) setopstate->ps.plan;
123  ExprContext *econtext = setopstate->ps.ps_ExprContext;
124  TupleDesc desc = ExecGetResultType(outerPlanState(setopstate));
125 
126  Assert(node->strategy == SETOP_HASHED);
127  Assert(node->numGroups > 0);
128 
129  setopstate->hashtable = BuildTupleHashTableExt(&setopstate->ps,
130  desc,
131  node->numCols,
132  node->dupColIdx,
133  setopstate->eqfuncoids,
134  setopstate->hashfunctions,
135  node->dupCollations,
136  node->numGroups,
137  0,
138  setopstate->ps.state->es_query_cxt,
139  setopstate->tableContext,
140  econtext->ecxt_per_tuple_memory,
141  false);
142 }
#define Assert(condition)
Definition: c.h:858
TupleHashTable BuildTupleHashTableExt(PlanState *parent, TupleDesc inputDesc, int numCols, AttrNumber *keyColIdx, const Oid *eqfuncoids, FmgrInfo *hashfunctions, Oid *collations, long nbuckets, Size additionalsize, MemoryContext metacxt, MemoryContext tablecxt, MemoryContext tempcxt, bool use_variable_hash_iv)
Definition: execGrouping.c:153
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:493
#define outerPlanState(node)
Definition: execnodes.h:1213
@ SETOP_HASHED
Definition: nodes.h:406
MemoryContext es_query_cxt
Definition: execnodes.h:667
Plan * plan
Definition: execnodes.h:1117
EState * state
Definition: execnodes.h:1119
ExprContext * ps_ExprContext
Definition: execnodes.h:1156
MemoryContext tableContext
Definition: execnodes.h:2788
PlanState ps
Definition: execnodes.h:2777
Oid * eqfuncoids
Definition: execnodes.h:2779
TupleHashTable hashtable
Definition: execnodes.h:2787
FmgrInfo * hashfunctions
Definition: execnodes.h:2780
SetOpStrategy strategy
Definition: plannodes.h:1225
int numCols
Definition: plannodes.h:1228
long numGroups
Definition: plannodes.h:1244

References Assert, BuildTupleHashTableExt(), SetOpState::eqfuncoids, EState::es_query_cxt, ExecGetResultType(), SetOpState::hashfunctions, SetOpState::hashtable, SetOp::numCols, SetOp::numGroups, outerPlanState, PlanState::plan, SetOpState::ps, PlanState::ps_ExprContext, SETOP_HASHED, PlanState::state, SetOp::strategy, and SetOpState::tableContext.

Referenced by ExecInitSetOp().

◆ ExecEndSetOp()

void ExecEndSetOp ( SetOpState node)

Definition at line 583 of file nodeSetOp.c.

584 {
585  /* free subsidiary stuff including hashtable */
586  if (node->tableContext)
588 
590 }
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:557
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454

References ExecEndNode(), MemoryContextDelete(), outerPlanState, and SetOpState::tableContext.

Referenced by ExecEndNode().

◆ ExecInitSetOp()

SetOpState* ExecInitSetOp ( SetOp node,
EState estate,
int  eflags 
)

Definition at line 481 of file nodeSetOp.c.

482 {
483  SetOpState *setopstate;
484  TupleDesc outerDesc;
485 
486  /* check for unsupported flags */
487  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
488 
489  /*
490  * create state structure
491  */
492  setopstate = makeNode(SetOpState);
493  setopstate->ps.plan = (Plan *) node;
494  setopstate->ps.state = estate;
495  setopstate->ps.ExecProcNode = ExecSetOp;
496 
497  setopstate->eqfuncoids = NULL;
498  setopstate->hashfunctions = NULL;
499  setopstate->setop_done = false;
500  setopstate->numOutput = 0;
501  setopstate->pergroup = NULL;
502  setopstate->grp_firstTuple = NULL;
503  setopstate->hashtable = NULL;
504  setopstate->tableContext = NULL;
505 
506  /*
507  * create expression context
508  */
509  ExecAssignExprContext(estate, &setopstate->ps);
510 
511  /*
512  * If hashing, we also need a longer-lived context to store the hash
513  * table. The table can't just be kept in the per-query context because
514  * we want to be able to throw it away in ExecReScanSetOp.
515  */
516  if (node->strategy == SETOP_HASHED)
517  setopstate->tableContext =
519  "SetOp hash table",
521 
522  /*
523  * initialize child nodes
524  *
525  * If we are hashing then the child plan does not need to handle REWIND
526  * efficiently; see ExecReScanSetOp.
527  */
528  if (node->strategy == SETOP_HASHED)
529  eflags &= ~EXEC_FLAG_REWIND;
530  outerPlanState(setopstate) = ExecInitNode(outerPlan(node), estate, eflags);
531  outerDesc = ExecGetResultType(outerPlanState(setopstate));
532 
533  /*
534  * Initialize result slot and type. Setop nodes do no projections, so
535  * initialize projection info for this node appropriately.
536  */
537  ExecInitResultTupleSlotTL(&setopstate->ps,
538  node->strategy == SETOP_HASHED ?
540  setopstate->ps.ps_ProjInfo = NULL;
541 
542  /*
543  * Precompute fmgr lookup data for inner loop. We need both equality and
544  * hashing functions to do it by hashing, but only equality if not
545  * hashing.
546  */
547  if (node->strategy == SETOP_HASHED)
549  node->dupOperators,
550  &setopstate->eqfuncoids,
551  &setopstate->hashfunctions);
552  else
553  setopstate->eqfunction =
554  execTuplesMatchPrepare(outerDesc,
555  node->numCols,
556  node->dupColIdx,
557  node->dupOperators,
558  node->dupCollations,
559  &setopstate->ps);
560 
561  if (node->strategy == SETOP_HASHED)
562  {
563  build_hash_table(setopstate);
564  setopstate->table_filled = false;
565  }
566  else
567  {
568  setopstate->pergroup =
570  }
571 
572  return setopstate;
573 }
void execTuplesHashPrepare(int numCols, const Oid *eqOperators, Oid **eqFuncOids, FmgrInfo **hashFunctions)
Definition: execGrouping.c:95
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, const AttrNumber *keyColIdx, const Oid *eqOperators, const Oid *collations, PlanState *parent)
Definition: execGrouping.c:58
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:142
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1886
const TupleTableSlotOps TTSOpsHeapTuple
Definition: execTuples.c:85
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:86
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:483
struct SetOpStatePerGroupData * SetOpStatePerGroup
Definition: execnodes.h:2773
#define EXEC_FLAG_BACKWARD
Definition: executor.h:68
#define EXEC_FLAG_REWIND
Definition: executor.h:67
#define EXEC_FLAG_MARK
Definition: executor.h:69
void * palloc0(Size size)
Definition: mcxt.c:1346
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
static void build_hash_table(SetOpState *setopstate)
Definition: nodeSetOp.c:120
static TupleTableSlot * ExecSetOp(PlanState *pstate)
Definition: nodeSetOp.c:190
#define makeNode(_type_)
Definition: nodes.h:155
#define outerPlan(node)
Definition: plannodes.h:182
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:1157
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1123
long numOutput
Definition: execnodes.h:2782
HeapTuple grp_firstTuple
Definition: execnodes.h:2785
SetOpStatePerGroup pergroup
Definition: execnodes.h:2784
ExprState * eqfunction
Definition: execnodes.h:2778
bool table_filled
Definition: execnodes.h:2789
bool setop_done
Definition: execnodes.h:2781

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, build_hash_table(), CurrentMemoryContext, SetOpState::eqfuncoids, SetOpState::eqfunction, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, EXEC_FLAG_REWIND, ExecAssignExprContext(), ExecGetResultType(), ExecInitNode(), ExecInitResultTupleSlotTL(), PlanState::ExecProcNode, ExecSetOp(), execTuplesHashPrepare(), execTuplesMatchPrepare(), SetOpState::grp_firstTuple, SetOpState::hashfunctions, SetOpState::hashtable, makeNode, SetOp::numCols, SetOpState::numOutput, outerPlan, outerPlanState, palloc0(), SetOpState::pergroup, PlanState::plan, SetOpState::ps, PlanState::ps_ProjInfo, SetOpState::setop_done, SETOP_HASHED, PlanState::state, SetOp::strategy, SetOpState::table_filled, SetOpState::tableContext, TTSOpsHeapTuple, and TTSOpsMinimalTuple.

Referenced by ExecInitNode().

◆ ExecReScanSetOp()

void ExecReScanSetOp ( SetOpState node)

Definition at line 594 of file nodeSetOp.c.

595 {
597 
599  node->setop_done = false;
600  node->numOutput = 0;
601 
602  if (((SetOp *) node->ps.plan)->strategy == SETOP_HASHED)
603  {
604  /*
605  * In the hashed case, if we haven't yet built the hash table then we
606  * can just return; nothing done yet, so nothing to undo. If subnode's
607  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
608  * else no reason to re-scan it at all.
609  */
610  if (!node->table_filled)
611  return;
612 
613  /*
614  * If we do have the hash table and the subplan does not have any
615  * parameter changes, then we can just rescan the existing hash table;
616  * no need to build it again.
617  */
618  if (outerPlan->chgParam == NULL)
619  {
621  return;
622  }
623  }
624 
625  /* Release first tuple of group, if we have made a copy */
626  if (node->grp_firstTuple != NULL)
627  {
629  node->grp_firstTuple = NULL;
630  }
631 
632  /* Release any hashtable storage */
633  if (node->tableContext)
635 
636  /* And rebuild empty hashtable if needed */
637  if (((SetOp *) node->ps.plan)->strategy == SETOP_HASHED)
638  {
640  node->table_filled = false;
641  }
642 
643  /*
644  * if chgParam of subnode is not null then plan will be re-scanned by
645  * first ExecProcNode.
646  */
647  if (outerPlan->chgParam == NULL)
649 }
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
void ResetTupleHashTable(TupleHashTable hashtable)
Definition: execGrouping.c:284
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:846
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1155
TupleHashIterator hashiter
Definition: execnodes.h:2790
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454

References ExecClearTuple(), ExecReScan(), SetOpState::grp_firstTuple, SetOpState::hashiter, SetOpState::hashtable, heap_freetuple(), MemoryContextReset(), SetOpState::numOutput, outerPlan, outerPlanState, PlanState::plan, SetOpState::ps, PlanState::ps_ResultTupleSlot, ResetTupleHashIterator, ResetTupleHashTable(), SetOpState::setop_done, SETOP_HASHED, SetOpState::table_filled, and SetOpState::tableContext.

Referenced by ExecReScan().

◆ ExecSetOp()

static TupleTableSlot* ExecSetOp ( PlanState pstate)
static

Definition at line 190 of file nodeSetOp.c.

191 {
192  SetOpState *node = castNode(SetOpState, pstate);
193  SetOp *plannode = (SetOp *) node->ps.plan;
194  TupleTableSlot *resultTupleSlot = node->ps.ps_ResultTupleSlot;
195 
197 
198  /*
199  * If the previously-returned tuple needs to be returned more than once,
200  * keep returning it.
201  */
202  if (node->numOutput > 0)
203  {
204  node->numOutput--;
205  return resultTupleSlot;
206  }
207 
208  /* Otherwise, we're done if we are out of groups */
209  if (node->setop_done)
210  return NULL;
211 
212  /* Fetch the next tuple group according to the correct strategy */
213  if (plannode->strategy == SETOP_HASHED)
214  {
215  if (!node->table_filled)
216  setop_fill_hash_table(node);
217  return setop_retrieve_hash_table(node);
218  }
219  else
220  return setop_retrieve_direct(node);
221 }
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
static void setop_fill_hash_table(SetOpState *setopstate)
Definition: nodeSetOp.c:339
static TupleTableSlot * setop_retrieve_hash_table(SetOpState *setopstate)
Definition: nodeSetOp.c:425
static TupleTableSlot * setop_retrieve_direct(SetOpState *setopstate)
Definition: nodeSetOp.c:227
#define castNode(_type_, nodeptr)
Definition: nodes.h:176

References castNode, CHECK_FOR_INTERRUPTS, SetOpState::numOutput, PlanState::plan, SetOpState::ps, PlanState::ps_ResultTupleSlot, SetOpState::setop_done, setop_fill_hash_table(), SETOP_HASHED, setop_retrieve_direct(), setop_retrieve_hash_table(), SetOp::strategy, and SetOpState::table_filled.

Referenced by ExecInitSetOp().

◆ fetch_tuple_flag()

static int fetch_tuple_flag ( SetOpState setopstate,
TupleTableSlot inputslot 
)
static

Definition at line 102 of file nodeSetOp.c.

103 {
104  SetOp *node = (SetOp *) setopstate->ps.plan;
105  int flag;
106  bool isNull;
107 
108  flag = DatumGetInt32(slot_getattr(inputslot,
109  node->flagColIdx,
110  &isNull));
111  Assert(!isNull);
112  Assert(flag == 0 || flag == 1);
113  return flag;
114 }
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:202
AttrNumber flagColIdx
Definition: plannodes.h:1238
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:395

References Assert, DatumGetInt32(), flag(), SetOp::flagColIdx, PlanState::plan, SetOpState::ps, and slot_getattr().

Referenced by setop_fill_hash_table(), and setop_retrieve_direct().

◆ initialize_counts()

static void initialize_counts ( SetOpStatePerGroup  pergroup)
inlinestatic

Definition at line 80 of file nodeSetOp.c.

81 {
82  pergroup->numLeft = pergroup->numRight = 0;
83 }

References SetOpStatePerGroupData::numLeft, and SetOpStatePerGroupData::numRight.

Referenced by setop_fill_hash_table(), and setop_retrieve_direct().

◆ set_output_count()

static void set_output_count ( SetOpState setopstate,
SetOpStatePerGroup  pergroup 
)
static

Definition at line 150 of file nodeSetOp.c.

151 {
152  SetOp *plannode = (SetOp *) setopstate->ps.plan;
153 
154  switch (plannode->cmd)
155  {
156  case SETOPCMD_INTERSECT:
157  if (pergroup->numLeft > 0 && pergroup->numRight > 0)
158  setopstate->numOutput = 1;
159  else
160  setopstate->numOutput = 0;
161  break;
163  setopstate->numOutput =
164  (pergroup->numLeft < pergroup->numRight) ?
165  pergroup->numLeft : pergroup->numRight;
166  break;
167  case SETOPCMD_EXCEPT:
168  if (pergroup->numLeft > 0 && pergroup->numRight == 0)
169  setopstate->numOutput = 1;
170  else
171  setopstate->numOutput = 0;
172  break;
173  case SETOPCMD_EXCEPT_ALL:
174  setopstate->numOutput =
175  (pergroup->numLeft < pergroup->numRight) ?
176  0 : (pergroup->numLeft - pergroup->numRight);
177  break;
178  default:
179  elog(ERROR, "unrecognized set op: %d", (int) plannode->cmd);
180  break;
181  }
182 }
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
@ SETOPCMD_EXCEPT
Definition: nodes.h:399
@ SETOPCMD_EXCEPT_ALL
Definition: nodes.h:400
@ SETOPCMD_INTERSECT_ALL
Definition: nodes.h:398
@ SETOPCMD_INTERSECT
Definition: nodes.h:397
SetOpCmd cmd
Definition: plannodes.h:1222

References SetOp::cmd, elog, ERROR, if(), SetOpStatePerGroupData::numLeft, SetOpState::numOutput, SetOpStatePerGroupData::numRight, PlanState::plan, SetOpState::ps, SETOPCMD_EXCEPT, SETOPCMD_EXCEPT_ALL, SETOPCMD_INTERSECT, and SETOPCMD_INTERSECT_ALL.

Referenced by setop_retrieve_direct(), and setop_retrieve_hash_table().

◆ setop_fill_hash_table()

static void setop_fill_hash_table ( SetOpState setopstate)
static

Definition at line 339 of file nodeSetOp.c.

340 {
341  SetOp *node = (SetOp *) setopstate->ps.plan;
343  int firstFlag;
344  bool in_first_rel PG_USED_FOR_ASSERTS_ONLY;
345  ExprContext *econtext = setopstate->ps.ps_ExprContext;
346 
347  /*
348  * get state info from node
349  */
350  outerPlan = outerPlanState(setopstate);
351  firstFlag = node->firstFlag;
352  /* verify planner didn't mess up */
353  Assert(firstFlag == 0 ||
354  (firstFlag == 1 &&
355  (node->cmd == SETOPCMD_INTERSECT ||
356  node->cmd == SETOPCMD_INTERSECT_ALL)));
357 
358  /*
359  * Process each outer-plan tuple, and then fetch the next one, until we
360  * exhaust the outer plan.
361  */
362  in_first_rel = true;
363  for (;;)
364  {
365  TupleTableSlot *outerslot;
366  int flag;
367  TupleHashEntryData *entry;
368  bool isnew;
369 
370  outerslot = ExecProcNode(outerPlan);
371  if (TupIsNull(outerslot))
372  break;
373 
374  /* Identify whether it's left or right input */
375  flag = fetch_tuple_flag(setopstate, outerslot);
376 
377  if (flag == firstFlag)
378  {
379  /* (still) in first input relation */
380  Assert(in_first_rel);
381 
382  /* Find or build hashtable entry for this tuple's group */
383  entry = LookupTupleHashEntry(setopstate->hashtable, outerslot,
384  &isnew, NULL);
385 
386  /* If new tuple group, initialize counts */
387  if (isnew)
388  {
389  entry->additional = (SetOpStatePerGroup)
391  sizeof(SetOpStatePerGroupData));
393  }
394 
395  /* Advance the counts */
397  }
398  else
399  {
400  /* reached second relation */
401  in_first_rel = false;
402 
403  /* For tuples not seen previously, do not make hashtable entry */
404  entry = LookupTupleHashEntry(setopstate->hashtable, outerslot,
405  NULL, NULL);
406 
407  /* Advance the counts if entry is already present */
408  if (entry)
410  }
411 
412  /* Must reset expression context after each hashtable lookup */
413  ResetExprContext(econtext);
414  }
415 
416  setopstate->table_filled = true;
417  /* Initialize to walk the hash table */
418  ResetTupleHashIterator(setopstate->hashtable, &setopstate->hashiter);
419 }
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:182
TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew, uint32 *hash)
Definition: execGrouping.c:305
#define ResetExprContext(econtext)
Definition: executor.h:544
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:269
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1180
static void initialize_counts(SetOpStatePerGroup pergroup)
Definition: nodeSetOp.c:80
static int fetch_tuple_flag(SetOpState *setopstate, TupleTableSlot *inputslot)
Definition: nodeSetOp.c:102
static void advance_counts(SetOpStatePerGroup pergroup, int flag)
Definition: nodeSetOp.c:89
int firstFlag
Definition: plannodes.h:1241
MemoryContext tablecxt
Definition: execnodes.h:823
#define TupIsNull(slot)
Definition: tuptable.h:306

References TupleHashEntryData::additional, advance_counts(), Assert, SetOp::cmd, ExecProcNode(), fetch_tuple_flag(), SetOp::firstFlag, flag(), SetOpState::hashiter, SetOpState::hashtable, initialize_counts(), LookupTupleHashEntry(), MemoryContextAlloc(), outerPlan, outerPlanState, PG_USED_FOR_ASSERTS_ONLY, PlanState::plan, SetOpState::ps, PlanState::ps_ExprContext, ResetExprContext, ResetTupleHashIterator, SETOPCMD_INTERSECT, SETOPCMD_INTERSECT_ALL, SetOpState::table_filled, TupleHashTableData::tablecxt, and TupIsNull.

Referenced by ExecSetOp().

◆ setop_retrieve_direct()

static TupleTableSlot * setop_retrieve_direct ( SetOpState setopstate)
static

Definition at line 227 of file nodeSetOp.c.

228 {
230  SetOpStatePerGroup pergroup;
231  TupleTableSlot *outerslot;
232  TupleTableSlot *resultTupleSlot;
233  ExprContext *econtext = setopstate->ps.ps_ExprContext;
234 
235  /*
236  * get state info from node
237  */
238  outerPlan = outerPlanState(setopstate);
239  pergroup = (SetOpStatePerGroup) setopstate->pergroup;
240  resultTupleSlot = setopstate->ps.ps_ResultTupleSlot;
241 
242  /*
243  * We loop retrieving groups until we find one we should return
244  */
245  while (!setopstate->setop_done)
246  {
247  /*
248  * If we don't already have the first tuple of the new group, fetch it
249  * from the outer plan.
250  */
251  if (setopstate->grp_firstTuple == NULL)
252  {
253  outerslot = ExecProcNode(outerPlan);
254  if (!TupIsNull(outerslot))
255  {
256  /* Make a copy of the first input tuple */
257  setopstate->grp_firstTuple = ExecCopySlotHeapTuple(outerslot);
258  }
259  else
260  {
261  /* outer plan produced no tuples at all */
262  setopstate->setop_done = true;
263  return NULL;
264  }
265  }
266 
267  /*
268  * Store the copied first input tuple in the tuple table slot reserved
269  * for it. The tuple will be deleted when it is cleared from the
270  * slot.
271  */
273  resultTupleSlot,
274  true);
275  setopstate->grp_firstTuple = NULL; /* don't keep two pointers */
276 
277  /* Initialize working state for a new input tuple group */
278  initialize_counts(pergroup);
279 
280  /* Count the first input tuple */
281  advance_counts(pergroup,
282  fetch_tuple_flag(setopstate, resultTupleSlot));
283 
284  /*
285  * Scan the outer plan until we exhaust it or cross a group boundary.
286  */
287  for (;;)
288  {
289  outerslot = ExecProcNode(outerPlan);
290  if (TupIsNull(outerslot))
291  {
292  /* no more outer-plan tuples available */
293  setopstate->setop_done = true;
294  break;
295  }
296 
297  /*
298  * Check whether we've crossed a group boundary.
299  */
300  econtext->ecxt_outertuple = resultTupleSlot;
301  econtext->ecxt_innertuple = outerslot;
302 
303  if (!ExecQualAndReset(setopstate->eqfunction, econtext))
304  {
305  /*
306  * Save the first input tuple of the next group.
307  */
308  setopstate->grp_firstTuple = ExecCopySlotHeapTuple(outerslot);
309  break;
310  }
311 
312  /* Still in same group, so count this tuple */
313  advance_counts(pergroup,
314  fetch_tuple_flag(setopstate, outerslot));
315  }
316 
317  /*
318  * Done scanning input tuple group. See if we should emit any copies
319  * of result tuple, and if so return the first copy.
320  */
321  set_output_count(setopstate, pergroup);
322 
323  if (setopstate->numOutput > 0)
324  {
325  setopstate->numOutput--;
326  return resultTupleSlot;
327  }
328  }
329 
330  /* No more groups */
331  ExecClearTuple(resultTupleSlot);
332  return NULL;
333 }
TupleTableSlot * ExecStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1439
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:440
static void set_output_count(SetOpState *setopstate, SetOpStatePerGroup pergroup)
Definition: nodeSetOp.c:150
while(p+4<=pend)
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:257
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:259
static HeapTuple ExecCopySlotHeapTuple(TupleTableSlot *slot)
Definition: tuptable.h:481

References advance_counts(), ExprContext::ecxt_innertuple, ExprContext::ecxt_outertuple, SetOpState::eqfunction, ExecClearTuple(), ExecCopySlotHeapTuple(), ExecProcNode(), ExecQualAndReset(), ExecStoreHeapTuple(), fetch_tuple_flag(), SetOpState::grp_firstTuple, initialize_counts(), SetOpState::numOutput, outerPlan, outerPlanState, SetOpState::pergroup, SetOpState::ps, PlanState::ps_ExprContext, PlanState::ps_ResultTupleSlot, set_output_count(), SetOpState::setop_done, TupIsNull, and while().

Referenced by ExecSetOp().

◆ setop_retrieve_hash_table()

static TupleTableSlot * setop_retrieve_hash_table ( SetOpState setopstate)
static

Definition at line 425 of file nodeSetOp.c.

426 {
427  TupleHashEntryData *entry;
428  TupleTableSlot *resultTupleSlot;
429 
430  /*
431  * get state info from node
432  */
433  resultTupleSlot = setopstate->ps.ps_ResultTupleSlot;
434 
435  /*
436  * We loop retrieving groups until we find one we should return
437  */
438  while (!setopstate->setop_done)
439  {
441 
442  /*
443  * Find the next entry in the hash table
444  */
445  entry = ScanTupleHashTable(setopstate->hashtable, &setopstate->hashiter);
446  if (entry == NULL)
447  {
448  /* No more entries in hashtable, so done */
449  setopstate->setop_done = true;
450  return NULL;
451  }
452 
453  /*
454  * See if we should emit any copies of this tuple, and if so return
455  * the first copy.
456  */
457  set_output_count(setopstate, (SetOpStatePerGroup) entry->additional);
458 
459  if (setopstate->numOutput > 0)
460  {
461  setopstate->numOutput--;
462  return ExecStoreMinimalTuple(entry->firstTuple,
463  resultTupleSlot,
464  false);
465  }
466  }
467 
468  /* No more groups */
469  ExecClearTuple(resultTupleSlot);
470  return NULL;
471 }
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1533
#define ScanTupleHashTable(htable, iter)
Definition: execnodes.h:848
MinimalTuple firstTuple
Definition: execnodes.h:801

References TupleHashEntryData::additional, CHECK_FOR_INTERRUPTS, ExecClearTuple(), ExecStoreMinimalTuple(), TupleHashEntryData::firstTuple, SetOpState::hashiter, SetOpState::hashtable, SetOpState::numOutput, SetOpState::ps, PlanState::ps_ResultTupleSlot, ScanTupleHashTable, set_output_count(), and SetOpState::setop_done.

Referenced by ExecSetOp().