* get_memoize_path * If possible, make and return a Memoize path atop of 'inner_path'. * Otherwise return NULL. */
| 595 | * Otherwise return NULL. |
| 596 | */ |
| 597 | static Path * |
| 598 | get_memoize_path(PlannerInfo *root, RelOptInfo *innerrel, |
| 599 | RelOptInfo *outerrel, Path *inner_path, |
| 600 | Path *outer_path, JoinType jointype, |
| 601 | JoinPathExtraData *extra) |
| 602 | { |
| 603 | List *param_exprs; |
| 604 | List *hash_operators; |
| 605 | ListCell *lc; |
| 606 | bool binary_mode; |
| 607 | |
| 608 | /* Obviously not if it's disabled */ |
| 609 | if (!enable_memoize) |
| 610 | return NULL; |
| 611 | |
| 612 | /* |
| 613 | * We can safely not bother with all this unless we expect to perform more |
| 614 | * than one inner scan. The first scan is always going to be a cache |
| 615 | * miss. This would likely fail later anyway based on costs, so this is |
| 616 | * really just to save some wasted effort. |
| 617 | */ |
| 618 | if (outer_path->parent->rows < 2) |
| 619 | return NULL; |
| 620 | |
| 621 | /* |
| 622 | * We can only have a memoize node when there's some kind of cache key, |
| 623 | * either parameterized path clauses or lateral Vars. No cache key sounds |
| 624 | * more like something a Materialize node might be more useful for. |
| 625 | */ |
| 626 | if ((inner_path->param_info == NULL || |
| 627 | inner_path->param_info->ppi_clauses == NIL) && |
| 628 | innerrel->lateral_vars == NIL) |
| 629 | return NULL; |
| 630 | |
| 631 | /* |
| 632 | * Currently we don't do this for SEMI and ANTI joins unless they're |
| 633 | * marked as inner_unique. This is because nested loop SEMI/ANTI joins |
| 634 | * don't scan the inner node to completion, which will mean memoize cannot |
| 635 | * mark the cache entry as complete. |
| 636 | * |
| 637 | * XXX Currently we don't attempt to mark SEMI/ANTI joins as inner_unique |
| 638 | * = true. Should we? See add_paths_to_joinrel() |
| 639 | */ |
| 640 | if (!extra->inner_unique && (jointype == JOIN_SEMI || |
| 641 | jointype == JOIN_ANTI)) |
| 642 | return NULL; |
| 643 | |
| 644 | /* |
| 645 | * Memoize normally marks cache entries as complete when it runs out of |
| 646 | * tuples to read from its subplan. However, with unique joins, Nested |
| 647 | * Loop will skip to the next outer tuple after finding the first matching |
| 648 | * inner tuple. This means that we may not read the inner side of the |
| 649 | * join to completion which leaves no opportunity to mark the cache entry |
| 650 | * as complete. To work around that, when the join is unique we |
| 651 | * automatically mark cache entries as complete after fetching the first |
| 652 | * tuple. This works when the entire join condition is parameterized. |
| 653 | * Otherwise, when the parameterization is only a subset of the join |
| 654 | * condition, we can't be sure which part of it causes the join to be |
no test coverage detected