diff options
Diffstat (limited to 'src/backend/optimizer/util')
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 42 |
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 |