On 2015/07/22 19:10, Etsuro Fujita wrote: > While working on the issue "Foreign join pushdown vs EvalPlanQual", I > happened to notice odd behaviors of late row locking in FDWs.
> I think the reason for that is because we don't check pushed-down quals > inside an EPQ testing even if what was fetched by RefetchForeignRow was > an updated version of the tuple rather than the same version previously > obtained. So, to fix this, I'd like to propose that pushed-down quals > be checked in ForeignRecheck. Attached is a patch for that. * I've modified ForeignRecheck so as to check pushed-down quals whether doing late locking or early locking. I think we could probably make ForeignRecheck do so only when doing late locking, but I'm not sure it's worth complicating the code. * I've made the above change only for simple foreign table scans that have scanrelid > 0 and fdw_scan_tlist = NIL. As for simple foreign table scans that have scanrelid > 0 and *fdw_scan_tlist is non-NIL*, I think we are under discussion in another thread I started. Will update as necessary. * Sorry, I've not fully updated comments and docs yet. Will update. I'd be happy if I could get feedback earlier. Best regards, Etsuro Fujita
*** a/contrib/file_fdw/file_fdw.c --- b/contrib/file_fdw/file_fdw.c *************** *** 563,569 **** fileGetForeignPlan(PlannerInfo *root, scan_relid, NIL, /* no expressions to evaluate */ best_path->fdw_private, ! NIL /* no custom tlist */ ); } /* --- 563,570 ---- scan_relid, NIL, /* no expressions to evaluate */ best_path->fdw_private, ! NIL, /* no custom tlist */ ! NIL /* no pushed-down qual */ ); } /* *** a/contrib/postgres_fdw/postgres_fdw.c --- b/contrib/postgres_fdw/postgres_fdw.c *************** *** 748,753 **** postgresGetForeignPlan(PlannerInfo *root, --- 748,754 ---- Index scan_relid = baserel->relid; List *fdw_private; List *remote_conds = NIL; + List *remote_exprs = NIL; List *local_exprs = NIL; List *params_list = NIL; List *retrieved_attrs; *************** *** 769,776 **** postgresGetForeignPlan(PlannerInfo *root, * * This code must match "extract_actual_clauses(scan_clauses, false)" * except for the additional decision about remote versus local execution. ! * Note however that we only strip the RestrictInfo nodes from the ! * local_exprs list, since appendWhereClause expects a list of * RestrictInfos. */ foreach(lc, scan_clauses) --- 770,777 ---- * * This code must match "extract_actual_clauses(scan_clauses, false)" * except for the additional decision about remote versus local execution. ! * Note however that we don't strip the RestrictInfo nodes from the ! * remote_conds list, since appendWhereClause expects a list of * RestrictInfos. */ foreach(lc, scan_clauses) *************** *** 784,794 **** postgresGetForeignPlan(PlannerInfo *root, --- 785,801 ---- continue; if (list_member_ptr(fpinfo->remote_conds, rinfo)) + { remote_conds = lappend(remote_conds, rinfo); + remote_exprs = lappend(remote_exprs, rinfo->clause); + } else if (list_member_ptr(fpinfo->local_conds, rinfo)) local_exprs = lappend(local_exprs, rinfo->clause); else if (is_foreign_expr(root, baserel, rinfo->clause)) + { remote_conds = lappend(remote_conds, rinfo); + remote_exprs = lappend(remote_exprs, rinfo->clause); + } else local_exprs = lappend(local_exprs, rinfo->clause); } *************** *** 874,880 **** postgresGetForeignPlan(PlannerInfo *root, scan_relid, params_list, fdw_private, ! NIL /* no custom tlist */ ); } /* --- 881,888 ---- scan_relid, params_list, fdw_private, ! NIL, /* no custom tlist */ ! remote_exprs); } /* *** a/src/backend/executor/nodeForeignscan.c --- b/src/backend/executor/nodeForeignscan.c *************** *** 72,79 **** ForeignNext(ForeignScanState *node) static bool ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot) { ! /* There are no access-method-specific conditions to recheck. */ ! return true; } /* ---------------------------------------------------------------- --- 72,90 ---- static bool ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot) { ! ExprContext *econtext; ! ! /* ! * extract necessary information from foreign scan node ! */ ! econtext = node->ss.ps.ps_ExprContext; ! ! /* Does the tuple meet the pushed-down-qual condition? */ ! econtext->ecxt_scantuple = slot; ! ! ResetExprContext(econtext); ! ! return ExecQual(node->pushedDownQual, econtext, false); } /* ---------------------------------------------------------------- *************** *** 135,140 **** ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags) --- 146,154 ---- scanstate->ss.ps.qual = (List *) ExecInitExpr((Expr *) node->scan.plan.qual, (PlanState *) scanstate); + scanstate->pushedDownQual = (List *) + ExecInitExpr((Expr *) node->pushedDownQual, + (PlanState *) scanstate); /* * tuple table initialization *** a/src/backend/nodes/copyfuncs.c --- b/src/backend/nodes/copyfuncs.c *************** *** 604,609 **** _copyForeignScan(const ForeignScan *from) --- 604,610 ---- COPY_NODE_FIELD(fdw_private); COPY_NODE_FIELD(fdw_scan_tlist); COPY_BITMAPSET_FIELD(fs_relids); + COPY_NODE_FIELD(pushedDownQual); COPY_SCALAR_FIELD(fsSystemCol); return newnode; *** a/src/backend/nodes/outfuncs.c --- b/src/backend/nodes/outfuncs.c *************** *** 570,575 **** _outForeignScan(StringInfo str, const ForeignScan *node) --- 570,576 ---- WRITE_NODE_FIELD(fdw_private); WRITE_NODE_FIELD(fdw_scan_tlist); WRITE_BITMAPSET_FIELD(fs_relids); + WRITE_NODE_FIELD(pushedDownQual); WRITE_BOOL_FIELD(fsSystemCol); } *** a/src/backend/optimizer/plan/createplan.c --- b/src/backend/optimizer/plan/createplan.c *************** *** 2109,2114 **** create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path, --- 2109,2116 ---- replace_nestloop_params(root, (Node *) scan_plan->scan.plan.qual); scan_plan->fdw_exprs = (List *) replace_nestloop_params(root, (Node *) scan_plan->fdw_exprs); + scan_plan->pushedDownQual = (List *) + replace_nestloop_params(root, (Node *) scan_plan->pushedDownQual); } /* *************** *** 3692,3698 **** make_foreignscan(List *qptlist, Index scanrelid, List *fdw_exprs, List *fdw_private, ! List *fdw_scan_tlist) { ForeignScan *node = makeNode(ForeignScan); Plan *plan = &node->scan.plan; --- 3694,3701 ---- Index scanrelid, List *fdw_exprs, List *fdw_private, ! List *fdw_scan_tlist, ! List *pushedDownQual) { ForeignScan *node = makeNode(ForeignScan); Plan *plan = &node->scan.plan; *************** *** 3710,3715 **** make_foreignscan(List *qptlist, --- 3713,3719 ---- node->fdw_scan_tlist = fdw_scan_tlist; /* fs_relids will be filled in by create_foreignscan_plan */ node->fs_relids = NULL; + node->pushedDownQual = pushedDownQual; /* fsSystemCol will be filled in by create_foreignscan_plan */ node->fsSystemCol = false; *** a/src/backend/optimizer/plan/setrefs.c --- b/src/backend/optimizer/plan/setrefs.c *************** *** 1132,1137 **** set_foreignscan_references(PlannerInfo *root, --- 1132,1140 ---- fix_scan_list(root, fscan->scan.plan.qual, rtoffset); fscan->fdw_exprs = fix_scan_list(root, fscan->fdw_exprs, rtoffset); + /* pushedDownQual needs the same adjustments, too */ + fscan->pushedDownQual = + fix_scan_list(root, fscan->pushedDownQual, rtoffset); } /* Adjust fs_relids if needed */ *** a/src/backend/optimizer/plan/subselect.c --- b/src/backend/optimizer/plan/subselect.c *************** *** 2368,2373 **** finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params, --- 2368,2379 ---- case T_ForeignScan: finalize_primnode((Node *) ((ForeignScan *) plan)->fdw_exprs, &context); + + /* + * we need not look at pushedDownQual, since it will have the same + * param references as fdw_exprs. + */ + /* We assume fdw_scan_tlist cannot contain Params */ context.paramids = bms_add_members(context.paramids, scan_params); break; *** a/src/include/nodes/execnodes.h --- b/src/include/nodes/execnodes.h *************** *** 1571,1576 **** typedef struct WorkTableScanState --- 1571,1577 ---- typedef struct ForeignScanState { ScanState ss; /* its first field is NodeTag */ + List *pushedDownQual; /* list of pushed-down quals, if any */ /* use struct pointer to avoid including fdwapi.h here */ struct FdwRoutine *fdwroutine; void *fdw_state; /* foreign-data wrapper can keep state here */ *** a/src/include/nodes/plannodes.h --- b/src/include/nodes/plannodes.h *************** *** 517,522 **** typedef struct ForeignScan --- 517,523 ---- List *fdw_private; /* private data for FDW */ List *fdw_scan_tlist; /* optional tlist describing scan tuple */ Bitmapset *fs_relids; /* RTIs generated by this scan */ + List *pushedDownQual; /* list of pushed-down quals, if any */ bool fsSystemCol; /* true if any "system column" is needed */ } ForeignScan; *** a/src/include/optimizer/planmain.h --- b/src/include/optimizer/planmain.h *************** *** 45,51 **** extern SubqueryScan *make_subqueryscan(List *qptlist, List *qpqual, Index scanrelid, Plan *subplan); extern ForeignScan *make_foreignscan(List *qptlist, List *qpqual, Index scanrelid, List *fdw_exprs, List *fdw_private, ! List *fdw_scan_tlist); extern Append *make_append(List *appendplans, List *tlist); extern RecursiveUnion *make_recursive_union(List *tlist, Plan *lefttree, Plan *righttree, int wtParam, --- 45,51 ---- Index scanrelid, Plan *subplan); extern ForeignScan *make_foreignscan(List *qptlist, List *qpqual, Index scanrelid, List *fdw_exprs, List *fdw_private, ! List *fdw_scan_tlist, List *pushedDownQual); extern Append *make_append(List *appendplans, List *tlist); extern RecursiveUnion *make_recursive_union(List *tlist, Plan *lefttree, Plan *righttree, int wtParam,
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers