/* * ExecSetOp for hashed case: phase 1, read input and build hash table */ static void setop_fill_hash_table(SetOpState *setopstate) { SetOp *node = (SetOp *) setopstate->ps.plan; PlanState *outerPlan; int firstFlag; bool in_first_rel PG_USED_FOR_ASSERTS_ONLY; /* * get state info from node */ outerPlan = outerPlanState(setopstate); firstFlag = node->firstFlag; /* verify planner didn't mess up */ Assert(firstFlag == 0 || (firstFlag == 1 && (node->cmd == SETOPCMD_INTERSECT || node->cmd == SETOPCMD_INTERSECT_ALL))); /* * Process each outer-plan tuple, and then fetch the next one, until we * exhaust the outer plan. */ in_first_rel = true; for (;;) { TupleTableSlot *outerslot; int flag; SetOpHashEntry entry; bool isnew; outerslot = ExecProcNode(outerPlan); if (TupIsNull(outerslot)) break; /* Identify whether it's left or right input */ flag = fetch_tuple_flag(setopstate, outerslot); if (flag == firstFlag) { /* (still) in first input relation */ Assert(in_first_rel); /* Find or build hashtable entry for this tuple's group */ entry = (SetOpHashEntry) LookupTupleHashEntry(setopstate->hashtable, outerslot, &isnew); /* If new tuple group, initialize counts */ if (isnew) initialize_counts(&entry->pergroup); /* Advance the counts */ advance_counts(&entry->pergroup, flag); } else { /* reached second relation */ in_first_rel = false; /* For tuples not seen previously, do not make hashtable entry */ entry = (SetOpHashEntry) LookupTupleHashEntry(setopstate->hashtable, outerslot, NULL); /* Advance the counts if entry is already present */ if (entry) advance_counts(&entry->pergroup, flag); } /* Must reset temp context after each hashtable lookup */ MemoryContextReset(setopstate->tempContext); } setopstate->table_filled = true; /* Initialize to walk the hash table */ ResetTupleHashIterator(setopstate->hashtable, &setopstate->hashiter); }
/* ---------------------------------------------------------------- * ExecRecursiveUnion(node) * * Scans the recursive query sequentially and returns the next * qualifying tuple. * * 1. evaluate non recursive term and assign the result to RT * * 2. execute recursive terms * * 2.1 WT := RT * 2.2 while WT is not empty repeat 2.3 to 2.6. if WT is empty returns RT * 2.3 replace the name of recursive term with WT * 2.4 evaluate the recursive term and store into WT * 2.5 append WT to RT * 2.6 go back to 2.2 * ---------------------------------------------------------------- */ TupleTableSlot * ExecRecursiveUnion(RecursiveUnionState *node) { PlanState *outerPlan = outerPlanState(node); PlanState *innerPlan = innerPlanState(node); RecursiveUnion *plan = (RecursiveUnion *) node->ps.plan; TupleTableSlot *slot; RUHashEntry entry; bool isnew; /* 1. Evaluate non-recursive term */ if (!node->recursing) { for (;;) { slot = ExecProcNode(outerPlan); if (TupIsNull(slot)) break; if (plan->numCols > 0) { /* Find or build hashtable entry for this tuple's group */ entry = (RUHashEntry) LookupTupleHashEntry(node->hashtable, slot, &isnew); /* Must reset temp context after each hashtable lookup */ MemoryContextReset(node->tempContext); /* Ignore tuple if already seen */ if (!isnew) continue; } /* Each non-duplicate tuple goes to the working table ... */ tuplestore_puttupleslot(node->working_table, slot); /* ... and to the caller */ return slot; } node->recursing = true; } /* 2. Execute recursive term */ for (;;) { slot = ExecProcNode(innerPlan); if (TupIsNull(slot)) { /* Done if there's nothing in the intermediate table */ if (node->intermediate_empty) break; /* done with old working table ... */ tuplestore_end(node->working_table); /* intermediate table becomes working table */ node->working_table = node->intermediate_table; /* create new empty intermediate table */ node->intermediate_table = tuplestore_begin_heap(false, false, work_mem); node->intermediate_empty = true; /* reset the recursive term */ innerPlan->chgParam = bms_add_member(innerPlan->chgParam, plan->wtParam); /* and continue fetching from recursive term */ continue; } if (plan->numCols > 0) { /* Find or build hashtable entry for this tuple's group */ entry = (RUHashEntry) LookupTupleHashEntry(node->hashtable, slot, &isnew); /* Must reset temp context after each hashtable lookup */ MemoryContextReset(node->tempContext); /* Ignore tuple if already seen */ if (!isnew) continue; } /* Else, tuple is good; stash it in intermediate table ... */ node->intermediate_empty = false; tuplestore_puttupleslot(node->intermediate_table, slot); /* ... and return it */ return slot; } return NULL; }