Coverage Report

Created: 2025-06-13 06:06

/src/postgres/src/backend/nodes/extensible.c
Line
Count
Source (jump to first uncovered line)
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-2025, 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
RegisterExtensibleNodeEntry(HTAB **p_htable, const char *htable_label,
40
              const char *extnodename,
41
              const void *extnodemethods)
42
0
{
43
0
  ExtensibleNodeEntry *entry;
44
0
  bool    found;
45
46
0
  if (*p_htable == NULL)
47
0
  {
48
0
    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
0
                HASH_ELEM | HASH_STRINGS);
55
0
  }
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
0
                        extnodename,
62
0
                        HASH_ENTER, &found);
63
0
  if (found)
64
0
    ereport(ERROR,
65
0
        (errcode(ERRCODE_DUPLICATE_OBJECT),
66
0
         errmsg("extensible node type \"%s\" already exists",
67
0
            extnodename)));
68
69
0
  entry->extnodemethods = extnodemethods;
70
0
}
71
72
/*
73
 * Register a new type of extensible node.
74
 */
75
void
76
RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *methods)
77
0
{
78
0
  RegisterExtensibleNodeEntry(&extensible_node_methods,
79
0
                "Extensible Node Methods",
80
0
                methods->extnodename,
81
0
                methods);
82
0
}
83
84
/*
85
 * Register a new type of custom scan node
86
 */
87
void
88
RegisterCustomScanMethods(const CustomScanMethods *methods)
89
0
{
90
0
  RegisterExtensibleNodeEntry(&custom_scan_methods,
91
0
                "Custom Scan Methods",
92
0
                methods->CustomName,
93
0
                methods);
94
0
}
95
96
/*
97
 * An internal routine to get an ExtensibleNodeEntry by the given identifier
98
 */
99
static const void *
100
GetExtensibleNodeEntry(HTAB *htable, const char *extnodename, bool missing_ok)
101
0
{
102
0
  ExtensibleNodeEntry *entry = NULL;
103
104
0
  if (htable != NULL)
105
0
    entry = (ExtensibleNodeEntry *) hash_search(htable,
106
0
                          extnodename,
107
0
                          HASH_FIND, NULL);
108
0
  if (!entry)
109
0
  {
110
0
    if (missing_ok)
111
0
      return NULL;
112
0
    ereport(ERROR,
113
0
        (errcode(ERRCODE_UNDEFINED_OBJECT),
114
0
         errmsg("ExtensibleNodeMethods \"%s\" was not registered",
115
0
            extnodename)));
116
0
  }
117
118
0
  return entry->extnodemethods;
119
0
}
120
121
/*
122
 * Get the methods for a given type of extensible node.
123
 */
124
const ExtensibleNodeMethods *
125
GetExtensibleNodeMethods(const char *extnodename, bool missing_ok)
126
0
{
127
0
  return (const ExtensibleNodeMethods *)
128
0
    GetExtensibleNodeEntry(extensible_node_methods,
129
0
                 extnodename,
130
0
                 missing_ok);
131
0
}
132
133
/*
134
 * Get the methods for a given name of CustomScanMethods
135
 */
136
const CustomScanMethods *
137
GetCustomScanMethods(const char *CustomName, bool missing_ok)
138
0
{
139
0
  return (const CustomScanMethods *)
140
0
    GetExtensibleNodeEntry(custom_scan_methods,
141
0
                 CustomName,
142
0
                 missing_ok);
143
0
}