do not use Append with redistributed childrels as a partial path
authorTomas Vondra <[email protected]>
Wed, 18 Jan 2017 14:59:29 +0000 (15:59 +0100)
committerTomas Vondra <[email protected]>
Wed, 18 Jan 2017 14:59:29 +0000 (15:59 +0100)
Currently the subpaths are redistributed in create_append_path,
but even though that sets path.parallel_safe=false, it's too late
for set_append_rel_pathlist() to realize that.

It simply grabs the first path from childrel->partial_pathlist and
builds an AppendPath on top of that, assuming the resulting Append
is also parallel_safe.

But if the child relations had to be redistributed by adding a
RemoteSubplan on each of them, then the Append is parallel unsafe
and the attempt to add Gather on top of that fails because of
tripping on Assert(subpath->parallel_safe).

Make sure the result of create_append_path is also parallel safe
before adding it as a partial path.

I'd be surprised if there were no other places relying on the same
assumption. Ultimately, we probably want to build the redistributed
paths before calling create_append_path().

src/backend/optimizer/path/allpaths.c

index d1233989f4c768f9162933af57d0091ac5f5f76a..34bc42b19689b4379fb3b19416f9f11e0a3e24ab 100644 (file)
@@ -1326,7 +1326,13 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
                /* Generate a partial append path. */
                appendpath = create_append_path(rel, partial_subpaths, NULL,
                                                                                parallel_workers);
-               add_partial_path(rel, (Path *) appendpath);
+
+               /*
+                * XL: In case we had to re-distribute the child relations, don't
+                * do anything. Otherwise create_gather_path hits an Assert etc.
+                */
+               if (appendpath->path.parallel_safe)
+                       add_partial_path(rel, (Path *) appendpath);
        }
 
        /*