[PATCH] Add row estimate tests for unnest() and integer generate_series()

Started by shihao zhong10 days ago2 messageshackers
Beta feature

Hackorum builds and tests every patch posted to the lists, not only commitfest submissions. This is Hackorum's own CI rather than the PostgreSQL project's, and it is still under testing - please report anything that looks wrong.

appliessuccessCI history

You can run a PostgreSQL built from this patch straight from Docker, with no checkout and no build:

docker run --rm -p 5432:5432 ghcr.io/hackorum-dev/postgres-patch:t253612
psql -h localhost -U postgres

Built from patchset v1 (message #1), September 09, 2026 at 01:14 AM.

Every patchset is also pushed to a branch of our PostgreSQL fork, so you can check out the same tree CI built. Without a PostgreSQL checkout:

git clone --branch t253612_1 https://github.com/hackorum-dev/postgres.git

In a checkout you already have, add the fork once:

git remote add hackorum https://github.com/hackorum-dev/postgres.git

then, for this patchset and every later one:

git fetch hackorum t253612_1 && git checkout t253612_1

Patchset v1 (message #1) is on t253612_1

Jump to latest
#1shihao zhong
zhong950419@gmail.com

Hi hackers,

The support functions for unnest() and the integer variants of
generate_series() have no regression tests for their row estimates.

They were added in v12, before planner_est.sql existed. The numeric
and timestamp variants got tests together with their support
functions.

The attached patch adds sections for both, following the existing
style. Test changes only.

Thanks,
Shihao

Attachments:

t253612_1
0001-Add-row-estimate-tests-for-the-older-SRF-support-fun.patchapplication/octet-stream; name=0001-Add-row-estimate-tests-for-the-older-SRF-support-fun.patchDownload+264-1
#2韩建桥
hanjianqiao@gmail.com
In reply to: shihao zhong (#1)
Re: [PATCH] Add row estimate tests for unnest() and integer generate_series()

Hi Shihao,

On Mon, 31 Aug 2026 at 10:21, shihao zhong <zhong950419@gmail.com> wrote:

The support functions for unnest() and the integer variants of
generate_series() have no regression tests for their row estimates.

They were added in v12, before planner_est.sql existed. The numeric
and timestamp variants got tests together with their support
functions.

The attached patch adds sections for both, following the existing
style. Test changes only.

This is my first patch review, so I picked this one because
it's tagged "Good First Review" -- thanks for a clean, well-scoped
patch to start with.

I reviewed and tested this patch with my Ubuntu 26.04 LTS Desktop.

Applied cleanly against the current master (3b120b1e94dd,
Tue Sep 1 11:42:13 2026 +0900). Full rebuild produced no compiler
warnings, and planner_est passes with the expected output exactly
matching a real run.

I also manually reviewed the new test cases and their expected
output against the SupportRequestRows behavior:

1. generate_series(1, 25) -> 25 rows.
2. generate_series(1,25,2) -> 13 rows: (25 - 1) / 2 + 1 = 13.
3. generate_series(25,1,-1) -> 25 rows descending.
4. generate_series(25,1) -> 0 row.
5. generate_series(1, NULL::int4) -> 0 row.
6. generate_series(1::int8, 25::int8, 3::int8) -> 9 rows: (25 - 1) / 3 + 1 = 9.
7. generate_series(1, 25, 0) -> Error, explain_mask_costs returns
default prorows value: 1000.
8. generate_series(1::int8, 10000000000::int8) -> 10000000000.
9. unnest('{1,2,3,4,5}'::int[]) -> 5 rows.
10. unnest('{{1,2,3},{4,5,6}}'::int[]) -> 6 rows, expand all elements by
row-major order.
11. unnest('{}'::int[]) -> 0 row.
12. unnest(NULL::int[]) -> 0 row.
13. unnest(ARRAY[1, 2, (SELECT 3)]) -> 3 rows, (SELECT 3) is 1 row.
14. unnest_table_1 case: arrays are all exactly 7 distinct elements,
so the DECHIST-based estimate of 7 per row (100 x 7 = 700).
15. unnest_table_2 case: only "id" is analyzed, so the array column
has no stats and the default estimate is 10 from function:
"estimate_array_length(...)". So the estimate is 5 x 10 = 50 and
15 rows actually.

Alias naming style makes sense: 'g(s)' for the extended
generate_series() cases,
and 'u(e)' for new unnest() cases - 'u' for unnest, 'e' for elements.

This looks good to me.

--
Regards,
hanjianqiao