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 @@
#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"
......
......@@ -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);
}
......@@ -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
......
......@@ -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();
......
......@@ -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"
......
......@@ -14,6 +14,7 @@
#include "access/parallel.h"
#include "nodes/execnodes.h"
#include "nodes/extensible.h"
/*
* General executor code
......
......@@ -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;
/* ----------------------------------------------------------------
......
/*-------------------------------------------------------------------------
*
* 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 */
......@@ -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;
/*
......
......@@ -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;
/*
......
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