---------------------------------------------------------------- * ExecHashJoinImpl * * This function implements the Hybrid Hashjoin algorithm. It is marked * with an always-inline attribute so that ExecHashJoin() and * ExecParallelHashJoin() can inline it. Compilers that respect the * attribute should create versions specialized for parallel == true and * parallel == false with unn
| 193 | * ---------------------------------------------------------------- |
| 194 | */ |
| 195 | static pg_attribute_always_inline TupleTableSlot * |
| 196 | ExecHashJoinImpl(PlanState *pstate, bool parallel) |
| 197 | { |
| 198 | HashJoinState *node = castNode(HashJoinState, pstate); |
| 199 | PlanState *outerNode; |
| 200 | HashState *hashNode; |
| 201 | ExprState *joinqual; |
| 202 | ExprState *otherqual; |
| 203 | ExprContext *econtext; |
| 204 | HashJoinTable hashtable; |
| 205 | TupleTableSlot *outerTupleSlot; |
| 206 | uint32 hashvalue; |
| 207 | int batchno; |
| 208 | ParallelHashJoinState *parallel_state; |
| 209 | EState *estate; |
| 210 | |
| 211 | /* |
| 212 | * get information from HashJoin node |
| 213 | */ |
| 214 | estate = node->js.ps.state; |
| 215 | joinqual = node->js.joinqual; |
| 216 | otherqual = node->js.ps.qual; |
| 217 | hashNode = (HashState *) innerPlanState(node); |
| 218 | outerNode = outerPlanState(node); |
| 219 | hashtable = node->hj_HashTable; |
| 220 | econtext = node->js.ps.ps_ExprContext; |
| 221 | parallel_state = hashNode->parallel_state; |
| 222 | /* CBDB_PARALLEL_FIXME: When parallel is true and parallel_state is NULL */ |
| 223 | parallel = parallel && (parallel_state != NULL); |
| 224 | |
| 225 | /* |
| 226 | * Reset per-tuple memory context to free any expression evaluation |
| 227 | * storage allocated in the previous tuple cycle. |
| 228 | */ |
| 229 | ResetExprContext(econtext); |
| 230 | |
| 231 | /* |
| 232 | * Executor try to squelch nodes in it‘s subtree after a node returning a NULL tuple. |
| 233 | * If the chgParam is not null, squelching is not safe. |
| 234 | * If outer node gets empty tuple, squelching the outer node is too early. |
| 235 | * To fix that, we should add delayEagerFree logic to Limit node, |
| 236 | * to not call ExecSquelchNode() when the node might get rescanned later. |
| 237 | */ |
| 238 | if (outerNode->chgParam != NULL) |
| 239 | node->delayEagerFree = true; |
| 240 | /* |
| 241 | * run the hash join state machine |
| 242 | */ |
| 243 | for (;;) |
| 244 | { |
| 245 | /* We must never use an eagerly released hash table */ |
| 246 | Assert(hashtable == NULL || !hashtable->eagerlyReleased); |
| 247 | /* |
| 248 | * It's possible to iterate this loop many times before returning a |
| 249 | * tuple, in some pathological cases such as needing to move much of |
| 250 | * the current batch to a later batch. So let's check for interrupts |
| 251 | * each time through. |
| 252 | */ |
no test coverage detected