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

Reply via email to