|
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 | #definePG_RMGR(symname,name,redo,desc,identify,startup,cleanup,mask,decode) \
|
35 | 39 | { name, redo, desc, identify, startup, cleanup, mask, decode },
|
36 | 40 |
|
37 |
| -constRmgrDataRmgrTable[RM_MAX_ID+1]= { |
| 41 | +RmgrDataRmgrTable[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 (intrmid=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 (intrmid=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(RmgrIdrmid) |
| 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(RmgrIdrmid,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 (intexisting_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 | +#definePG_GET_RESOURCE_MANAGERS_COLS 3 |
| 144 | +ReturnSetInfo*rsinfo= (ReturnSetInfo*)fcinfo->resultinfo; |
| 145 | +Datumvalues[PG_GET_RESOURCE_MANAGERS_COLS]; |
| 146 | +boolnulls[PG_GET_RESOURCE_MANAGERS_COLS]= {0}; |
| 147 | + |
| 148 | +SetSingleFuncCall(fcinfo,0); |
| 149 | + |
| 150 | +for (intrmid=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 | +} |