From 5c555fb67037d34f3a90be6052cb2fa26f34769a Mon Sep 17 00:00:00 2001 From: Richard Guo Date: Mon, 9 Oct 2023 17:10:59 +0800 Subject: [PATCH v1] Don't assume that cheapest_startup_path exists Normally only unparameterized paths are considered candidates for cheapest_startup_path, because startup cost does not have too much value for parameterized paths since they are on the inside of a nestloop. So if there are no unparameterized paths, the cheapest_startup_path will be NULL. In add_paths_to_append_rel() we should not assume that cheapest_startup_path always exists. --- src/backend/optimizer/path/allpaths.c | 12 ++++++++++-- src/test/regress/expected/union.out | 16 ++++++++++++++++ src/test/regress/sql/union.sql | 9 ++++++++- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 7af001feaa..5c4e3695e5 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -1352,12 +1352,20 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, * When the planner is considering cheap startup plans, we'll also * collect all the cheapest_startup_paths and build an AppendPath * containing those as subpaths. + * + * Only unparameterized paths are considered candidates for + * cheapest_startup_path, so that will be NULL if there are no + * unparameterized paths. We have to explicitly check that we have a + * valid cheapest_startup_path. */ - if (rel->consider_startup && childrel->pathlist != NIL && - childrel->cheapest_startup_path->param_info == NULL) + if (rel->consider_startup && childrel->cheapest_startup_path != NULL) + { + /* cheapest_startup_path must be unparameterized path. */ + Assert(childrel->cheapest_startup_path->param_info == NULL); accumulate_append_subpath(childrel->cheapest_startup_path, &startup_subpaths, NULL); + } else startup_subpaths_valid = false; diff --git a/src/test/regress/expected/union.out b/src/test/regress/expected/union.out index f046e522de..a4619cb014 100644 --- a/src/test/regress/expected/union.out +++ b/src/test/regress/expected/union.out @@ -1453,3 +1453,19 @@ inner join tenk2 t2 on t1.tenthous = t2.tenthous -> Result (8 rows) +-- Ensure there is no problem if cheapest_startup_path is NULL +explain (costs off) +select * from tenk1 t1 +left join lateral + (select t1.tenthous from tenk2 t2 union all (values(1))) +on true limit 1; + QUERY PLAN +------------------------------------------------------------------- + Limit + -> Nested Loop Left Join + -> Seq Scan on tenk1 t1 + -> Append + -> Index Only Scan using tenk2_hundred on tenk2 t2 + -> Result +(6 rows) + diff --git a/src/test/regress/sql/union.sql b/src/test/regress/sql/union.sql index d65ca9f86d..213309e226 100644 --- a/src/test/regress/sql/union.sql +++ b/src/test/regress/sql/union.sql @@ -550,4 +550,11 @@ explain (costs off) select t1.unique1 from tenk1 t1 inner join tenk2 t2 on t1.tenthous = t2.tenthous union all -(values(1)) limit 1; \ No newline at end of file +(values(1)) limit 1; + +-- Ensure there is no problem if cheapest_startup_path is NULL +explain (costs off) +select * from tenk1 t1 +left join lateral + (select t1.tenthous from tenk2 t2 union all (values(1))) +on true limit 1; -- 2.31.0