Foreign Data Wrapper Callback Routines
| PostgreSQL 9.4.15 Documentation | |||
|---|---|---|---|
| Prev | Up | Chapter 53. Writing A Foreign Data Wrapper | Next | 
The FDW handler function returns a palloc'd FdwRoutine struct containing pointers to the callback functions described below. The scan-related functions are required, the rest are optional.
The FdwRoutine struct type is declared in src/include/foreign/fdwapi.h , which see for additional details.
53.2.1. FDW Routines For Scanning Foreign Tables
void
GetForeignRelSize (PlannerInfo *root,
                   RelOptInfo *baserel,
                   Oid foreigntableid);
  Obtain relation size estimates for a foreign table. This is called at the beginning of planning for a query that scans a foreign table. root is the planner's global information about the query; baserel is the planner's information about this table; and foreigntableid is the pg_class OID of the foreign table. ( foreigntableid could be obtained from the planner data structures, but it's passed explicitly to save effort.)
This function should update baserel->rows to be the expected number of rows returned by the table scan, after accounting for the filtering done by the restriction quals. The initial value of baserel->rows is just a constant default estimate, which should be replaced if at all possible. The function may also choose to update baserel->width if it can compute a better estimate of the average result row width.
See Section 53.4 for additional information.
void
GetForeignPaths (PlannerInfo *root,
                 RelOptInfo *baserel,
                 Oid foreigntableid);
  
   Create possible access paths for a scan on a foreign table.
     This is called during query planning.
     The parameters are the same as for
   
    GetForeignRelSize
   
   ,
     which has already been called.
  
   This function must generate at least one access path
     (
   
    ForeignPath
   
   node) for a scan on the foreign table and
     must call
   
    add_path
   
   to add each such path to
   
    baserel->pathlist
   
   .  It's recommended to use
   
    create_foreignscan_path
   
   to build the
   
    ForeignPath
   
   nodes.  The function can generate multiple
     access paths, e.g., a path which has valid
   
    pathkeys
   
   to
     represent a pre-sorted result.  Each access path must contain cost
     estimates, and can contain any FDW-private information that is needed to
     identify the specific scan method intended.
  
See Section 53.4 for additional information.
ForeignScan *
GetForeignPlan (PlannerInfo *root,
                RelOptInfo *baserel,
                Oid foreigntableid,
                ForeignPath *best_path,
                List *tlist,
                List *scan_clauses);
  
   Create a
   
    ForeignScan
   
   plan node from the selected foreign
     access path.  This is called at the end of query planning.
     The parameters are as for
   
    GetForeignRelSize
   
   , plus
     the selected
   
    ForeignPath
   
   (previously produced by
   
    GetForeignPaths
   
   ), the target list to be emitted by the
     plan node, and the restriction clauses to be enforced by the plan node.
  
   This function must create and return a
   
    ForeignScan
   
   plan
     node; it's recommended to use
   
    make_foreignscan
   
   to build the
   
    ForeignScan
   
   node.
  
See Section 53.4 for additional information.
void
BeginForeignScan (ForeignScanState *node,
                  int eflags);
  
   Begin executing a foreign scan. This is called during executor startup.
     It should perform any initialization needed before the scan can start,
     but not start executing the actual scan (that should be done upon the
     first call to
   
    IterateForeignScan
   
   ).
     The
   
    ForeignScanState
   
   node has already been created, but
     its
   
    fdw_state
   
   field is still NULL.  Information about
     the table to scan is accessible through the
   
    ForeignScanState
   
   node (in particular, from the underlying
   
    ForeignScan
   
   plan node, which contains any FDW-private
     information provided by
   
    GetForeignPlan
   
   ).
   
    eflags
   
   contains flag bits describing the executor's
     operating mode for this plan node.
  
   Note that when
   
    (eflags & EXEC_FLAG_EXPLAIN_ONLY)
   
   is
     true, this function should not perform any externally-visible actions;
     it should only do the minimum required to make the node state valid
     for
   
    ExplainForeignScan
   
   and
   
    EndForeignScan
   
   .
  
TupleTableSlot * IterateForeignScan (ForeignScanState *node);
   Fetch one row from the foreign source, returning it in a tuple table slot
     (the node's
   
    ScanTupleSlot
   
   should be used for this
     purpose).  Return NULL if no more rows are available.  The tuple table
     slot infrastructure allows either a physical or virtual tuple to be
     returned; in most cases the latter choice is preferable from a
     performance standpoint.  Note that this is called in a short-lived memory
     context that will be reset between invocations.  Create a memory context
     in
   
    BeginForeignScan
   
   if you need longer-lived storage, or use
     the
   
    es_query_cxt
   
   of the node's
   
    EState
   
   .
  
The rows returned must match the column signature of the foreign table being scanned. If you choose to optimize away fetching columns that are not needed, you should insert nulls in those column positions.
Note that PostgreSQL 's executor doesn't care whether the rows returned violate any NOT NULL constraints that were defined on the foreign table columns - but the planner does care, and may optimize queries incorrectly if NULL values are present in a column declared not to contain them. If a NULL value is encountered when the user has declared that none should be present, it may be appropriate to raise an error (just as you would need to do in the case of a data type mismatch).
void ReScanForeignScan (ForeignScanState *node);
Restart the scan from the beginning. Note that any parameters the scan depends on may have changed value, so the new scan does not necessarily return exactly the same rows.
void EndForeignScan (ForeignScanState *node);
End the scan and release resources. It is normally not important to release palloc'd memory, but for example open files and connections to remote servers should be cleaned up.
53.2.2. FDW Routines For Updating Foreign Tables
If an FDW supports writable foreign tables, it should provide some or all of the following callback functions depending on the needs and capabilities of the FDW:
void
AddForeignUpdateTargets (Query *parsetree,
                         RangeTblEntry *target_rte,
                         Relation target_relation);
  UPDATE and DELETE operations are performed against rows previously fetched by the table-scanning functions. The FDW may need extra information, such as a row ID or the values of primary-key columns, to ensure that it can identify the exact row to update or delete. To support that, this function can add extra hidden, or "junk" , target columns to the list of columns that are to be retrieved from the foreign table during an UPDATE or DELETE .
To do that, add TargetEntry items to parsetree->targetList , containing expressions for the extra values to be fetched. Each such entry must be marked resjunk = true , and must have a distinct resname that will identify it at execution time. Avoid using names matching ctid N , wholerow , or wholerow N , as the core system can generate junk columns of these names.
This function is called in the rewriter, not the planner, so the information available is a bit different from that available to the planning routines. parsetree is the parse tree for the UPDATE or DELETE command, while target_rte and target_relation describe the target foreign table.
   If the
   
    AddForeignUpdateTargets
   
   pointer is set to
   
    NULL
   
   , no extra target expressions are added.
     (This will make it impossible to implement
   
    DELETE
   
   operations, though
   
    UPDATE
   
   may still be feasible if the FDW
     relies on an unchanging primary key to identify rows.)
  
List *
PlanForeignModify (PlannerInfo *root,
                   ModifyTable *plan,
                   Index resultRelation,
                   int subplan_index);
  
   Perform any additional planning actions needed for an insert, update, or
     delete on a foreign table.  This function generates the FDW-private
     information that will be attached to the
   
    ModifyTable
   
   plan
     node that performs the update action.  This private information must
     have the form of a
   
    List
   
   , and will be delivered to
   
    BeginForeignModify
   
   during the execution stage.
  
root is the planner's global information about the query. plan is the ModifyTable plan node, which is complete except for the fdwPrivLists field. resultRelation identifies the target foreign table by its range table index. subplan_index identifies which target of the ModifyTable plan node this is, counting from zero; use this if you want to index into plan->plans or other substructure of the plan node.
See Section 53.4 for additional information.
   If the
   
    PlanForeignModify
   
   pointer is set to
   
    NULL
   
   , no additional plan-time actions are taken, and the
   
    fdw_private
   
   list delivered to
   
    BeginForeignModify
   
   will be NIL.
  
void
BeginForeignModify (ModifyTableState *mtstate,
                    ResultRelInfo *rinfo,
                    List *fdw_private,
                    int subplan_index,
                    int eflags);
  
   Begin executing a foreign table modification operation.  This routine is
     called during executor startup.  It should perform any initialization
     needed prior to the actual table modifications.  Subsequently,
   
    ExecForeignInsert
   
   ,
   
    ExecForeignUpdate
   
   or
   
    ExecForeignDelete
   
   will be called for each tuple to be
     inserted, updated, or deleted.
  
   
    mtstate
   
   is the overall state of the
   
    ModifyTable
   
   plan node being executed; global data about
     the plan and execution state is available via this structure.
   
    rinfo
   
   is the
   
    ResultRelInfo
   
   struct describing
     the target foreign table.  (The
   
    ri_FdwState
   
   field of
   
    ResultRelInfo
   
   is available for the FDW to store any
     private state it needs for this operation.)
   
    fdw_private
   
   contains the private data generated by
   
    PlanForeignModify
   
   , if any.
   
    subplan_index
   
   identifies which target of
     the
   
    ModifyTable
   
   plan node this is.
   
    eflags
   
   contains flag bits describing the executor's
     operating mode for this plan node.
  
   Note that when
   
    (eflags & EXEC_FLAG_EXPLAIN_ONLY)
   
   is
     true, this function should not perform any externally-visible actions;
     it should only do the minimum required to make the node state valid
     for
   
    ExplainForeignModify
   
   and
   
    EndForeignModify
   
   .
  
   If the
   
    BeginForeignModify
   
   pointer is set to
   
    NULL
   
   , no action is taken during executor startup.
  
TupleTableSlot *
ExecForeignInsert (EState *estate,
                   ResultRelInfo *rinfo,
                   TupleTableSlot *slot,
                   TupleTableSlot *planSlot);
  Insert one tuple into the foreign table. estate is global execution state for the query. rinfo is the ResultRelInfo struct describing the target foreign table. slot contains the tuple to be inserted; it will match the row-type definition of the foreign table. planSlot contains the tuple that was generated by the ModifyTable plan node's subplan; it differs from slot in possibly containing additional "junk" columns. (The planSlot is typically of little interest for INSERT cases, but is provided for completeness.)
The return value is either a slot containing the data that was actually inserted (this might differ from the data supplied, for example as a result of trigger actions), or NULL if no row was actually inserted (again, typically as a result of triggers). The passed-in slot can be re-used for this purpose.
The data in the returned slot is used only if the INSERT query has a RETURNING clause or the foreign table has an AFTER ROW trigger. Triggers require all columns, but the FDW could choose to optimize away returning some or all columns depending on the contents of the RETURNING clause. Regardless, some slot must be returned to indicate success, or the query's reported row count will be wrong.
   If the
   
    ExecForeignInsert
   
   pointer is set to
   
    NULL
   
   , attempts to insert into the foreign table will fail
     with an error message.
  
TupleTableSlot *
ExecForeignUpdate (EState *estate,
                   ResultRelInfo *rinfo,
                   TupleTableSlot *slot,
                   TupleTableSlot *planSlot);
  
   Update one tuple in the foreign table.
   
    estate
   
   is global execution state for the query.
   
    rinfo
   
   is the
   
    ResultRelInfo
   
   struct describing
     the target foreign table.
   
    slot
   
   contains the new data for the tuple; it will match the
     row-type definition of the foreign table.
   
    planSlot
   
   contains the tuple that was generated by the
   
    ModifyTable
   
   plan node's subplan; it differs from
   
    slot
   
   in possibly containing additional
   
    "junk"
   
   columns.  In particular, any junk columns that were requested by
   
    AddForeignUpdateTargets
   
   will be available from this slot.
  
The return value is either a slot containing the row as it was actually updated (this might differ from the data supplied, for example as a result of trigger actions), or NULL if no row was actually updated (again, typically as a result of triggers). The passed-in slot can be re-used for this purpose.
The data in the returned slot is used only if the UPDATE query has a RETURNING clause or the foreign table has an AFTER ROW trigger. Triggers require all columns, but the FDW could choose to optimize away returning some or all columns depending on the contents of the RETURNING clause. Regardless, some slot must be returned to indicate success, or the query's reported row count will be wrong.
   If the
   
    ExecForeignUpdate
   
   pointer is set to
   
    NULL
   
   , attempts to update the foreign table will fail
     with an error message.
  
TupleTableSlot *
ExecForeignDelete (EState *estate,
                   ResultRelInfo *rinfo,
                   TupleTableSlot *slot,
                   TupleTableSlot *planSlot);
  
   Delete one tuple from the foreign table.
   
    estate
   
   is global execution state for the query.
   
    rinfo
   
   is the
   
    ResultRelInfo
   
   struct describing
     the target foreign table.
   
    slot
   
   contains nothing useful upon call, but can be used to
     hold the returned tuple.
   
    planSlot
   
   contains the tuple that was generated by the
   
    ModifyTable
   
   plan node's subplan; in particular, it will
     carry any junk columns that were requested by
   
    AddForeignUpdateTargets
   
   .  The junk column(s) must be used
     to identify the tuple to be deleted.
  
The return value is either a slot containing the row that was deleted, or NULL if no row was deleted (typically as a result of triggers). The passed-in slot can be used to hold the tuple to be returned.
The data in the returned slot is used only if the DELETE query has a RETURNING clause or the foreign table has an AFTER ROW trigger. Triggers require all columns, but the FDW could choose to optimize away returning some or all columns depending on the contents of the RETURNING clause. Regardless, some slot must be returned to indicate success, or the query's reported row count will be wrong.
   If the
   
    ExecForeignDelete
   
   pointer is set to
   
    NULL
   
   , attempts to delete from the foreign table will fail
     with an error message.
  
void
EndForeignModify (EState *estate,
                  ResultRelInfo *rinfo);
  End the table update and release resources. It is normally not important to release palloc'd memory, but for example open files and connections to remote servers should be cleaned up.
   If the
   
    EndForeignModify
   
   pointer is set to
   
    NULL
   
   , no action is taken during executor shutdown.
  
int IsForeignRelUpdatable (Relation rel);
Report which update operations the specified foreign table supports. The return value should be a bit mask of rule event numbers indicating which operations are supported by the foreign table, using the CmdType enumeration; that is, (1 << CMD_UPDATE) = 4 for UPDATE , (1 << CMD_INSERT) = 8 for INSERT , and (1 << CMD_DELETE) = 16 for DELETE .
   If the
   
    IsForeignRelUpdatable
   
   pointer is set to
   
    NULL
   
   , foreign tables are assumed to be insertable, updatable,
     or deletable if the FDW provides
   
    ExecForeignInsert
   
   ,
   
    ExecForeignUpdate
   
   , or
   
    ExecForeignDelete
   
   respectively.  This function is only needed if the FDW supports some
     tables that are updatable and some that are not.  (Even then, it's
     permissible to throw an error in the execution routine instead of
     checking in this function.  However, this function is used to determine
     updatability for display in the
   
    information_schema
   
   views.)
  
53.2.3. FDW Routines for EXPLAIN
void
ExplainForeignScan (ForeignScanState *node,
                    ExplainState *es);
  
   Print additional
   
    EXPLAIN
   
   output for a foreign table scan.
     This function can call
   
    ExplainPropertyText
   
   and
     related functions to add fields to the
   
    EXPLAIN
   
   output.
     The flag fields in
   
    es
   
   can be used to determine what to
     print, and the state of the
   
    ForeignScanState
   
   node
     can be inspected to provide run-time statistics in the
   
    EXPLAIN
     ANALYZE
   
   case.
  
   If the
   
    ExplainForeignScan
   
   pointer is set to
   
    NULL
   
   , no additional information is printed during
   
    EXPLAIN
   
   .
  
void
ExplainForeignModify (ModifyTableState *mtstate,
                      ResultRelInfo *rinfo,
                      List *fdw_private,
                      int subplan_index,
                      struct ExplainState *es);
  
   Print additional
   
    EXPLAIN
   
   output for a foreign table update.
     This function can call
   
    ExplainPropertyText
   
   and
     related functions to add fields to the
   
    EXPLAIN
   
   output.
     The flag fields in
   
    es
   
   can be used to determine what to
     print, and the state of the
   
    ModifyTableState
   
   node
     can be inspected to provide run-time statistics in the
   
    EXPLAIN
     ANALYZE
   
   case.  The first four arguments are the same as for
   
    BeginForeignModify
   
   .
  
   If the
   
    ExplainForeignModify
   
   pointer is set to
   
    NULL
   
   , no additional information is printed during
   
    EXPLAIN
   
   .
  
53.2.4. FDW Routines for ANALYZE
bool
AnalyzeForeignTable (Relation relation,
                     AcquireSampleRowsFunc *func,
                     BlockNumber *totalpages);
  This function is called when ANALYZE is executed on a foreign table. If the FDW can collect statistics for this foreign table, it should return true , and provide a pointer to a function that will collect sample rows from the table in func , plus the estimated size of the table in pages in totalpages . Otherwise, return false .
   If the FDW does not support collecting statistics for any tables, the
   
    AnalyzeForeignTable
   
   pointer can be set to
   
    NULL
   
   .
  
If provided, the sample collection function must have the signature
int
AcquireSampleRowsFunc (Relation relation, int elevel,
                       HeapTuple *rows, int targrows,
                       double *totalrows,
                       double *totaldeadrows);
  A random sample of up to targrows rows should be collected from the table and stored into the caller-provided rows array. The actual number of rows collected must be returned. In addition, store estimates of the total numbers of live and dead rows in the table into the output parameters totalrows and totaldeadrows . (Set totaldeadrows to zero if the FDW does not have any concept of dead rows.)