Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * extensible.c
4 : * Support for extensible node types
5 : *
6 : * Loadable modules can define what are in effect new types of nodes using
7 : * the routines in this file. All such nodes are flagged T_ExtensibleNode,
8 : * with the extnodename field distinguishing the specific type. Use
9 : * RegisterExtensibleNodeMethods to register a new type of extensible node,
10 : * and GetExtensibleNodeMethods to get information about a previously
11 : * registered type of extensible node.
12 : *
13 : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
14 : * Portions Copyright (c) 1994, Regents of the University of California
15 : *
16 : * IDENTIFICATION
17 : * src/backend/nodes/extensible.c
18 : *
19 : *-------------------------------------------------------------------------
20 : */
21 : #include "postgres.h"
22 :
23 : #include "nodes/extensible.h"
24 : #include "utils/hsearch.h"
25 :
26 : static HTAB *extensible_node_methods = NULL;
27 : static HTAB *custom_scan_methods = NULL;
28 :
29 : typedef struct
30 : {
31 : char extnodename[EXTNODENAME_MAX_LEN];
32 : const void *extnodemethods;
33 : } ExtensibleNodeEntry;
34 :
35 : /*
36 : * An internal function to register a new callback structure
37 : */
38 : static void
39 0 : RegisterExtensibleNodeEntry(HTAB **p_htable, const char *htable_label,
40 : const char *extnodename,
41 : const void *extnodemethods)
42 : {
43 : ExtensibleNodeEntry *entry;
44 : bool found;
45 :
46 0 : if (*p_htable == NULL)
47 : {
48 : HASHCTL ctl;
49 :
50 0 : ctl.keysize = EXTNODENAME_MAX_LEN;
51 0 : ctl.entrysize = sizeof(ExtensibleNodeEntry);
52 :
53 0 : *p_htable = hash_create(htable_label, 100, &ctl,
54 : HASH_ELEM | HASH_STRINGS);
55 : }
56 :
57 0 : if (strlen(extnodename) >= EXTNODENAME_MAX_LEN)
58 0 : elog(ERROR, "extensible node name is too long");
59 :
60 0 : entry = (ExtensibleNodeEntry *) hash_search(*p_htable,
61 : extnodename,
62 : HASH_ENTER, &found);
63 0 : if (found)
64 0 : ereport(ERROR,
65 : (errcode(ERRCODE_DUPLICATE_OBJECT),
66 : errmsg("extensible node type \"%s\" already exists",
67 : extnodename)));
68 :
69 0 : entry->extnodemethods = extnodemethods;
70 0 : }
71 :
72 : /*
73 : * Register a new type of extensible node.
74 : */
75 : void
76 0 : RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *methods)
77 : {
78 0 : RegisterExtensibleNodeEntry(&extensible_node_methods,
79 : "Extensible Node Methods",
80 : methods->extnodename,
81 : methods);
82 0 : }
83 :
84 : /*
85 : * Register a new type of custom scan node
86 : */
87 : void
88 0 : RegisterCustomScanMethods(const CustomScanMethods *methods)
89 : {
90 0 : RegisterExtensibleNodeEntry(&custom_scan_methods,
91 : "Custom Scan Methods",
92 : methods->CustomName,
93 : methods);
94 0 : }
95 :
96 : /*
97 : * An internal routine to get an ExtensibleNodeEntry by the given identifier
98 : */
99 : static const void *
100 0 : GetExtensibleNodeEntry(HTAB *htable, const char *extnodename, bool missing_ok)
101 : {
102 0 : ExtensibleNodeEntry *entry = NULL;
103 :
104 0 : if (htable != NULL)
105 0 : entry = (ExtensibleNodeEntry *) hash_search(htable,
106 : extnodename,
107 : HASH_FIND, NULL);
108 0 : if (!entry)
109 : {
110 0 : if (missing_ok)
111 0 : return NULL;
112 0 : ereport(ERROR,
113 : (errcode(ERRCODE_UNDEFINED_OBJECT),
114 : errmsg("ExtensibleNodeMethods \"%s\" was not registered",
115 : extnodename)));
116 : }
117 :
118 0 : return entry->extnodemethods;
119 : }
120 :
121 : /*
122 : * Get the methods for a given type of extensible node.
123 : */
124 : const ExtensibleNodeMethods *
125 0 : GetExtensibleNodeMethods(const char *extnodename, bool missing_ok)
126 : {
127 0 : return (const ExtensibleNodeMethods *)
128 0 : GetExtensibleNodeEntry(extensible_node_methods,
129 : extnodename,
130 : missing_ok);
131 : }
132 :
133 : /*
134 : * Get the methods for a given name of CustomScanMethods
135 : */
136 : const CustomScanMethods *
137 0 : GetCustomScanMethods(const char *CustomName, bool missing_ok)
138 : {
139 0 : return (const CustomScanMethods *)
140 0 : GetExtensibleNodeEntry(custom_scan_methods,
141 : CustomName,
142 : missing_ok);
143 : }
|