From d3a222c3f563c9dbc36ed3f2c713b7cc2bfcdacb Mon Sep 17 00:00:00 2001 From: Shigeru Hanada Date: Thu, 11 Nov 2010 13:41:17 +0900 Subject: [PATCH] Allow FDWs to set function pointers in FdwRoutine other than Iterate to NULL. This change would make implementation of FDW a little simpler. --- doc/src/sgml/postgresql-fdw.sgml | 4 ++- src/backend/commands/foreigncmds.c | 10 ++++++ src/backend/executor/nodeForeignscan.c | 28 ++++++++++----- src/backend/foreign/file_fdw.c | 48 ++++---------------------- src/backend/optimizer/path/costsize.c | 3 +- src/include/nodes/execnodes.h | 5 ++- 6 files changed, 44 insertions(+), 54 deletions(-) diff --git a/doc/src/sgml/postgresql-fdw.sgml b/doc/src/sgml/postgresql-fdw.sgml index 0d7791010c..36f1bbc7c4 100644 --- a/doc/src/sgml/postgresql-fdw.sgml +++ b/doc/src/sgml/postgresql-fdw.sgml @@ -33,7 +33,9 @@ Internally, it returns a pointer to a FdwRoutine 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. diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index 6a9c0eeccd..8149f343e7 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -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 { diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c index ecc730a311..b5a5be89e2 100644 --- a/src/backend/executor/nodeForeignscan.c +++ b/src/backend/executor/nodeForeignscan.c @@ -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); } diff --git a/src/backend/foreign/file_fdw.c b/src/backend/foreign/file_fdw.c index 707a3eeedc..852a49e88f 100644 --- a/src/backend/foreign/file_fdw.c +++ b/src/backend/foreign/file_fdw.c @@ -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. diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index adcff826fd..6a8faf8bde 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -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); } /* diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 2abda678bc..a47df10f2f 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -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); -- 2.39.5