On 2015/10/14 17:31, Etsuro Fujita wrote:
As KaiGai-san also pointed out before, I think we should address this in
each of the following cases:
1) remote qual (scanrelid>0)
2) remote join (scanrelid==0)
As for #2, I updated the patch, which uses a local join execution plan
for an EvalPlanQual rechech, according to the comment from Robert [1].
Attached is an updated version of the patch. This is a WIP patch, but
it would be appreciated if I could get feedback earlier.
For tests, apply the patches:
foreign-recheck-for-foreign-join-1.patch
usermapping_matching.patch [2]
add_GetUserMappingById.patch [2]
foreign_join_v16_efujita.patch [3]
Since that as I said upthread, what I'd like to discuss is changes to
the PG core, I didn't do anything about the postgres_fdw patches.
Best regards,
Etsuro Fujita
[1]
http://www.postgresql.org/message-id/ca+tgmoaazs0dr23r7ptbseqfwotuvcpnbqdhxebo9gi+dmx...@mail.gmail.com
[2]
http://www.postgresql.org/message-id/CAEZqfEe9KGy=1_wagh2rgzpg0o4pqgd+iauyaj8wtze+cyj...@mail.gmail.com
[3] http://www.postgresql.org/message-id/55cb2d45.7040...@lab.ntt.co.jp
*** a/contrib/file_fdw/file_fdw.c
--- b/contrib/file_fdw/file_fdw.c
***************
*** 525,530 **** fileGetForeignPaths(PlannerInfo *root,
--- 525,531 ----
total_cost,
NIL, /* no pathkeys */
NULL, /* no outer rel either */
+ NULL, /* no alternative path */
coptions));
/*
*** a/contrib/postgres_fdw/postgres_fdw.c
--- b/contrib/postgres_fdw/postgres_fdw.c
***************
*** 560,565 **** postgresGetForeignPaths(PlannerInfo *root,
--- 560,566 ----
fpinfo->total_cost,
NIL, /* no pathkeys */
NULL, /* no outer rel either */
+ NULL, /* no alternative path */
NIL); /* no fdw_private list */
add_path(baserel, (Path *) path);
***************
*** 727,732 **** postgresGetForeignPaths(PlannerInfo *root,
--- 728,734 ----
total_cost,
NIL, /* no pathkeys */
param_info->ppi_req_outer,
+ NULL, /* no alternative path */
NIL); /* no fdw_private list */
add_path(baserel, (Path *) path);
}
*** a/src/backend/executor/execScan.c
--- b/src/backend/executor/execScan.c
***************
*** 48,59 **** ExecScanFetch(ScanState *node,
* conditions.
*/
Index scanrelid = ((Scan *) node->ps.plan)->scanrelid;
Assert(scanrelid > 0);
if (estate->es_epqTupleSet[scanrelid - 1])
{
- TupleTableSlot *slot = node->ss_ScanTupleSlot;
-
/* Return empty slot if we already returned a tuple */
if (estate->es_epqScanDone[scanrelid - 1])
return ExecClearTuple(slot);
--- 48,67 ----
* conditions.
*/
Index scanrelid = ((Scan *) node->ps.plan)->scanrelid;
+ TupleTableSlot *slot = node->ss_ScanTupleSlot;
+
+ /*
+ * Execute recheck plan and get the next tuple if foreign join.
+ */
+ if (scanrelid == 0)
+ {
+ (*recheckMtd) (node, slot);
+ return slot;
+ }
Assert(scanrelid > 0);
if (estate->es_epqTupleSet[scanrelid - 1])
{
/* Return empty slot if we already returned a tuple */
if (estate->es_epqScanDone[scanrelid - 1])
return ExecClearTuple(slot);
***************
*** 347,352 **** ExecScanReScan(ScanState *node)
--- 355,363 ----
{
Index scanrelid = ((Scan *) node->ps.plan)->scanrelid;
+ if (scanrelid == 0)
+ return; /* nothing to do */
+
Assert(scanrelid > 0);
estate->es_epqScanDone[scanrelid - 1] = false;
*** a/src/backend/executor/nodeForeignscan.c
--- b/src/backend/executor/nodeForeignscan.c
***************
*** 24,29 ****
--- 24,30 ----
#include "executor/executor.h"
#include "executor/nodeForeignscan.h"
+ #include "executor/tuptable.h"
#include "foreign/fdwapi.h"
#include "utils/memutils.h"
#include "utils/rel.h"
***************
*** 80,85 **** ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot)
--- 81,103 ----
*/
econtext = node->ss.ps.ps_ExprContext;
+ if (node->fdw_recheck_plan != NULL)
+ {
+ TupleTableSlot *result;
+ MemoryContext oldcontext;
+
+ /* Must be in query context to call recheck plan */
+ oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
+ /* Execute recheck plan */
+ result = ExecProcNode(node->fdw_recheck_plan);
+ MemoryContextSwitchTo(oldcontext);
+ if (TupIsNull(result))
+ return false;
+ /* Store result in the given slot */
+ ExecCopySlot(slot, result);
+ return true;
+ }
+
/* Does the tuple meet the remote qual condition? */
econtext->ecxt_scantuple = slot;
***************
*** 200,205 **** ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
--- 218,229 ----
ExecAssignScanProjectionInfoWithVarno(&scanstate->ss, tlistvarno);
/*
+ * Initialize recheck plan.
+ */
+ scanstate->fdw_recheck_plan = ExecInitNode(node->fdw_recheck_plan,
+ estate, eflags);
+
+ /*
* Initialize FDW-related state.
*/
scanstate->fdwroutine = fdwroutine;
***************
*** 235,240 **** ExecEndForeignScan(ForeignScanState *node)
--- 259,267 ----
/* close the relation. */
if (node->ss.ss_currentRelation)
ExecCloseScanRelation(node->ss.ss_currentRelation);
+
+ /* shut down recheck plan. */
+ ExecEndNode(node->fdw_recheck_plan);
}
/* ----------------------------------------------------------------
***************
*** 249,252 **** ExecReScanForeignScan(ForeignScanState *node)
--- 276,296 ----
node->fdwroutine->ReScanForeignScan(node);
ExecScanReScan(&node->ss);
+
+ if (node->fdw_recheck_plan != NULL)
+ {
+ /*
+ * set chgParam for recheck plan
+ */
+ if (((PlanState *) node)->chgParam != NULL)
+ UpdateChangedParamSet(node->fdw_recheck_plan,
+ ((PlanState *) node)->chgParam);
+
+ /*
+ * if chgParam of recheck plan is not null then the plan will be
+ * re-scanned by first ExecProcNode.
+ */
+ if (node->fdw_recheck_plan->chgParam == NULL)
+ ExecReScan(node->fdw_recheck_plan);
+ }
}
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
***************
*** 648,653 **** _copyForeignScan(const ForeignScan *from)
--- 648,654 ----
COPY_NODE_FIELD(fdw_exprs);
COPY_NODE_FIELD(fdw_private);
COPY_NODE_FIELD(fdw_scan_tlist);
+ COPY_NODE_FIELD(fdw_recheck_plan);
COPY_NODE_FIELD(fdw_recheck_quals);
COPY_BITMAPSET_FIELD(fs_relids);
COPY_SCALAR_FIELD(fsSystemCol);
*** a/src/backend/nodes/outfuncs.c
--- b/src/backend/nodes/outfuncs.c
***************
*** 594,599 **** _outForeignScan(StringInfo str, const ForeignScan *node)
--- 594,600 ----
WRITE_NODE_FIELD(fdw_exprs);
WRITE_NODE_FIELD(fdw_private);
WRITE_NODE_FIELD(fdw_scan_tlist);
+ WRITE_NODE_FIELD(fdw_recheck_plan);
WRITE_NODE_FIELD(fdw_recheck_quals);
WRITE_BITMAPSET_FIELD(fs_relids);
WRITE_BOOL_FIELD(fsSystemCol);
*** a/src/backend/nodes/readfuncs.c
--- b/src/backend/nodes/readfuncs.c
***************
*** 1798,1803 **** _readForeignScan(void)
--- 1798,1804 ----
READ_NODE_FIELD(fdw_exprs);
READ_NODE_FIELD(fdw_private);
READ_NODE_FIELD(fdw_scan_tlist);
+ READ_NODE_FIELD(fdw_recheck_plan);
READ_NODE_FIELD(fdw_recheck_quals);
READ_BITMAPSET_FIELD(fs_relids);
READ_BOOL_FIELD(fsSystemCol);
*** a/src/backend/optimizer/plan/createplan.c
--- b/src/backend/optimizer/plan/createplan.c
***************
*** 2141,2146 **** create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path,
--- 2141,2157 ----
scan_plan->fs_relids = best_path->path.parent->relids;
/*
+ * If we're scanning a join relation, generate a recheck plan for
+ * EvalPlanQual support. (Irrelevant if scanning a base relation.)
+ */
+ if (scan_relid == 0)
+ {
+ scan_plan->fdw_recheck_plan =
+ create_plan_recurse(root, best_path->fdw_recheck_path);
+ scan_plan->fdw_recheck_plan->targetlist = scan_plan->fdw_scan_tlist;
+ }
+
+ /*
* Replace any outer-relation variables with nestloop params in the qual
* and fdw_exprs expressions. We do this last so that the FDW doesn't
* have to be involved. (Note that parts of fdw_exprs could have come
***************
*** 3758,3763 **** make_foreignscan(List *qptlist,
--- 3769,3776 ----
node->fdw_exprs = fdw_exprs;
node->fdw_private = fdw_private;
node->fdw_scan_tlist = fdw_scan_tlist;
+ /* fdw_recheck_plan will be filled in by create_foreignscan_plan */
+ node->fdw_recheck_plan = NULL;
node->fdw_recheck_quals = fdw_recheck_quals;
/* fs_relids will be filled in by create_foreignscan_plan */
node->fs_relids = NULL;
*** a/src/backend/optimizer/plan/setrefs.c
--- b/src/backend/optimizer/plan/setrefs.c
***************
*** 1130,1135 **** set_foreignscan_references(PlannerInfo *root,
--- 1130,1137 ----
/* fdw_scan_tlist itself just needs fix_scan_list() adjustments */
fscan->fdw_scan_tlist =
fix_scan_list(root, fscan->fdw_scan_tlist, rtoffset);
+ /* fdw_recheck_plan needs set_plan_refs() adjustments */
+ set_plan_refs(root, fscan->fdw_recheck_plan, rtoffset);
}
else
{
*** a/src/backend/optimizer/plan/subselect.c
--- b/src/backend/optimizer/plan/subselect.c
***************
*** 2405,2410 **** finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
--- 2405,2419 ----
/* We assume fdw_scan_tlist cannot contain Params */
context.paramids = bms_add_members(context.paramids,
scan_params);
+
+ /* recheck plan if foreign join */
+ if (fscan->scan.scanrelid == 0)
+ context.paramids =
+ bms_add_members(context.paramids,
+ finalize_plan(root,
+ fscan->fdw_recheck_plan,
+ valid_params,
+ scan_params));
}
break;
*** a/src/backend/optimizer/util/pathnode.c
--- b/src/backend/optimizer/util/pathnode.c
***************
*** 1488,1493 **** create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
--- 1488,1494 ----
double rows, Cost startup_cost, Cost total_cost,
List *pathkeys,
Relids required_outer,
+ Path *fdw_recheck_path,
List *fdw_private)
{
ForeignPath *pathnode = makeNode(ForeignPath);
***************
*** 1501,1506 **** create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
--- 1502,1508 ----
pathnode->path.total_cost = total_cost;
pathnode->path.pathkeys = pathkeys;
+ pathnode->fdw_recheck_path = fdw_recheck_path;
pathnode->fdw_private = fdw_private;
return pathnode;
*** a/src/include/nodes/execnodes.h
--- b/src/include/nodes/execnodes.h
***************
*** 1579,1584 **** typedef struct WorkTableScanState
--- 1579,1585 ----
typedef struct ForeignScanState
{
ScanState ss; /* its first field is NodeTag */
+ PlanState *fdw_recheck_plan; /* local join execution plan */
List *fdw_recheck_quals; /* original quals not in ss.ps.qual */
/* use struct pointer to avoid including fdwapi.h here */
struct FdwRoutine *fdwroutine;
*** a/src/include/nodes/plannodes.h
--- b/src/include/nodes/plannodes.h
***************
*** 529,534 **** typedef struct ForeignScan
--- 529,535 ----
List *fdw_exprs; /* expressions that FDW may evaluate */
List *fdw_private; /* private data for FDW */
List *fdw_scan_tlist; /* optional tlist describing scan tuple */
+ Plan *fdw_recheck_plan; /* local join execution plan */
List *fdw_recheck_quals; /* original quals not in scan.plan.quals */
Bitmapset *fs_relids; /* RTIs generated by this scan */
bool fsSystemCol; /* true if any "system column" is needed */
*** a/src/include/nodes/relation.h
--- b/src/include/nodes/relation.h
***************
*** 903,912 **** typedef struct TidPath
--- 903,916 ----
* generally a good idea to use a representation that can be dumped by
* nodeToString(), so that you can examine the structure during debugging
* with tools like pprint().
+ *
+ * If a ForeignPath node represents a remote join, then fdw_recheck_path is
+ * a local join execution path for use in EvalPlanQual. (Else it is NULL.)
*/
typedef struct ForeignPath
{
Path path;
+ Path *fdw_recheck_path;
List *fdw_private;
} ForeignPath;
*** a/src/include/optimizer/pathnode.h
--- b/src/include/optimizer/pathnode.h
***************
*** 86,91 **** extern ForeignPath *create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
--- 86,92 ----
double rows, Cost startup_cost, Cost total_cost,
List *pathkeys,
Relids required_outer,
+ Path *fdw_recheck_path,
List *fdw_private);
extern Relids calc_nestloop_required_outer(Path *outer_path, Path *inner_path);
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers