PostgreSQL Source Code git master
Loading...
Searching...
No Matches
nodeRecursiveunion.c File Reference
#include "postgres.h"
#include "executor/executor.h"
#include "executor/nodeRecursiveunion.h"
#include "miscadmin.h"
#include "utils/memutils.h"
#include "utils/tuplestore.h"
Include dependency graph for nodeRecursiveunion.c:

Go to the source code of this file.

Functions

static void build_hash_table (RecursiveUnionState *rustate)
 
static TupleTableSlotExecRecursiveUnion (PlanState *pstate)
 
RecursiveUnionStateExecInitRecursiveUnion (RecursiveUnion *node, EState *estate, int eflags)
 
void ExecEndRecursiveUnion (RecursiveUnionState *node)
 
void ExecReScanRecursiveUnion (RecursiveUnionState *node)
 

Function Documentation

◆ build_hash_table()

static void build_hash_table ( RecursiveUnionState rustate)
static

Definition at line 33 of file nodeRecursiveunion.c.

34{
35 RecursiveUnion *node = (RecursiveUnion *) rustate->ps.plan;
37
38 Assert(node->numCols > 0);
39
40 /*
41 * If both child plans deliver the same fixed tuple slot type, we can tell
42 * BuildTupleHashTable to expect that slot type as input. Otherwise,
43 * we'll pass NULL denoting that any slot type is possible.
44 */
45 rustate->hashtable = BuildTupleHashTable(&rustate->ps,
46 desc,
48 node->numCols,
49 node->dupColIdx,
50 rustate->eqfuncoids,
51 rustate->hashfunctions,
52 node->dupCollations,
53 node->numGroups,
54 0,
55 rustate->ps.state->es_query_cxt,
56 rustate->tuplesContext,
57 rustate->tempContext,
58 false);
59}
#define Assert(condition)
Definition c.h:945
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)
TupleDesc ExecGetResultType(PlanState *planstate)
Definition execUtils.c:500
const TupleTableSlotOps * ExecGetCommonChildSlotOps(PlanState *ps)
Definition execUtils.c:568
#define outerPlanState(node)
Definition execnodes.h:1273
MemoryContext es_query_cxt
Definition execnodes.h:722
Plan * plan
Definition execnodes.h:1177
EState * state
Definition execnodes.h:1179
MemoryContext tempContext
Definition execnodes.h:1585
MemoryContext tuplesContext
Definition execnodes.h:1587
FmgrInfo * hashfunctions
Definition execnodes.h:1584
TupleHashTable hashtable
Definition execnodes.h:1586

References Assert, BuildTupleHashTable(), RecursiveUnionState::eqfuncoids, EState::es_query_cxt, ExecGetCommonChildSlotOps(), ExecGetResultType(), RecursiveUnionState::hashfunctions, RecursiveUnionState::hashtable, RecursiveUnion::numCols, RecursiveUnion::numGroups, outerPlanState, PlanState::plan, RecursiveUnionState::ps, PlanState::state, RecursiveUnionState::tempContext, and RecursiveUnionState::tuplesContext.

Referenced by ExecInitRecursiveUnion().

◆ ExecEndRecursiveUnion()

void ExecEndRecursiveUnion ( RecursiveUnionState node)

Definition at line 286 of file nodeRecursiveunion.c.

287{
288 /* Release tuplestores */
291
292 /* free subsidiary stuff including hashtable data */
293 if (node->tempContext)
295 if (node->tuplesContext)
297
298 /*
299 * close down subplans
300 */
303}
void ExecEndNode(PlanState *node)
#define innerPlanState(node)
Definition execnodes.h:1272
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
Tuplestorestate * working_table
Definition execnodes.h:1580
Tuplestorestate * intermediate_table
Definition execnodes.h:1581
void tuplestore_end(Tuplestorestate *state)
Definition tuplestore.c:493

References ExecEndNode(), innerPlanState, RecursiveUnionState::intermediate_table, MemoryContextDelete(), outerPlanState, RecursiveUnionState::tempContext, RecursiveUnionState::tuplesContext, tuplestore_end(), and RecursiveUnionState::working_table.

Referenced by ExecEndNode().

◆ ExecInitRecursiveUnion()

RecursiveUnionState * ExecInitRecursiveUnion ( RecursiveUnion node,
EState estate,
int  eflags 
)

Definition at line 180 of file nodeRecursiveunion.c.

181{
182 RecursiveUnionState *rustate;
184
185 /* check for unsupported flags */
187
188 /*
189 * create state structure
190 */
191 rustate = makeNode(RecursiveUnionState);
192 rustate->ps.plan = (Plan *) node;
193 rustate->ps.state = estate;
195
196 rustate->eqfuncoids = NULL;
197 rustate->hashfunctions = NULL;
198 rustate->hashtable = NULL;
199 rustate->tempContext = NULL;
200 rustate->tuplesContext = NULL;
201
202 /* initialize processing state */
203 rustate->recursing = false;
204 rustate->intermediate_empty = true;
205 rustate->working_table = tuplestore_begin_heap(false, false, work_mem);
206 rustate->intermediate_table = tuplestore_begin_heap(false, false, work_mem);
207
208 /*
209 * If hashing, we need a per-tuple memory context for comparisons, and a
210 * longer-lived context to store the hash table. The table can't just be
211 * kept in the per-query context because we want to be able to throw it
212 * away when rescanning. We can use a BumpContext to save storage,
213 * because we will have no need to delete individual table entries.
214 */
215 if (node->numCols > 0)
216 {
217 rustate->tempContext =
219 "RecursiveUnion",
221 rustate->tuplesContext =
223 "RecursiveUnion hashed tuples",
225 }
226
227 /*
228 * Make the state structure available to descendant WorkTableScan nodes
229 * via the Param slot reserved for it.
230 */
231 prmdata = &(estate->es_param_exec_vals[node->wtParam]);
232 Assert(prmdata->execPlan == NULL);
233 prmdata->value = PointerGetDatum(rustate);
234 prmdata->isnull = false;
235
236 /*
237 * Miscellaneous initialization
238 *
239 * RecursiveUnion plans don't have expression contexts because they never
240 * call ExecQual or ExecProject.
241 */
242 Assert(node->plan.qual == NIL);
243
244 /*
245 * RecursiveUnion nodes still have Result slots, which hold pointers to
246 * tuples, so we have to initialize them.
247 */
248 ExecInitResultTypeTL(&rustate->ps);
249
250 /*
251 * Initialize result tuple type. (Note: we have to set up the result type
252 * before initializing child nodes, because nodeWorktablescan.c expects it
253 * to be valid.)
254 */
255 rustate->ps.ps_ProjInfo = NULL;
256
257 /*
258 * initialize child nodes
259 */
260 outerPlanState(rustate) = ExecInitNode(outerPlan(node), estate, eflags);
261 innerPlanState(rustate) = ExecInitNode(innerPlan(node), estate, eflags);
262
263 /*
264 * If hashing, precompute fmgr lookup data for inner loop, and create the
265 * hash table.
266 */
267 if (node->numCols > 0)
268 {
270 node->dupOperators,
271 &rustate->eqfuncoids,
272 &rustate->hashfunctions);
273 build_hash_table(rustate);
274 }
275
276 return rustate;
277}
MemoryContext BumpContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition bump.c:133
void execTuplesHashPrepare(int numCols, const Oid *eqOperators, Oid **eqFuncOids, FmgrInfo **hashFunctions)
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
void ExecInitResultTypeTL(PlanState *planstate)
#define EXEC_FLAG_BACKWARD
Definition executor.h:70
#define EXEC_FLAG_MARK
Definition executor.h:71
int work_mem
Definition globals.c:131
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
static void build_hash_table(RecursiveUnionState *rustate)
static TupleTableSlot * ExecRecursiveUnion(PlanState *pstate)
#define makeNode(_type_)
Definition nodes.h:161
#define NIL
Definition pg_list.h:68
#define innerPlan(node)
Definition plannodes.h:264
#define outerPlan(node)
Definition plannodes.h:265
static Datum PointerGetDatum(const void *X)
Definition postgres.h:342
static int fb(int x)
ParamExecData * es_param_exec_vals
Definition execnodes.h:717
ProjectionInfo * ps_ProjInfo
Definition execnodes.h:1217
ExecProcNodeMtd ExecProcNode
Definition execnodes.h:1183
List * qual
Definition plannodes.h:235
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition tuplestore.c:331

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, build_hash_table(), BumpContextCreate(), CurrentMemoryContext, RecursiveUnionState::eqfuncoids, EState::es_param_exec_vals, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, ExecInitNode(), ExecInitResultTypeTL(), PlanState::ExecProcNode, ExecRecursiveUnion(), execTuplesHashPrepare(), fb(), RecursiveUnionState::hashfunctions, RecursiveUnionState::hashtable, innerPlan, innerPlanState, RecursiveUnionState::intermediate_empty, RecursiveUnionState::intermediate_table, makeNode, NIL, RecursiveUnion::numCols, outerPlan, outerPlanState, PlanState::plan, RecursiveUnion::plan, PointerGetDatum(), RecursiveUnionState::ps, PlanState::ps_ProjInfo, Plan::qual, RecursiveUnionState::recursing, PlanState::state, RecursiveUnionState::tempContext, RecursiveUnionState::tuplesContext, tuplestore_begin_heap(), work_mem, RecursiveUnionState::working_table, and RecursiveUnion::wtParam.

Referenced by ExecInitNode().

◆ ExecRecursiveUnion()

static TupleTableSlot * ExecRecursiveUnion ( PlanState pstate)
static

Definition at line 81 of file nodeRecursiveunion.c.

82{
87 TupleTableSlot *slot;
88 bool isnew;
89
91
92 /* 1. Evaluate non-recursive term */
93 if (!node->recursing)
94 {
95 for (;;)
96 {
97 slot = ExecProcNode(outerPlan);
98 if (TupIsNull(slot))
99 break;
100 if (plan->numCols > 0)
101 {
102 /* Find or build hashtable entry for this tuple's group */
103 LookupTupleHashEntry(node->hashtable, slot, &isnew, NULL);
104 /* Must reset temp context after each hashtable lookup */
105 MemoryContextReset(node->tempContext);
106 /* Ignore tuple if already seen */
107 if (!isnew)
108 continue;
109 }
110 /* Each non-duplicate tuple goes to the working table ... */
111 tuplestore_puttupleslot(node->working_table, slot);
112 /* ... and to the caller */
113 return slot;
114 }
115 node->recursing = true;
116 }
117
118 /* 2. Execute recursive term */
119 for (;;)
120 {
121 slot = ExecProcNode(innerPlan);
122 if (TupIsNull(slot))
123 {
125
126 /* Done if there's nothing in the intermediate table */
127 if (node->intermediate_empty)
128 break;
129
130 /*
131 * Now we let the intermediate table become the work table. We
132 * need a fresh intermediate table, so delete the tuples from the
133 * current working table and use that as the new intermediate
134 * table. This saves a round of free/malloc from creating a new
135 * tuple store.
136 */
137 tuplestore_clear(node->working_table);
138
139 swaptemp = node->working_table;
140 node->working_table = node->intermediate_table;
141 node->intermediate_table = swaptemp;
142
143 /* mark the intermediate table as empty */
144 node->intermediate_empty = true;
145
146 /* reset the recursive term */
147 innerPlan->chgParam = bms_add_member(innerPlan->chgParam,
148 plan->wtParam);
149
150 /* and continue fetching from recursive term */
151 continue;
152 }
153
154 if (plan->numCols > 0)
155 {
156 /* Find or build hashtable entry for this tuple's group */
157 LookupTupleHashEntry(node->hashtable, slot, &isnew, NULL);
158 /* Must reset temp context after each hashtable lookup */
159 MemoryContextReset(node->tempContext);
160 /* Ignore tuple if already seen */
161 if (!isnew)
162 continue;
163 }
164
165 /* Else, tuple is good; stash it in intermediate table ... */
166 node->intermediate_empty = false;
167 tuplestore_puttupleslot(node->intermediate_table, slot);
168 /* ... and return it */
169 return slot;
170 }
171
172 return NULL;
173}
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:799
TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew, uint32 *hash)
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition executor.h:315
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:403
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
#define castNode(_type_, nodeptr)
Definition nodes.h:182
#define plan(x)
Definition pg_regress.c:161
void tuplestore_puttupleslot(Tuplestorestate *state, TupleTableSlot *slot)
Definition tuplestore.c:743
void tuplestore_clear(Tuplestorestate *state)
Definition tuplestore.c:431
#define TupIsNull(slot)
Definition tuptable.h:325

References bms_add_member(), castNode, CHECK_FOR_INTERRUPTS, ExecProcNode(), fb(), RecursiveUnionState::hashtable, innerPlan, innerPlanState, RecursiveUnionState::intermediate_empty, RecursiveUnionState::intermediate_table, LookupTupleHashEntry(), MemoryContextReset(), outerPlan, outerPlanState, PlanState::plan, plan, RecursiveUnionState::ps, RecursiveUnionState::recursing, RecursiveUnionState::tempContext, TupIsNull, tuplestore_clear(), tuplestore_puttupleslot(), and RecursiveUnionState::working_table.

Referenced by ExecInitRecursiveUnion().

◆ ExecReScanRecursiveUnion()

void ExecReScanRecursiveUnion ( RecursiveUnionState node)

Definition at line 312 of file nodeRecursiveunion.c.

313{
317
318 /*
319 * Set recursive term's chgParam to tell it that we'll modify the working
320 * table and therefore it has to rescan.
321 */
322 innerPlan->chgParam = bms_add_member(innerPlan->chgParam, plan->wtParam);
323
324 /*
325 * if chgParam of subnode is not null then plan will be re-scanned by
326 * first ExecProcNode. Because of above, we only have to do this to the
327 * non-recursive term.
328 */
329 if (outerPlan->chgParam == NULL)
331
332 /* Empty hashtable if needed */
333 if (plan->numCols > 0)
335
336 /* reset processing state */
337 node->recursing = false;
338 node->intermediate_empty = true;
341}
void ExecReScan(PlanState *node)
Definition execAmi.c:78
void ResetTupleHashTable(TupleHashTable hashtable)

References bms_add_member(), ExecReScan(), fb(), RecursiveUnionState::hashtable, innerPlan, innerPlanState, RecursiveUnionState::intermediate_empty, RecursiveUnionState::intermediate_table, outerPlan, outerPlanState, PlanState::plan, plan, RecursiveUnionState::ps, RecursiveUnionState::recursing, ResetTupleHashTable(), tuplestore_clear(), and RecursiveUnionState::working_table.

Referenced by ExecReScan().