---------------------------------------------------------------- * 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
| 72 | * ---------------------------------------------------------------- |
| 73 | */ |
| 74 | static TupleTableSlot * |
| 75 | ExecRecursiveUnion(PlanState *pstate) |
| 76 | { |
| 77 | RecursiveUnionState *node = castNode(RecursiveUnionState, pstate); |
| 78 | PlanState *outerPlan = outerPlanState(node); |
| 79 | PlanState *innerPlan = innerPlanState(node); |
| 80 | RecursiveUnion *plan = (RecursiveUnion *) node->ps.plan; |
| 81 | TupleTableSlot *slot; |
| 82 | bool isnew; |
| 83 | |
| 84 | CHECK_FOR_INTERRUPTS(); |
| 85 | |
| 86 | /* 1. Evaluate non-recursive term */ |
| 87 | if (!node->recursing) |
| 88 | { |
| 89 | for (;;) |
| 90 | { |
| 91 | slot = ExecProcNode(outerPlan); |
| 92 | if (TupIsNull(slot)) |
| 93 | break; |
| 94 | /* |
| 95 | * RECURSIVE_CTE_FIXME: It suppose plan->numCols should be 0 if we don't |
| 96 | * support recursive union. QP should fix this later. |
| 97 | */ |
| 98 | if (plan->numCols > 0) |
| 99 | { |
| 100 | /* Find or build hashtable entry for this tuple's group */ |
| 101 | LookupTupleHashEntry(node->hashtable, slot, &isnew, NULL); |
| 102 | /* Must reset temp context after each hashtable lookup */ |
| 103 | MemoryContextReset(node->tempContext); |
| 104 | /* Ignore tuple if already seen */ |
| 105 | if (!isnew) |
| 106 | continue; |
| 107 | } |
| 108 | /* Each non-duplicate tuple goes to the working table ... */ |
| 109 | tuplestore_puttupleslot(node->working_table, slot); |
| 110 | /* ... and to the caller */ |
| 111 | return slot; |
| 112 | } |
| 113 | node->recursing = true; |
| 114 | } |
| 115 | |
| 116 | /* 2. Execute recursive term */ |
| 117 | for (;;) |
| 118 | { |
| 119 | slot = ExecProcNode(innerPlan); |
| 120 | if (TupIsNull(slot)) |
| 121 | { |
| 122 | /* Done if there's nothing in the intermediate table */ |
| 123 | if (node->intermediate_empty) |
| 124 | break; |
| 125 | |
| 126 | /* done with old working table ... */ |
| 127 | tuplestore_end(node->working_table); |
| 128 | |
| 129 | /* intermediate table becomes working table */ |
| 130 | node->working_table = node->intermediate_table; |
| 131 | for (int k = 1; k < node->refcount; k++) |
nothing calls this directly
no test coverage detected