Commit f9143d10 authored by Robert Haas's avatar Robert Haas

Rework custom scans to work more like the new extensible node stuff.

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.
parent 534da379
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "commands/prepare.h" #include "commands/prepare.h"
#include "executor/hashjoin.h" #include "executor/hashjoin.h"
#include "foreign/fdwapi.h" #include "foreign/fdwapi.h"
#include "nodes/extensible.h"
#include "nodes/nodeFuncs.h" #include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/planmain.h" #include "optimizer/planmain.h"
......
...@@ -24,61 +24,87 @@ ...@@ -24,61 +24,87 @@
#include "utils/hsearch.h" #include "utils/hsearch.h"
static HTAB *extensible_node_methods = NULL; static HTAB *extensible_node_methods = NULL;
static HTAB *custom_scan_methods = NULL;
typedef struct typedef struct
{ {
char extnodename[EXTNODENAME_MAX_LEN]; char extnodename[EXTNODENAME_MAX_LEN];
const ExtensibleNodeMethods *methods; const void *extnodemethods;
} ExtensibleNodeEntry; } ExtensibleNodeEntry;
/* /*
* Register a new type of extensible node. * An internal function to register a new callback structure
*/ */
void static void
RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *methods) RegisterExtensibleNodeEntry(HTAB **p_htable, const char *htable_label,
const char *extnodename,
const void *extnodemethods)
{ {
ExtensibleNodeEntry *entry; ExtensibleNodeEntry *entry;
bool found; bool found;
if (extensible_node_methods == NULL) if (*p_htable == NULL)
{ {
HASHCTL ctl; HASHCTL ctl;
memset(&ctl, 0, sizeof(HASHCTL)); memset(&ctl, 0, sizeof(HASHCTL));
ctl.keysize = EXTNODENAME_MAX_LEN; ctl.keysize = EXTNODENAME_MAX_LEN;
ctl.entrysize = sizeof(ExtensibleNodeEntry); 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"); elog(ERROR, "extensible node name is too long");
entry = (ExtensibleNodeEntry *) hash_search(extensible_node_methods, entry = (ExtensibleNodeEntry *) hash_search(*p_htable,
methods->extnodename, extnodename,
HASH_ENTER, &found); HASH_ENTER, &found);
if (found) if (found)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT), (errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("extensible node type \"%s\" already exists", 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 * void
GetExtensibleNodeMethods(const char *extnodename, bool missing_ok) 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; ExtensibleNodeEntry *entry = NULL;
if (extensible_node_methods != NULL) if (htable != NULL)
entry = (ExtensibleNodeEntry *) hash_search(extensible_node_methods, entry = (ExtensibleNodeEntry *) hash_search(htable,
extnodename, extnodename,
HASH_FIND, NULL); HASH_FIND, NULL);
if (!entry) if (!entry)
{ {
if (missing_ok) if (missing_ok)
...@@ -89,5 +115,29 @@ GetExtensibleNodeMethods(const char *extnodename, bool missing_ok) ...@@ -89,5 +115,29 @@ GetExtensibleNodeMethods(const char *extnodename, bool missing_ok)
extnodename))); 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);
} }
...@@ -632,11 +632,9 @@ _outCustomScan(StringInfo str, const CustomScan *node) ...@@ -632,11 +632,9 @@ _outCustomScan(StringInfo str, const CustomScan *node)
WRITE_NODE_FIELD(custom_private); WRITE_NODE_FIELD(custom_private);
WRITE_NODE_FIELD(custom_scan_tlist); WRITE_NODE_FIELD(custom_scan_tlist);
WRITE_BITMAPSET_FIELD(custom_relids); WRITE_BITMAPSET_FIELD(custom_relids);
/* Dump library and symbol name instead of raw pointer */ /* CustomName is a key to lookup CustomScanMethods */
appendStringInfoString(str, " :methods "); appendStringInfoString(str, " :methods ");
_outToken(str, node->methods->LibraryName); _outToken(str, node->methods->CustomName);
appendStringInfoChar(str, ' ');
_outToken(str, node->methods->SymbolName);
} }
static void static void
......
...@@ -1827,8 +1827,7 @@ static CustomScan * ...@@ -1827,8 +1827,7 @@ static CustomScan *
_readCustomScan(void) _readCustomScan(void)
{ {
READ_LOCALS(CustomScan); READ_LOCALS(CustomScan);
char *library_name; char *custom_name;
char *symbol_name;
const CustomScanMethods *methods; const CustomScanMethods *methods;
ReadCommonScan(&local_node->scan); ReadCommonScan(&local_node->scan);
...@@ -1840,19 +1839,11 @@ _readCustomScan(void) ...@@ -1840,19 +1839,11 @@ _readCustomScan(void)
READ_NODE_FIELD(custom_scan_tlist); READ_NODE_FIELD(custom_scan_tlist);
READ_BITMAPSET_FIELD(custom_relids); READ_BITMAPSET_FIELD(custom_relids);
/* /* Lookup CustomScanMethods by CustomName */
* Reconstruction of methods using library and symbol name
*/
token = pg_strtok(&length); /* skip methods: */ token = pg_strtok(&length); /* skip methods: */
token = pg_strtok(&length); /* LibraryName */ token = pg_strtok(&length); /* CustomName */
library_name = nullable_string(token, length); custom_name = nullable_string(token, length);
token = pg_strtok(&length); /* SymbolName */ methods = GetCustomScanMethods(custom_name, false);
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);
local_node->methods = methods; local_node->methods = methods;
READ_DONE(); READ_DONE();
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "catalog/pg_class.h" #include "catalog/pg_class.h"
#include "foreign/fdwapi.h" #include "foreign/fdwapi.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/extensible.h"
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h" #include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "access/parallel.h" #include "access/parallel.h"
#include "nodes/execnodes.h" #include "nodes/execnodes.h"
#include "nodes/extensible.h"
/* /*
* General executor code * General executor code
......
...@@ -1606,38 +1606,7 @@ typedef struct ForeignScanState ...@@ -1606,38 +1606,7 @@ typedef struct ForeignScanState
* the BeginCustomScan method. * the BeginCustomScan method.
* ---------------- * ----------------
*/ */
struct ParallelContext; /* avoid including parallel.h here */ struct CustomExecMethods;
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;
typedef struct CustomScanState typedef struct CustomScanState
{ {
...@@ -1645,7 +1614,7 @@ typedef struct CustomScanState ...@@ -1645,7 +1614,7 @@ typedef struct CustomScanState
uint32 flags; /* mask of CUSTOMPATH_* flags, see relation.h */ uint32 flags; /* mask of CUSTOMPATH_* flags, see relation.h */
List *custom_ps; /* list of child PlanState nodes, if any */ List *custom_ps; /* list of child PlanState nodes, if any */
Size pscan_len; /* size of parallel coordination information */ Size pscan_len; /* size of parallel coordination information */
const CustomExecMethods *methods; const struct CustomExecMethods *methods;
} CustomScanState; } CustomScanState;
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* extensible.h * extensible.h
* Definitions for extensible node type * Definitions for extensible nodes and custom scans
* *
* *
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
...@@ -14,8 +14,13 @@ ...@@ -14,8 +14,13 @@
#ifndef EXTENSIBLE_H #ifndef EXTENSIBLE_H
#define 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 #define EXTNODENAME_MAX_LEN 64
/* /*
...@@ -69,4 +74,80 @@ extern void RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *method); ...@@ -69,4 +74,80 @@ extern void RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *method);
extern const ExtensibleNodeMethods *GetExtensibleNodeMethods(const char *name, extern const ExtensibleNodeMethods *GetExtensibleNodeMethods(const char *name,
bool missing_ok); 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 */ #endif /* EXTENSIBLE_H */
...@@ -555,17 +555,7 @@ typedef struct ForeignScan ...@@ -555,17 +555,7 @@ typedef struct ForeignScan
* a larger struct will not work. * a larger struct will not work.
* ---------------- * ----------------
*/ */
struct CustomScan; struct CustomScanMethods;
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;
typedef struct CustomScan typedef struct CustomScan
{ {
...@@ -577,7 +567,7 @@ typedef struct CustomScan ...@@ -577,7 +567,7 @@ typedef struct CustomScan
List *custom_scan_tlist; /* optional tlist describing scan List *custom_scan_tlist; /* optional tlist describing scan
* tuple */ * tuple */
Bitmapset *custom_relids; /* RTIs generated by this scan */ Bitmapset *custom_relids; /* RTIs generated by this scan */
const CustomScanMethods *methods; const struct CustomScanMethods *methods;
} CustomScan; } CustomScan;
/* /*
......
...@@ -1030,23 +1030,8 @@ typedef struct ForeignPath ...@@ -1030,23 +1030,8 @@ typedef struct ForeignPath
* FDW case, we provide a "custom_private" field in CustomPath; providers * FDW case, we provide a "custom_private" field in CustomPath; providers
* may prefer to use that rather than define another struct type. * may prefer to use that rather than define another struct type.
*/ */
struct CustomPath;
#define CUSTOMPATH_SUPPORT_BACKWARD_SCAN 0x0001 struct CustomPathMethods;
#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;
typedef struct CustomPath typedef struct CustomPath
{ {
...@@ -1054,7 +1039,7 @@ typedef struct CustomPath ...@@ -1054,7 +1039,7 @@ typedef struct CustomPath
uint32 flags; /* mask of CUSTOMPATH_* flags, see above */ uint32 flags; /* mask of CUSTOMPATH_* flags, see above */
List *custom_paths; /* list of child Path nodes, if any */ List *custom_paths; /* list of child Path nodes, if any */
List *custom_private; List *custom_private;
const CustomPathMethods *methods; const struct CustomPathMethods *methods;
} CustomPath; } CustomPath;
/* /*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment