mirror of
https://github.com/postgres/postgres.git
synced 2025-11-06 07:49:08 +03:00
Re-allow FDWs and custom scan providers to replace joins with pseudoconstant quals.
This was disabled in commit 6f80a8d9c due to the lack of support for
handling of pseudoconstant quals assigned to replaced joins in
createplan.c. To re-allow it, this patch adds the support by 1)
modifying the ForeignPath and CustomPath structs so that if they
represent foreign and custom scans replacing a join with a scan, they
store the list of RestrictInfo nodes to apply to the join, as in
JoinPaths, and by 2) modifying create_scan_plan() in createplan.c so
that it uses that list in that case, instead of the baserestrictinfo
list, to get pseudoconstant quals assigned to the join, as mentioned in
the commit message for that commit.
Important item for the release notes: this is non-backwards-compatible
since it modifies the ForeignPath and CustomPath structs, as mentioned
above, and changes the argument lists for FDW helper functions
create_foreignscan_path(), create_foreign_join_path(), and
create_foreign_upper_path().
Richard Guo, with some additional changes by me, reviewed by Nishant
Sharma, Suraj Kharage, and Richard Guo.
Discussion: https://postgr.es/m/CADrsxdbcN1vejBaf8a%2BQhrZY5PXL-04mCd4GDu6qm6FigDZd6Q%40mail.gmail.com
This commit is contained in:
@@ -24,7 +24,6 @@
|
||||
#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() */
|
||||
@@ -131,7 +130,6 @@ add_paths_to_joinrel(PlannerInfo *root,
|
||||
{
|
||||
JoinPathExtraData extra;
|
||||
bool mergejoin_allowed = true;
|
||||
bool consider_join_pushdown = false;
|
||||
ListCell *lc;
|
||||
Relids joinrelids;
|
||||
|
||||
@@ -323,25 +321,13 @@ add_paths_to_joinrel(PlannerInfo *root,
|
||||
hash_inner_and_outer(root, joinrel, outerrel, innerrel,
|
||||
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 &&
|
||||
consider_join_pushdown)
|
||||
joinrel->fdwroutine->GetForeignJoinPaths)
|
||||
joinrel->fdwroutine->GetForeignJoinPaths(root, joinrel,
|
||||
outerrel, innerrel,
|
||||
jointype, &extra);
|
||||
@@ -349,8 +335,7 @@ add_paths_to_joinrel(PlannerInfo *root,
|
||||
/*
|
||||
* 6. Finally, give extensions a chance to manipulate the path list.
|
||||
*/
|
||||
if (set_join_pathlist_hook &&
|
||||
consider_join_pushdown)
|
||||
if (set_join_pathlist_hook)
|
||||
set_join_pathlist_hook(root, joinrel, outerrel, innerrel,
|
||||
jointype, &extra);
|
||||
}
|
||||
|
||||
@@ -599,8 +599,27 @@ create_scan_plan(PlannerInfo *root, Path *best_path, int flags)
|
||||
* Detect whether we have any pseudoconstant quals to deal with. Then, if
|
||||
* we'll need a gating Result node, it will be able to project, so there
|
||||
* are no requirements on the child's tlist.
|
||||
*
|
||||
* If this replaces a join, it must be a foreign scan or a custom scan,
|
||||
* and the FDW or the custom scan provider would have stored in the best
|
||||
* path the list of RestrictInfo nodes to apply to the join; check against
|
||||
* that list in that case.
|
||||
*/
|
||||
gating_clauses = get_gating_quals(root, scan_clauses);
|
||||
if (IS_JOIN_REL(rel))
|
||||
{
|
||||
List *join_clauses;
|
||||
|
||||
Assert(best_path->pathtype == T_ForeignScan ||
|
||||
best_path->pathtype == T_CustomScan);
|
||||
if (best_path->pathtype == T_ForeignScan)
|
||||
join_clauses = ((ForeignPath *) best_path)->fdw_restrictinfo;
|
||||
else
|
||||
join_clauses = ((CustomPath *) best_path)->custom_restrictinfo;
|
||||
|
||||
gating_clauses = get_gating_quals(root, join_clauses);
|
||||
}
|
||||
else
|
||||
gating_clauses = get_gating_quals(root, scan_clauses);
|
||||
if (gating_clauses)
|
||||
flags = 0;
|
||||
|
||||
|
||||
@@ -2229,6 +2229,7 @@ create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
|
||||
List *pathkeys,
|
||||
Relids required_outer,
|
||||
Path *fdw_outerpath,
|
||||
List *fdw_restrictinfo,
|
||||
List *fdw_private)
|
||||
{
|
||||
ForeignPath *pathnode = makeNode(ForeignPath);
|
||||
@@ -2250,6 +2251,7 @@ create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
|
||||
pathnode->path.pathkeys = pathkeys;
|
||||
|
||||
pathnode->fdw_outerpath = fdw_outerpath;
|
||||
pathnode->fdw_restrictinfo = fdw_restrictinfo;
|
||||
pathnode->fdw_private = fdw_private;
|
||||
|
||||
return pathnode;
|
||||
@@ -2273,6 +2275,7 @@ create_foreign_join_path(PlannerInfo *root, RelOptInfo *rel,
|
||||
List *pathkeys,
|
||||
Relids required_outer,
|
||||
Path *fdw_outerpath,
|
||||
List *fdw_restrictinfo,
|
||||
List *fdw_private)
|
||||
{
|
||||
ForeignPath *pathnode = makeNode(ForeignPath);
|
||||
@@ -2300,6 +2303,7 @@ create_foreign_join_path(PlannerInfo *root, RelOptInfo *rel,
|
||||
pathnode->path.pathkeys = pathkeys;
|
||||
|
||||
pathnode->fdw_outerpath = fdw_outerpath;
|
||||
pathnode->fdw_restrictinfo = fdw_restrictinfo;
|
||||
pathnode->fdw_private = fdw_private;
|
||||
|
||||
return pathnode;
|
||||
@@ -2322,6 +2326,7 @@ create_foreign_upper_path(PlannerInfo *root, RelOptInfo *rel,
|
||||
double rows, Cost startup_cost, Cost total_cost,
|
||||
List *pathkeys,
|
||||
Path *fdw_outerpath,
|
||||
List *fdw_restrictinfo,
|
||||
List *fdw_private)
|
||||
{
|
||||
ForeignPath *pathnode = makeNode(ForeignPath);
|
||||
@@ -2345,6 +2350,7 @@ create_foreign_upper_path(PlannerInfo *root, RelOptInfo *rel,
|
||||
pathnode->path.pathkeys = pathkeys;
|
||||
|
||||
pathnode->fdw_outerpath = fdw_outerpath;
|
||||
pathnode->fdw_restrictinfo = fdw_restrictinfo;
|
||||
pathnode->fdw_private = fdw_private;
|
||||
|
||||
return pathnode;
|
||||
@@ -4149,6 +4155,8 @@ do { \
|
||||
FLAT_COPY_PATH(fpath, path, ForeignPath);
|
||||
if (fpath->fdw_outerpath)
|
||||
REPARAMETERIZE_CHILD_PATH(fpath->fdw_outerpath);
|
||||
if (fpath->fdw_restrictinfo)
|
||||
ADJUST_CHILD_ATTRS(fpath->fdw_restrictinfo);
|
||||
|
||||
/* Hand over to FDW if needed. */
|
||||
rfpc_func =
|
||||
@@ -4166,6 +4174,8 @@ do { \
|
||||
|
||||
FLAT_COPY_PATH(cpath, path, CustomPath);
|
||||
REPARAMETERIZE_CHILD_PATH_LIST(cpath->custom_paths);
|
||||
if (cpath->custom_restrictinfo)
|
||||
ADJUST_CHILD_ATTRS(cpath->custom_restrictinfo);
|
||||
if (cpath->methods &&
|
||||
cpath->methods->ReparameterizeCustomPathByChild)
|
||||
cpath->custom_private =
|
||||
|
||||
@@ -549,36 +549,6 @@ 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 &&
|
||||
!rinfo_is_constant_true(rinfo))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* join_clause_is_movable_to
|
||||
* Test whether a join clause is a safe candidate for parameterization
|
||||
|
||||
Reference in New Issue
Block a user