to NULL.
This change would make implementation of FDW a little simpler.
<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>
#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"
*/
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
{
ForeignScanState *scanstate;
Relation currentRelation;
Oid userid;
+ FdwRoutine *routine;
/*
* foreign scan has no child node.
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
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;
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;
void
ExecForeignReScan(ForeignScanState *node)
{
- node->routine->ReOpen(node);
+ if (node->routine->ReOpen != NULL)
+ node->routine->ReOpen(node);
ExecScanReScan((ScanState *) node);
}
/*
* 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);
{
static FdwRoutine file_fdw_routine =
{
- ConnectServer,
- FreeFSConnection,
+ NULL, /* ConnectServer */
+ NULL, /* FreeFSConnection */
EstimateCosts,
- Open,
+ NULL, /* Open */
BeginScan,
Iterate,
Close,
}
/*
- * 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;
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.
wrapper = GetForeignDataWrapper(server->fdwid);
routine = GetFdwRoutine(wrapper->fdwhandler);
- routine->EstimateCosts(path, root, baserel);
+ if (routine->EstimateCosts != NULL)
+ routine->EstimateCosts(path, root, baserel);
}
/*
/*
* 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
{
/*
* Fetch the next record and fill tupleslot with it.
+ * This routine can't be NULL.
*/
void (*Iterate)(ForeignScanState *scanstate);