From fc4089f3c65a5f1b413a3299ba02b66a8e5e37d0 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Tue, 10 Oct 2023 16:50:03 +1300 Subject: [PATCH] Fix possible crash in add_paths_to_append_rel() While working on a8a968a82, I failed to consider that cheapest_startup_path can be NULL when there is no non-parameterized path in the pathlist. This is well documented in set_cheapest(), I just failed to notice. Here we adjust the code to just check if the RelOptInfo has a cheapest_startup_path set before adding it to the startup_subpaths list. Reported-by: Richard Guo Author: Richard Guo Discussion: https://postgr.es/m/CAMbWs49w3t03V69XhdCuw+GDwivny4uQUxrkVp6Gejaspt0wMQ@mail.gmail.com --- src/backend/optimizer/path/allpaths.c | 11 +++++++---- src/test/regress/expected/union.out | 16 ++++++++++++++++ src/test/regress/sql/union.sql | 9 ++++++++- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 7af001feaac..eea49cca7bb 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -1350,14 +1350,17 @@ 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. + * collect all the cheapest_startup_paths (if set) and build an + * AppendPath containing those as subpaths. */ - 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 not be a parameterized 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 f046e522dea..64cebe48336 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 d65ca9f86de..599013e7c9d 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;