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.

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

Referenced by setop_fill_hash_table(), and setop_retrieve_direct().

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

◆ build_hash_table()

static void build_hash_table ( SetOpState setopstate)
static

Definition at line 120 of file nodeSetOp.c.

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

Referenced by ExecInitSetOp(), and ExecReScanSetOp().

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 = BuildTupleHashTable(&setopstate->ps,
130  desc,
131  node->numCols,
132  node->dupColIdx,
133  setopstate->eqfuncoids,
134  setopstate->hashfunctions,
135  node->numGroups,
136  0,
137  setopstate->tableContext,
138  econtext->ecxt_per_tuple_memory,
139  false);
140 }
SetOpStrategy strategy
Definition: plannodes.h:913
MemoryContext tableContext
Definition: execnodes.h:2165
long numGroups
Definition: plannodes.h:920
Oid * eqfuncoids
Definition: execnodes.h:2156
ExprContext * ps_ExprContext
Definition: execnodes.h:947
PlanState ps
Definition: execnodes.h:2154
AttrNumber * dupColIdx
Definition: plannodes.h:916
int numCols
Definition: plannodes.h:914
#define outerPlanState(node)
Definition: execnodes.h:966
FmgrInfo * hashfunctions
Definition: execnodes.h:2157
Plan * plan
Definition: execnodes.h:912
#define Assert(condition)
Definition: c.h:699
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:438
TupleHashTable BuildTupleHashTable(PlanState *parent, TupleDesc inputDesc, int numCols, AttrNumber *keyColIdx, Oid *eqfuncoids, FmgrInfo *hashfunctions, long nbuckets, Size additionalsize, MemoryContext tablecxt, MemoryContext tempcxt, bool use_variable_hash_iv)
Definition: execGrouping.c:152
TupleHashTable hashtable
Definition: execnodes.h:2164

◆ ExecEndSetOp()

void ExecEndSetOp ( SetOpState node)

Definition at line 579 of file nodeSetOp.c.

References ExecClearTuple(), ExecEndNode(), ExecFreeExprContext(), MemoryContextDelete(), outerPlanState, SetOpState::ps, PlanState::ps_ResultTupleSlot, and SetOpState::tableContext.

Referenced by ExecEndNode().

580 {
581  /* clean up tuple table */
583 
584  /* free subsidiary stuff including hashtable */
585  if (node->tableContext)
587  ExecFreeExprContext(&node->ps);
588 
590 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
MemoryContext tableContext
Definition: execnodes.h:2165
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:538
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:475
PlanState ps
Definition: execnodes.h:2154
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:566
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:946
#define outerPlanState(node)
Definition: execnodes.h:966

◆ ExecInitSetOp()

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

Definition at line 480 of file nodeSetOp.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, build_hash_table(), CurrentMemoryContext, SetOp::dupColIdx, SetOp::dupOperators, 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, and SetOpState::tableContext.

Referenced by ExecInitNode().

481 {
482  SetOpState *setopstate;
483  TupleDesc outerDesc;
484 
485  /* check for unsupported flags */
486  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
487 
488  /*
489  * create state structure
490  */
491  setopstate = makeNode(SetOpState);
492  setopstate->ps.plan = (Plan *) node;
493  setopstate->ps.state = estate;
494  setopstate->ps.ExecProcNode = ExecSetOp;
495 
496  setopstate->eqfuncoids = NULL;
497  setopstate->hashfunctions = NULL;
498  setopstate->setop_done = false;
499  setopstate->numOutput = 0;
500  setopstate->pergroup = NULL;
501  setopstate->grp_firstTuple = NULL;
502  setopstate->hashtable = NULL;
503  setopstate->tableContext = NULL;
504 
505  /*
506  * create expression context
507  */
508  ExecAssignExprContext(estate, &setopstate->ps);
509 
510  /*
511  * If hashing, we also need a longer-lived context to store the hash
512  * table. The table can't just be kept in the per-query context because
513  * we want to be able to throw it away in ExecReScanSetOp.
514  */
515  if (node->strategy == SETOP_HASHED)
516  setopstate->tableContext =
518  "SetOp hash table",
520 
521  /*
522  * initialize child nodes
523  *
524  * If we are hashing then the child plan does not need to handle REWIND
525  * efficiently; see ExecReScanSetOp.
526  */
527  if (node->strategy == SETOP_HASHED)
528  eflags &= ~EXEC_FLAG_REWIND;
529  outerPlanState(setopstate) = ExecInitNode(outerPlan(node), estate, eflags);
530  outerDesc = ExecGetResultType(outerPlanState(setopstate));
531 
532  /*
533  * Initialize result slot and type. Setop nodes do no projections, so
534  * initialize projection info for this node appropriately.
535  */
536  ExecInitResultTupleSlotTL(estate, &setopstate->ps);
537  setopstate->ps.ps_ProjInfo = NULL;
538 
539  /*
540  * Precompute fmgr lookup data for inner loop. We need both equality and
541  * hashing functions to do it by hashing, but only equality if not
542  * hashing.
543  */
544  if (node->strategy == SETOP_HASHED)
546  node->dupOperators,
547  &setopstate->eqfuncoids,
548  &setopstate->hashfunctions);
549  else
550  setopstate->eqfunction =
551  execTuplesMatchPrepare(outerDesc,
552  node->numCols,
553  node->dupColIdx,
554  node->dupOperators,
555  &setopstate->ps);
556 
557  if (node->strategy == SETOP_HASHED)
558  {
559  build_hash_table(setopstate);
560  setopstate->table_filled = false;
561  }
562  else
563  {
564  setopstate->pergroup =
566  }
567 
568  return setopstate;
569 }
void execTuplesHashPrepare(int numCols, Oid *eqOperators, Oid **eqFuncOids, FmgrInfo **hashFunctions)
Definition: execGrouping.c:95
SetOpStrategy strategy
Definition: plannodes.h:913
MemoryContext tableContext
Definition: execnodes.h:2165
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:948
struct SetOpStatePerGroupData * SetOpStatePerGroup
Definition: execnodes.h:2150
ExprState * eqfunction
Definition: execnodes.h:2155
Oid * eqfuncoids
Definition: execnodes.h:2156
PlanState ps
Definition: execnodes.h:2154
AttrNumber * dupColIdx
Definition: plannodes.h:916
HeapTuple grp_firstTuple
Definition: execnodes.h:2162
EState * state
Definition: execnodes.h:914
int numCols
Definition: plannodes.h:914
static void build_hash_table(SetOpState *setopstate)
Definition: nodeSetOp.c:120
Oid * dupOperators
Definition: plannodes.h:917
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
#define EXEC_FLAG_BACKWARD
Definition: executor.h:60
#define outerPlanState(node)
Definition: execnodes.h:966
bool table_filled
Definition: execnodes.h:2166
long numOutput
Definition: execnodes.h:2159
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define EXEC_FLAG_REWIND
Definition: executor.h:59
#define outerPlan(node)
Definition: plannodes.h:176
static TupleTableSlot * ExecSetOp(PlanState *pstate)
Definition: nodeSetOp.c:188
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:170
void * palloc0(Size size)
Definition: mcxt.c:955
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:918
void ExecInitResultTupleSlotTL(EState *estate, PlanState *planstate)
Definition: execTuples.c:890
FmgrInfo * hashfunctions
Definition: execnodes.h:2157
Plan * plan
Definition: execnodes.h:912
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, AttrNumber *keyColIdx, Oid *eqOperators, PlanState *parent)
Definition: execGrouping.c:60
#define makeNode(_type_)
Definition: nodes.h:565
#define Assert(condition)
Definition: c.h:699
#define EXEC_FLAG_MARK
Definition: executor.h:61
bool setop_done
Definition: execnodes.h:2158
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:428
SetOpStatePerGroup pergroup
Definition: execnodes.h:2161
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:438
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:139
TupleHashTable hashtable
Definition: execnodes.h:2164

◆ ExecReScanSetOp()

void ExecReScanSetOp ( SetOpState node)

Definition at line 594 of file nodeSetOp.c.

References build_hash_table(), PlanState::chgParam, ExecClearTuple(), ExecReScan(), SetOpState::grp_firstTuple, SetOpState::hashiter, SetOpState::hashtable, heap_freetuple(), PlanState::lefttree, MemoryContextResetAndDeleteChildren, SetOpState::numOutput, PlanState::plan, SetOpState::ps, PlanState::ps_ResultTupleSlot, ResetTupleHashIterator, SetOpState::setop_done, SETOP_HASHED, SetOpState::table_filled, and SetOpState::tableContext.

Referenced by ExecReScan().

595 {
597  node->setop_done = false;
598  node->numOutput = 0;
599 
600  if (((SetOp *) node->ps.plan)->strategy == SETOP_HASHED)
601  {
602  /*
603  * In the hashed case, if we haven't yet built the hash table then we
604  * can just return; nothing done yet, so nothing to undo. If subnode's
605  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
606  * else no reason to re-scan it at all.
607  */
608  if (!node->table_filled)
609  return;
610 
611  /*
612  * If we do have the hash table and the subplan does not have any
613  * parameter changes, then we can just rescan the existing hash table;
614  * no need to build it again.
615  */
616  if (node->ps.lefttree->chgParam == NULL)
617  {
619  return;
620  }
621  }
622 
623  /* Release first tuple of group, if we have made a copy */
624  if (node->grp_firstTuple != NULL)
625  {
627  node->grp_firstTuple = NULL;
628  }
629 
630  /* Release any hashtable storage */
631  if (node->tableContext)
633 
634  /* And rebuild empty hashtable if needed */
635  if (((SetOp *) node->ps.plan)->strategy == SETOP_HASHED)
636  {
637  build_hash_table(node);
638  node->table_filled = false;
639  }
640 
641  /*
642  * if chgParam of subnode is not null then plan will be re-scanned by
643  * first ExecProcNode.
644  */
645  if (node->ps.lefttree->chgParam == NULL)
646  ExecReScan(node->ps.lefttree);
647 }
MemoryContext tableContext
Definition: execnodes.h:2165
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:475
PlanState ps
Definition: execnodes.h:2154
HeapTuple grp_firstTuple
Definition: execnodes.h:2162
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
struct PlanState * lefttree
Definition: execnodes.h:931
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:946
static void build_hash_table(SetOpState *setopstate)
Definition: nodeSetOp.c:120
bool table_filled
Definition: execnodes.h:2166
long numOutput
Definition: execnodes.h:2159
TupleHashIterator hashiter
Definition: execnodes.h:2167
Bitmapset * chgParam
Definition: execnodes.h:941
#define MemoryContextResetAndDeleteChildren(ctx)
Definition: memutils.h:67
Plan * plan
Definition: execnodes.h:912
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:695
bool setop_done
Definition: execnodes.h:2158
TupleHashTable hashtable
Definition: execnodes.h:2164

◆ ExecSetOp()

static TupleTableSlot* ExecSetOp ( PlanState pstate)
static

Definition at line 188 of file nodeSetOp.c.

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().

189 {
190  SetOpState *node = castNode(SetOpState, pstate);
191  SetOp *plannode = (SetOp *) node->ps.plan;
192  TupleTableSlot *resultTupleSlot = node->ps.ps_ResultTupleSlot;
193 
195 
196  /*
197  * If the previously-returned tuple needs to be returned more than once,
198  * keep returning it.
199  */
200  if (node->numOutput > 0)
201  {
202  node->numOutput--;
203  return resultTupleSlot;
204  }
205 
206  /* Otherwise, we're done if we are out of groups */
207  if (node->setop_done)
208  return NULL;
209 
210  /* Fetch the next tuple group according to the correct strategy */
211  if (plannode->strategy == SETOP_HASHED)
212  {
213  if (!node->table_filled)
214  setop_fill_hash_table(node);
215  return setop_retrieve_hash_table(node);
216  }
217  else
218  return setop_retrieve_direct(node);
219 }
SetOpStrategy strategy
Definition: plannodes.h:913
#define castNode(_type_, nodeptr)
Definition: nodes.h:586
PlanState ps
Definition: execnodes.h:2154
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:946
static void setop_fill_hash_table(SetOpState *setopstate)
Definition: nodeSetOp.c:338
bool table_filled
Definition: execnodes.h:2166
static TupleTableSlot * setop_retrieve_direct(SetOpState *setopstate)
Definition: nodeSetOp.c:225
long numOutput
Definition: execnodes.h:2159
static TupleTableSlot * setop_retrieve_hash_table(SetOpState *setopstate)
Definition: nodeSetOp.c:424
Plan * plan
Definition: execnodes.h:912
bool setop_done
Definition: execnodes.h:2158
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98

◆ fetch_tuple_flag()

static int fetch_tuple_flag ( SetOpState setopstate,
TupleTableSlot inputslot 
)
static

Definition at line 102 of file nodeSetOp.c.

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

Referenced by setop_fill_hash_table(), and setop_retrieve_direct().

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 }
#define DatumGetInt32(X)
Definition: postgres.h:457
PlanState ps
Definition: execnodes.h:2154
AttrNumber flagColIdx
Definition: plannodes.h:918
char * flag(int b)
Definition: test-ctype.c:33
Plan * plan
Definition: execnodes.h:912
#define Assert(condition)
Definition: c.h:699
Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: heaptuple.c:1518

◆ initialize_counts()

static void initialize_counts ( SetOpStatePerGroup  pergroup)
inlinestatic

Definition at line 80 of file nodeSetOp.c.

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

Referenced by setop_fill_hash_table(), and setop_retrieve_direct().

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

◆ set_output_count()

static void set_output_count ( SetOpState setopstate,
SetOpStatePerGroup  pergroup 
)
static

Definition at line 148 of file nodeSetOp.c.

References SetOp::cmd, elog, ERROR, 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().

149 {
150  SetOp *plannode = (SetOp *) setopstate->ps.plan;
151 
152  switch (plannode->cmd)
153  {
154  case SETOPCMD_INTERSECT:
155  if (pergroup->numLeft > 0 && pergroup->numRight > 0)
156  setopstate->numOutput = 1;
157  else
158  setopstate->numOutput = 0;
159  break;
161  setopstate->numOutput =
162  (pergroup->numLeft < pergroup->numRight) ?
163  pergroup->numLeft : pergroup->numRight;
164  break;
165  case SETOPCMD_EXCEPT:
166  if (pergroup->numLeft > 0 && pergroup->numRight == 0)
167  setopstate->numOutput = 1;
168  else
169  setopstate->numOutput = 0;
170  break;
171  case SETOPCMD_EXCEPT_ALL:
172  setopstate->numOutput =
173  (pergroup->numLeft < pergroup->numRight) ?
174  0 : (pergroup->numLeft - pergroup->numRight);
175  break;
176  default:
177  elog(ERROR, "unrecognized set op: %d", (int) plannode->cmd);
178  break;
179  }
180 }
SetOpCmd cmd
Definition: plannodes.h:912
PlanState ps
Definition: execnodes.h:2154
#define ERROR
Definition: elog.h:43
long numOutput
Definition: execnodes.h:2159
Plan * plan
Definition: execnodes.h:912
#define elog
Definition: elog.h:219

◆ setop_fill_hash_table()

static void setop_fill_hash_table ( SetOpState setopstate)
static

Definition at line 338 of file nodeSetOp.c.

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().

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

◆ setop_retrieve_direct()

static TupleTableSlot * setop_retrieve_direct ( SetOpState setopstate)
static

Definition at line 225 of file nodeSetOp.c.

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

Referenced by ExecSetOp().

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

◆ setop_retrieve_hash_table()

static TupleTableSlot * setop_retrieve_hash_table ( SetOpState setopstate)
static

Definition at line 424 of file nodeSetOp.c.

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().

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