* This is called when the node above us has finished and will not need any more * rows from us. */
| 618 | * rows from us. |
| 619 | */ |
| 620 | void |
| 621 | ExecSquelchShareInputScan(ShareInputScanState *node, bool force) |
| 622 | { |
| 623 | EState *estate = node->ss.ps.state; |
| 624 | ShareInputScan *sisc = (ShareInputScan *) node->ss.ps.plan; |
| 625 | shareinput_local_state *local_state = node->local_state; |
| 626 | |
| 627 | if (node->ss.ps.squelched) |
| 628 | return; |
| 629 | |
| 630 | /* clean up tuple table */ |
| 631 | ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); |
| 632 | |
| 633 | /* |
| 634 | * If this ShareInputScan is shared within the same slice then its |
| 635 | * subtree may still need to be executed and the motions in the subtree |
| 636 | * cannot yet be stopped. Thus, don't recurse in this case. |
| 637 | * |
| 638 | * In squelching a cross-slice ShareInputScan writer, we need to ensure |
| 639 | * we don't block any reader on other slices as a result of not |
| 640 | * materializing the shared plan. |
| 641 | * |
| 642 | * Note that we emphatically can't "fake" an empty tuple store and just |
| 643 | * go ahead waking up the readers because that can lead to wrong results. |
| 644 | */ |
| 645 | if (sisc->cross_slice && node->ref) |
| 646 | { |
| 647 | if (currentSliceId == sisc->producer_slice_id || estate->es_plannedstmt->numSlices == 1) |
| 648 | { |
| 649 | /* |
| 650 | * We are the producer. If we haven't materialized the tuplestore |
| 651 | * yet, we need to do it now, even though we won't need the data |
| 652 | * for anything. There might be other consumers that need it, and |
| 653 | * they will hang waiting for us forever otherwise. |
| 654 | */ |
| 655 | if (!local_state->ready) |
| 656 | { |
| 657 | elog((Debug_shareinput_xslice ? LOG : DEBUG1), "SISC WRITER (shareid=%d, slice=%d): initializing because squelched", |
| 658 | sisc->share_id, currentSliceId); |
| 659 | init_tuplestore_state(node); |
| 660 | } |
| 661 | } |
| 662 | else |
| 663 | { |
| 664 | /* We are a consumer. Let the producer know that we're done. */ |
| 665 | Assert(!local_state->closed); |
| 666 | |
| 667 | local_state->ndone++; |
| 668 | |
| 669 | if (local_state->ndone == local_state->nsharers) |
| 670 | { |
| 671 | shareinput_reader_notifydone(node->ref, sisc->nconsumers); |
| 672 | local_state->closed = true; |
| 673 | } |
| 674 | release_shareinput_reference(node->ref, true); |
| 675 | node->ref = NULL; |
| 676 | } |
| 677 | } |
no test coverage detected