aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/pathnode.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2020-07-14 18:56:49 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2020-07-14 18:56:56 -0400
commit689696c7110f148ede8004aae50d7543d05b5587 (patch)
tree852f7e573b2f66451a538aa347f5fc4734db6e35 /src/backend/optimizer/util/pathnode.c
parentde8feb1f3a23465b5737e8a8c160e8ca62f61339 (diff)
downloadpostgresql-689696c7110f148ede8004aae50d7543d05b5587.tar.gz
postgresql-689696c7110f148ede8004aae50d7543d05b5587.zip
Fix bitmap AND/OR scans on the inside of a nestloop partition-wise join.
reparameterize_path_by_child() failed to reparameterize BitmapAnd and BitmapOr paths. This matters only if such a path is chosen as the inside of a nestloop partition-wise join, where we have to pass in parameters from the outside of the nestloop. If that did happen, we generated a bad plan that would likely lead to crashes at execution. This is not entirely reparameterize_path_by_child()'s fault though; it's the victim of an ancient decision (my ancient decision, I think) to not bother filling in param_info in BitmapAnd/Or path nodes. That caused the function to believe that such nodes and their children contain no parameter references and so need not be processed. In hindsight that decision looks pretty penny-wise and pound-foolish: while it saves a few cycles during path node setup, we do commonly need the information later. In particular, by reversing the decision and requiring valid param_info data in all nodes of a bitmap path tree, we can get rid of indxpath.c's get_bitmap_tree_required_outer() function, which computed the data on-demand. It's not unlikely that that nets out as a savings of cycles in many scenarios. A couple of other things in indxpath.c can be simplified as well. While here, get rid of some cases in reparameterize_path_by_child() that are visibly dead or useless, given that we only care about reparameterizing paths that can be on the inside of a parameterized nestloop. This case reminds one of the maxim that untested code probably does not work, so I'm unwilling to leave unreachable code in this function. (I did leave the T_Gather case in place even though it's not reached in the regression tests. It's not very clear to me when the planner might prefer to put Gather below rather than above a nestloop, but at least in principle the case might be interesting.) Per bug #16536, originally from Arne Roland but with a test case by Andrew Gierth. Back-patch to v11 where this code came in. Discussion: https://postgr.es/m/16536-2213ee0b3aad41fd@postgresql.org
Diffstat (limited to 'src/backend/optimizer/util/pathnode.c')
-rw-r--r--src/backend/optimizer/util/pathnode.c100
1 files changed, 46 insertions, 54 deletions
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index e845a4b1ae1..5110a6b8060 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1081,11 +1081,27 @@ create_bitmap_and_path(PlannerInfo *root,
List *bitmapquals)
{
BitmapAndPath *pathnode = makeNode(BitmapAndPath);
+ Relids required_outer = NULL;
+ ListCell *lc;
pathnode->path.pathtype = T_BitmapAnd;
pathnode->path.parent = rel;
pathnode->path.pathtarget = rel->reltarget;
- pathnode->path.param_info = NULL; /* not used in bitmap trees */
+
+ /*
+ * Identify the required outer rels as the union of what the child paths
+ * depend on. (Alternatively, we could insist that the caller pass this
+ * in, but it's more convenient and reliable to compute it here.)
+ */
+ foreach(lc, bitmapquals)
+ {
+ Path *bitmapqual = (Path *) lfirst(lc);
+
+ required_outer = bms_add_members(required_outer,
+ PATH_REQ_OUTER(bitmapqual));
+ }
+ pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
+ required_outer);
/*
* Currently, a BitmapHeapPath, BitmapAndPath, or BitmapOrPath will be
@@ -1117,11 +1133,27 @@ create_bitmap_or_path(PlannerInfo *root,
List *bitmapquals)
{
BitmapOrPath *pathnode = makeNode(BitmapOrPath);
+ Relids required_outer = NULL;
+ ListCell *lc;
pathnode->path.pathtype = T_BitmapOr;
pathnode->path.parent = rel;
pathnode->path.pathtarget = rel->reltarget;
- pathnode->path.param_info = NULL; /* not used in bitmap trees */
+
+ /*
+ * Identify the required outer rels as the union of what the child paths
+ * depend on. (Alternatively, we could insist that the caller pass this
+ * in, but it's more convenient and reliable to compute it here.)
+ */
+ foreach(lc, bitmapquals)
+ {
+ Path *bitmapqual = (Path *) lfirst(lc);
+
+ required_outer = bms_add_members(required_outer,
+ PATH_REQ_OUTER(bitmapqual));
+ }
+ pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
+ required_outer);
/*
* Currently, a BitmapHeapPath, BitmapAndPath, or BitmapOrPath will be
@@ -3885,7 +3917,18 @@ do { \
!bms_overlap(PATH_REQ_OUTER(path), child_rel->top_parent_relids))
return path;
- /* Reparameterize a copy of given path. */
+ /*
+ * If possible, reparameterize the given path, making a copy.
+ *
+ * This function is currently only applied to the inner side of a nestloop
+ * join that is being partitioned by the partitionwise-join code. Hence,
+ * we need only support path types that plausibly arise in that context.
+ * (In particular, supporting sorted path types would be a waste of code
+ * and cycles: even if we translated them here, they'd just lose in
+ * subsequent cost comparisons.) If we do see an unsupported path type,
+ * that just means we won't be able to generate a partitionwise-join plan
+ * using that path type.
+ */
switch (nodeTag(path))
{
case T_Path:
@@ -3932,16 +3975,6 @@ do { \
}
break;
- case T_TidPath:
- {
- TidPath *tpath;
-
- FLAT_COPY_PATH(tpath, path, TidPath);
- ADJUST_CHILD_ATTRS(tpath->tidquals);
- new_path = (Path *) tpath;
- }
- break;
-
case T_ForeignPath:
{
ForeignPath *fpath;
@@ -4032,37 +4065,6 @@ do { \
}
break;
- case T_MergeAppendPath:
- {
- MergeAppendPath *mapath;
-
- FLAT_COPY_PATH(mapath, path, MergeAppendPath);
- REPARAMETERIZE_CHILD_PATH_LIST(mapath->subpaths);
- new_path = (Path *) mapath;
- }
- break;
-
- case T_MaterialPath:
- {
- MaterialPath *mpath;
-
- FLAT_COPY_PATH(mpath, path, MaterialPath);
- REPARAMETERIZE_CHILD_PATH(mpath->subpath);
- new_path = (Path *) mpath;
- }
- break;
-
- case T_UniquePath:
- {
- UniquePath *upath;
-
- FLAT_COPY_PATH(upath, path, UniquePath);
- REPARAMETERIZE_CHILD_PATH(upath->subpath);
- ADJUST_CHILD_ATTRS(upath->uniq_exprs);
- new_path = (Path *) upath;
- }
- break;
-
case T_GatherPath:
{
GatherPath *gpath;
@@ -4073,16 +4075,6 @@ do { \
}
break;
- case T_GatherMergePath:
- {
- GatherMergePath *gmpath;
-
- FLAT_COPY_PATH(gmpath, path, GatherMergePath);
- REPARAMETERIZE_CHILD_PATH(gmpath->subpath);
- new_path = (Path *) gmpath;
- }
- break;
-
default:
/* We don't know how to reparameterize this path. */