Prevent generation of bogus subquery scan paths.

Commit 0927d2f46d didn't check that
consider_parallel was set for the target relation or account for
the possibility that required_outer might be non-empty.

To prevent future bugs of this ilk, add some assertions to
add_partial_path and do a bit of future-proofing of the code
recently added to recurse_set_operations.

Report by Andreas Seltenreich.  Patch by Jeevan Chalke.  Review
by Amit Kapila and by me.

Discussion: http://postgr.es/m/CAM2+6=U+9otsyF2fYB8x_2TBeHTR90itarqW=qAEjN-kHaC7kw@mail.gmail.com
This commit is contained in:
Robert Haas 2018-04-25 15:14:14 -04:00
parent f35f30f74b
commit dc1057fcd8
5 changed files with 55 additions and 18 deletions

View File

@ -2243,26 +2243,31 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
pathkeys, required_outer));
}
/* If consider_parallel is false, there should be no partial paths. */
Assert(sub_final_rel->consider_parallel ||
sub_final_rel->partial_pathlist == NIL);
/* Same for partial paths. */
foreach(lc, sub_final_rel->partial_pathlist)
/* If outer rel allows parallelism, do same for partial paths. */
if (rel->consider_parallel && bms_is_empty(required_outer))
{
Path *subpath = (Path *) lfirst(lc);
List *pathkeys;
/* If consider_parallel is false, there should be no partial paths. */
Assert(sub_final_rel->consider_parallel ||
sub_final_rel->partial_pathlist == NIL);
/* Convert subpath's pathkeys to outer representation */
pathkeys = convert_subquery_pathkeys(root,
rel,
subpath->pathkeys,
make_tlist_from_pathtarget(subpath->pathtarget));
/* Same for partial paths. */
foreach(lc, sub_final_rel->partial_pathlist)
{
Path *subpath = (Path *) lfirst(lc);
List *pathkeys;
/* Generate outer path using this subpath */
add_partial_path(rel, (Path *)
create_subqueryscan_path(root, rel, subpath,
pathkeys, required_outer));
/* Convert subpath's pathkeys to outer representation */
pathkeys = convert_subquery_pathkeys(root,
rel,
subpath->pathkeys,
make_tlist_from_pathtarget(subpath->pathtarget));
/* Generate outer path using this subpath */
add_partial_path(rel, (Path *)
create_subqueryscan_path(root, rel, subpath,
pathkeys,
required_outer));
}
}
}

View File

@ -330,7 +330,8 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
* to build a partial path for this relation. But there's no point in
* considering any path but the cheapest.
*/
if (final_rel->partial_pathlist != NIL)
if (rel->consider_parallel && bms_is_empty(rel->lateral_relids) &&
final_rel->partial_pathlist != NIL)
{
Path *partial_subpath;
Path *partial_path;

View File

@ -770,6 +770,12 @@ add_partial_path(RelOptInfo *parent_rel, Path *new_path)
/* Check for query cancel. */
CHECK_FOR_INTERRUPTS();
/* Path to be added must be parallel safe. */
Assert(new_path->parallel_safe);
/* Relation should be OK for parallelism, too. */
Assert(parent_rel->consider_parallel);
/*
* As in add_path, throw out any paths which are dominated by the new
* path, but throw out the new path if some existing path dominates it.

View File

@ -955,4 +955,23 @@ ORDER BY 1, 2, 3;
------------------------------+---------------------------+-------------+--------------
(0 rows)
-- test interation between subquery and partial_paths
SET LOCAL min_parallel_table_scan_size TO 0;
CREATE VIEW tenk1_vw_sec WITH (security_barrier) AS SELECT * FROM tenk1;
EXPLAIN (COSTS OFF)
SELECT 1 FROM tenk1_vw_sec WHERE EXISTS (SELECT 1 WHERE unique1 = 0);
QUERY PLAN
-------------------------------------------------------------------
Subquery Scan on tenk1_vw_sec
Filter: (alternatives: SubPlan 1 or hashed SubPlan 2)
-> Gather
Workers Planned: 4
-> Parallel Index Only Scan using tenk1_unique1 on tenk1
SubPlan 1
-> Result
One-Time Filter: (tenk1_vw_sec.unique1 = 0)
SubPlan 2
-> Result
(10 rows)
rollback;

View File

@ -383,4 +383,10 @@ ORDER BY 1;
SELECT * FROM information_schema.foreign_data_wrapper_options
ORDER BY 1, 2, 3;
-- test interation between subquery and partial_paths
SET LOCAL min_parallel_table_scan_size TO 0;
CREATE VIEW tenk1_vw_sec WITH (security_barrier) AS SELECT * FROM tenk1;
EXPLAIN (COSTS OFF)
SELECT 1 FROM tenk1_vw_sec WHERE EXISTS (SELECT 1 WHERE unique1 = 0);
rollback;