| 1 | /*------------------------------------------------------------------------- | 
| 2 |  * | 
| 3 |  * reloptions.h | 
| 4 |  *	  Core support for relation and tablespace options (pg_class.reloptions | 
| 5 |  *	  and pg_tablespace.spcoptions) | 
| 6 |  * | 
| 7 |  * Note: the functions dealing with text-array reloptions values declare | 
| 8 |  * them as Datum, not ArrayType *, to avoid needing to include array.h | 
| 9 |  * into a lot of low-level code. | 
| 10 |  * | 
| 11 |  * | 
| 12 |  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group | 
| 13 |  * Portions Copyright (c) 1994, Regents of the University of California | 
| 14 |  * | 
| 15 |  * src/include/access/reloptions.h | 
| 16 |  * | 
| 17 |  *------------------------------------------------------------------------- | 
| 18 |  */ | 
| 19 | #ifndef RELOPTIONS_H | 
| 20 | #define RELOPTIONS_H | 
| 21 |  | 
| 22 | #include "access/amapi.h" | 
| 23 | #include "access/htup.h" | 
| 24 | #include "access/tupdesc.h" | 
| 25 | #include "nodes/pg_list.h" | 
| 26 | #include "storage/lock.h" | 
| 27 |  | 
| 28 | /* types supported by reloptions */ | 
| 29 | typedef enum relopt_type | 
| 30 | { | 
| 31 | 	RELOPT_TYPE_BOOL, | 
| 32 | 	RELOPT_TYPE_INT, | 
| 33 | 	RELOPT_TYPE_REAL, | 
| 34 | 	RELOPT_TYPE_STRING | 
| 35 | } relopt_type; | 
| 36 |  | 
| 37 | /* kinds supported by reloptions */ | 
| 38 | typedef enum relopt_kind | 
| 39 | { | 
| 40 | 	RELOPT_KIND_HEAP = (1 << 0), | 
| 41 | 	RELOPT_KIND_TOAST = (1 << 1), | 
| 42 | 	RELOPT_KIND_BTREE = (1 << 2), | 
| 43 | 	RELOPT_KIND_HASH = (1 << 3), | 
| 44 | 	RELOPT_KIND_GIN = (1 << 4), | 
| 45 | 	RELOPT_KIND_GIST = (1 << 5), | 
| 46 | 	RELOPT_KIND_ATTRIBUTE = (1 << 6), | 
| 47 | 	RELOPT_KIND_TABLESPACE = (1 << 7), | 
| 48 | 	RELOPT_KIND_SPGIST = (1 << 8), | 
| 49 | 	RELOPT_KIND_VIEW = (1 << 9), | 
| 50 | 	RELOPT_KIND_BRIN = (1 << 10), | 
| 51 | 	RELOPT_KIND_PARTITIONED = (1 << 11), | 
| 52 | 	/* if you add a new kind, make sure you update "last_default" too */ | 
| 53 | 	RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_PARTITIONED, | 
| 54 | 	/* some compilers treat enums as signed ints, so we can't use 1 << 31 */ | 
| 55 | 	RELOPT_KIND_MAX = (1 << 30) | 
| 56 | } relopt_kind; | 
| 57 |  | 
| 58 | /* reloption namespaces allowed for heaps -- currently only TOAST */ | 
| 59 | #define HEAP_RELOPT_NAMESPACES { "toast", NULL } | 
| 60 |  | 
| 61 | /* generic struct to hold shared data */ | 
| 62 | typedef struct relopt_gen | 
| 63 | { | 
| 64 | 	const char *name;			/* must be first (used as list termination | 
| 65 | 								 * marker) */ | 
| 66 | 	const char *desc; | 
| 67 | 	bits32		kinds; | 
| 68 | 	LOCKMODE	lockmode; | 
| 69 | 	int			namelen; | 
| 70 | 	relopt_type type; | 
| 71 | } relopt_gen; | 
| 72 |  | 
| 73 | /* holds a parsed value */ | 
| 74 | typedef struct relopt_value | 
| 75 | { | 
| 76 | 	relopt_gen *gen; | 
| 77 | 	bool		isset; | 
| 78 | 	union | 
| 79 | 	{ | 
| 80 | 		bool		bool_val; | 
| 81 | 		int			int_val; | 
| 82 | 		double		real_val; | 
| 83 | 		char	   *string_val; /* allocated separately */ | 
| 84 | 	}			values; | 
| 85 | } relopt_value; | 
| 86 |  | 
| 87 | /* reloptions records for specific variable types */ | 
| 88 | typedef struct relopt_bool | 
| 89 | { | 
| 90 | 	relopt_gen	gen; | 
| 91 | 	bool		default_val; | 
| 92 | } relopt_bool; | 
| 93 |  | 
| 94 | typedef struct relopt_int | 
| 95 | { | 
| 96 | 	relopt_gen	gen; | 
| 97 | 	int			default_val; | 
| 98 | 	int			min; | 
| 99 | 	int			max; | 
| 100 | } relopt_int; | 
| 101 |  | 
| 102 | typedef struct relopt_real | 
| 103 | { | 
| 104 | 	relopt_gen	gen; | 
| 105 | 	double		default_val; | 
| 106 | 	double		min; | 
| 107 | 	double		max; | 
| 108 | } relopt_real; | 
| 109 |  | 
| 110 | /* validation routines for strings */ | 
| 111 | typedef void (*validate_string_relopt) (const char *value); | 
| 112 |  | 
| 113 | typedef struct relopt_string | 
| 114 | { | 
| 115 | 	relopt_gen	gen; | 
| 116 | 	int			default_len; | 
| 117 | 	bool		default_isnull; | 
| 118 | 	validate_string_relopt validate_cb; | 
| 119 | 	char	   *default_val; | 
| 120 | } relopt_string; | 
| 121 |  | 
| 122 | /* This is the table datatype for fillRelOptions */ | 
| 123 | typedef struct | 
| 124 | { | 
| 125 | 	const char *optname;		/* option's name */ | 
| 126 | 	relopt_type opttype;		/* option's datatype */ | 
| 127 | 	int			offset;			/* offset of field in result struct */ | 
| 128 | } relopt_parse_elt; | 
| 129 |  | 
| 130 |  | 
| 131 | /* | 
| 132 |  * These macros exist for the convenience of amoptions writers (but consider | 
| 133 |  * using fillRelOptions, which is a lot simpler).  Beware of multiple | 
| 134 |  * evaluation of arguments! | 
| 135 |  * | 
| 136 |  * The last argument in the HANDLE_*_RELOPTION macros allows the caller to | 
| 137 |  * determine whether the option was set (true), or its value acquired from | 
| 138 |  * defaults (false); it can be passed as (char *) NULL if the caller does not | 
| 139 |  * need this information. | 
| 140 |  * | 
| 141 |  * optname is the option name (a string), var is the variable | 
| 142 |  * on which the value should be stored (e.g. StdRdOptions->fillfactor), and | 
| 143 |  * option is a relopt_value pointer. | 
| 144 |  * | 
| 145 |  * The normal way to use this is to loop on the relopt_value array returned by | 
| 146 |  * parseRelOptions: | 
| 147 |  * for (i = 0; options[i].gen->name; i++) | 
| 148 |  * { | 
| 149 |  *		if (HAVE_RELOPTION("fillfactor", options[i]) | 
| 150 |  *		{ | 
| 151 |  *			HANDLE_INT_RELOPTION("fillfactor", rdopts->fillfactor, options[i], &isset); | 
| 152 |  *			continue; | 
| 153 |  *		} | 
| 154 |  *		if (HAVE_RELOPTION("default_row_acl", options[i]) | 
| 155 |  *		{ | 
| 156 |  *			... | 
| 157 |  *		} | 
| 158 |  *		... | 
| 159 |  *		if (validate) | 
| 160 |  *			ereport(ERROR, | 
| 161 |  *					(errmsg("unknown option"))); | 
| 162 |  *	} | 
| 163 |  * | 
| 164 |  *	Note that this is more or less the same that fillRelOptions does, so only | 
| 165 |  *	use this if you need to do something non-standard within some option's | 
| 166 |  *	code block. | 
| 167 |  */ | 
| 168 | #define HAVE_RELOPTION(optname, option) \ | 
| 169 | 	(strncmp(option.gen->name, optname, option.gen->namelen + 1) == 0) | 
| 170 |  | 
| 171 | #define HANDLE_INT_RELOPTION(optname, var, option, wasset)		\ | 
| 172 | 	do {														\ | 
| 173 | 		if (option.isset)										\ | 
| 174 | 			var = option.values.int_val;						\ | 
| 175 | 		else													\ | 
| 176 | 			var = ((relopt_int *) option.gen)->default_val;		\ | 
| 177 | 		(wasset) != NULL ? *(wasset) = option.isset : (dummyret)NULL; \ | 
| 178 | 	} while (0) | 
| 179 |  | 
| 180 | #define HANDLE_BOOL_RELOPTION(optname, var, option, wasset)			\ | 
| 181 | 	do {															\ | 
| 182 | 		if (option.isset)										\ | 
| 183 | 			var = option.values.bool_val;						\ | 
| 184 | 		else													\ | 
| 185 | 			var = ((relopt_bool *) option.gen)->default_val;	\ | 
| 186 | 		(wasset) != NULL ? *(wasset) = option.isset : (dummyret) NULL; \ | 
| 187 | 	} while (0) | 
| 188 |  | 
| 189 | #define HANDLE_REAL_RELOPTION(optname, var, option, wasset)		\ | 
| 190 | 	do {														\ | 
| 191 | 		if (option.isset)										\ | 
| 192 | 			var = option.values.real_val;						\ | 
| 193 | 		else													\ | 
| 194 | 			var = ((relopt_real *) option.gen)->default_val;	\ | 
| 195 | 		(wasset) != NULL ? *(wasset) = option.isset : (dummyret) NULL; \ | 
| 196 | 	} while (0) | 
| 197 |  | 
| 198 | /* | 
| 199 |  * Note that this assumes that the variable is already allocated at the tail of | 
| 200 |  * reloptions structure (StdRdOptions or equivalent). | 
| 201 |  * | 
| 202 |  * "base" is a pointer to the reloptions structure, and "offset" is an integer | 
| 203 |  * variable that must be initialized to sizeof(reloptions structure).  This | 
| 204 |  * struct must have been allocated with enough space to hold any string option | 
| 205 |  * present, including terminating \0 for every option.  SET_VARSIZE() must be | 
| 206 |  * called on the struct with this offset as the second argument, after all the | 
| 207 |  * string options have been processed. | 
| 208 |  */ | 
| 209 | #define HANDLE_STRING_RELOPTION(optname, var, option, base, offset, wasset) \ | 
| 210 | 	do {														\ | 
| 211 | 		relopt_string *optstring = (relopt_string *) option.gen;\ | 
| 212 | 		char *string_val;										\ | 
| 213 | 		if (option.isset)										\ | 
| 214 | 			string_val = option.values.string_val;				\ | 
| 215 | 		else if (!optstring->default_isnull)					\ | 
| 216 | 			string_val = optstring->default_val;				\ | 
| 217 | 		else													\ | 
| 218 | 			string_val = NULL;									\ | 
| 219 | 		(wasset) != NULL ? *(wasset) = option.isset : (dummyret) NULL; \ | 
| 220 | 		if (string_val == NULL)									\ | 
| 221 | 			var = 0;											\ | 
| 222 | 		else													\ | 
| 223 | 		{														\ | 
| 224 | 			strcpy(((char *)(base)) + (offset), string_val);	\ | 
| 225 | 			var = (offset);										\ | 
| 226 | 			(offset) += strlen(string_val) + 1;					\ | 
| 227 | 		}														\ | 
| 228 | 	} while (0) | 
| 229 |  | 
| 230 | /* | 
| 231 |  * For use during amoptions: get the strlen of a string option | 
| 232 |  * (either default or the user defined value) | 
| 233 |  */ | 
| 234 | #define GET_STRING_RELOPTION_LEN(option) \ | 
| 235 | 	((option).isset ? strlen((option).values.string_val) : \ | 
| 236 | 	 ((relopt_string *) (option).gen)->default_len) | 
| 237 |  | 
| 238 | /* | 
| 239 |  * For use by code reading options already parsed: get a pointer to the string | 
| 240 |  * value itself.  "optstruct" is the StdRdOption struct or equivalent, "member" | 
| 241 |  * is the struct member corresponding to the string option | 
| 242 |  */ | 
| 243 | #define GET_STRING_RELOPTION(optstruct, member) \ | 
| 244 | 	((optstruct)->member == 0 ? NULL : \ | 
| 245 | 	 (char *)(optstruct) + (optstruct)->member) | 
| 246 |  | 
| 247 |  | 
| 248 | extern relopt_kind add_reloption_kind(void); | 
| 249 | extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, | 
| 250 | 							   bool default_val); | 
| 251 | extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, | 
| 252 | 							  int default_val, int min_val, int max_val); | 
| 253 | extern void add_real_reloption(bits32 kinds, const char *name, const char *desc, | 
| 254 | 							   double default_val, double min_val, double max_val); | 
| 255 | extern void add_string_reloption(bits32 kinds, const char *name, const char *desc, | 
| 256 | 								 const char *default_val, validate_string_relopt validator); | 
| 257 |  | 
| 258 | extern Datum transformRelOptions(Datum oldOptions, List *defList, | 
| 259 | 								 const char *namspace, char *validnsps[], | 
| 260 | 								 bool acceptOidsOff, bool isReset); | 
| 261 | extern List *untransformRelOptions(Datum options); | 
| 262 | extern bytea *(HeapTuple tuple, TupleDesc tupdesc, | 
| 263 | 								amoptions_function amoptions); | 
| 264 | extern relopt_value *parseRelOptions(Datum options, bool validate, | 
| 265 | 									 relopt_kind kind, int *numrelopts); | 
| 266 | extern void *allocateReloptStruct(Size base, relopt_value *options, | 
| 267 | 								  int numoptions); | 
| 268 | extern void fillRelOptions(void *rdopts, Size basesize, | 
| 269 | 						   relopt_value *options, int numoptions, | 
| 270 | 						   bool validate, | 
| 271 | 						   const relopt_parse_elt *elems, int nelems); | 
| 272 |  | 
| 273 | extern bytea *default_reloptions(Datum reloptions, bool validate, | 
| 274 | 								 relopt_kind kind); | 
| 275 | extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate); | 
| 276 | extern bytea *view_reloptions(Datum reloptions, bool validate); | 
| 277 | extern bytea *index_reloptions(amoptions_function amoptions, Datum reloptions, | 
| 278 | 							   bool validate); | 
| 279 | extern bytea *attribute_reloptions(Datum reloptions, bool validate); | 
| 280 | extern bytea *tablespace_reloptions(Datum reloptions, bool validate); | 
| 281 | extern LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList); | 
| 282 |  | 
| 283 | #endif							/* RELOPTIONS_H */ | 
| 284 |  |