PostgreSQL Source Code git master
Loading...
Searching...
No Matches
nodeSetOp.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * nodeSetOp.c
4 * Routines to handle INTERSECT and EXCEPT selection
5 *
6 * The input of a SetOp node consists of two relations (outer and inner)
7 * with identical column sets. In EXCEPT queries the outer relation is
8 * always the left side, while in INTERSECT cases the planner tries to
9 * make the outer relation be the smaller of the two inputs.
10 *
11 * In SETOP_SORTED mode, each input has been sorted according to all the
12 * grouping columns. The SetOp node essentially performs a merge join on
13 * the grouping columns, except that it is only interested in counting how
14 * many tuples from each input match. Then it is a simple matter to emit
15 * the output demanded by the SQL spec for INTERSECT, INTERSECT ALL, EXCEPT,
16 * or EXCEPT ALL.
17 *
18 * In SETOP_HASHED mode, the inputs are delivered in no particular order.
19 * We read the outer relation and build a hash table in memory with one entry
20 * for each group of identical tuples, counting the number of tuples in the
21 * group. Then we read the inner relation and count the number of tuples
22 * matching each outer group. (We can disregard any tuples appearing only
23 * in the inner relation, since they cannot result in any output.) After
24 * seeing all the input, we scan the hashtable and generate the correct
25 * output using those counts.
26 *
27 * This node type is not used for UNION or UNION ALL, since those can be
28 * implemented more cheaply (there's no need to count the number of
29 * matching tuples).
30 *
31 * Note that SetOp does no qual checking nor projection. The delivered
32 * output tuples are just copies of the first-to-arrive tuple in each
33 * input group.
34 *
35 *
36 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
37 * Portions Copyright (c) 1994, Regents of the University of California
38 *
39 *
40 * IDENTIFICATION
41 * src/backend/executor/nodeSetOp.c
42 *
43 *-------------------------------------------------------------------------
44 */
45
46#include "postgres.h"
47
48#include "access/htup_details.h"
49#include "executor/executor.h"
50#include "executor/nodeSetOp.h"
51#include "miscadmin.h"
52#include "utils/memutils.h"
53#include "utils/sortsupport.h"
54
55
56/*
57 * SetOpStatePerGroupData - per-group working state
58 *
59 * In SETOP_SORTED mode, we need only one of these structs, and it's just a
60 * local in setop_retrieve_sorted. In SETOP_HASHED mode, the hash table
61 * contains one of these for each tuple group.
62 */
64{
65 int64 numLeft; /* number of left-input dups in group */
66 int64 numRight; /* number of right-input dups in group */
68
70
71
79
80
81/*
82 * Initialize the hash table to empty.
83 */
84static void
86{
87 SetOp *node = (SetOp *) setopstate->ps.plan;
88 ExprContext *econtext = setopstate->ps.ps_ExprContext;
90
92
93 /*
94 * If both child plans deliver the same fixed tuple slot type, we can tell
95 * BuildTupleHashTable to expect that slot type as input. Otherwise,
96 * we'll pass NULL denoting that any slot type is possible.
97 */
99 desc,
101 node->numCols,
102 node->cmpColIdx,
103 setopstate->eqfuncoids,
104 setopstate->hashfunctions,
105 node->cmpCollations,
106 node->numGroups,
108 setopstate->ps.state->es_query_cxt,
109 setopstate->tuplesContext,
110 econtext->ecxt_per_tuple_memory,
111 false);
112}
113
114/* Planner support routine to estimate space needed for hash table */
115Size
117{
118 return EstimateTupleHashTableSpace(nentries,
120 sizeof(SetOpStatePerGroupData));
121}
122
123/*
124 * We've completed processing a tuple group. Decide how many copies (if any)
125 * of its representative row to emit, and store the count into numOutput.
126 * This logic is straight from the SQL92 specification.
127 */
128static void
130{
132
133 switch (plannode->cmd)
134 {
136 if (pergroup->numLeft > 0 && pergroup->numRight > 0)
137 setopstate->numOutput = 1;
138 else
139 setopstate->numOutput = 0;
140 break;
142 setopstate->numOutput =
143 (pergroup->numLeft < pergroup->numRight) ?
144 pergroup->numLeft : pergroup->numRight;
145 break;
146 case SETOPCMD_EXCEPT:
147 if (pergroup->numLeft > 0 && pergroup->numRight == 0)
148 setopstate->numOutput = 1;
149 else
150 setopstate->numOutput = 0;
151 break;
153 setopstate->numOutput =
154 (pergroup->numLeft < pergroup->numRight) ?
155 0 : (pergroup->numLeft - pergroup->numRight);
156 break;
157 default:
158 elog(ERROR, "unrecognized set op: %d", (int) plannode->cmd);
159 break;
160 }
161}
162
163
164/* ----------------------------------------------------------------
165 * ExecSetOp
166 * ----------------------------------------------------------------
167 */
168static TupleTableSlot * /* return: a tuple or NULL */
170{
171 SetOpState *node = castNode(SetOpState, pstate);
172 SetOp *plannode = (SetOp *) node->ps.plan;
174
176
177 /*
178 * If the previously-returned tuple needs to be returned more than once,
179 * keep returning it.
180 */
181 if (node->numOutput > 0)
182 {
183 node->numOutput--;
184 return resultTupleSlot;
185 }
186
187 /* Otherwise, we're done if we are out of groups */
188 if (node->setop_done)
189 return NULL;
190
191 /* Fetch the next tuple group according to the correct strategy */
192 if (plannode->strategy == SETOP_HASHED)
193 {
194 if (!node->table_filled)
196 return setop_retrieve_hash_table(node);
197 }
198 else
199 return setop_retrieve_sorted(node);
200}
201
202/*
203 * ExecSetOp for non-hashed case
204 */
205static TupleTableSlot *
207{
211
212 /*
213 * get state info from node
214 */
217 resultTupleSlot = setopstate->ps.ps_ResultTupleSlot;
218
219 /*
220 * If first time through, establish the invariant that setop_load_group
221 * expects: each side's nextTupleSlot is the next output from the child
222 * plan, or empty if there is no more output from it.
223 */
224 if (setopstate->need_init)
225 {
226 setopstate->need_init = false;
227
228 setopstate->leftInput.nextTupleSlot = ExecProcNode(outerPlan);
229
230 /*
231 * If the outer relation is empty, then we will emit nothing, and we
232 * don't need to read the inner relation at all.
233 */
234 if (TupIsNull(setopstate->leftInput.nextTupleSlot))
235 {
236 setopstate->setop_done = true;
237 return NULL;
238 }
239
240 setopstate->rightInput.nextTupleSlot = ExecProcNode(innerPlan);
241
242 /* Set flags that we've not completed either side's group */
243 setopstate->leftInput.needGroup = true;
244 setopstate->rightInput.needGroup = true;
245 }
246
247 /*
248 * We loop retrieving groups until we find one we should return
249 */
250 while (!setopstate->setop_done)
251 {
252 int cmpresult;
254
255 /*
256 * Fetch the rest of the current outer group, if we didn't already.
257 */
258 if (setopstate->leftInput.needGroup)
260
261 /*
262 * If no more outer groups, we're done, and don't need to look at any
263 * more of the inner relation.
264 */
265 if (setopstate->leftInput.numTuples == 0)
266 {
267 setopstate->setop_done = true;
268 break;
269 }
270
271 /*
272 * Fetch the rest of the current inner group, if we didn't already.
273 */
274 if (setopstate->rightInput.needGroup)
276
277 /*
278 * Determine whether we have matching groups on both sides (this is
279 * basically like the core logic of a merge join).
280 */
281 if (setopstate->rightInput.numTuples == 0)
282 cmpresult = -1; /* as though left input is lesser */
283 else
284 cmpresult = setop_compare_slots(setopstate->leftInput.firstTupleSlot,
285 setopstate->rightInput.firstTupleSlot,
286 setopstate);
287
288 if (cmpresult < 0)
289 {
290 /* Left group is first, and has no right matches */
291 pergroup.numLeft = setopstate->leftInput.numTuples;
292 pergroup.numRight = 0;
293 /* We'll need another left group next time */
294 setopstate->leftInput.needGroup = true;
295 }
296 else if (cmpresult == 0)
297 {
298 /* We have matching groups */
299 pergroup.numLeft = setopstate->leftInput.numTuples;
300 pergroup.numRight = setopstate->rightInput.numTuples;
301 /* We'll need to read from both sides next time */
302 setopstate->leftInput.needGroup = true;
303 setopstate->rightInput.needGroup = true;
304 }
305 else
306 {
307 /* Right group has no left matches, so we can ignore it */
308 setopstate->rightInput.needGroup = true;
309 continue;
310 }
311
312 /*
313 * Done scanning these input tuple groups. See if we should emit any
314 * copies of result tuple, and if so return the first copy. (Note
315 * that the result tuple is the same as the left input's firstTuple
316 * slot.)
317 */
319
320 if (setopstate->numOutput > 0)
321 {
322 setopstate->numOutput--;
323 return resultTupleSlot;
324 }
325 }
326
327 /* No more groups */
329 return NULL;
330}
331
332/*
333 * Load next group of tuples from one child plan or the other.
334 *
335 * On entry, we've already read the first tuple of the next group
336 * (if there is one) into input->nextTupleSlot. This invariant
337 * is maintained on exit.
338 */
339static void
342{
343 input->needGroup = false;
344
345 /* If we've exhausted this child plan, report an empty group */
346 if (TupIsNull(input->nextTupleSlot))
347 {
348 ExecClearTuple(input->firstTupleSlot);
349 input->numTuples = 0;
350 return;
351 }
352
353 /* Make a local copy of the first tuple for comparisons */
355 input->firstTupleSlot,
356 true);
357 /* and count it */
358 input->numTuples = 1;
359
360 /* Scan till we find the end-of-group */
361 for (;;)
362 {
363 int cmpresult;
364
365 /* Get next input tuple, if there is one */
366 input->nextTupleSlot = ExecProcNode(inputPlan);
367 if (TupIsNull(input->nextTupleSlot))
368 break;
369
370 /* There is; does it belong to same group as firstTuple? */
371 cmpresult = setop_compare_slots(input->firstTupleSlot,
372 input->nextTupleSlot,
373 setopstate);
374 Assert(cmpresult <= 0); /* else input is mis-sorted */
375 if (cmpresult != 0)
376 break;
377
378 /* Still in same group, so count this tuple */
379 input->numTuples++;
380 }
381}
382
383/*
384 * Compare the tuples in the two given slots.
385 */
386static int
389{
390 /* We'll often need to fetch all the columns, so just do it */
393 for (int nkey = 0; nkey < setopstate->numCols; nkey++)
394 {
395 SortSupport sortKey = setopstate->sortKeys + nkey;
397 Datum datum1 = s1->tts_values[attno - 1],
398 datum2 = s2->tts_values[attno - 1];
399 bool isNull1 = s1->tts_isnull[attno - 1],
400 isNull2 = s2->tts_isnull[attno - 1];
401 int compare;
402
405 sortKey);
406 if (compare != 0)
407 return compare;
408 }
409 return 0;
410}
411
412/*
413 * ExecSetOp for hashed case: phase 1, read inputs and build hash table
414 */
415static void
417{
420 ExprContext *econtext = setopstate->ps.ps_ExprContext;
421 bool have_tuples = false;
422
423 /*
424 * get state info from node
425 */
428
429 /*
430 * Process each outer-plan tuple, and then fetch the next one, until we
431 * exhaust the outer plan.
432 */
433 for (;;)
434 {
436 TupleHashTable hashtable = setopstate->hashtable;
437 TupleHashEntryData *entry;
439 bool isnew;
440
442 if (TupIsNull(outerslot))
443 break;
444 have_tuples = true;
445
446 /* Find or build hashtable entry for this tuple's group */
447 entry = LookupTupleHashEntry(hashtable,
448 outerslot,
449 &isnew, NULL);
450
451 pergroup = TupleHashEntryGetAdditional(hashtable, entry);
452 /* If new tuple group, initialize counts to zero */
453 if (isnew)
454 {
455 pergroup->numLeft = 0;
456 pergroup->numRight = 0;
457 }
458
459 /* Advance the counts */
460 pergroup->numLeft++;
461
462 /* Must reset expression context after each hashtable lookup */
463 ResetExprContext(econtext);
464 }
465
466 /*
467 * If the outer relation is empty, then we will emit nothing, and we don't
468 * need to read the inner relation at all.
469 */
470 if (have_tuples)
471 {
472 /*
473 * Process each inner-plan tuple, and then fetch the next one, until
474 * we exhaust the inner plan.
475 */
476 for (;;)
477 {
479 TupleHashTable hashtable = setopstate->hashtable;
480 TupleHashEntryData *entry;
481
483 if (TupIsNull(innerslot))
484 break;
485
486 /* For tuples not seen previously, do not make hashtable entry */
487 entry = LookupTupleHashEntry(hashtable,
488 innerslot,
489 NULL, NULL);
490
491 /* Advance the counts if entry is already present */
492 if (entry)
493 {
495
496 pergroup->numRight++;
497 }
498
499 /* Must reset expression context after each hashtable lookup */
500 ResetExprContext(econtext);
501 }
502 }
503
504 setopstate->table_filled = true;
505 /* Initialize to walk the hash table */
506 ResetTupleHashIterator(setopstate->hashtable, &setopstate->hashiter);
507}
508
509/*
510 * ExecSetOp for hashed case: phase 2, retrieving groups from hash table
511 */
512static TupleTableSlot *
514{
515 TupleHashEntry entry;
517
518 /*
519 * get state info from node
520 */
521 resultTupleSlot = setopstate->ps.ps_ResultTupleSlot;
522
523 /*
524 * We loop retrieving groups until we find one we should return
525 */
526 while (!setopstate->setop_done)
527 {
528 TupleHashTable hashtable = setopstate->hashtable;
530
532
533 /*
534 * Find the next entry in the hash table
535 */
536 entry = ScanTupleHashTable(hashtable, &setopstate->hashiter);
537 if (entry == NULL)
538 {
539 /* No more entries in hashtable, so done */
540 setopstate->setop_done = true;
541 return NULL;
542 }
543
544 /*
545 * See if we should emit any copies of this tuple, and if so return
546 * the first copy.
547 */
548 pergroup = TupleHashEntryGetAdditional(hashtable, entry);
550
551 if (setopstate->numOutput > 0)
552 {
553 setopstate->numOutput--;
556 false);
557 }
558 }
559
560 /* No more groups */
562 return NULL;
563}
564
565/* ----------------------------------------------------------------
566 * ExecInitSetOp
567 *
568 * This initializes the setop node state structures and
569 * the node's subplan.
570 * ----------------------------------------------------------------
571 */
573ExecInitSetOp(SetOp *node, EState *estate, int eflags)
574{
576
577 /* check for unsupported flags */
579
580 /*
581 * create state structure
582 */
584 setopstate->ps.plan = (Plan *) node;
585 setopstate->ps.state = estate;
586 setopstate->ps.ExecProcNode = ExecSetOp;
587
588 setopstate->setop_done = false;
589 setopstate->numOutput = 0;
590 setopstate->numCols = node->numCols;
591 setopstate->need_init = true;
592
593 /*
594 * create expression context
595 */
596 ExecAssignExprContext(estate, &setopstate->ps);
597
598 /*
599 * If hashing, we also need a longer-lived context to store the hash
600 * table. The table can't just be kept in the per-query context because
601 * we want to be able to throw it away in ExecReScanSetOp. We can use a
602 * BumpContext to save storage, because we will have no need to delete
603 * individual table entries.
604 */
605 if (node->strategy == SETOP_HASHED)
606 setopstate->tuplesContext =
608 "SetOp hashed tuples",
610
611 /*
612 * initialize child nodes
613 *
614 * If we are hashing then the child plans do not need to handle REWIND
615 * efficiently; see ExecReScanSetOp.
616 */
617 if (node->strategy == SETOP_HASHED)
618 eflags &= ~EXEC_FLAG_REWIND;
619 outerPlanState(setopstate) = ExecInitNode(outerPlan(node), estate, eflags);
620 innerPlanState(setopstate) = ExecInitNode(innerPlan(node), estate, eflags);
621
622 /*
623 * Initialize locally-allocated slots. In hashed mode, we just need a
624 * result slot. In sorted mode, we need one first-tuple-of-group slot for
625 * each input; we use the result slot for the left input's slot and create
626 * another for the right input. (Note: the nextTupleSlot slots are not
627 * ours, but just point to the last slot returned by the input plan node.)
628 */
630 if (node->strategy != SETOP_HASHED)
631 {
632 setopstate->leftInput.firstTupleSlot =
633 setopstate->ps.ps_ResultTupleSlot;
634 setopstate->rightInput.firstTupleSlot =
636 setopstate->ps.ps_ResultTupleDesc,
638 }
639
640 /* Setop nodes do no projections. */
641 setopstate->ps.ps_ProjInfo = NULL;
642
643 /*
644 * Precompute fmgr lookup data for inner loop. We need equality and
645 * hashing functions to do it by hashing, while for sorting we need
646 * SortSupport data.
647 */
648 if (node->strategy == SETOP_HASHED)
650 node->cmpOperators,
651 &setopstate->eqfuncoids,
652 &setopstate->hashfunctions);
653 else
654 {
655 int nkeys = node->numCols;
656
657 setopstate->sortKeys = (SortSupport)
658 palloc0(nkeys * sizeof(SortSupportData));
659 for (int i = 0; i < nkeys; i++)
660 {
661 SortSupport sortKey = setopstate->sortKeys + i;
662
664 sortKey->ssup_collation = node->cmpCollations[i];
665 sortKey->ssup_nulls_first = node->cmpNullsFirst[i];
666 sortKey->ssup_attno = node->cmpColIdx[i];
667 /* abbreviated key conversion is not useful here */
668 sortKey->abbreviate = false;
669
670 PrepareSortSupportFromOrderingOp(node->cmpOperators[i], sortKey);
671 }
672 }
673
674 /* Create a hash table if needed */
675 if (node->strategy == SETOP_HASHED)
676 {
678 setopstate->table_filled = false;
679 }
680
681 return setopstate;
682}
683
684/* ----------------------------------------------------------------
685 * ExecEndSetOp
686 *
687 * This shuts down the subplans and frees resources allocated
688 * to this node.
689 * ----------------------------------------------------------------
690 */
691void
693{
694 /* free subsidiary stuff including hashtable data */
695 if (node->tuplesContext)
697
700}
701
702
703void
705{
708
710 node->setop_done = false;
711 node->numOutput = 0;
712
713 if (((SetOp *) node->ps.plan)->strategy == SETOP_HASHED)
714 {
715 /*
716 * In the hashed case, if we haven't yet built the hash table then we
717 * can just return; nothing done yet, so nothing to undo. If subnode's
718 * chgParam is not NULL then it will be re-scanned by ExecProcNode,
719 * else no reason to re-scan it at all.
720 */
721 if (!node->table_filled)
722 return;
723
724 /*
725 * If we do have the hash table and the subplans do not have any
726 * parameter changes, then we can just rescan the existing hash table;
727 * no need to build it again.
728 */
729 if (outerPlan->chgParam == NULL && innerPlan->chgParam == NULL)
730 {
732 return;
733 }
734
735 /* Else, we must rebuild the hashtable */
737 node->table_filled = false;
738 }
739 else
740 {
741 /* Need to re-read first input from each side */
742 node->need_init = true;
743 }
744
745 /*
746 * if chgParam of subnode is not null then plan will be re-scanned by
747 * first ExecProcNode.
748 */
749 if (outerPlan->chgParam == NULL)
751 if (innerPlan->chgParam == NULL)
753}
int16 AttrNumber
Definition attnum.h:21
MemoryContext BumpContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition bump.c:133
#define Assert(condition)
Definition c.h:945
int64_t int64
Definition c.h:615
size_t Size
Definition c.h:691
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
void ExecReScan(PlanState *node)
Definition execAmi.c:78
void execTuplesHashPrepare(int numCols, const Oid *eqOperators, Oid **eqFuncOids, FmgrInfo **hashFunctions)
TupleHashTable BuildTupleHashTable(PlanState *parent, TupleDesc inputDesc, const TupleTableSlotOps *inputOps, int numCols, AttrNumber *keyColIdx, const Oid *eqfuncoids, FmgrInfo *hashfunctions, Oid *collations, double nelements, Size additionalsize, MemoryContext metacxt, MemoryContext tuplescxt, MemoryContext tempcxt, bool use_variable_hash_iv)
TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew, uint32 *hash)
Size EstimateTupleHashTableSpace(double nentries, Size tupleWidth, Size additionalsize)
void ResetTupleHashTable(TupleHashTable hashtable)
void ExecEndNode(PlanState *node)
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
const TupleTableSlotOps TTSOpsMinimalTuple
Definition execTuples.c:86
TupleDesc ExecGetResultType(PlanState *planstate)
Definition execUtils.c:500
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition execUtils.c:490
const TupleTableSlotOps * ExecGetCommonChildSlotOps(PlanState *ps)
Definition execUtils.c:568
#define outerPlanState(node)
Definition execnodes.h:1273
#define ScanTupleHashTable(htable, iter)
Definition execnodes.h:912
struct SortSupportData * SortSupport
Definition execnodes.h:60
#define ResetTupleHashIterator(htable, iter)
Definition execnodes.h:910
#define innerPlanState(node)
Definition execnodes.h:1272
static MinimalTuple TupleHashEntryGetTuple(TupleHashEntry entry)
Definition executor.h:179
#define EXEC_FLAG_BACKWARD
Definition executor.h:70
static void * TupleHashEntryGetAdditional(TupleHashTable hashtable, TupleHashEntry entry)
Definition executor.h:193
#define ResetExprContext(econtext)
Definition executor.h:654
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition executor.h:315
#define EXEC_FLAG_MARK
Definition executor.h:71
static int compare(const void *arg1, const void *arg2)
Definition geqo_pool.c:144
FILE * input
int i
Definition isn.c:77
void * palloc0(Size size)
Definition mcxt.c:1417
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
Size EstimateSetOpHashTableSpace(double nentries, Size tupleWidth)
Definition nodeSetOp.c:116
static void setop_fill_hash_table(SetOpState *setopstate)
Definition nodeSetOp.c:416
static void setop_load_group(SetOpStatePerInput *input, PlanState *inputPlan, SetOpState *setopstate)
Definition nodeSetOp.c:340
static void build_hash_table(SetOpState *setopstate)
Definition nodeSetOp.c:85
void ExecEndSetOp(SetOpState *node)
Definition nodeSetOp.c:692
static void set_output_count(SetOpState *setopstate, SetOpStatePerGroup pergroup)
Definition nodeSetOp.c:129
static TupleTableSlot * ExecSetOp(PlanState *pstate)
Definition nodeSetOp.c:169
static TupleTableSlot * setop_retrieve_hash_table(SetOpState *setopstate)
Definition nodeSetOp.c:513
static int setop_compare_slots(TupleTableSlot *s1, TupleTableSlot *s2, SetOpState *setopstate)
Definition nodeSetOp.c:387
static TupleTableSlot * setop_retrieve_sorted(SetOpState *setopstate)
Definition nodeSetOp.c:206
SetOpState * ExecInitSetOp(SetOp *node, EState *estate, int eflags)
Definition nodeSetOp.c:573
SetOpStatePerGroupData * SetOpStatePerGroup
Definition nodeSetOp.c:69
void ExecReScanSetOp(SetOpState *node)
Definition nodeSetOp.c:704
@ SETOPCMD_EXCEPT
Definition nodes.h:410
@ SETOPCMD_EXCEPT_ALL
Definition nodes.h:411
@ SETOPCMD_INTERSECT_ALL
Definition nodes.h:409
@ SETOPCMD_INTERSECT
Definition nodes.h:408
@ SETOP_HASHED
Definition nodes.h:417
#define makeNode(_type_)
Definition nodes.h:161
#define castNode(_type_, nodeptr)
Definition nodes.h:182
#define innerPlan(node)
Definition plannodes.h:264
#define outerPlan(node)
Definition plannodes.h:265
uint64_t Datum
Definition postgres.h:70
static int fb(int x)
char * s1
char * s2
void PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
static int ApplySortComparator(Datum datum1, bool isNull1, Datum datum2, bool isNull2, SortSupport ssup)
MemoryContext ecxt_per_tuple_memory
Definition execnodes.h:292
Plan * plan
Definition execnodes.h:1177
TupleTableSlot * ps_ResultTupleSlot
Definition execnodes.h:1215
bool need_init
Definition execnodes.h:2720
MemoryContext tuplesContext
Definition execnodes.h:2726
TupleHashIterator hashiter
Definition execnodes.h:2728
bool table_filled
Definition execnodes.h:2727
PlanState ps
Definition execnodes.h:2711
TupleHashTable hashtable
Definition execnodes.h:2725
int64 numOutput
Definition execnodes.h:2713
bool setop_done
Definition execnodes.h:2712
SetOpStrategy strategy
Definition plannodes.h:1450
int numCols
Definition plannodes.h:1453
Plan plan
Definition plannodes.h:1444
Cardinality numGroups
Definition plannodes.h:1466
AttrNumber ssup_attno
Definition sortsupport.h:81
MemoryContext ssup_cxt
Definition sortsupport.h:66
static MinimalTuple ExecCopySlotMinimalTuple(TupleTableSlot *slot)
Definition tuptable.h:514
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition tuptable.h:476
#define TupIsNull(slot)
Definition tuptable.h:325
static void slot_getallattrs(TupleTableSlot *slot)
Definition tuptable.h:390