mirror of
https://github.com/postgres/postgres.git
synced 2025-06-26 12:21:12 +03:00
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.
This commit is contained in:
@ -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;
|
||||
|
||||
/*
|
||||
* An internal function to register a new callback structure
|
||||
*/
|
||||
static void
|
||||
RegisterExtensibleNodeEntry(HTAB **p_htable, const char *htable_label,
|
||||
const char *extnodename,
|
||||
const void *extnodemethods)
|
||||
{
|
||||
ExtensibleNodeEntry *entry;
|
||||
bool found;
|
||||
|
||||
if (*p_htable == NULL)
|
||||
{
|
||||
HASHCTL ctl;
|
||||
|
||||
memset(&ctl, 0, sizeof(HASHCTL));
|
||||
ctl.keysize = EXTNODENAME_MAX_LEN;
|
||||
ctl.entrysize = sizeof(ExtensibleNodeEntry);
|
||||
|
||||
*p_htable = hash_create(htable_label, 100, &ctl, HASH_ELEM);
|
||||
}
|
||||
|
||||
if (strlen(extnodename) >= EXTNODENAME_MAX_LEN)
|
||||
elog(ERROR, "extensible node name is too long");
|
||||
|
||||
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",
|
||||
extnodename)));
|
||||
|
||||
entry->extnodemethods = extnodemethods;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register a new type of extensible node.
|
||||
*/
|
||||
void
|
||||
RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *methods)
|
||||
{
|
||||
ExtensibleNodeEntry *entry;
|
||||
bool found;
|
||||
|
||||
if (extensible_node_methods == 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);
|
||||
}
|
||||
|
||||
if (strlen(methods->extnodename) >= EXTNODENAME_MAX_LEN)
|
||||
elog(ERROR, "extensible node name is too long");
|
||||
|
||||
entry = (ExtensibleNodeEntry *) hash_search(extensible_node_methods,
|
||||
methods->extnodename,
|
||||
HASH_ENTER, &found);
|
||||
if (found)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
||||
errmsg("extensible node type \"%s\" already exists",
|
||||
methods->extnodename)));
|
||||
|
||||
entry->methods = methods;
|
||||
RegisterExtensibleNodeEntry(&extensible_node_methods,
|
||||
"Extensible Node Methods",
|
||||
methods->extnodename,
|
||||
methods);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the methods for a given type of extensible node.
|
||||
* Register a new type of custom scan node
|
||||
*/
|
||||
const ExtensibleNodeMethods *
|
||||
GetExtensibleNodeMethods(const char *extnodename, bool missing_ok)
|
||||
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();
|
||||
|
Reference in New Issue
Block a user