diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 787b0b93cced229ab3d3ee1fde77c7784173a74d..09c230468bbced3ee108161d01fd990630466f82 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -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" diff --git a/src/backend/nodes/extensible.c b/src/backend/nodes/extensible.c index 2473b658b175bee07294533706dd4cf59b955d7d..d61be58c45dce3cc754ab734c82d0725ae32f0a8 100644 --- a/src/backend/nodes/extensible.c +++ b/src/backend/nodes/extensible.c @@ -24,61 +24,87 @@ #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); } diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 32d03f7f257ca483b6d340c0992bab0fe50fe6d4..83abaa68a386e2d7406fc6628faf73f3a30a3188 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -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 diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 6db0492e152ada149ccf6ee9a30bba67d50dffb1..cb0752a6ad895862df25c22ef4f48ae5809d6036 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -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(); diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index d159a17fd264ace9478945197343e827bc04151c..e4bc14a1510e0044fc79fe6a4491a15da4240545 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -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" diff --git a/src/include/executor/nodeCustom.h b/src/include/executor/nodeCustom.h index 410a3ad14db8e86cdc46b4126d99abf9938aacf4..9d0b3935288506e105a510620247181dc39dcd60 100644 --- a/src/include/executor/nodeCustom.h +++ b/src/include/executor/nodeCustom.h @@ -14,6 +14,7 @@ #include "access/parallel.h" #include "nodes/execnodes.h" +#include "nodes/extensible.h" /* * General executor code diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 0113e5c663cfaf4d18d6ba3a8f9d269208bfc4c7..bf2a09bc39c8085359fb140556324055b23e98af 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -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; /* ---------------------------------------------------------------- diff --git a/src/include/nodes/extensible.h b/src/include/nodes/extensible.h index 96ae7bc9291b9c71faad2d571132daf5fab9e239..9df1377a8e6943077dcec18aeba9469e775f03db 100644 --- a/src/include/nodes/extensible.h +++ b/src/include/nodes/extensible.h @@ -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 @@ -14,8 +14,13 @@ #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 */ diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 00b1d35d75993b03b3184a2c4c8e18520e3aa6cb..465d72fe890d697378ec4df121d74741f4ba2b6a 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -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; /* diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index ee7007aacec6ff1d92bb450ca84f5995481fdec2..32f04b25dde08699ac257cc3c749d31cd2d87816 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -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; /*