mirror of
https://github.com/postgres/postgres.git
synced 2025-06-13 07:41:39 +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:
@ -581,6 +581,7 @@ fileGetForeignPaths(PlannerInfo *root,
|
|||||||
NIL, /* no pathkeys */
|
NIL, /* no pathkeys */
|
||||||
baserel->lateral_relids,
|
baserel->lateral_relids,
|
||||||
NULL, /* no extra plan */
|
NULL, /* no extra plan */
|
||||||
|
NIL, /* no fdw_restrictinfo list */
|
||||||
coptions));
|
coptions));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2316,31 +2316,21 @@ SELECT t1."C 1" FROM "S 1"."T 1" t1, LATERAL (SELECT DISTINCT t2.c1, t3.c1 FROM
|
|||||||
1
|
1
|
||||||
(10 rows)
|
(10 rows)
|
||||||
|
|
||||||
-- join with pseudoconstant quals, not pushed down.
|
-- join with pseudoconstant quals
|
||||||
EXPLAIN (VERBOSE, COSTS OFF)
|
EXPLAIN (VERBOSE, COSTS OFF)
|
||||||
SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1 AND CURRENT_USER = SESSION_USER) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
|
SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1 AND CURRENT_USER = SESSION_USER) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
-------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
Limit
|
Limit
|
||||||
Output: t1.c1, t2.c1, t1.c3
|
Output: t1.c1, t2.c1, t1.c3
|
||||||
-> Sort
|
-> Result
|
||||||
Output: t1.c1, t2.c1, t1.c3
|
Output: t1.c1, t2.c1, t1.c3
|
||||||
Sort Key: t1.c3, t1.c1
|
One-Time Filter: (CURRENT_USER = SESSION_USER)
|
||||||
-> Result
|
-> Foreign Scan
|
||||||
Output: t1.c1, t2.c1, t1.c3
|
Output: t1.c1, t1.c3, t2.c1
|
||||||
One-Time Filter: (CURRENT_USER = SESSION_USER)
|
Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
|
||||||
-> Hash Join
|
Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3 FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r1."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST
|
||||||
Output: t1.c1, t1.c3, t2.c1
|
(9 rows)
|
||||||
Hash Cond: (t2.c1 = t1.c1)
|
|
||||||
-> Foreign Scan on public.ft2 t2
|
|
||||||
Output: t2.c1
|
|
||||||
Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
|
|
||||||
-> Hash
|
|
||||||
Output: t1.c1, t1.c3
|
|
||||||
-> Foreign Scan on public.ft1 t1
|
|
||||||
Output: t1.c1, t1.c3
|
|
||||||
Remote SQL: SELECT "C 1", c3 FROM "S 1"."T 1"
|
|
||||||
(19 rows)
|
|
||||||
|
|
||||||
-- non-Var items in targetlist of the nullable rel of a join preventing
|
-- non-Var items in targetlist of the nullable rel of a join preventing
|
||||||
-- push-down in some cases
|
-- push-down in some cases
|
||||||
|
@ -524,7 +524,7 @@ static List *get_useful_pathkeys_for_relation(PlannerInfo *root,
|
|||||||
RelOptInfo *rel);
|
RelOptInfo *rel);
|
||||||
static List *get_useful_ecs_for_relation(PlannerInfo *root, RelOptInfo *rel);
|
static List *get_useful_ecs_for_relation(PlannerInfo *root, RelOptInfo *rel);
|
||||||
static void add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel,
|
static void add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel,
|
||||||
Path *epq_path);
|
Path *epq_path, List *restrictlist);
|
||||||
static void add_foreign_grouping_paths(PlannerInfo *root,
|
static void add_foreign_grouping_paths(PlannerInfo *root,
|
||||||
RelOptInfo *input_rel,
|
RelOptInfo *input_rel,
|
||||||
RelOptInfo *grouped_rel,
|
RelOptInfo *grouped_rel,
|
||||||
@ -1034,11 +1034,12 @@ postgresGetForeignPaths(PlannerInfo *root,
|
|||||||
NIL, /* no pathkeys */
|
NIL, /* no pathkeys */
|
||||||
baserel->lateral_relids,
|
baserel->lateral_relids,
|
||||||
NULL, /* no extra plan */
|
NULL, /* no extra plan */
|
||||||
|
NIL, /* no fdw_restrictinfo list */
|
||||||
NIL); /* no fdw_private list */
|
NIL); /* no fdw_private list */
|
||||||
add_path(baserel, (Path *) path);
|
add_path(baserel, (Path *) path);
|
||||||
|
|
||||||
/* Add paths with pathkeys */
|
/* Add paths with pathkeys */
|
||||||
add_paths_with_pathkeys_for_rel(root, baserel, NULL);
|
add_paths_with_pathkeys_for_rel(root, baserel, NULL, NIL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we're not using remote estimates, stop here. We have no way to
|
* If we're not using remote estimates, stop here. We have no way to
|
||||||
@ -1206,6 +1207,7 @@ postgresGetForeignPaths(PlannerInfo *root,
|
|||||||
NIL, /* no pathkeys */
|
NIL, /* no pathkeys */
|
||||||
param_info->ppi_req_outer,
|
param_info->ppi_req_outer,
|
||||||
NULL,
|
NULL,
|
||||||
|
NIL, /* no fdw_restrictinfo list */
|
||||||
NIL); /* no fdw_private list */
|
NIL); /* no fdw_private list */
|
||||||
add_path(baserel, (Path *) path);
|
add_path(baserel, (Path *) path);
|
||||||
}
|
}
|
||||||
@ -5991,7 +5993,7 @@ foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype,
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel,
|
add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel,
|
||||||
Path *epq_path)
|
Path *epq_path, List *restrictlist)
|
||||||
{
|
{
|
||||||
List *useful_pathkeys_list = NIL; /* List of all pathkeys */
|
List *useful_pathkeys_list = NIL; /* List of all pathkeys */
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
@ -6085,6 +6087,7 @@ add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel,
|
|||||||
useful_pathkeys,
|
useful_pathkeys,
|
||||||
rel->lateral_relids,
|
rel->lateral_relids,
|
||||||
sorted_epq_path,
|
sorted_epq_path,
|
||||||
|
NIL, /* no fdw_restrictinfo list */
|
||||||
NIL));
|
NIL));
|
||||||
else
|
else
|
||||||
add_path(rel, (Path *)
|
add_path(rel, (Path *)
|
||||||
@ -6096,6 +6099,7 @@ add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel,
|
|||||||
useful_pathkeys,
|
useful_pathkeys,
|
||||||
rel->lateral_relids,
|
rel->lateral_relids,
|
||||||
sorted_epq_path,
|
sorted_epq_path,
|
||||||
|
restrictlist,
|
||||||
NIL));
|
NIL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6348,13 +6352,15 @@ postgresGetForeignJoinPaths(PlannerInfo *root,
|
|||||||
NIL, /* no pathkeys */
|
NIL, /* no pathkeys */
|
||||||
joinrel->lateral_relids,
|
joinrel->lateral_relids,
|
||||||
epq_path,
|
epq_path,
|
||||||
|
extra->restrictlist,
|
||||||
NIL); /* no fdw_private */
|
NIL); /* no fdw_private */
|
||||||
|
|
||||||
/* Add generated path into joinrel by add_path(). */
|
/* Add generated path into joinrel by add_path(). */
|
||||||
add_path(joinrel, (Path *) joinpath);
|
add_path(joinrel, (Path *) joinpath);
|
||||||
|
|
||||||
/* Consider pathkeys for the join relation */
|
/* Consider pathkeys for the join relation */
|
||||||
add_paths_with_pathkeys_for_rel(root, joinrel, epq_path);
|
add_paths_with_pathkeys_for_rel(root, joinrel, epq_path,
|
||||||
|
extra->restrictlist);
|
||||||
|
|
||||||
/* XXX Consider parameterized paths for the join relation */
|
/* XXX Consider parameterized paths for the join relation */
|
||||||
}
|
}
|
||||||
@ -6735,6 +6741,7 @@ add_foreign_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
|
|||||||
total_cost,
|
total_cost,
|
||||||
NIL, /* no pathkeys */
|
NIL, /* no pathkeys */
|
||||||
NULL,
|
NULL,
|
||||||
|
NIL, /* no fdw_restrictinfo list */
|
||||||
NIL); /* no fdw_private */
|
NIL); /* no fdw_private */
|
||||||
|
|
||||||
/* Add generated path into grouped_rel by add_path(). */
|
/* Add generated path into grouped_rel by add_path(). */
|
||||||
@ -6868,6 +6875,7 @@ add_foreign_ordered_paths(PlannerInfo *root, RelOptInfo *input_rel,
|
|||||||
total_cost,
|
total_cost,
|
||||||
root->sort_pathkeys,
|
root->sort_pathkeys,
|
||||||
NULL, /* no extra plan */
|
NULL, /* no extra plan */
|
||||||
|
NIL, /* no fdw_restrictinfo list */
|
||||||
fdw_private);
|
fdw_private);
|
||||||
|
|
||||||
/* and add it to the ordered_rel */
|
/* and add it to the ordered_rel */
|
||||||
@ -6983,7 +6991,8 @@ add_foreign_final_paths(PlannerInfo *root, RelOptInfo *input_rel,
|
|||||||
path->total_cost,
|
path->total_cost,
|
||||||
path->pathkeys,
|
path->pathkeys,
|
||||||
NULL, /* no extra plan */
|
NULL, /* no extra plan */
|
||||||
NULL); /* no fdw_private */
|
NIL, /* no fdw_restrictinfo list */
|
||||||
|
NIL); /* no fdw_private */
|
||||||
|
|
||||||
/* and add it to the final_rel */
|
/* and add it to the final_rel */
|
||||||
add_path(final_rel, (Path *) final_path);
|
add_path(final_rel, (Path *) final_path);
|
||||||
@ -7103,6 +7112,7 @@ add_foreign_final_paths(PlannerInfo *root, RelOptInfo *input_rel,
|
|||||||
total_cost,
|
total_cost,
|
||||||
pathkeys,
|
pathkeys,
|
||||||
NULL, /* no extra plan */
|
NULL, /* no extra plan */
|
||||||
|
NIL, /* no fdw_restrictinfo list */
|
||||||
fdw_private);
|
fdw_private);
|
||||||
|
|
||||||
/* and add it to the final_rel */
|
/* and add it to the final_rel */
|
||||||
|
@ -640,7 +640,7 @@ SELECT t1c1, avg(t1c1 + t2c1) FROM (SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2
|
|||||||
EXPLAIN (VERBOSE, COSTS OFF)
|
EXPLAIN (VERBOSE, COSTS OFF)
|
||||||
SELECT t1."C 1" FROM "S 1"."T 1" t1, LATERAL (SELECT DISTINCT t2.c1, t3.c1 FROM ft1 t2, ft2 t3 WHERE t2.c1 = t3.c1 AND t2.c2 = t1.c2) q ORDER BY t1."C 1" OFFSET 10 LIMIT 10;
|
SELECT t1."C 1" FROM "S 1"."T 1" t1, LATERAL (SELECT DISTINCT t2.c1, t3.c1 FROM ft1 t2, ft2 t3 WHERE t2.c1 = t3.c1 AND t2.c2 = t1.c2) q ORDER BY t1."C 1" OFFSET 10 LIMIT 10;
|
||||||
SELECT t1."C 1" FROM "S 1"."T 1" t1, LATERAL (SELECT DISTINCT t2.c1, t3.c1 FROM ft1 t2, ft2 t3 WHERE t2.c1 = t3.c1 AND t2.c2 = t1.c2) q ORDER BY t1."C 1" OFFSET 10 LIMIT 10;
|
SELECT t1."C 1" FROM "S 1"."T 1" t1, LATERAL (SELECT DISTINCT t2.c1, t3.c1 FROM ft1 t2, ft2 t3 WHERE t2.c1 = t3.c1 AND t2.c2 = t1.c2) q ORDER BY t1."C 1" OFFSET 10 LIMIT 10;
|
||||||
-- join with pseudoconstant quals, not pushed down.
|
-- join with pseudoconstant quals
|
||||||
EXPLAIN (VERBOSE, COSTS OFF)
|
EXPLAIN (VERBOSE, COSTS OFF)
|
||||||
SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1 AND CURRENT_USER = SESSION_USER) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
|
SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1 AND CURRENT_USER = SESSION_USER) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ typedef struct CustomPath
|
|||||||
Path path;
|
Path path;
|
||||||
uint32 flags;
|
uint32 flags;
|
||||||
List *custom_paths;
|
List *custom_paths;
|
||||||
|
List *custom_restrictinfo;
|
||||||
List *custom_private;
|
List *custom_private;
|
||||||
const CustomPathMethods *methods;
|
const CustomPathMethods *methods;
|
||||||
} CustomPath;
|
} CustomPath;
|
||||||
@ -85,6 +86,10 @@ typedef struct CustomPath
|
|||||||
An optional <structfield>custom_paths</structfield> is a list of <structname>Path</structname>
|
An optional <structfield>custom_paths</structfield> is a list of <structname>Path</structname>
|
||||||
nodes used by this custom-path node; these will be transformed into
|
nodes used by this custom-path node; these will be transformed into
|
||||||
<structname>Plan</structname> nodes by planner.
|
<structname>Plan</structname> nodes by planner.
|
||||||
|
As described below, custom paths can be created for join relations as
|
||||||
|
well. In such a case, <structfield>custom_restrictinfo</structfield>
|
||||||
|
should be used to store the set of join clauses to apply to the join the
|
||||||
|
custom path replaces. Otherwise it should be NIL.
|
||||||
<structfield>custom_private</structfield> can be used to store the custom path's
|
<structfield>custom_private</structfield> can be used to store the custom path's
|
||||||
private data. Private data should be stored in a form that can be handled
|
private data. Private data should be stored in a form that can be handled
|
||||||
by <literal>nodeToString</literal>, so that debugging routines that attempt to
|
by <literal>nodeToString</literal>, so that debugging routines that attempt to
|
||||||
@ -114,6 +119,17 @@ extern PGDLLIMPORT set_join_pathlist_hook_type set_join_pathlist_hook;
|
|||||||
responsibility of the hook to minimize duplicated work.
|
responsibility of the hook to minimize duplicated work.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Note also that the set of join clauses to apply to the join,
|
||||||
|
which is passed as <literal>extra->restrictlist</literal>, varies
|
||||||
|
depending on the combination of inner and outer relations. A
|
||||||
|
<structname>CustomPath</structname> path generated for the
|
||||||
|
<literal>joinrel</literal> must contain the set of join clauses it uses,
|
||||||
|
which will be used by the planner to convert the
|
||||||
|
<structname>CustomPath</structname> path into a plan, if it is selected
|
||||||
|
by the planner as the best path for the <literal>joinrel</literal>.
|
||||||
|
</para>
|
||||||
|
|
||||||
<sect2 id="custom-scan-path-callbacks">
|
<sect2 id="custom-scan-path-callbacks">
|
||||||
<title>Custom Scan Path Callbacks</title>
|
<title>Custom Scan Path Callbacks</title>
|
||||||
|
|
||||||
|
@ -333,6 +333,17 @@ GetForeignJoinPaths(PlannerInfo *root,
|
|||||||
the responsibility of the FDW to minimize duplicated work.
|
the responsibility of the FDW to minimize duplicated work.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Note also that the set of join clauses to apply to the join,
|
||||||
|
which is passed as <literal>extra->restrictlist</literal>, varies
|
||||||
|
depending on the combination of inner and outer relations. A
|
||||||
|
<structname>ForeignPath</structname> path generated for the
|
||||||
|
<literal>joinrel</literal> must contain the set of join clauses it uses,
|
||||||
|
which will be used by the planner to convert the
|
||||||
|
<structname>ForeignPath</structname> path into a plan, if it is selected
|
||||||
|
by the planner as the best path for the <literal>joinrel</literal>.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If a <structname>ForeignPath</structname> path is chosen for the join, it will
|
If a <structname>ForeignPath</structname> path is chosen for the join, it will
|
||||||
represent the entire join process; paths generated for the component
|
represent the entire join process; paths generated for the component
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include "optimizer/pathnode.h"
|
#include "optimizer/pathnode.h"
|
||||||
#include "optimizer/paths.h"
|
#include "optimizer/paths.h"
|
||||||
#include "optimizer/planmain.h"
|
#include "optimizer/planmain.h"
|
||||||
#include "optimizer/restrictinfo.h"
|
|
||||||
#include "utils/typcache.h"
|
#include "utils/typcache.h"
|
||||||
|
|
||||||
/* Hook for plugins to get control in add_paths_to_joinrel() */
|
/* Hook for plugins to get control in add_paths_to_joinrel() */
|
||||||
@ -131,7 +130,6 @@ add_paths_to_joinrel(PlannerInfo *root,
|
|||||||
{
|
{
|
||||||
JoinPathExtraData extra;
|
JoinPathExtraData extra;
|
||||||
bool mergejoin_allowed = true;
|
bool mergejoin_allowed = true;
|
||||||
bool consider_join_pushdown = false;
|
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
Relids joinrelids;
|
Relids joinrelids;
|
||||||
|
|
||||||
@ -323,25 +321,13 @@ add_paths_to_joinrel(PlannerInfo *root,
|
|||||||
hash_inner_and_outer(root, joinrel, outerrel, innerrel,
|
hash_inner_and_outer(root, joinrel, outerrel, innerrel,
|
||||||
jointype, &extra);
|
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
|
* 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
|
* to the same server and assigned to the same user to check access
|
||||||
* permissions as, give the FDW a chance to push down joins.
|
* permissions as, give the FDW a chance to push down joins.
|
||||||
*/
|
*/
|
||||||
if (joinrel->fdwroutine &&
|
if (joinrel->fdwroutine &&
|
||||||
joinrel->fdwroutine->GetForeignJoinPaths &&
|
joinrel->fdwroutine->GetForeignJoinPaths)
|
||||||
consider_join_pushdown)
|
|
||||||
joinrel->fdwroutine->GetForeignJoinPaths(root, joinrel,
|
joinrel->fdwroutine->GetForeignJoinPaths(root, joinrel,
|
||||||
outerrel, innerrel,
|
outerrel, innerrel,
|
||||||
jointype, &extra);
|
jointype, &extra);
|
||||||
@ -349,8 +335,7 @@ add_paths_to_joinrel(PlannerInfo *root,
|
|||||||
/*
|
/*
|
||||||
* 6. Finally, give extensions a chance to manipulate the path list.
|
* 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,
|
set_join_pathlist_hook(root, joinrel, outerrel, innerrel,
|
||||||
jointype, &extra);
|
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
|
* 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
|
* we'll need a gating Result node, it will be able to project, so there
|
||||||
* are no requirements on the child's tlist.
|
* 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)
|
if (gating_clauses)
|
||||||
flags = 0;
|
flags = 0;
|
||||||
|
|
||||||
|
@ -2229,6 +2229,7 @@ create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
|
|||||||
List *pathkeys,
|
List *pathkeys,
|
||||||
Relids required_outer,
|
Relids required_outer,
|
||||||
Path *fdw_outerpath,
|
Path *fdw_outerpath,
|
||||||
|
List *fdw_restrictinfo,
|
||||||
List *fdw_private)
|
List *fdw_private)
|
||||||
{
|
{
|
||||||
ForeignPath *pathnode = makeNode(ForeignPath);
|
ForeignPath *pathnode = makeNode(ForeignPath);
|
||||||
@ -2250,6 +2251,7 @@ create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
|
|||||||
pathnode->path.pathkeys = pathkeys;
|
pathnode->path.pathkeys = pathkeys;
|
||||||
|
|
||||||
pathnode->fdw_outerpath = fdw_outerpath;
|
pathnode->fdw_outerpath = fdw_outerpath;
|
||||||
|
pathnode->fdw_restrictinfo = fdw_restrictinfo;
|
||||||
pathnode->fdw_private = fdw_private;
|
pathnode->fdw_private = fdw_private;
|
||||||
|
|
||||||
return pathnode;
|
return pathnode;
|
||||||
@ -2273,6 +2275,7 @@ create_foreign_join_path(PlannerInfo *root, RelOptInfo *rel,
|
|||||||
List *pathkeys,
|
List *pathkeys,
|
||||||
Relids required_outer,
|
Relids required_outer,
|
||||||
Path *fdw_outerpath,
|
Path *fdw_outerpath,
|
||||||
|
List *fdw_restrictinfo,
|
||||||
List *fdw_private)
|
List *fdw_private)
|
||||||
{
|
{
|
||||||
ForeignPath *pathnode = makeNode(ForeignPath);
|
ForeignPath *pathnode = makeNode(ForeignPath);
|
||||||
@ -2300,6 +2303,7 @@ create_foreign_join_path(PlannerInfo *root, RelOptInfo *rel,
|
|||||||
pathnode->path.pathkeys = pathkeys;
|
pathnode->path.pathkeys = pathkeys;
|
||||||
|
|
||||||
pathnode->fdw_outerpath = fdw_outerpath;
|
pathnode->fdw_outerpath = fdw_outerpath;
|
||||||
|
pathnode->fdw_restrictinfo = fdw_restrictinfo;
|
||||||
pathnode->fdw_private = fdw_private;
|
pathnode->fdw_private = fdw_private;
|
||||||
|
|
||||||
return pathnode;
|
return pathnode;
|
||||||
@ -2322,6 +2326,7 @@ create_foreign_upper_path(PlannerInfo *root, RelOptInfo *rel,
|
|||||||
double rows, Cost startup_cost, Cost total_cost,
|
double rows, Cost startup_cost, Cost total_cost,
|
||||||
List *pathkeys,
|
List *pathkeys,
|
||||||
Path *fdw_outerpath,
|
Path *fdw_outerpath,
|
||||||
|
List *fdw_restrictinfo,
|
||||||
List *fdw_private)
|
List *fdw_private)
|
||||||
{
|
{
|
||||||
ForeignPath *pathnode = makeNode(ForeignPath);
|
ForeignPath *pathnode = makeNode(ForeignPath);
|
||||||
@ -2345,6 +2350,7 @@ create_foreign_upper_path(PlannerInfo *root, RelOptInfo *rel,
|
|||||||
pathnode->path.pathkeys = pathkeys;
|
pathnode->path.pathkeys = pathkeys;
|
||||||
|
|
||||||
pathnode->fdw_outerpath = fdw_outerpath;
|
pathnode->fdw_outerpath = fdw_outerpath;
|
||||||
|
pathnode->fdw_restrictinfo = fdw_restrictinfo;
|
||||||
pathnode->fdw_private = fdw_private;
|
pathnode->fdw_private = fdw_private;
|
||||||
|
|
||||||
return pathnode;
|
return pathnode;
|
||||||
@ -4149,6 +4155,8 @@ do { \
|
|||||||
FLAT_COPY_PATH(fpath, path, ForeignPath);
|
FLAT_COPY_PATH(fpath, path, ForeignPath);
|
||||||
if (fpath->fdw_outerpath)
|
if (fpath->fdw_outerpath)
|
||||||
REPARAMETERIZE_CHILD_PATH(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. */
|
/* Hand over to FDW if needed. */
|
||||||
rfpc_func =
|
rfpc_func =
|
||||||
@ -4166,6 +4174,8 @@ do { \
|
|||||||
|
|
||||||
FLAT_COPY_PATH(cpath, path, CustomPath);
|
FLAT_COPY_PATH(cpath, path, CustomPath);
|
||||||
REPARAMETERIZE_CHILD_PATH_LIST(cpath->custom_paths);
|
REPARAMETERIZE_CHILD_PATH_LIST(cpath->custom_paths);
|
||||||
|
if (cpath->custom_restrictinfo)
|
||||||
|
ADJUST_CHILD_ATTRS(cpath->custom_restrictinfo);
|
||||||
if (cpath->methods &&
|
if (cpath->methods &&
|
||||||
cpath->methods->ReparameterizeCustomPathByChild)
|
cpath->methods->ReparameterizeCustomPathByChild)
|
||||||
cpath->custom_private =
|
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
|
* join_clause_is_movable_to
|
||||||
* Test whether a join clause is a safe candidate for parameterization
|
* Test whether a join clause is a safe candidate for parameterization
|
||||||
|
@ -1822,6 +1822,10 @@ typedef struct SubqueryScanPath
|
|||||||
* ForeignPath represents a potential scan of a foreign table, foreign join
|
* ForeignPath represents a potential scan of a foreign table, foreign join
|
||||||
* or foreign upper-relation.
|
* or foreign upper-relation.
|
||||||
*
|
*
|
||||||
|
* In the case of a foreign join, fdw_restrictinfo stores the RestrictInfos to
|
||||||
|
* apply to the join, which are used by createplan.c to get pseudoconstant
|
||||||
|
* clauses evaluated as one-time quals in a gating Result plan node.
|
||||||
|
*
|
||||||
* fdw_private stores FDW private data about the scan. While fdw_private is
|
* fdw_private stores FDW private data about the scan. While fdw_private is
|
||||||
* not actually touched by the core code during normal operations, it's
|
* not actually touched by the core code during normal operations, it's
|
||||||
* generally a good idea to use a representation that can be dumped by
|
* generally a good idea to use a representation that can be dumped by
|
||||||
@ -1832,6 +1836,7 @@ typedef struct ForeignPath
|
|||||||
{
|
{
|
||||||
Path path;
|
Path path;
|
||||||
Path *fdw_outerpath;
|
Path *fdw_outerpath;
|
||||||
|
List *fdw_restrictinfo;
|
||||||
List *fdw_private;
|
List *fdw_private;
|
||||||
} ForeignPath;
|
} ForeignPath;
|
||||||
|
|
||||||
@ -1849,6 +1854,10 @@ typedef struct ForeignPath
|
|||||||
* relation by set_rel_pathlist_hook or set_join_pathlist_hook functions,
|
* relation by set_rel_pathlist_hook or set_join_pathlist_hook functions,
|
||||||
* respectively.
|
* respectively.
|
||||||
*
|
*
|
||||||
|
* In the case of a table join, custom_restrictinfo stores the RestrictInfos
|
||||||
|
* to apply to the join, which are used by createplan.c to get pseudoconstant
|
||||||
|
* clauses evaluated as one-time quals in a gating Result plan node.
|
||||||
|
*
|
||||||
* Core code must avoid assuming that the CustomPath is only as large as
|
* Core code must avoid assuming that the CustomPath is only as large as
|
||||||
* the structure declared here; providers are allowed to make it the first
|
* the structure declared here; providers are allowed to make it the first
|
||||||
* element in a larger structure. (Since the planner never copies Paths,
|
* element in a larger structure. (Since the planner never copies Paths,
|
||||||
@ -1865,6 +1874,7 @@ typedef struct CustomPath
|
|||||||
uint32 flags; /* mask of CUSTOMPATH_* flags, see
|
uint32 flags; /* mask of CUSTOMPATH_* flags, see
|
||||||
* nodes/extensible.h */
|
* nodes/extensible.h */
|
||||||
List *custom_paths; /* list of child Path nodes, if any */
|
List *custom_paths; /* list of child Path nodes, if any */
|
||||||
|
List *custom_restrictinfo;
|
||||||
List *custom_private;
|
List *custom_private;
|
||||||
const struct CustomPathMethods *methods;
|
const struct CustomPathMethods *methods;
|
||||||
} CustomPath;
|
} CustomPath;
|
||||||
|
@ -128,6 +128,7 @@ extern ForeignPath *create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
|
|||||||
List *pathkeys,
|
List *pathkeys,
|
||||||
Relids required_outer,
|
Relids required_outer,
|
||||||
Path *fdw_outerpath,
|
Path *fdw_outerpath,
|
||||||
|
List *fdw_restrictinfo,
|
||||||
List *fdw_private);
|
List *fdw_private);
|
||||||
extern ForeignPath *create_foreign_join_path(PlannerInfo *root, RelOptInfo *rel,
|
extern ForeignPath *create_foreign_join_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
PathTarget *target,
|
PathTarget *target,
|
||||||
@ -135,12 +136,14 @@ extern ForeignPath *create_foreign_join_path(PlannerInfo *root, RelOptInfo *rel,
|
|||||||
List *pathkeys,
|
List *pathkeys,
|
||||||
Relids required_outer,
|
Relids required_outer,
|
||||||
Path *fdw_outerpath,
|
Path *fdw_outerpath,
|
||||||
|
List *fdw_restrictinfo,
|
||||||
List *fdw_private);
|
List *fdw_private);
|
||||||
extern ForeignPath *create_foreign_upper_path(PlannerInfo *root, RelOptInfo *rel,
|
extern ForeignPath *create_foreign_upper_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
PathTarget *target,
|
PathTarget *target,
|
||||||
double rows, Cost startup_cost, Cost total_cost,
|
double rows, Cost startup_cost, Cost total_cost,
|
||||||
List *pathkeys,
|
List *pathkeys,
|
||||||
Path *fdw_outerpath,
|
Path *fdw_outerpath,
|
||||||
|
List *fdw_restrictinfo,
|
||||||
List *fdw_private);
|
List *fdw_private);
|
||||||
|
|
||||||
extern Relids calc_nestloop_required_outer(Relids outerrelids,
|
extern Relids calc_nestloop_required_outer(Relids outerrelids,
|
||||||
|
@ -43,8 +43,6 @@ extern void extract_actual_join_clauses(List *restrictinfo_list,
|
|||||||
Relids joinrelids,
|
Relids joinrelids,
|
||||||
List **joinquals,
|
List **joinquals,
|
||||||
List **otherquals);
|
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_to(RestrictInfo *rinfo, RelOptInfo *baserel);
|
||||||
extern bool join_clause_is_movable_into(RestrictInfo *rinfo,
|
extern bool join_clause_is_movable_into(RestrictInfo *rinfo,
|
||||||
Relids currentrelids,
|
Relids currentrelids,
|
||||||
|
Reference in New Issue
Block a user