|
24 | 24 | #include "commands/dbcommands_xlog.h"
|
25 | 25 | #include "commands/sequence.h"
|
26 | 26 | #include "commands/tablespace.h"
|
| 27 | +#include "fmgr.h" |
| 28 | +#include "funcapi.h" |
| 29 | +#include "miscadmin.h" |
27 | 30 | #include "replication/decode.h"
|
28 | 31 | #include "replication/message.h"
|
29 | 32 | #include "replication/origin.h"
|
30 | 33 | #include "storage/standby.h"
|
| 34 | +#include "utils/builtins.h" |
31 | 35 | #include "utils/relmapper.h"
|
32 | 36 |
|
33 | 37 | /* must be kept in sync with RmgrData definition in xlog_internal.h */
|
34 | 38 | #define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup,mask,decode) \
|
35 | 39 | { name, redo, desc, identify, startup, cleanup, mask, decode },
|
36 | 40 |
|
37 |
| -const RmgrData RmgrTable[RM_MAX_ID + 1] = { |
| 41 | +RmgrData RmgrTable[RM_MAX_ID + 1] = { |
38 | 42 | #include "access/rmgrlist.h"
|
39 | 43 | };
|
| 44 | + |
| 45 | +/* |
| 46 | + * Start up all resource managers. |
| 47 | + */ |
| 48 | +void |
| 49 | +RmgrStartup(void) |
| 50 | +{ |
| 51 | + for (int rmid = 0; rmid <= RM_MAX_ID; rmid++) |
| 52 | + { |
| 53 | + if (!RmgrIdExists(rmid)) |
| 54 | + continue; |
| 55 | + |
| 56 | + if (RmgrTable[rmid].rm_startup != NULL) |
| 57 | + RmgrTable[rmid].rm_startup(); |
| 58 | + } |
| 59 | +} |
| 60 | + |
| 61 | +/* |
| 62 | + * Clean up all resource managers. |
| 63 | + */ |
| 64 | +void |
| 65 | +RmgrCleanup(void) |
| 66 | +{ |
| 67 | + for (int rmid = 0; rmid <= RM_MAX_ID; rmid++) |
| 68 | + { |
| 69 | + if (!RmgrIdExists(rmid)) |
| 70 | + continue; |
| 71 | + |
| 72 | + if (RmgrTable[rmid].rm_cleanup != NULL) |
| 73 | + RmgrTable[rmid].rm_cleanup(); |
| 74 | + } |
| 75 | +} |
| 76 | + |
| 77 | +/* |
| 78 | + * Emit ERROR when we encounter a record with an RmgrId we don't |
| 79 | + * recognize. |
| 80 | + */ |
| 81 | +void |
| 82 | +RmgrNotFound(RmgrId rmid) |
| 83 | +{ |
| 84 | + ereport(ERROR, (errmsg("resource manager with ID %d not registered", rmid), |
| 85 | + errhint("Include the extension module that implements this resource manager in shared_preload_libraries."))); |
| 86 | +} |
| 87 | + |
| 88 | +/* |
| 89 | + * Register a new custom WAL resource manager. |
| 90 | + * |
| 91 | + * Resource manager IDs must be globally unique across all extensions. Refer |
| 92 | + * to https://wiki.postgresql.org/wiki/CustomWALResourceManager to reserve a |
| 93 | + * unique RmgrId for your extension, to avoid conflicts with other extension |
| 94 | + * developers. During development, use RM_EXPERIMENTAL_ID to avoid needlessly |
| 95 | + * reserving a new ID. |
| 96 | + */ |
| 97 | +void |
| 98 | +RegisterCustomRmgr(RmgrId rmid, RmgrData *rmgr) |
| 99 | +{ |
| 100 | + if (rmgr->rm_name == NULL || strlen(rmgr->rm_name) == 0) |
| 101 | + ereport(ERROR, (errmsg("custom resource manager name is invalid"), |
| 102 | + errhint("Provide a non-empty name for the custom resource manager."))); |
| 103 | + |
| 104 | + if (!RMID_IS_CUSTOM(rmid)) |
| 105 | + ereport(ERROR, (errmsg("custom resource manager ID %d is out of range", rmid), |
| 106 | + errhint("Provide a custom resource manager ID between %d and %d.", |
| 107 | + RM_MIN_CUSTOM_ID, RM_MAX_CUSTOM_ID))); |
| 108 | + |
| 109 | + if (!process_shared_preload_libraries_in_progress) |
| 110 | + ereport(ERROR, |
| 111 | + (errmsg("failed to register custom resource manager \"%s\" with ID %d", rmgr->rm_name, rmid), |
| 112 | + errdetail("Custom resource manager must be registered while initializing modules in shared_preload_libraries."))); |
| 113 | + |
| 114 | + if (RmgrTable[rmid].rm_name != NULL) |
| 115 | + ereport(ERROR, |
| 116 | + (errmsg("failed to register custom resource manager \"%s\" with ID %d", rmgr->rm_name, rmid), |
| 117 | + errdetail("Custom resource manager \"%s\" already registered with the same ID.", |
| 118 | + RmgrTable[rmid].rm_name))); |
| 119 | + |
| 120 | + /* check for existing rmgr with the same name */ |
| 121 | + for (int existing_rmid = 0; existing_rmid <= RM_MAX_ID; existing_rmid++) |
| 122 | + { |
| 123 | + if (!RmgrIdExists(existing_rmid)) |
| 124 | + continue; |
| 125 | + |
| 126 | + if (!pg_strcasecmp(RmgrTable[existing_rmid].rm_name, rmgr->rm_name)) |
| 127 | + ereport(ERROR, |
| 128 | + (errmsg("failed to register custom resource manager \"%s\" with ID %d", rmgr->rm_name, rmid), |
| 129 | + errdetail("Existing resource manager with ID %d has the same name.", existing_rmid))); |
| 130 | + } |
| 131 | + |
| 132 | + /* register it */ |
| 133 | + RmgrTable[rmid] = *rmgr; |
| 134 | + ereport(LOG, |
| 135 | + (errmsg("registered custom resource manager \"%s\" with ID %d", |
| 136 | + rmgr->rm_name, rmid))); |
| 137 | +} |
| 138 | + |
| 139 | +/* SQL SRF showing loaded resource managers */ |
| 140 | +Datum |
| 141 | +pg_get_wal_resource_managers(PG_FUNCTION_ARGS) |
| 142 | +{ |
| 143 | +#define PG_GET_RESOURCE_MANAGERS_COLS 3 |
| 144 | + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; |
| 145 | + Datum values[PG_GET_RESOURCE_MANAGERS_COLS]; |
| 146 | + bool nulls[PG_GET_RESOURCE_MANAGERS_COLS] = {0}; |
| 147 | + |
| 148 | + SetSingleFuncCall(fcinfo, 0); |
| 149 | + |
| 150 | + for (int rmid = 0; rmid <= RM_MAX_ID; rmid++) |
| 151 | + { |
| 152 | + if (!RmgrIdExists(rmid)) |
| 153 | + continue; |
| 154 | + values[0] = Int32GetDatum(rmid); |
| 155 | + values[1] = CStringGetTextDatum(GetRmgr(rmid).rm_name); |
| 156 | + values[2] = BoolGetDatum(RMID_IS_BUILTIN(rmid)); |
| 157 | + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); |
| 158 | + } |
| 159 | + |
| 160 | + return (Datum) 0; |
| 161 | +} |
0 commit comments