aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/nodeResultCache.c2
-rw-r--r--src/backend/optimizer/path/joinpath.c31
2 files changed, 32 insertions, 1 deletions
diff --git a/src/backend/executor/nodeResultCache.c b/src/backend/executor/nodeResultCache.c
index 919238d1ff1..471900346f1 100644
--- a/src/backend/executor/nodeResultCache.c
+++ b/src/backend/executor/nodeResultCache.c
@@ -760,7 +760,7 @@ ExecResultCache(PlanState *pstate)
/*
* Validate if the planner properly set the singlerow flag. It
* should only set that if each cache entry can, at most,
- * return 1 row. XXX maybe this should be an Assert?
+ * return 1 row.
*/
if (unlikely(entry->complete))
elog(ERROR, "cache entry already complete");
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index 4c30c655640..d9d48827a9a 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -504,6 +504,37 @@ get_resultcache_path(PlannerInfo *root, RelOptInfo *innerrel,
return NULL;
/*
+ * Result Cache normally marks cache entries as complete when it runs out
+ * of tuples to read from its subplan. However, with unique joins, Nested
+ * Loop will skip to the next outer tuple after finding the first matching
+ * inner tuple. This means that we may not read the inner side of the
+ * join to completion which leaves no opportunity to mark the cache entry
+ * as complete. To work around that, when the join is unique we
+ * automatically mark cache entries as complete after fetching the first
+ * tuple. This works when the entire join condition is parameterized.
+ * Otherwise, when the parameterization is only a subset of the join
+ * condition, we can't be sure which part of it causes the join to be
+ * unique. This means there are no guarantees that only 1 tuple will be
+ * read. We cannot mark the cache entry as complete after reading the
+ * first tuple without that guarantee. This means the scope of Result
+ * Cache's usefulness is limited to only outer rows that have no join
+ * partner as this is the only case where Nested Loop would exhaust the
+ * inner scan of a unique join. Since the scope is limited to that, we
+ * just don't bother making a result cache path in this case.
+ *
+ * Lateral vars needn't be considered here as they're not considered when
+ * determining if the join is unique.
+ *
+ * XXX this could be enabled if the remaining join quals were made part of
+ * the inner scan's filter instead of the join filter. Maybe it's worth
+ * considering doing that?
+ */
+ if (extra->inner_unique &&
+ list_length(inner_path->param_info->ppi_clauses) <
+ list_length(extra->restrictlist))
+ return NULL;
+
+ /*
* We can't use a result cache if there are volatile functions in the
* inner rel's target list or restrict list. A cache hit could reduce the
* number of calls to these functions.