summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util')
-rw-r--r--src/backend/optimizer/util/clauses.c42
1 files changed, 39 insertions, 3 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 73f5e11abef..c2d36ca38d8 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -661,10 +661,12 @@ find_window_functions_walker(Node *node, WindowFuncLists *lists)
/*
* expression_returns_set_rows
- * Estimate the number of rows in a set result.
+ * Estimate the number of rows returned by a set-returning expression.
+ * The result is 1 if there are no set-returning functions.
*
* We use the product of the rowcount estimates of all the functions in
- * the given tree. The result is 1 if there are no set-returning functions.
+ * the given tree (this corresponds to the behavior of ExecMakeFunctionResult
+ * for nested set-returning functions).
*
* Note: keep this in sync with expression_returns_set() in nodes/nodeFuncs.c.
*/
@@ -674,7 +676,7 @@ expression_returns_set_rows(Node *clause)
double result = 1;
(void) expression_returns_set_rows_walker(clause, &result);
- return result;
+ return clamp_row_est(result);
}
static bool
@@ -736,6 +738,40 @@ expression_returns_set_rows_walker(Node *node, double *count)
(void *) count);
}
+/*
+ * tlist_returns_set_rows
+ * Estimate the number of rows returned by a set-returning targetlist.
+ * The result is 1 if there are no set-returning functions.
+ *
+ * Here, the result is the largest rowcount estimate of any of the tlist's
+ * expressions, not the product as you would get from naively applying
+ * expression_returns_set_rows() to the whole tlist. The behavior actually
+ * implemented by ExecTargetList produces a number of rows equal to the least
+ * common multiple of the expression rowcounts, so that the product would be
+ * a worst-case estimate that is typically not realistic. Taking the max as
+ * we do here is a best-case estimate that might not be realistic either,
+ * but it's probably closer for typical usages. We don't try to compute the
+ * actual LCM because we're working with very approximate estimates, so their
+ * LCM would be unduly noisy.
+ */
+double
+tlist_returns_set_rows(List *tlist)
+{
+ double result = 1;
+ ListCell *lc;
+
+ foreach(lc, tlist)
+ {
+ TargetEntry *tle = (TargetEntry *) lfirst(lc);
+ double colresult;
+
+ colresult = expression_returns_set_rows((Node *) tle->expr);
+ if (result < colresult)
+ result = colresult;
+ }
+ return result;
+}
+
/*****************************************************************************
* Subplan clause manipulation