* search_plan_tree * * Search through a PlanState tree for a scan node on the specified table. * Return NULL if not found or multiple candidates. * * CAUTION: this function is not charged simply with finding some candidate * scan, but with ensuring that that scan returned the plan tree's current * output row. That's why we must reject multiple-match cases. * * If a candidate is found, se
| 586 | * if multiple candidates are found.) |
| 587 | */ |
| 588 | static ScanState * |
| 589 | search_plan_tree(PlanState *node, Oid table_oid, |
| 590 | bool *pending_rescan) |
| 591 | { |
| 592 | ScanState *result = NULL; |
| 593 | |
| 594 | if (node == NULL) |
| 595 | return NULL; |
| 596 | switch (nodeTag(node)) |
| 597 | { |
| 598 | /* |
| 599 | * Relation scan nodes can all be treated alike: check to see if |
| 600 | * they are scanning the specified table. |
| 601 | * |
| 602 | * ForeignScan and CustomScan might not have a currentRelation, in |
| 603 | * which case we just ignore them. (We dare not descend to any |
| 604 | * child plan nodes they might have, since we do not know the |
| 605 | * relationship of such a node's current output tuple to the |
| 606 | * children's current outputs.) |
| 607 | */ |
| 608 | case T_SeqScanState: |
| 609 | case T_SampleScanState: |
| 610 | case T_IndexScanState: |
| 611 | case T_IndexOnlyScanState: |
| 612 | case T_BitmapHeapScanState: |
| 613 | case T_TidScanState: |
| 614 | case T_TidRangeScanState: |
| 615 | case T_ForeignScanState: |
| 616 | case T_CustomScanState: |
| 617 | { |
| 618 | ScanState *sstate = (ScanState *) node; |
| 619 | |
| 620 | if (sstate->ss_currentRelation && |
| 621 | RelationGetRelid(sstate->ss_currentRelation) == table_oid) |
| 622 | result = sstate; |
| 623 | break; |
| 624 | } |
| 625 | |
| 626 | /* |
| 627 | * For Append, we can check each input node. It is safe to |
| 628 | * descend to the inputs because only the input that resulted in |
| 629 | * the Append's current output node could be positioned on a tuple |
| 630 | * at all; the other inputs are either at EOF or not yet started. |
| 631 | * Hence, if the desired table is scanned by some |
| 632 | * currently-inactive input node, we will find that node but then |
| 633 | * our caller will realize that it didn't emit the tuple of |
| 634 | * interest. |
| 635 | * |
| 636 | * We do need to watch out for multiple matches (possible if |
| 637 | * Append was from UNION ALL rather than an inheritance tree). |
| 638 | * |
| 639 | * Note: we can NOT descend through MergeAppend similarly, since |
| 640 | * its inputs are likely all active, and we don't know which one |
| 641 | * returned the current output tuple. (Perhaps that could be |
| 642 | * fixed if we were to let this code know more about MergeAppend's |
| 643 | * internal state, but it does not seem worth the trouble. Users |
| 644 | * should not expect plans for ORDER BY queries to be considered |
| 645 | * simply-updatable, since they won't be if the sorting is |