aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEtsuro Fujita <efujita@postgresql.org>2023-07-28 15:45:02 +0900
committerEtsuro Fujita <efujita@postgresql.org>2023-07-28 15:45:02 +0900
commitd1ef5631e620f9a5b6480a32bb70124c857af4f1 (patch)
tree2a419ed90878ca112c8c0a72078001e1aa7f5dee /src
parent313ceda2fe2ee8dd903ad4773f54de14807807c6 (diff)
downloadpostgresql-d1ef5631e620f9a5b6480a32bb70124c857af4f1.tar.gz
postgresql-d1ef5631e620f9a5b6480a32bb70124c857af4f1.zip
Disallow replacing joins with scans in problematic cases.
Commit e7cb7ee14, which introduced the infrastructure for FDWs and custom scan providers to replace joins with scans, failed to add support handling of pseudoconstant quals assigned to replaced joins in createplan.c, leading to an incorrect plan without a gating Result node when postgres_fdw replaced a join with such a qual. To fix, we could add the support by 1) modifying the ForeignPath and CustomPath structs to store the list of RestrictInfo nodes to apply to the join, as in JoinPaths, if they represent foreign and custom scans replacing a join with a scan, and by 2) modifying create_scan_plan() in createplan.c to use that list in that case, instead of the baserestrictinfo list, to get pseudoconstant quals assigned to the join; but #1 would cause an ABI break. So fix by modifying the infrastructure to just disallow replacing joins with such quals. Back-patch to all supported branches. Reported by Nishant Sharma. Patch by me, reviewed by Nishant Sharma and Richard Guo. Discussion: https://postgr.es/m/CADrsxdbcN1vejBaf8a%2BQhrZY5PXL-04mCd4GDu6qm6FigDZd6Q%40mail.gmail.com
Diffstat (limited to 'src')
-rw-r--r--src/backend/optimizer/path/joinpath.c19
-rw-r--r--src/backend/optimizer/util/restrictinfo.c29
-rw-r--r--src/include/optimizer/restrictinfo.h2
3 files changed, 48 insertions, 2 deletions
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index cda9d4c1a8f..c09f0e1df3e 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -24,6 +24,7 @@
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/planmain.h"
+#include "optimizer/restrictinfo.h"
#include "utils/typcache.h"
/* Hook for plugins to get control in add_paths_to_joinrel() */
@@ -130,6 +131,7 @@ add_paths_to_joinrel(PlannerInfo *root,
{
JoinPathExtraData extra;
bool mergejoin_allowed = true;
+ bool consider_join_pushdown = false;
ListCell *lc;
Relids joinrelids;
@@ -319,12 +321,24 @@ add_paths_to_joinrel(PlannerInfo *root,
jointype, &extra);
/*
+ * createplan.c does not currently support handling of pseudoconstant
+ * clauses assigned to joins pushed down by extensions; check if the
+ * restrictlist has such clauses, and if so, disallow pushing down joins.
+ */
+ if ((joinrel->fdwroutine &&
+ joinrel->fdwroutine->GetForeignJoinPaths) ||
+ set_join_pathlist_hook)
+ consider_join_pushdown = !has_pseudoconstant_clauses(root,
+ restrictlist);
+
+ /*
* 5. If inner and outer relations are foreign tables (or joins) belonging
* to the same server and assigned to the same user to check access
* permissions as, give the FDW a chance to push down joins.
*/
if (joinrel->fdwroutine &&
- joinrel->fdwroutine->GetForeignJoinPaths)
+ joinrel->fdwroutine->GetForeignJoinPaths &&
+ consider_join_pushdown)
joinrel->fdwroutine->GetForeignJoinPaths(root, joinrel,
outerrel, innerrel,
jointype, &extra);
@@ -332,7 +346,8 @@ add_paths_to_joinrel(PlannerInfo *root,
/*
* 6. Finally, give extensions a chance to manipulate the path list.
*/
- if (set_join_pathlist_hook)
+ if (set_join_pathlist_hook &&
+ consider_join_pushdown)
set_join_pathlist_hook(root, joinrel, outerrel, innerrel,
jointype, &extra);
}
diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c
index ef8df3d098e..e7764f43091 100644
--- a/src/backend/optimizer/util/restrictinfo.c
+++ b/src/backend/optimizer/util/restrictinfo.c
@@ -497,6 +497,35 @@ extract_actual_join_clauses(List *restrictinfo_list,
}
}
+/*
+ * has_pseudoconstant_clauses
+ *
+ * Returns true if 'restrictinfo_list' includes pseudoconstant clauses.
+ *
+ * This is used when we determine whether to allow extensions to consider
+ * pushing down joins in add_paths_to_joinrel().
+ */
+bool
+has_pseudoconstant_clauses(PlannerInfo *root,
+ List *restrictinfo_list)
+{
+ ListCell *l;
+
+ /* No need to look if we know there are no pseudoconstants */
+ if (!root->hasPseudoConstantQuals)
+ return false;
+
+ /* See if there are pseudoconstants in the RestrictInfo list */
+ foreach(l, restrictinfo_list)
+ {
+ RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
+
+ if (rinfo->pseudoconstant)
+ return true;
+ }
+ return false;
+}
+
/*
* join_clause_is_movable_to
diff --git a/src/include/optimizer/restrictinfo.h b/src/include/optimizer/restrictinfo.h
index 6d30bd5e9d2..fd7a0ec69df 100644
--- a/src/include/optimizer/restrictinfo.h
+++ b/src/include/optimizer/restrictinfo.h
@@ -41,6 +41,8 @@ extern void extract_actual_join_clauses(List *restrictinfo_list,
Relids joinrelids,
List **joinquals,
List **otherquals);
+extern bool has_pseudoconstant_clauses(PlannerInfo *root,
+ List *restrictinfo_list);
extern bool join_clause_is_movable_to(RestrictInfo *rinfo, RelOptInfo *baserel);
extern bool join_clause_is_movable_into(RestrictInfo *rinfo,
Relids currentrelids,