1 /*-------------------------------------------------------------------------
4 * Core support for relation options (pg_class.reloptions)
6 * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/access/common/reloptions.c
13 *-------------------------------------------------------------------------
18 #include "access/gist_private.h"
19 #include "access/hash.h"
20 #include "access/htup_details.h"
21 #include "access/nbtree.h"
22 #include "access/reloptions.h"
23 #include "access/spgist.h"
24 #include "catalog/pg_type.h"
25 #include "commands/defrem.h"
26 #include "commands/tablespace.h"
27 #include "commands/view.h"
28 #include "nodes/makefuncs.h"
29 #include "utils/array.h"
30 #include "utils/attoptcache.h"
31 #include "utils/builtins.h"
32 #include "utils/guc.h"
33 #include "utils/memutils.h"
34 #include "utils/rel.h"
37 * Contents of pg_class.reloptions
41 * (i) decide on a type (integer, real, bool, string), name, default value,
42 * upper and lower bounds (if applicable); for strings, consider a validation
44 * (ii) add a record below (or use add_<type>_reloption).
45 * (iii) add it to the appropriate options struct (perhaps StdRdOptions)
46 * (iv) add it to the appropriate handling routine (perhaps
48 * (v) don't forget to document the option
50 * Note that we don't handle "oids" in relOpts because it is handled by
51 * interpretOidsOption().
54 static relopt_bool boolRelOpts[] =
59 "Enables autovacuum in this relation",
60 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST
67 "Declare a table as an additional catalog table, e.g. for the purpose of logical replication",
75 "Enables \"fast update\" feature for this GIN index",
83 "View acts as a row security barrier",
92 static relopt_int intRelOpts[] =
97 "Packs table pages only to this percentage",
100 HEAP_DEFAULT_FILLFACTOR, HEAP_MIN_FILLFACTOR, 100
105 "Packs btree index pages only to this percentage",
108 BTREE_DEFAULT_FILLFACTOR, BTREE_MIN_FILLFACTOR, 100
113 "Packs hash index pages only to this percentage",
116 HASH_DEFAULT_FILLFACTOR, HASH_MIN_FILLFACTOR, 100
121 "Packs gist index pages only to this percentage",
124 GIST_DEFAULT_FILLFACTOR, GIST_MIN_FILLFACTOR, 100
129 "Packs spgist index pages only to this percentage",
132 SPGIST_DEFAULT_FILLFACTOR, SPGIST_MIN_FILLFACTOR, 100
136 "autovacuum_vacuum_threshold",
137 "Minimum number of tuple updates or deletes prior to vacuum",
138 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST
144 "autovacuum_analyze_threshold",
145 "Minimum number of tuple inserts, updates or deletes prior to analyze",
152 "autovacuum_vacuum_cost_delay",
153 "Vacuum cost delay in milliseconds, for autovacuum",
154 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST
160 "autovacuum_vacuum_cost_limit",
161 "Vacuum cost amount available before napping, for autovacuum",
162 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST
168 "autovacuum_freeze_min_age",
169 "Minimum age at which VACUUM should freeze a table row, for autovacuum",
170 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST
176 "autovacuum_freeze_max_age",
177 "Age at which to autovacuum a table to prevent transaction ID wraparound",
178 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST
180 -1, 100000000, 2000000000
184 "autovacuum_freeze_table_age",
185 "Age at which VACUUM should perform a full table sweep to replace old Xid values with FrozenXID",
186 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST
189 /* list terminator */
193 static relopt_real realRelOpts[] =
197 "autovacuum_vacuum_scale_factor",
198 "Number of tuple updates or deletes prior to vacuum as a fraction of reltuples",
199 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST
205 "autovacuum_analyze_scale_factor",
206 "Number of tuple inserts, updates or deletes prior to analyze as a fraction of reltuples",
214 "Sets the planner's estimate of the cost of a sequentially fetched disk page.",
215 RELOPT_KIND_TABLESPACE
222 "Sets the planner's estimate of the cost of a nonsequentially fetched disk page.",
223 RELOPT_KIND_TABLESPACE
230 "Sets the planner's estimate of the number of distinct values appearing in a column (excluding child relations).",
231 RELOPT_KIND_ATTRIBUTE
237 "n_distinct_inherited",
238 "Sets the planner's estimate of the number of distinct values appearing in a column (including child relations).",
239 RELOPT_KIND_ATTRIBUTE
243 /* list terminator */
247 static relopt_string stringRelOpts[] =
252 "Enables buffering build for this GiST index",
257 gistValidateBufferingOption,
263 "View has WITH CHECK OPTION defined (local or cascaded).",
268 validateWithCheckOption,
271 /* list terminator */
275 static relopt_gen **relOpts = NULL;
276 static bits32 last_assigned_kind = RELOPT_KIND_LAST_DEFAULT;
278 static int num_custom_options = 0;
279 static relopt_gen **custom_options = NULL;
280 static bool need_initialization = true;
282 static void initialize_reloptions(void);
283 static void parse_one_reloption(relopt_value *option, char *text_str,
284 int text_len, bool validate);
287 * initialize_reloptions
288 * initialization routine, must be called before parsing
290 * Initialize the relOpts array and fill each variable's type and name length.
293 initialize_reloptions(void)
299 for (i = 0; boolRelOpts[i].gen.name; i++)
301 for (i = 0; intRelOpts[i].gen.name; i++)
303 for (i = 0; realRelOpts[i].gen.name; i++)
305 for (i = 0; stringRelOpts[i].gen.name; i++)
307 j += num_custom_options;
311 relOpts = MemoryContextAlloc(TopMemoryContext,
312 (j + 1) * sizeof(relopt_gen *));
315 for (i = 0; boolRelOpts[i].gen.name; i++)
317 relOpts[j] = &boolRelOpts[i].gen;
318 relOpts[j]->type = RELOPT_TYPE_BOOL;
319 relOpts[j]->namelen = strlen(relOpts[j]->name);
323 for (i = 0; intRelOpts[i].gen.name; i++)
325 relOpts[j] = &intRelOpts[i].gen;
326 relOpts[j]->type = RELOPT_TYPE_INT;
327 relOpts[j]->namelen = strlen(relOpts[j]->name);
331 for (i = 0; realRelOpts[i].gen.name; i++)
333 relOpts[j] = &realRelOpts[i].gen;
334 relOpts[j]->type = RELOPT_TYPE_REAL;
335 relOpts[j]->namelen = strlen(relOpts[j]->name);
339 for (i = 0; stringRelOpts[i].gen.name; i++)
341 relOpts[j] = &stringRelOpts[i].gen;
342 relOpts[j]->type = RELOPT_TYPE_STRING;
343 relOpts[j]->namelen = strlen(relOpts[j]->name);
347 for (i = 0; i < num_custom_options; i++)
349 relOpts[j] = custom_options[i];
353 /* add a list terminator */
356 /* flag the work is complete */
357 need_initialization = false;
362 * Create a new relopt_kind value, to be used in custom reloptions by
366 add_reloption_kind(void)
368 /* don't hand out the last bit so that the enum's behavior is portable */
369 if (last_assigned_kind >= RELOPT_KIND_MAX)
371 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
372 errmsg("user-defined relation parameter types limit exceeded")));
373 last_assigned_kind <<= 1;
374 return (relopt_kind) last_assigned_kind;
379 * Add an already-created custom reloption to the list, and recompute the
383 add_reloption(relopt_gen *newoption)
385 static int max_custom_options = 0;
387 if (num_custom_options >= max_custom_options)
389 MemoryContext oldcxt;
391 oldcxt = MemoryContextSwitchTo(TopMemoryContext);
393 if (max_custom_options == 0)
395 max_custom_options = 8;
396 custom_options = palloc(max_custom_options * sizeof(relopt_gen *));
400 max_custom_options *= 2;
401 custom_options = repalloc(custom_options,
402 max_custom_options * sizeof(relopt_gen *));
404 MemoryContextSwitchTo(oldcxt);
406 custom_options[num_custom_options++] = newoption;
408 need_initialization = true;
413 * Allocate a new reloption and initialize the type-agnostic fields
414 * (for types other than string)
417 allocate_reloption(bits32 kinds, int type, char *name, char *desc)
419 MemoryContext oldcxt;
421 relopt_gen *newoption;
423 oldcxt = MemoryContextSwitchTo(TopMemoryContext);
427 case RELOPT_TYPE_BOOL:
428 size = sizeof(relopt_bool);
430 case RELOPT_TYPE_INT:
431 size = sizeof(relopt_int);
433 case RELOPT_TYPE_REAL:
434 size = sizeof(relopt_real);
436 case RELOPT_TYPE_STRING:
437 size = sizeof(relopt_string);
440 elog(ERROR, "unsupported option type");
441 return NULL; /* keep compiler quiet */
444 newoption = palloc(size);
446 newoption->name = pstrdup(name);
448 newoption->desc = pstrdup(desc);
450 newoption->desc = NULL;
451 newoption->kinds = kinds;
452 newoption->namelen = strlen(name);
453 newoption->type = type;
455 MemoryContextSwitchTo(oldcxt);
462 * Add a new boolean reloption
465 add_bool_reloption(bits32 kinds, char *name, char *desc, bool default_val)
467 relopt_bool *newoption;
469 newoption = (relopt_bool *) allocate_reloption(kinds, RELOPT_TYPE_BOOL,
471 newoption->default_val = default_val;
473 add_reloption((relopt_gen *) newoption);
478 * Add a new integer reloption
481 add_int_reloption(bits32 kinds, char *name, char *desc, int default_val,
482 int min_val, int max_val)
484 relopt_int *newoption;
486 newoption = (relopt_int *) allocate_reloption(kinds, RELOPT_TYPE_INT,
488 newoption->default_val = default_val;
489 newoption->min = min_val;
490 newoption->max = max_val;
492 add_reloption((relopt_gen *) newoption);
497 * Add a new float reloption
500 add_real_reloption(bits32 kinds, char *name, char *desc, double default_val,
501 double min_val, double max_val)
503 relopt_real *newoption;
505 newoption = (relopt_real *) allocate_reloption(kinds, RELOPT_TYPE_REAL,
507 newoption->default_val = default_val;
508 newoption->min = min_val;
509 newoption->max = max_val;
511 add_reloption((relopt_gen *) newoption);
515 * add_string_reloption
516 * Add a new string reloption
518 * "validator" is an optional function pointer that can be used to test the
519 * validity of the values. It must elog(ERROR) when the argument string is
520 * not acceptable for the variable. Note that the default value must pass
524 add_string_reloption(bits32 kinds, char *name, char *desc, char *default_val,
525 validate_string_relopt validator)
527 relopt_string *newoption;
529 /* make sure the validator/default combination is sane */
531 (validator) (default_val);
533 newoption = (relopt_string *) allocate_reloption(kinds, RELOPT_TYPE_STRING,
535 newoption->validate_cb = validator;
538 newoption->default_val = MemoryContextStrdup(TopMemoryContext,
540 newoption->default_len = strlen(default_val);
541 newoption->default_isnull = false;
545 newoption->default_val = "";
546 newoption->default_len = 0;
547 newoption->default_isnull = true;
550 add_reloption((relopt_gen *) newoption);
554 * Transform a relation options list (list of DefElem) into the text array
555 * format that is kept in pg_class.reloptions, including only those options
556 * that are in the passed namespace. The output values do not include the
559 * This is used for three cases: CREATE TABLE/INDEX, ALTER TABLE SET, and
560 * ALTER TABLE RESET. In the ALTER cases, oldOptions is the existing
561 * reloptions value (possibly NULL), and we replace or remove entries
564 * If ignoreOids is true, then we should ignore any occurrence of "oids"
565 * in the list (it will be or has been handled by interpretOidsOption()).
567 * Note that this is not responsible for determining whether the options
568 * are valid, but it does check that namespaces for all the options given are
569 * listed in validnsps. The NULL namespace is always valid and need not be
570 * explicitly listed. Passing a NULL pointer means that only the NULL
571 * namespace is valid.
573 * Both oldOptions and the result are text arrays (or NULL for "default"),
574 * but we declare them as Datums to avoid including array.h in reloptions.h.
577 transformRelOptions(Datum oldOptions, List *defList, char *namspace,
578 char *validnsps[], bool ignoreOids, bool isReset)
581 ArrayBuildState *astate;
584 /* no change if empty list */
588 /* We build new array using accumArrayResult */
591 /* Copy any oldOptions that aren't to be replaced */
592 if (PointerIsValid(DatumGetPointer(oldOptions)))
594 ArrayType *array = DatumGetArrayTypeP(oldOptions);
599 Assert(ARR_ELEMTYPE(array) == TEXTOID);
601 deconstruct_array(array, TEXTOID, -1, false, 'i',
602 &oldoptions, NULL, &noldoptions);
604 for (i = 0; i < noldoptions; i++)
606 text *oldoption = DatumGetTextP(oldoptions[i]);
607 char *text_str = VARDATA(oldoption);
608 int text_len = VARSIZE(oldoption) - VARHDRSZ;
610 /* Search for a match in defList */
611 foreach(cell, defList)
613 DefElem *def = (DefElem *) lfirst(cell);
616 /* ignore if not in the same namespace */
617 if (namspace == NULL)
619 if (def->defnamespace != NULL)
622 else if (def->defnamespace == NULL)
624 else if (pg_strcasecmp(def->defnamespace, namspace) != 0)
627 kw_len = strlen(def->defname);
628 if (text_len > kw_len && text_str[kw_len] == '=' &&
629 pg_strncasecmp(text_str, def->defname, kw_len) == 0)
634 /* No match, so keep old option */
635 astate = accumArrayResult(astate, oldoptions[i],
637 CurrentMemoryContext);
643 * If CREATE/SET, add new options to array; if RESET, just check that the
644 * user didn't say RESET (option=val). (Must do this because the grammar
645 * doesn't enforce it.)
647 foreach(cell, defList)
649 DefElem *def = (DefElem *) lfirst(cell);
653 if (def->arg != NULL)
655 (errcode(ERRCODE_SYNTAX_ERROR),
656 errmsg("RESET must not include values for parameters")));
665 * Error out if the namespace is not valid. A NULL namespace is
668 if (def->defnamespace != NULL)
675 for (i = 0; validnsps[i]; i++)
677 if (pg_strcasecmp(def->defnamespace,
688 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
689 errmsg("unrecognized parameter namespace \"%s\"",
690 def->defnamespace)));
693 if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0)
696 /* ignore if not in the same namespace */
697 if (namspace == NULL)
699 if (def->defnamespace != NULL)
702 else if (def->defnamespace == NULL)
704 else if (pg_strcasecmp(def->defnamespace, namspace) != 0)
708 * Flatten the DefElem into a text string like "name=arg". If we
709 * have just "name", assume "name=true" is meant. Note: the
710 * namespace is not output.
712 if (def->arg != NULL)
713 value = defGetString(def);
716 len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
717 /* +1 leaves room for sprintf's trailing null */
718 t = (text *) palloc(len + 1);
720 sprintf(VARDATA(t), "%s=%s", def->defname, value);
722 astate = accumArrayResult(astate, PointerGetDatum(t),
724 CurrentMemoryContext);
729 result = makeArrayResult(astate, CurrentMemoryContext);
738 * Convert the text-array format of reloptions into a List of DefElem.
739 * This is the inverse of transformRelOptions().
742 untransformRelOptions(Datum options)
750 /* Nothing to do if no options */
751 if (!PointerIsValid(DatumGetPointer(options)))
754 array = DatumGetArrayTypeP(options);
756 Assert(ARR_ELEMTYPE(array) == TEXTOID);
758 deconstruct_array(array, TEXTOID, -1, false, 'i',
759 &optiondatums, NULL, &noptions);
761 for (i = 0; i < noptions; i++)
767 s = TextDatumGetCString(optiondatums[i]);
772 val = (Node *) makeString(pstrdup(p));
774 result = lappend(result, makeDefElem(pstrdup(s), val));
781 * Extract and parse reloptions from a pg_class tuple.
783 * This is a low-level routine, expected to be used by relcache code and
784 * callers that do not have a table's relcache entry (e.g. autovacuum). For
785 * other uses, consider grabbing the rd_options pointer from the relcache entry
788 * tupdesc is pg_class' tuple descriptor. amoptions is the amoptions regproc
789 * in the case of the tuple corresponding to an index, or InvalidOid otherwise.
792 extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, Oid amoptions)
797 Form_pg_class classForm;
799 datum = fastgetattr(tuple,
800 Anum_pg_class_reloptions,
806 classForm = (Form_pg_class) GETSTRUCT(tuple);
808 /* Parse into appropriate format; don't error out here */
809 switch (classForm->relkind)
811 case RELKIND_RELATION:
812 case RELKIND_TOASTVALUE:
814 case RELKIND_MATVIEW:
815 options = heap_reloptions(classForm->relkind, datum, false);
818 options = index_reloptions(amoptions, datum, false);
820 case RELKIND_FOREIGN_TABLE:
824 Assert(false); /* can't get here */
825 options = NULL; /* keep compiler quiet */
833 * Interpret reloptions that are given in text-array format.
835 * options is a reloption text array as constructed by transformRelOptions.
836 * kind specifies the family of options to be processed.
838 * The return value is a relopt_value * array on which the options actually
839 * set in the options array are marked with isset=true. The length of this
840 * array is returned in *numrelopts. Options not set are also present in the
841 * array; this is so that the caller can easily locate the default values.
843 * If there are no options of the given kind, numrelopts is set to 0 and NULL
846 * Note: values of type int, bool and real are allocated as part of the
847 * returned array. Values of type string are allocated separately and must
848 * be freed by the caller.
851 parseRelOptions(Datum options, bool validate, relopt_kind kind,
854 relopt_value *reloptions;
859 if (need_initialization)
860 initialize_reloptions();
862 /* Build a list of expected options, based on kind */
864 for (i = 0; relOpts[i]; i++)
865 if (relOpts[i]->kinds & kind)
874 reloptions = palloc(numoptions * sizeof(relopt_value));
876 for (i = 0, j = 0; relOpts[i]; i++)
878 if (relOpts[i]->kinds & kind)
880 reloptions[j].gen = relOpts[i];
881 reloptions[j].isset = false;
886 /* Done if no options */
887 if (PointerIsValid(DatumGetPointer(options)))
893 array = DatumGetArrayTypeP(options);
895 Assert(ARR_ELEMTYPE(array) == TEXTOID);
897 deconstruct_array(array, TEXTOID, -1, false, 'i',
898 &optiondatums, NULL, &noptions);
900 for (i = 0; i < noptions; i++)
902 text *optiontext = DatumGetTextP(optiondatums[i]);
903 char *text_str = VARDATA(optiontext);
904 int text_len = VARSIZE(optiontext) - VARHDRSZ;
907 /* Search for a match in reloptions */
908 for (j = 0; j < numoptions; j++)
910 int kw_len = reloptions[j].gen->namelen;
912 if (text_len > kw_len && text_str[kw_len] == '=' &&
913 pg_strncasecmp(text_str, reloptions[j].gen->name,
916 parse_one_reloption(&reloptions[j], text_str, text_len,
922 if (j >= numoptions && validate)
927 s = TextDatumGetCString(optiondatums[i]);
932 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
933 errmsg("unrecognized parameter \"%s\"", s)));
938 *numrelopts = numoptions;
943 * Subroutine for parseRelOptions, to parse and validate a single option's
947 parse_one_reloption(relopt_value *option, char *text_str, int text_len,
955 if (option->isset && validate)
957 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
958 errmsg("parameter \"%s\" specified more than once",
959 option->gen->name)));
961 value_len = text_len - option->gen->namelen - 1;
962 value = (char *) palloc(value_len + 1);
963 memcpy(value, text_str + option->gen->namelen + 1, value_len);
964 value[value_len] = '\0';
966 switch (option->gen->type)
968 case RELOPT_TYPE_BOOL:
970 parsed = parse_bool(value, &option->values.bool_val);
971 if (validate && !parsed)
973 (errmsg("invalid value for boolean option \"%s\": %s",
974 option->gen->name, value)));
977 case RELOPT_TYPE_INT:
979 relopt_int *optint = (relopt_int *) option->gen;
981 parsed = parse_int(value, &option->values.int_val, 0, NULL);
982 if (validate && !parsed)
984 (errmsg("invalid value for integer option \"%s\": %s",
985 option->gen->name, value)));
986 if (validate && (option->values.int_val < optint->min ||
987 option->values.int_val > optint->max))
989 (errmsg("value %s out of bounds for option \"%s\"",
990 value, option->gen->name),
991 errdetail("Valid values are between \"%d\" and \"%d\".",
992 optint->min, optint->max)));
995 case RELOPT_TYPE_REAL:
997 relopt_real *optreal = (relopt_real *) option->gen;
999 parsed = parse_real(value, &option->values.real_val);
1000 if (validate && !parsed)
1002 (errmsg("invalid value for floating point option \"%s\": %s",
1003 option->gen->name, value)));
1004 if (validate && (option->values.real_val < optreal->min ||
1005 option->values.real_val > optreal->max))
1007 (errmsg("value %s out of bounds for option \"%s\"",
1008 value, option->gen->name),
1009 errdetail("Valid values are between \"%f\" and \"%f\".",
1010 optreal->min, optreal->max)));
1013 case RELOPT_TYPE_STRING:
1015 relopt_string *optstring = (relopt_string *) option->gen;
1017 option->values.string_val = value;
1019 if (validate && optstring->validate_cb)
1020 (optstring->validate_cb) (value);
1025 elog(ERROR, "unsupported reloption type %d", option->gen->type);
1026 parsed = true; /* quiet compiler */
1031 option->isset = true;
1037 * Given the result from parseRelOptions, allocate a struct that's of the
1038 * specified base size plus any extra space that's needed for string variables.
1040 * "base" should be sizeof(struct) of the reloptions struct (StdRdOptions or
1044 allocateReloptStruct(Size base, relopt_value *options, int numoptions)
1049 for (i = 0; i < numoptions; i++)
1050 if (options[i].gen->type == RELOPT_TYPE_STRING)
1051 size += GET_STRING_RELOPTION_LEN(options[i]) + 1;
1053 return palloc0(size);
1057 * Given the result of parseRelOptions and a parsing table, fill in the
1058 * struct (previously allocated with allocateReloptStruct) with the parsed
1061 * rdopts is the pointer to the allocated struct to be filled.
1062 * basesize is the sizeof(struct) that was passed to allocateReloptStruct.
1063 * options, of length numoptions, is parseRelOptions' output.
1064 * elems, of length numelems, is the table describing the allowed options.
1065 * When validate is true, it is expected that all options appear in elems.
1068 fillRelOptions(void *rdopts, Size basesize,
1069 relopt_value *options, int numoptions,
1071 const relopt_parse_elt *elems, int numelems)
1074 int offset = basesize;
1076 for (i = 0; i < numoptions; i++)
1081 for (j = 0; j < numelems; j++)
1083 if (pg_strcasecmp(options[i].gen->name, elems[j].optname) == 0)
1085 relopt_string *optstring;
1086 char *itempos = ((char *) rdopts) + elems[j].offset;
1089 switch (options[i].gen->type)
1091 case RELOPT_TYPE_BOOL:
1092 *(bool *) itempos = options[i].isset ?
1093 options[i].values.bool_val :
1094 ((relopt_bool *) options[i].gen)->default_val;
1096 case RELOPT_TYPE_INT:
1097 *(int *) itempos = options[i].isset ?
1098 options[i].values.int_val :
1099 ((relopt_int *) options[i].gen)->default_val;
1101 case RELOPT_TYPE_REAL:
1102 *(double *) itempos = options[i].isset ?
1103 options[i].values.real_val :
1104 ((relopt_real *) options[i].gen)->default_val;
1106 case RELOPT_TYPE_STRING:
1107 optstring = (relopt_string *) options[i].gen;
1108 if (options[i].isset)
1109 string_val = options[i].values.string_val;
1110 else if (!optstring->default_isnull)
1111 string_val = optstring->default_val;
1115 if (string_val == NULL)
1116 *(int *) itempos = 0;
1119 strcpy((char *) rdopts + offset, string_val);
1120 *(int *) itempos = offset;
1121 offset += strlen(string_val) + 1;
1125 elog(ERROR, "unrecognized reloption type %c",
1126 options[i].gen->type);
1133 if (validate && !found)
1134 elog(ERROR, "reloption \"%s\" not found in parse table",
1135 options[i].gen->name);
1137 SET_VARSIZE(rdopts, offset);
1142 * Option parser for anything that uses StdRdOptions (i.e. fillfactor and
1146 default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
1148 relopt_value *options;
1149 StdRdOptions *rdopts;
1151 static const relopt_parse_elt tab[] = {
1152 {"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
1153 {"autovacuum_enabled", RELOPT_TYPE_BOOL,
1154 offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, enabled)},
1155 {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,
1156 offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, vacuum_threshold)},
1157 {"autovacuum_analyze_threshold", RELOPT_TYPE_INT,
1158 offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, analyze_threshold)},
1159 {"autovacuum_vacuum_cost_delay", RELOPT_TYPE_INT,
1160 offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, vacuum_cost_delay)},
1161 {"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,
1162 offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, vacuum_cost_limit)},
1163 {"autovacuum_freeze_min_age", RELOPT_TYPE_INT,
1164 offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, freeze_min_age)},
1165 {"autovacuum_freeze_max_age", RELOPT_TYPE_INT,
1166 offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, freeze_max_age)},
1167 {"autovacuum_freeze_table_age", RELOPT_TYPE_INT,
1168 offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, freeze_table_age)},
1169 {"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
1170 offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, vacuum_scale_factor)},
1171 {"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
1172 offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, analyze_scale_factor)},
1173 {"security_barrier", RELOPT_TYPE_BOOL,
1174 offsetof(StdRdOptions, security_barrier)},
1175 {"check_option", RELOPT_TYPE_STRING,
1176 offsetof(StdRdOptions, check_option_offset)},
1177 {"user_catalog_table", RELOPT_TYPE_BOOL,
1178 offsetof(StdRdOptions, user_catalog_table)}
1181 options = parseRelOptions(reloptions, validate, kind, &numoptions);
1183 /* if none set, we're done */
1184 if (numoptions == 0)
1187 rdopts = allocateReloptStruct(sizeof(StdRdOptions), options, numoptions);
1189 fillRelOptions((void *) rdopts, sizeof(StdRdOptions), options, numoptions,
1190 validate, tab, lengthof(tab));
1194 return (bytea *) rdopts;
1198 * Parse options for heaps, views and toast tables.
1201 heap_reloptions(char relkind, Datum reloptions, bool validate)
1203 StdRdOptions *rdopts;
1207 case RELKIND_TOASTVALUE:
1208 rdopts = (StdRdOptions *)
1209 default_reloptions(reloptions, validate, RELOPT_KIND_TOAST);
1212 /* adjust default-only parameters for TOAST relations */
1213 rdopts->fillfactor = 100;
1214 rdopts->autovacuum.analyze_threshold = -1;
1215 rdopts->autovacuum.analyze_scale_factor = -1;
1217 return (bytea *) rdopts;
1218 case RELKIND_RELATION:
1219 case RELKIND_MATVIEW:
1220 return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
1222 return default_reloptions(reloptions, validate, RELOPT_KIND_VIEW);
1224 /* other relkinds are not supported */
1231 * Parse options for indexes.
1233 * amoptions Oid of option parser
1234 * reloptions options as text[] datum
1235 * validate error flag
1238 index_reloptions(RegProcedure amoptions, Datum reloptions, bool validate)
1241 FunctionCallInfoData fcinfo;
1244 Assert(RegProcedureIsValid(amoptions));
1246 /* Assume function is strict */
1247 if (!PointerIsValid(DatumGetPointer(reloptions)))
1250 /* Can't use OidFunctionCallN because we might get a NULL result */
1251 fmgr_info(amoptions, &flinfo);
1253 InitFunctionCallInfoData(fcinfo, &flinfo, 2, InvalidOid, NULL, NULL);
1255 fcinfo.arg[0] = reloptions;
1256 fcinfo.arg[1] = BoolGetDatum(validate);
1257 fcinfo.argnull[0] = false;
1258 fcinfo.argnull[1] = false;
1260 result = FunctionCallInvoke(&fcinfo);
1262 if (fcinfo.isnull || DatumGetPointer(result) == NULL)
1265 return DatumGetByteaP(result);
1269 * Option parser for attribute reloptions
1272 attribute_reloptions(Datum reloptions, bool validate)
1274 relopt_value *options;
1275 AttributeOpts *aopts;
1277 static const relopt_parse_elt tab[] = {
1278 {"n_distinct", RELOPT_TYPE_REAL, offsetof(AttributeOpts, n_distinct)},
1279 {"n_distinct_inherited", RELOPT_TYPE_REAL, offsetof(AttributeOpts, n_distinct_inherited)}
1282 options = parseRelOptions(reloptions, validate, RELOPT_KIND_ATTRIBUTE,
1285 /* if none set, we're done */
1286 if (numoptions == 0)
1289 aopts = allocateReloptStruct(sizeof(AttributeOpts), options, numoptions);
1291 fillRelOptions((void *) aopts, sizeof(AttributeOpts), options, numoptions,
1292 validate, tab, lengthof(tab));
1296 return (bytea *) aopts;
1300 * Option parser for tablespace reloptions
1303 tablespace_reloptions(Datum reloptions, bool validate)
1305 relopt_value *options;
1306 TableSpaceOpts *tsopts;
1308 static const relopt_parse_elt tab[] = {
1309 {"random_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, random_page_cost)},
1310 {"seq_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, seq_page_cost)}
1313 options = parseRelOptions(reloptions, validate, RELOPT_KIND_TABLESPACE,
1316 /* if none set, we're done */
1317 if (numoptions == 0)
1320 tsopts = allocateReloptStruct(sizeof(TableSpaceOpts), options, numoptions);
1322 fillRelOptions((void *) tsopts, sizeof(TableSpaceOpts), options, numoptions,
1323 validate, tab, lengthof(tab));
1327 return (bytea *) tsopts;