Rework custom scans to work more like the new extensible node stuff.
authorRobert Haas <rhaas@postgresql.org>
Tue, 29 Mar 2016 15:00:18 +0000 (11:00 -0400)
committerRobert Haas <rhaas@postgresql.org>
Tue, 29 Mar 2016 15:28:04 +0000 (11:28 -0400)
Per discussion, the new extensible node framework is thought to be
better designed than the custom path/scan/scanstate stuff we added
in PostgreSQL 9.5.  Rework the latter to be more like the former.

This is not backward-compatible, but we generally don't promise that
for C APIs, and there probably aren't many people using this yet
anyway.

KaiGai Kohei, reviewed by Petr Jelinek and me.  Some further
cosmetic changes by me.

src/backend/commands/explain.c
src/backend/nodes/extensible.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/plan/createplan.c
src/include/executor/nodeCustom.h
src/include/nodes/execnodes.h
src/include/nodes/extensible.h
src/include/nodes/plannodes.h
src/include/nodes/relation.h

index 787b0b93cced229ab3d3ee1fde77c7784173a74d..09c230468bbced3ee108161d01fd990630466f82 100644 (file)
@@ -21,6 +21,7 @@
 #include "commands/prepare.h"
 #include "executor/hashjoin.h"
 #include "foreign/fdwapi.h"
+#include "nodes/extensible.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/planmain.h"
index 2473b658b175bee07294533706dd4cf59b955d7d..d61be58c45dce3cc754ab734c82d0725ae32f0a8 100644 (file)
 #include "utils/hsearch.h"
 
 static HTAB *extensible_node_methods = NULL;
+static HTAB *custom_scan_methods = NULL;
 
 typedef struct
 {
        char            extnodename[EXTNODENAME_MAX_LEN];
-       const ExtensibleNodeMethods *methods;
+       const void *extnodemethods;
 } ExtensibleNodeEntry;
 
 /*
- * Register a new type of extensible node.
+ * An internal function to register a new callback structure 
  */
-void
-RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *methods)
+static void
+RegisterExtensibleNodeEntry(HTAB **p_htable, const char *htable_label,
+                                                       const char *extnodename,
+                                                       const void *extnodemethods)
 {
        ExtensibleNodeEntry *entry;
        bool            found;
 
-       if (extensible_node_methods == NULL)
+       if (*p_htable == NULL)
        {
                HASHCTL         ctl;
 
                memset(&ctl, 0, sizeof(HASHCTL));
                ctl.keysize = EXTNODENAME_MAX_LEN;
                ctl.entrysize = sizeof(ExtensibleNodeEntry);
-               extensible_node_methods = hash_create("Extensible Node Methods",
-                                                                                         100, &ctl, HASH_ELEM);
+
+               *p_htable = hash_create(htable_label, 100, &ctl, HASH_ELEM);
        }
 
-       if (strlen(methods->extnodename) >= EXTNODENAME_MAX_LEN)
+       if (strlen(extnodename) >= EXTNODENAME_MAX_LEN)
                elog(ERROR, "extensible node name is too long");
 
-       entry = (ExtensibleNodeEntry *) hash_search(extensible_node_methods,
-                                                                                               methods->extnodename,
+       entry = (ExtensibleNodeEntry *) hash_search(*p_htable,
+                                                                                               extnodename,
                                                                                                HASH_ENTER, &found);
        if (found)
                ereport(ERROR,
                                (errcode(ERRCODE_DUPLICATE_OBJECT),
                                 errmsg("extensible node type \"%s\" already exists",
-                                               methods->extnodename)));
+                                               extnodename)));
 
-       entry->methods = methods;
+       entry->extnodemethods = extnodemethods;
 }
 
 /*
- * Get the methods for a given type of extensible node.
+ * Register a new type of extensible node.
  */
-const ExtensibleNodeMethods *
-GetExtensibleNodeMethods(const char *extnodename, bool missing_ok)
+void
+RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *methods)
+{
+       RegisterExtensibleNodeEntry(&extensible_node_methods,
+                                                               "Extensible Node Methods",
+                                                               methods->extnodename,
+                                                               methods);
+}
+
+/*
+ * Register a new type of custom scan node
+ */
+void
+RegisterCustomScanMethods(const CustomScanMethods *methods)
+{
+       RegisterExtensibleNodeEntry(&custom_scan_methods,
+                                                               "Custom Scan Methods",
+                                                               methods->CustomName,
+                                                               methods);
+}
+
+/*
+ * An internal routine to get an ExtensibleNodeEntry by the given identifier
+ */
+static const void *
+GetExtensibleNodeEntry(HTAB *htable, const char *extnodename, bool missing_ok)
 {
        ExtensibleNodeEntry *entry = NULL;
 
-       if (extensible_node_methods != NULL)
-               entry = (ExtensibleNodeEntry *) hash_search(extensible_node_methods,
+       if (htable != NULL)
+               entry = (ExtensibleNodeEntry *) hash_search(htable,
                                                                                                        extnodename,
                                                                                                        HASH_FIND, NULL);
-
        if (!entry)
        {
                if (missing_ok)
@@ -89,5 +115,29 @@ GetExtensibleNodeMethods(const char *extnodename, bool missing_ok)
                                                extnodename)));
        }
 
-       return entry->methods;
+       return entry->extnodemethods;
+}
+
+/*
+ * Get the methods for a given type of extensible node.
+ */
+const ExtensibleNodeMethods *
+GetExtensibleNodeMethods(const char *extnodename, bool missing_ok)
+{
+       return (const ExtensibleNodeMethods *)
+               GetExtensibleNodeEntry(extensible_node_methods,
+                                                          extnodename,
+                                                          missing_ok);
+}
+
+/*
+ * Get the methods for a given name of CustomScanMethods
+ */
+const CustomScanMethods *
+GetCustomScanMethods(const char *CustomName, bool missing_ok)
+{
+       return (const CustomScanMethods *)
+               GetExtensibleNodeEntry(custom_scan_methods,
+                                                          CustomName,
+                                                          missing_ok);
 }
index 32d03f7f257ca483b6d340c0992bab0fe50fe6d4..83abaa68a386e2d7406fc6628faf73f3a30a3188 100644 (file)
@@ -632,11 +632,9 @@ _outCustomScan(StringInfo str, const CustomScan *node)
        WRITE_NODE_FIELD(custom_private);
        WRITE_NODE_FIELD(custom_scan_tlist);
        WRITE_BITMAPSET_FIELD(custom_relids);
-       /* Dump library and symbol name instead of raw pointer */
+       /* CustomName is a key to lookup CustomScanMethods */
        appendStringInfoString(str, " :methods ");
-       _outToken(str, node->methods->LibraryName);
-       appendStringInfoChar(str, ' ');
-       _outToken(str, node->methods->SymbolName);
+       _outToken(str, node->methods->CustomName);
 }
 
 static void
index 6db0492e152ada149ccf6ee9a30bba67d50dffb1..cb0752a6ad895862df25c22ef4f48ae5809d6036 100644 (file)
@@ -1827,8 +1827,7 @@ static CustomScan *
 _readCustomScan(void)
 {
        READ_LOCALS(CustomScan);
-       char       *library_name;
-       char       *symbol_name;
+       char       *custom_name;
        const CustomScanMethods *methods;
 
        ReadCommonScan(&local_node->scan);
@@ -1840,19 +1839,11 @@ _readCustomScan(void)
        READ_NODE_FIELD(custom_scan_tlist);
        READ_BITMAPSET_FIELD(custom_relids);
 
-       /*
-        * Reconstruction of methods using library and symbol name
-        */
+       /* Lookup CustomScanMethods by CustomName */
        token = pg_strtok(&length);             /* skip methods: */
-       token = pg_strtok(&length);             /* LibraryName */
-       library_name = nullable_string(token, length);
-       token = pg_strtok(&length);             /* SymbolName */
-       symbol_name = nullable_string(token, length);
-
-       methods = (const CustomScanMethods *)
-               load_external_function(library_name, symbol_name, true, NULL);
-       Assert(strcmp(methods->LibraryName, library_name) == 0 &&
-                  strcmp(methods->SymbolName, symbol_name) == 0);
+       token = pg_strtok(&length);             /* CustomName */
+       custom_name = nullable_string(token, length);
+       methods = GetCustomScanMethods(custom_name, false);
        local_node->methods = methods;
 
        READ_DONE();
index d159a17fd264ace9478945197343e827bc04151c..e4bc14a1510e0044fc79fe6a4491a15da4240545 100644 (file)
@@ -24,6 +24,7 @@
 #include "catalog/pg_class.h"
 #include "foreign/fdwapi.h"
 #include "miscadmin.h"
+#include "nodes/extensible.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
index 410a3ad14db8e86cdc46b4126d99abf9938aacf4..9d0b3935288506e105a510620247181dc39dcd60 100644 (file)
@@ -14,6 +14,7 @@
 
 #include "access/parallel.h"
 #include "nodes/execnodes.h"
+#include "nodes/extensible.h"
 
 /*
  * General executor code
index 0113e5c663cfaf4d18d6ba3a8f9d269208bfc4c7..bf2a09bc39c8085359fb140556324055b23e98af 100644 (file)
@@ -1606,38 +1606,7 @@ typedef struct ForeignScanState
  * the BeginCustomScan method.
  * ----------------
  */
-struct ParallelContext;                        /* avoid including parallel.h here */
-struct shm_toc;                                        /* avoid including shm_toc.h here */
-struct ExplainState;                   /* avoid including explain.h here */
-struct CustomScanState;
-
-typedef struct CustomExecMethods
-{
-       const char *CustomName;
-
-       /* Executor methods: mark/restore are optional, the rest are required */
-       void            (*BeginCustomScan) (struct CustomScanState *node,
-                                                                                               EState *estate,
-                                                                                               int eflags);
-       TupleTableSlot *(*ExecCustomScan) (struct CustomScanState *node);
-       void            (*EndCustomScan) (struct CustomScanState *node);
-       void            (*ReScanCustomScan) (struct CustomScanState *node);
-       void            (*MarkPosCustomScan) (struct CustomScanState *node);
-       void            (*RestrPosCustomScan) (struct CustomScanState *node);
-       /* Optional: parallel execution support */
-       Size            (*EstimateDSMCustomScan) (struct CustomScanState *node,
-                                                                                          struct ParallelContext *pcxt);
-       void            (*InitializeDSMCustomScan) (struct CustomScanState *node,
-                                                                                               struct ParallelContext *pcxt,
-                                                                                                               void *coordinate);
-       void            (*InitializeWorkerCustomScan) (struct CustomScanState *node,
-                                                                                                                struct shm_toc *toc,
-                                                                                                                  void *coordinate);
-       /* Optional: print additional information in EXPLAIN */
-       void            (*ExplainCustomScan) (struct CustomScanState *node,
-                                                                                                 List *ancestors,
-                                                                                                 struct ExplainState *es);
-} CustomExecMethods;
+struct CustomExecMethods;
 
 typedef struct CustomScanState
 {
@@ -1645,7 +1614,7 @@ typedef struct CustomScanState
        uint32          flags;                  /* mask of CUSTOMPATH_* flags, see relation.h */
        List       *custom_ps;          /* list of child PlanState nodes, if any */
        Size            pscan_len;              /* size of parallel coordination information */
-       const CustomExecMethods *methods;
+       const struct CustomExecMethods *methods;
 } CustomScanState;
 
 /* ----------------------------------------------------------------
index 96ae7bc9291b9c71faad2d571132daf5fab9e239..9df1377a8e6943077dcec18aeba9469e775f03db 100644 (file)
@@ -1,7 +1,7 @@
 /*-------------------------------------------------------------------------
  *
  * extensible.h
- *    Definitions for extensible node type
+ *    Definitions for extensible nodes and custom scans
  *
  *
  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
 #ifndef EXTENSIBLE_H
 #define EXTENSIBLE_H
 
-#include "nodes/nodes.h"
+#include "access/parallel.h"
+#include "commands/explain.h"
+#include "nodes/execnodes.h"
+#include "nodes/plannodes.h"
+#include "nodes/relation.h"
 
+/* maximum length of an extensible node identifier */
 #define EXTNODENAME_MAX_LEN                                    64
 
 /*
@@ -69,4 +74,80 @@ extern void RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *method);
 extern const ExtensibleNodeMethods *GetExtensibleNodeMethods(const char *name,
                                                 bool missing_ok);
 
+/*
+ * Flags for custom paths, indicating what capabilities the resulting scan
+ * will have.
+ */
+#define CUSTOMPATH_SUPPORT_BACKWARD_SCAN       0x0001
+#define CUSTOMPATH_SUPPORT_MARK_RESTORE                0x0002
+
+/*
+ * Custom path methods.  Mostly, we just need to know how to convert a
+ * CustomPath to a plan.
+ */
+typedef struct CustomPathMethods
+{
+       const char *CustomName;
+
+       /* Convert Path to a Plan */
+       struct Plan *(*PlanCustomPath) (PlannerInfo *root,
+                                                                       RelOptInfo *rel,
+                                                                       struct CustomPath *best_path,
+                                                                       List *tlist,
+                                                                       List *clauses,
+                                                                       List *custom_plans);
+} CustomPathMethods;
+
+/*
+ * Custom scan.  Here again, there's not much to do: we need to be able to
+ * generate a ScanState corresponding to the scan.
+ */
+typedef struct CustomScanMethods
+{
+       const char *CustomName;
+
+       /* Create execution state (CustomScanState) from a CustomScan plan node */
+       Node       *(*CreateCustomScanState) (CustomScan *cscan);
+} CustomScanMethods;
+
+/*
+ * Execution-time methods for a CustomScanState.  This is more complex than
+ * what we need for a custom path or scan.
+ */
+typedef struct CustomExecMethods
+{
+       const char *CustomName;
+
+       /* Required executor methods */
+       void            (*BeginCustomScan) (CustomScanState *node,
+                                                                       EState *estate,
+                                                                       int eflags);
+       TupleTableSlot *(*ExecCustomScan) (CustomScanState *node);
+       void            (*EndCustomScan) (CustomScanState *node);
+       void            (*ReScanCustomScan) (CustomScanState *node);
+
+       /* Optional methods: needed if mark/restore is supported */
+       void            (*MarkPosCustomScan) (CustomScanState *node);
+       void            (*RestrPosCustomScan) (CustomScanState *node);
+
+       /* Optional methods: needed if parallel execution is supported */
+       Size            (*EstimateDSMCustomScan) (CustomScanState *node,
+                                                                                 ParallelContext *pcxt);
+       void            (*InitializeDSMCustomScan) (CustomScanState *node,
+                                                                                       ParallelContext *pcxt,
+                                                                                       void *coordinate);
+       void            (*InitializeWorkerCustomScan) (CustomScanState *node,
+                                                                                          shm_toc *toc,
+                                                                                          void *coordinate);
+
+       /* Optional: print additional information in EXPLAIN */
+       void            (*ExplainCustomScan) (CustomScanState *node,
+                                                                         List *ancestors,
+                                                                         ExplainState *es);
+} CustomExecMethods;
+
+extern void RegisterCustomScanMethods(const CustomScanMethods *methods);
+extern const CustomScanMethods *GetCustomScanMethods(const char *CustomName,
+                                                                                                        bool missing_ok);
+
 #endif /* EXTENSIBLE_H */
index 00b1d35d75993b03b3184a2c4c8e18520e3aa6cb..465d72fe890d697378ec4df121d74741f4ba2b6a 100644 (file)
@@ -555,17 +555,7 @@ typedef struct ForeignScan
  * a larger struct will not work.
  * ----------------
  */
-struct CustomScan;
-
-typedef struct CustomScanMethods
-{
-       const char *CustomName;
-       const char *LibraryName;
-       const char *SymbolName;
-
-       /* Create execution state (CustomScanState) from a CustomScan plan node */
-       Node       *(*CreateCustomScanState) (struct CustomScan *cscan);
-} CustomScanMethods;
+struct CustomScanMethods;
 
 typedef struct CustomScan
 {
@@ -577,7 +567,7 @@ typedef struct CustomScan
        List       *custom_scan_tlist;          /* optional tlist describing scan
                                                                                 * tuple */
        Bitmapset  *custom_relids;      /* RTIs generated by this scan */
-       const CustomScanMethods *methods;
+       const struct CustomScanMethods *methods;
 } CustomScan;
 
 /*
index ee7007aacec6ff1d92bb450ca84f5995481fdec2..32f04b25dde08699ac257cc3c749d31cd2d87816 100644 (file)
@@ -1030,23 +1030,8 @@ typedef struct ForeignPath
  * FDW case, we provide a "custom_private" field in CustomPath; providers
  * may prefer to use that rather than define another struct type.
  */
-struct CustomPath;
 
-#define CUSTOMPATH_SUPPORT_BACKWARD_SCAN       0x0001
-#define CUSTOMPATH_SUPPORT_MARK_RESTORE                0x0002
-
-typedef struct CustomPathMethods
-{
-       const char *CustomName;
-
-       /* Convert Path to a Plan */
-       struct Plan *(*PlanCustomPath) (PlannerInfo *root,
-                                                                                               RelOptInfo *rel,
-                                                                                               struct CustomPath *best_path,
-                                                                                               List *tlist,
-                                                                                               List *clauses,
-                                                                                               List *custom_plans);
-} CustomPathMethods;
+struct CustomPathMethods;
 
 typedef struct CustomPath
 {
@@ -1054,7 +1039,7 @@ typedef struct CustomPath
        uint32          flags;                  /* mask of CUSTOMPATH_* flags, see above */
        List       *custom_paths;       /* list of child Path nodes, if any */
        List       *custom_private;
-       const CustomPathMethods *methods;
+       const struct CustomPathMethods *methods;
 } CustomPath;
 
 /*