Allow FDWs to set function pointers in FdwRoutine other than Iterate
authorShigeru Hanada <[email protected]>
Thu, 11 Nov 2010 04:41:17 +0000 (13:41 +0900)
committerShigeru Hanada <[email protected]>
Thu, 11 Nov 2010 04:41:17 +0000 (13:41 +0900)
to NULL.

This change would make implementation of FDW a little simpler.

doc/src/sgml/postgresql-fdw.sgml
src/backend/commands/foreigncmds.c
src/backend/executor/nodeForeignscan.c
src/backend/foreign/file_fdw.c
src/backend/optimizer/path/costsize.c
src/include/nodes/execnodes.h

index 0d7791010c8c7afeb65db8d2456f91ccd411daa9..36f1bbc7c4e4c518512fee1679436a6708fb9e89 100644 (file)
@@ -33,7 +33,9 @@
      <para>
       Internally, it returns a pointer to a <structname>FdwRoutine</structname>
       object which has set of foreign-data wrapper API functions for handling
-      foreign scan on the external PostgreSQL server.
+      foreign scan on the external PostgreSQL server.  Functions other than
+      Iterate can be NULL if the foreign-data wrapper has nothing to do in the
+      function.
      </para>
     </listitem>
    </varlistentry>
index 6a9c0eeccdbcafe803049442a872c37a11dc7a3a..8149f343e70374ecc60def0c1f81d926c11a5626 100644 (file)
@@ -28,6 +28,7 @@
 #include "commands/defrem.h"
 #include "foreign/foreign.h"
 #include "miscadmin.h"
+#include "nodes/execnodes.h"
 #include "parser/parse_func.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
@@ -638,6 +639,15 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
         */
        if (defhandler->arg == NULL && have_foreign_table(fdwId))
            elog(ERROR, "cannot unset handler because foreign table depend on it");
+
+       /* Check whether the handler has valid Iterate routine. */
+       if (fdwhandler != InvalidOid)
+       {
+           FdwRoutine     *routine = GetFdwRoutine(fdwhandler);
+           if (routine->Iterate != NULL)
+               ereport(ERROR,
+                       (errmsg("HANDLER must have valid Iterate routine")));
+       }
    }
    else
    {
index ecc730a3116897996a4bbc29faf9ddd7a8627ca0..b5a5be89e2d055e3ffcbc2a95525248c6d67bf4c 100644 (file)
@@ -109,6 +109,7 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
    ForeignScanState   *scanstate;
    Relation            currentRelation;
    Oid                 userid;
+   FdwRoutine         *routine;
 
    /*
     * foreign scan has no child node.
@@ -169,8 +170,12 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
    scanstate->server = GetForeignServer(scanstate->table->serverid);
    scanstate->wrapper = GetForeignDataWrapper(scanstate->server->fdwid);
    scanstate->user = GetUserMapping(userid, scanstate->server->serverid);
-   scanstate->routine = GetFdwRoutine(scanstate->wrapper->fdwhandler);
-   scanstate->routine->Open(scanstate);
+   routine = GetFdwRoutine(scanstate->wrapper->fdwhandler);
+   scanstate->routine = routine;
+
+   /* Initialize the scan */
+   if (routine->Open != NULL)
+       routine->Open(scanstate);
 
    /*
     * If this execution was not for EXPLAIN w/o ANALYZE flag, initiate the
@@ -179,9 +184,11 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
    if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
    {
        /* connect to the foreign server and prepare to execute scan */
-       scanstate->conn = scanstate->routine->ConnectServer(scanstate->server,
-                                                           scanstate->user);
-       scanstate->routine->BeginScan(scanstate);
+       if (routine->ConnectServer != NULL)
+           scanstate->conn = routine->ConnectServer(scanstate->server,
+                                                    scanstate->user);
+       if (routine->BeginScan != NULL)
+           routine->BeginScan(scanstate);
    }
 
    return scanstate;
@@ -199,10 +206,12 @@ ExecEndForeignScan(ForeignScanState *node)
    Relation        relation;
 
    /* close the scan */
-   node->routine->Close(node);
+   if (node->routine->Close != NULL)
+       node->routine->Close(node);
 
-   /* close the foreign connection */
-   node->routine->FreeFSConnection(node->conn);
+   /* close the foreign connection for this scan node */
+   if (node->routine->FreeFSConnection != NULL)
+       node->routine->FreeFSConnection(node->conn);
 
    /* get information from node */
    relation = node->ss.ss_currentRelation;
@@ -232,7 +241,8 @@ ExecEndForeignScan(ForeignScanState *node)
 void
 ExecForeignReScan(ForeignScanState *node)
 {
-   node->routine->ReOpen(node);
+   if (node->routine->ReOpen != NULL)
+       node->routine->ReOpen(node);
 
    ExecScanReScan((ScanState *) node);
 }
index 707a3eeedce2a26e5fae1abc3b4cf4e0175b006a..852a49e88f67155a963b8f24bbd24cf7f7b4d168 100644 (file)
@@ -67,9 +67,6 @@ extern Datum file_fdw_handler(PG_FUNCTION_ARGS);
 /*
  * FDW routines
  */
-static FSConnection* ConnectServer(ForeignServer *server, UserMapping *user);
-static void FreeFSConnection(FSConnection *conn);
-static void Open(ForeignScanState *scanstate);
 static void BeginScan(ForeignScanState *scanstate);
 static void Iterate(ForeignScanState *scanstate);
 static void Close(ForeignScanState *scanstate);
@@ -250,10 +247,10 @@ file_fdw_handler(PG_FUNCTION_ARGS)
 {
    static FdwRoutine file_fdw_routine =
    {
-       ConnectServer,
-       FreeFSConnection,
+       NULL,               /* ConnectServer */
+       NULL,               /* FreeFSConnection */
        EstimateCosts,
-       Open,
+       NULL,               /* Open */
        BeginScan,
        Iterate,
        Close,
@@ -264,34 +261,11 @@ file_fdw_handler(PG_FUNCTION_ARGS)
 }
 
 /*
- * ConnectServer()
- *   - do nothing
- */
-static FSConnection *
-ConnectServer(ForeignServer *server, UserMapping *user)
-{
-   elog(DEBUG2, "%s called", __FUNCTION__);
-   /* file wrapper never needs connection */
-   return NULL;
-}
-
-/*
- * FreeFSConnection()
- *   - do nothing
- */
-static void
-FreeFSConnection(FSConnection *conn)
-{
-   elog(DEBUG2, "%s called", __FUNCTION__);
-   /* nothing to do here */
-}
-
-/*
- * Open()
- *   - create FileState to prepare scanning on the file.
+ * BeginScan()
+ *   - initiate access to the file, but we have nothing to do
  */
 static void
-Open(ForeignScanState *scanstate)
+BeginScan(ForeignScanState *scanstate)
 {
    FileState       fstate;
 
@@ -304,16 +278,6 @@ Open(ForeignScanState *scanstate)
    scanstate->reply = (FdwReply *) fstate;
 }
 
-/*
- * BeginScan()
- *   - initiate access to the file, but we have nothing to do
- */
-static void
-BeginScan(ForeignScanState *scanstate)
-{
-   elog(DEBUG2, "%s called", __FUNCTION__);
-}
-
 /*
  * Iterate()
  *   - create HeapTuple from the record in the file.
index adcff826fda2a9b118e1dbf4d25d693f3d13d971..6a8faf8bded5118baaf1ac9d52c1d25f8900d26c 100644 (file)
@@ -1046,7 +1046,8 @@ cost_foreignscan(ForeignPath *path, PlannerInfo *root,
    wrapper = GetForeignDataWrapper(server->fdwid);
    routine = GetFdwRoutine(wrapper->fdwhandler);
 
-   routine->EstimateCosts(path, root, baserel);
+   if (routine->EstimateCosts != NULL)
+       routine->EstimateCosts(path, root, baserel);
 }
 
 /*
index 2abda678bcebf5b248dfd839c89c7aaa1752b3ab..a47df10f2faeeaf84aac98a9785a7c1c54a29268 100644 (file)
@@ -1406,7 +1406,9 @@ typedef struct ForeignScanState
 
 /*
  * Common interface routines of FDW baed on SQL/MED standard.
- * A foreign-data wrapper must implement these routines.
+ * A foreign-data wrapper can implement FDW-specific works with these callback
+ * routines.  If there is nothing to do for a callback function other
+ * than Iterate, it can be NULL.
  */
 struct FdwRoutine
 {
@@ -1441,6 +1443,7 @@ struct FdwRoutine
 
    /*
     * Fetch the next record and fill tupleslot with it.
+    * This routine can't be NULL.
     */
    void (*Iterate)(ForeignScanState *scanstate);