postgresql-fdw-v2.patch

text/plain

Filename: postgresql-fdw-v2.patch
Type: text/plain
Part: 0
Message: Re: pgsql_fdw, FDW for PostgreSQL server

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: context
Series: patch v2
File+
contrib/file_fdw/file_fdw.c 16 0
doc/src/sgml/fdwhandler.sgml 17 6
src/backend/nodes/copyfuncs.c 0 0
src/backend/nodes/outfuncs.c 1 0
src/backend/optimizer/path/allpaths.c 3 0
src/backend/optimizer/plan/createplan.c 4 0
src/backend/optimizer/util/pathnode.c 6 0
src/include/foreign/fdwapi.h 1 0
src/include/nodes/nodes.h 0 0
src/include/nodes/plannodes.h 1 0
src/include/nodes/relation.h 7 0
src/include/optimizer/pathnode.h 1 0
*** a/contrib/file_fdw/file_fdw.c
--- b/contrib/file_fdw/file_fdw.c
***************
*** 25,30 ****
--- 25,31 ----
  #include "miscadmin.h"
  #include "nodes/makefuncs.h"
  #include "optimizer/cost.h"
+ #include "optimizer/pathnode.h"
  #include "utils/rel.h"
  #include "utils/syscache.h"
  
***************
*** 93,99 **** PG_FUNCTION_INFO_V1(file_fdw_validator);
  /*
   * FDW callback routines
   */
! static FdwPlan *filePlanForeignScan(Oid foreigntableid,
  					PlannerInfo *root,
  					RelOptInfo *baserel);
  static void fileExplainForeignScan(ForeignScanState *node, ExplainState *es);
--- 94,100 ----
  /*
   * FDW callback routines
   */
! static void filePlanForeignScan(Oid foreigntableid,
  					PlannerInfo *root,
  					RelOptInfo *baserel);
  static void fileExplainForeignScan(ForeignScanState *node, ExplainState *es);
***************
*** 406,432 **** get_file_fdw_attribute_options(Oid relid)
  
  /*
   * filePlanForeignScan
!  *		Create a FdwPlan for a scan on the foreign table
   */
! static FdwPlan *
  filePlanForeignScan(Oid foreigntableid,
  					PlannerInfo *root,
  					RelOptInfo *baserel)
  {
! 	FdwPlan    *fdwplan;
  	char	   *filename;
  	List	   *options;
  
  	/* Fetch options --- we only need filename at this point */
  	fileGetOptions(foreigntableid, &filename, &options);
  
! 	/* Construct FdwPlan with cost estimates */
! 	fdwplan = makeNode(FdwPlan);
  	estimate_costs(root, baserel, filename,
! 				   &fdwplan->startup_cost, &fdwplan->total_cost);
! 	fdwplan->fdw_private = NIL; /* not used */
  
! 	return fdwplan;
  }
  
  /*
--- 407,439 ----
  
  /*
   * filePlanForeignScan
!  *		Create the (single) path for a scan on the foreign table
   */
! static void
  filePlanForeignScan(Oid foreigntableid,
  					PlannerInfo *root,
  					RelOptInfo *baserel)
  {
! 	ForeignPath *pathnode = makeNode(ForeignPath);
  	char	   *filename;
  	List	   *options;
  
+ 	pathnode->path.pathtype = T_ForeignScan;
+ 	pathnode->path.parent = baserel;
+ 	pathnode->path.pathkeys = NIL;		/* result is always unordered */
+ 	pathnode->path.required_outer = NULL;
+ 	pathnode->path.param_clauses = NIL;
+ 	pathnode->fdw_private = NIL;		/* not used */
+ 
  	/* Fetch options --- we only need filename at this point */
  	fileGetOptions(foreigntableid, &filename, &options);
  
! 	/* Estimate costs of scanning the foreign table */
  	estimate_costs(root, baserel, filename,
! 				   &pathnode->path.startup_cost, &pathnode->path.total_cost);
! 	pathnode->path.rows = baserel->rows;
  
! 	add_path(baserel, (Path *) pathnode);
  }
  
  /*
*** a/doc/src/sgml/fdwhandler.sgml
--- b/doc/src/sgml/fdwhandler.sgml
***************
*** 88,108 ****
  
      <para>
  <programlisting>
! FdwPlan *
  PlanForeignScan (Oid foreigntableid,
                   PlannerInfo *root,
                   RelOptInfo *baserel);
  </programlisting>
  
!      Plan a scan on a foreign table. This is called when a query is planned.
       <literal>foreigntableid</> is the <structname>pg_class</> OID of the
       foreign table.  <literal>root</> is the planner's global information
       about the query, and <literal>baserel</> is the planner's information
       about this table.
!      The function must return a palloc'd struct that contains cost estimates
!      plus any FDW-private information that is needed to execute the foreign
!      scan at a later time.  (Note that the private information must be
!      represented in a form that <function>copyObject</> knows how to copy.)
      </para>
  
      <para>
--- 88,114 ----
  
      <para>
  <programlisting>
! void
  PlanForeignScan (Oid foreigntableid,
                   PlannerInfo *root,
                   RelOptInfo *baserel);
  </programlisting>
  
!      Create the access paths for a scan on a foreign table. This is called
!      when a query is planned.
       <literal>foreigntableid</> is the <structname>pg_class</> OID of the
       foreign table.  <literal>root</> is the planner's global information
       about the query, and <literal>baserel</> is the planner's information
       about this table.
!      The function must generate at least one access path for a scan on the
!      foreign table and call <function>add_path</> to add it to
!      <literal>baserel-&gt;pathlist</>.  The function may generate multiple
!      access paths for a scan on the foreign table and add them to
!      <literal>baserel-&gt;pathlist</> using <function>add_path</>.  Each
!      access path generated should contain cost estimates plus any FDW-private
!      information that is needed to execute the foreign scan at a later time.
!      (Note that the private information must be represented in a form that
!      <function>copyObject</> knows how to copy.)
      </para>
  
      <para>
***************
*** 159,167 **** BeginForeignScan (ForeignScanState *node,
       its <structfield>fdw_state</> field is still NULL.  Information about
       the table to scan is accessible through the
       <structname>ForeignScanState</> node (in particular, from the underlying
!      <structname>ForeignScan</> plan node, which contains a pointer to the
!      <structname>FdwPlan</> structure returned by
!      <function>PlanForeignScan</>).
      </para>
  
      <para>
--- 165,172 ----
       its <structfield>fdw_state</> field is still NULL.  Information about
       the table to scan is accessible through the
       <structname>ForeignScanState</> node (in particular, from the underlying
!      <structname>ForeignScan</> plan node, which contains FDW-private
!      information about it provided by <function>PlanForeignScan</>).
      </para>
  
      <para>
***************
*** 228,236 **** EndForeignScan (ForeignScanState *node);
      </para>
  
      <para>
!      The <structname>FdwRoutine</> and <structname>FdwPlan</> struct types
!      are declared in <filename>src/include/foreign/fdwapi.h</>, which see
!      for additional details.
      </para>
  
     </sect1>
--- 233,241 ----
      </para>
  
      <para>
!      The <structname>FdwRoutine</> struct type is declared
!      in <filename>src/include/foreign/fdwapi.h</>, which see for additional
!      details.
      </para>
  
     </sect1>
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
***************
*** 591,611 **** _copyForeignScan(const ForeignScan *from)
  	 * copy remainder of node
  	 */
  	COPY_SCALAR_FIELD(fsSystemCol);
- 	COPY_NODE_FIELD(fdwplan);
- 
- 	return newnode;
- }
- 
- /*
-  * _copyFdwPlan
-  */
- static FdwPlan *
- _copyFdwPlan(const FdwPlan *from)
- {
- 	FdwPlan    *newnode = makeNode(FdwPlan);
- 
- 	COPY_SCALAR_FIELD(startup_cost);
- 	COPY_SCALAR_FIELD(total_cost);
  	COPY_NODE_FIELD(fdw_private);
  
  	return newnode;
--- 591,596 ----
***************
*** 3841,3849 **** copyObject(const void *from)
  		case T_ForeignScan:
  			retval = _copyForeignScan(from);
  			break;
- 		case T_FdwPlan:
- 			retval = _copyFdwPlan(from);
- 			break;
  		case T_Join:
  			retval = _copyJoin(from);
  			break;
--- 3826,3831 ----
*** a/src/backend/nodes/outfuncs.c
--- b/src/backend/nodes/outfuncs.c
***************
*** 558,573 **** _outForeignScan(StringInfo str, const ForeignScan *node)
  	_outScanInfo(str, (const Scan *) node);
  
  	WRITE_BOOL_FIELD(fsSystemCol);
- 	WRITE_NODE_FIELD(fdwplan);
- }
- 
- static void
- _outFdwPlan(StringInfo str, const FdwPlan *node)
- {
- 	WRITE_NODE_TYPE("FDWPLAN");
- 
- 	WRITE_FLOAT_FIELD(startup_cost, "%.2f");
- 	WRITE_FLOAT_FIELD(total_cost, "%.2f");
  	WRITE_NODE_FIELD(fdw_private);
  }
  
--- 558,563 ----
***************
*** 1572,1578 **** _outForeignPath(StringInfo str, const ForeignPath *node)
  
  	_outPathInfo(str, (const Path *) node);
  
! 	WRITE_NODE_FIELD(fdwplan);
  }
  
  static void
--- 1562,1568 ----
  
  	_outPathInfo(str, (const Path *) node);
  
! 	WRITE_NODE_FIELD(fdw_private);
  }
  
  static void
***************
*** 2744,2752 **** _outNode(StringInfo str, const void *obj)
  			case T_ForeignScan:
  				_outForeignScan(str, obj);
  				break;
- 			case T_FdwPlan:
- 				_outFdwPlan(str, obj);
- 				break;
  			case T_Join:
  				_outJoin(str, obj);
  				break;
--- 2734,2739 ----
*** a/src/backend/optimizer/path/allpaths.c
--- b/src/backend/optimizer/path/allpaths.c
***************
*** 399,411 **** set_foreign_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
  
  /*
   * set_foreign_pathlist
!  *		Build the (single) access path for a foreign table RTE
   */
  static void
  set_foreign_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
  {
! 	/* Generate appropriate path */
! 	add_path(rel, (Path *) create_foreignscan_path(root, rel));
  
  	/* Select cheapest path (pretty easy in this case...) */
  	set_cheapest(rel);
--- 399,411 ----
  
  /*
   * set_foreign_pathlist
!  *		Build one or more access paths for a foreign table RTE
   */
  static void
  set_foreign_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
  {
! 	/* Generate appropriate paths */
! 	create_foreignscan_path(root, rel);
  
  	/* Select cheapest path (pretty easy in this case...) */
  	set_cheapest(rel);
*** a/src/backend/optimizer/plan/createplan.c
--- b/src/backend/optimizer/plan/createplan.c
***************
*** 121,127 **** static CteScan *make_ctescan(List *qptlist, List *qpqual,
  static WorkTableScan *make_worktablescan(List *qptlist, List *qpqual,
  				   Index scanrelid, int wtParam);
  static ForeignScan *make_foreignscan(List *qptlist, List *qpqual,
! 				 Index scanrelid, bool fsSystemCol, FdwPlan *fdwplan);
  static BitmapAnd *make_bitmap_and(List *bitmapplans);
  static BitmapOr *make_bitmap_or(List *bitmapplans);
  static NestLoop *make_nestloop(List *tlist,
--- 121,127 ----
  static WorkTableScan *make_worktablescan(List *qptlist, List *qpqual,
  				   Index scanrelid, int wtParam);
  static ForeignScan *make_foreignscan(List *qptlist, List *qpqual,
! 				 Index scanrelid, bool fsSystemCol, List *fdw_private);
  static BitmapAnd *make_bitmap_and(List *bitmapplans);
  static BitmapOr *make_bitmap_or(List *bitmapplans);
  static NestLoop *make_nestloop(List *tlist,
***************
*** 1847,1853 **** create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path,
  								 scan_clauses,
  								 scan_relid,
  								 fsSystemCol,
! 								 best_path->fdwplan);
  
  	copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
  
--- 1847,1853 ----
  								 scan_clauses,
  								 scan_relid,
  								 fsSystemCol,
! 								 best_path->fdw_private);
  
  	copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
  
***************
*** 3189,3195 **** make_foreignscan(List *qptlist,
  				 List *qpqual,
  				 Index scanrelid,
  				 bool fsSystemCol,
! 				 FdwPlan *fdwplan)
  {
  	ForeignScan *node = makeNode(ForeignScan);
  	Plan	   *plan = &node->scan.plan;
--- 3189,3195 ----
  				 List *qpqual,
  				 Index scanrelid,
  				 bool fsSystemCol,
! 				 List *fdw_private)
  {
  	ForeignScan *node = makeNode(ForeignScan);
  	Plan	   *plan = &node->scan.plan;
***************
*** 3201,3207 **** make_foreignscan(List *qptlist,
  	plan->righttree = NULL;
  	node->scan.scanrelid = scanrelid;
  	node->fsSystemCol = fsSystemCol;
! 	node->fdwplan = fdwplan;
  
  	return node;
  }
--- 3201,3207 ----
  	plan->righttree = NULL;
  	node->scan.scanrelid = scanrelid;
  	node->fsSystemCol = fsSystemCol;
! 	node->fdw_private = fdw_private;
  
  	return node;
  }
*** a/src/backend/optimizer/util/pathnode.c
--- b/src/backend/optimizer/util/pathnode.c
***************
*** 1764,1803 **** create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel)
  
  /*
   * create_foreignscan_path
!  *	  Creates a path corresponding to a scan of a foreign table,
!  *	  returning the pathnode.
   */
! ForeignPath *
  create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel)
  {
- 	ForeignPath *pathnode = makeNode(ForeignPath);
  	RangeTblEntry *rte;
  	FdwRoutine *fdwroutine;
- 	FdwPlan    *fdwplan;
- 
- 	pathnode->path.pathtype = T_ForeignScan;
- 	pathnode->path.parent = rel;
- 	pathnode->path.pathkeys = NIL;		/* result is always unordered */
- 	pathnode->path.required_outer = NULL;
- 	pathnode->path.param_clauses = NIL;
  
  	/* Get FDW's callback info */
  	rte = planner_rt_fetch(rel->relid, root);
  	fdwroutine = GetFdwRoutineByRelId(rte->relid);
  
  	/* Let the FDW do its planning */
! 	fdwplan = fdwroutine->PlanForeignScan(rte->relid, root, rel);
! 	if (fdwplan == NULL || !IsA(fdwplan, FdwPlan))
! 		elog(ERROR, "foreign-data wrapper PlanForeignScan function for relation %u did not return an FdwPlan struct",
! 			 rte->relid);
! 	pathnode->fdwplan = fdwplan;
! 
! 	/* use costs estimated by FDW */
! 	pathnode->path.rows = rel->rows;
! 	pathnode->path.startup_cost = fdwplan->startup_cost;
! 	pathnode->path.total_cost = fdwplan->total_cost;
! 
! 	return pathnode;
  }
  
  /*
--- 1764,1786 ----
  
  /*
   * create_foreignscan_path
!  *	  Creates one or more paths corresponding to a scan of a foreign table,
!  *	  returning void.
   */
! void
  create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel)
  {
  	RangeTblEntry *rte;
  	FdwRoutine *fdwroutine;
  
  	/* Get FDW's callback info */
  	rte = planner_rt_fetch(rel->relid, root);
  	fdwroutine = GetFdwRoutineByRelId(rte->relid);
  
  	/* Let the FDW do its planning */
! 	fdwroutine->PlanForeignScan(rte->relid, root, rel);
! 	if (rel->pathlist == NIL)
! 		elog(ERROR, "could not devise a query plan for the given query");
  }
  
  /*
*** a/src/include/foreign/fdwapi.h
--- b/src/include/foreign/fdwapi.h
***************
*** 20,58 **** struct ExplainState;
  
  
  /*
-  * FdwPlan is the information returned to the planner by PlanForeignScan.
-  */
- typedef struct FdwPlan
- {
- 	NodeTag		type;
- 
- 	/*
- 	 * Cost estimation info. The startup_cost is time before retrieving the
- 	 * first row, so it should include costs of connecting to the remote host,
- 	 * sending over the query, etc.  Note that PlanForeignScan also ought to
- 	 * set baserel->rows and baserel->width if it can produce any usable
- 	 * estimates of those values.
- 	 */
- 	Cost		startup_cost;	/* cost expended before fetching any tuples */
- 	Cost		total_cost;		/* total cost (assuming all tuples fetched) */
- 
- 	/*
- 	 * FDW private data, which will be available at execution time.
- 	 *
- 	 * Note that everything in this list must be copiable by copyObject(). One
- 	 * way to store an arbitrary blob of bytes is to represent it as a bytea
- 	 * Const.  Usually, though, you'll be better off choosing a representation
- 	 * that can be dumped usefully by nodeToString().
- 	 */
- 	List	   *fdw_private;
- } FdwPlan;
- 
- 
- /*
   * Callback function signatures --- see fdwhandler.sgml for more info.
   */
  
! typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid,
  														  PlannerInfo *root,
  														RelOptInfo *baserel);
  
--- 20,29 ----
  
  
  /*
   * Callback function signatures --- see fdwhandler.sgml for more info.
   */
  
! typedef void (*PlanForeignScan_function) (Oid foreigntableid,
  														  PlannerInfo *root,
  														RelOptInfo *baserel);
  
*** a/src/include/nodes/nodes.h
--- b/src/include/nodes/nodes.h
***************
*** 62,68 **** typedef enum NodeTag
  	T_CteScan,
  	T_WorkTableScan,
  	T_ForeignScan,
- 	T_FdwPlan,
  	T_Join,
  	T_NestLoop,
  	T_MergeJoin,
--- 62,67 ----
*** a/src/include/nodes/plannodes.h
--- b/src/include/nodes/plannodes.h
***************
*** 468,475 **** typedef struct ForeignScan
  {
  	Scan		scan;
  	bool		fsSystemCol;	/* true if any "system column" is needed */
! 	/* use struct pointer to avoid including fdwapi.h here */
! 	struct FdwPlan *fdwplan;
  } ForeignScan;
  
  
--- 468,474 ----
  {
  	Scan		scan;
  	bool		fsSystemCol;	/* true if any "system column" is needed */
! 	List	   *fdw_private;
  } ForeignScan;
  
  
*** a/src/include/nodes/relation.h
--- b/src/include/nodes/relation.h
***************
*** 794,805 **** typedef struct TidPath
  
  /*
   * ForeignPath represents a scan of a foreign table
   */
  typedef struct ForeignPath
  {
  	Path		path;
! 	/* use struct pointer to avoid including fdwapi.h here */
! 	struct FdwPlan *fdwplan;
  } ForeignPath;
  
  /*
--- 794,810 ----
  
  /*
   * ForeignPath represents a scan of a foreign table
+  *
+  * fdw_private is a list of FDW private data, which will be available at
+  * execution time.  Note that everything in this list must be copiable
+  * by copyObject().  One way to store an arbitrary blob of bytes is to
+  * represent it as a bytea Const.  Usually, though, you'll be better off
+  * choosing a representation that can be dumped usefully by nodeToString().
   */
  typedef struct ForeignPath
  {
  	Path		path;
! 	List	   *fdw_private;
  } ForeignPath;
  
  /*
*** a/src/include/optimizer/pathnode.h
--- b/src/include/optimizer/pathnode.h
***************
*** 68,74 **** extern Path *create_functionscan_path(PlannerInfo *root, RelOptInfo *rel);
  extern Path *create_valuesscan_path(PlannerInfo *root, RelOptInfo *rel);
  extern Path *create_ctescan_path(PlannerInfo *root, RelOptInfo *rel);
  extern Path *create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel);
! extern ForeignPath *create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel);
  
  extern Relids calc_nestloop_required_outer(Path *outer_path, Path *inner_path);
  extern Relids calc_non_nestloop_required_outer(Path *outer_path, Path *inner_path);
--- 68,74 ----
  extern Path *create_valuesscan_path(PlannerInfo *root, RelOptInfo *rel);
  extern Path *create_ctescan_path(PlannerInfo *root, RelOptInfo *rel);
  extern Path *create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel);
! extern void create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel);
  
  extern Relids calc_nestloop_required_outer(Path *outer_path, Path *inner_path);
  extern Relids calc_non_nestloop_required_outer(Path *outer_path, Path *inner_path);