1 /*-------------------------------------------------------------------------
4 * Core support for relation options (pg_class.reloptions)
6 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
13 *-------------------------------------------------------------------------
18 #include "access/gist_private.h"
19 #include "access/hash.h"
20 #include "access/nbtree.h"
21 #include "access/reloptions.h"
22 #include "catalog/pg_type.h"
23 #include "commands/defrem.h"
24 #include "nodes/makefuncs.h"
25 #include "utils/array.h"
26 #include "utils/builtins.h"
27 #include "utils/guc.h"
28 #include "utils/memutils.h"
29 #include "utils/rel.h"
32 * Contents of pg_class.reloptions
36 * (i) decide on a type (integer, real, bool, string), name, default value,
37 * upper and lower bounds (if applicable); for strings, consider a validation
39 * (ii) add a record below (or use add_<type>_reloption).
40 * (iii) add it to the appropriate options struct (perhaps StdRdOptions)
41 * (iv) add it to the appropriate handling routine (perhaps
43 * (v) don't forget to document the option
45 * Note that we don't handle "oids" in relOpts because it is handled by
46 * interpretOidsOption().
49 static relopt_bool boolRelOpts
[] =
54 "Enables autovacuum in this relation",
55 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
62 "Enables \"fast update\" feature for this GIN index",
71 static relopt_int intRelOpts
[] =
76 "Packs table pages only to this percentage",
79 HEAP_DEFAULT_FILLFACTOR
, HEAP_MIN_FILLFACTOR
, 100
84 "Packs btree index pages only to this percentage",
87 BTREE_DEFAULT_FILLFACTOR
, BTREE_MIN_FILLFACTOR
, 100
92 "Packs hash index pages only to this percentage",
95 HASH_DEFAULT_FILLFACTOR
, HASH_MIN_FILLFACTOR
, 100
100 "Packs gist index pages only to this percentage",
103 GIST_DEFAULT_FILLFACTOR
, GIST_MIN_FILLFACTOR
, 100
107 "autovacuum_vacuum_threshold",
108 "Minimum number of tuple updates or deletes prior to vacuum",
109 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
115 "autovacuum_analyze_threshold",
116 "Minimum number of tuple inserts, updates or deletes prior to analyze",
117 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
123 "autovacuum_vacuum_cost_delay",
124 "Vacuum cost delay in milliseconds, for autovacuum",
125 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
131 "autovacuum_vacuum_cost_limit",
132 "Vacuum cost amount available before napping, for autovacuum",
133 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
139 "autovacuum_freeze_min_age",
140 "Minimum age at which VACUUM should freeze a table row, for autovacuum",
141 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
143 100000000, 0, 1000000000
147 "autovacuum_freeze_max_age",
148 "Age at which to autovacuum a table to prevent transaction ID wraparound",
149 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
151 200000000, 100000000, 2000000000
155 "autovacuum_freeze_table_age",
156 "Age at which VACUUM should perform a full table sweep to replace old Xid values with FrozenXID",
157 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
158 }, 150000000, 0, 2000000000
160 /* list terminator */
164 static relopt_real realRelOpts
[] =
168 "autovacuum_vacuum_scale_factor",
169 "Number of tuple updates or deletes prior to vacuum as a fraction of reltuples",
170 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
176 "autovacuum_analyze_scale_factor",
177 "Number of tuple inserts, updates or deletes prior to analyze as a fraction of reltuples",
178 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
182 /* list terminator */
186 static relopt_string stringRelOpts
[] =
188 /* list terminator */
192 static relopt_gen
**relOpts
= NULL
;
193 static bits32 last_assigned_kind
= RELOPT_KIND_LAST_DEFAULT
;
195 static int num_custom_options
= 0;
196 static relopt_gen
**custom_options
= NULL
;
197 static bool need_initialization
= true;
199 static void initialize_reloptions(void);
200 static void parse_one_reloption(relopt_value
*option
, char *text_str
,
201 int text_len
, bool validate
);
204 * initialize_reloptions
205 * initialization routine, must be called before parsing
207 * Initialize the relOpts array and fill each variable's type and name length.
210 initialize_reloptions(void)
215 for (i
= 0; boolRelOpts
[i
].gen
.name
; i
++)
217 for (i
= 0; intRelOpts
[i
].gen
.name
; i
++)
219 for (i
= 0; realRelOpts
[i
].gen
.name
; i
++)
221 for (i
= 0; stringRelOpts
[i
].gen
.name
; i
++)
223 j
+= num_custom_options
;
227 relOpts
= MemoryContextAlloc(TopMemoryContext
,
228 (j
+ 1) * sizeof(relopt_gen
*));
231 for (i
= 0; boolRelOpts
[i
].gen
.name
; i
++)
233 relOpts
[j
] = &boolRelOpts
[i
].gen
;
234 relOpts
[j
]->type
= RELOPT_TYPE_BOOL
;
235 relOpts
[j
]->namelen
= strlen(relOpts
[j
]->name
);
239 for (i
= 0; intRelOpts
[i
].gen
.name
; i
++)
241 relOpts
[j
] = &intRelOpts
[i
].gen
;
242 relOpts
[j
]->type
= RELOPT_TYPE_INT
;
243 relOpts
[j
]->namelen
= strlen(relOpts
[j
]->name
);
247 for (i
= 0; realRelOpts
[i
].gen
.name
; i
++)
249 relOpts
[j
] = &realRelOpts
[i
].gen
;
250 relOpts
[j
]->type
= RELOPT_TYPE_REAL
;
251 relOpts
[j
]->namelen
= strlen(relOpts
[j
]->name
);
255 for (i
= 0; stringRelOpts
[i
].gen
.name
; i
++)
257 relOpts
[j
] = &stringRelOpts
[i
].gen
;
258 relOpts
[j
]->type
= RELOPT_TYPE_STRING
;
259 relOpts
[j
]->namelen
= strlen(relOpts
[j
]->name
);
263 for (i
= 0; i
< num_custom_options
; i
++)
265 relOpts
[j
] = custom_options
[i
];
269 /* add a list terminator */
275 * Create a new relopt_kind value, to be used in custom reloptions by
279 add_reloption_kind(void)
281 /* don't hand out the last bit so that the enum's behavior is portable */
282 if (last_assigned_kind
>= RELOPT_KIND_MAX
)
284 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED
),
285 errmsg("user-defined relation parameter types limit exceeded")));
286 last_assigned_kind
<<= 1;
287 return (relopt_kind
) last_assigned_kind
;
292 * Add an already-created custom reloption to the list, and recompute the
296 add_reloption(relopt_gen
*newoption
)
298 static int max_custom_options
= 0;
300 if (num_custom_options
>= max_custom_options
)
302 MemoryContext oldcxt
;
304 oldcxt
= MemoryContextSwitchTo(TopMemoryContext
);
306 if (max_custom_options
== 0)
308 max_custom_options
= 8;
309 custom_options
= palloc(max_custom_options
* sizeof(relopt_gen
*));
313 max_custom_options
*= 2;
314 custom_options
= repalloc(custom_options
,
315 max_custom_options
* sizeof(relopt_gen
*));
317 MemoryContextSwitchTo(oldcxt
);
319 custom_options
[num_custom_options
++] = newoption
;
321 need_initialization
= true;
326 * Allocate a new reloption and initialize the type-agnostic fields
327 * (for types other than string)
330 allocate_reloption(bits32 kinds
, int type
, char *name
, char *desc
)
332 MemoryContext oldcxt
;
334 relopt_gen
*newoption
;
336 Assert(type
!= RELOPT_TYPE_STRING
);
338 oldcxt
= MemoryContextSwitchTo(TopMemoryContext
);
342 case RELOPT_TYPE_BOOL
:
343 size
= sizeof(relopt_bool
);
345 case RELOPT_TYPE_INT
:
346 size
= sizeof(relopt_int
);
348 case RELOPT_TYPE_REAL
:
349 size
= sizeof(relopt_real
);
352 elog(ERROR
, "unsupported option type");
353 return NULL
; /* keep compiler quiet */
356 newoption
= palloc(size
);
358 newoption
->name
= pstrdup(name
);
360 newoption
->desc
= pstrdup(desc
);
362 newoption
->desc
= NULL
;
363 newoption
->kinds
= kinds
;
364 newoption
->namelen
= strlen(name
);
365 newoption
->type
= type
;
367 MemoryContextSwitchTo(oldcxt
);
374 * Add a new boolean reloption
377 add_bool_reloption(bits32 kinds
, char *name
, char *desc
, bool default_val
)
379 relopt_bool
*newoption
;
381 newoption
= (relopt_bool
*) allocate_reloption(kinds
, RELOPT_TYPE_BOOL
,
383 newoption
->default_val
= default_val
;
385 add_reloption((relopt_gen
*) newoption
);
390 * Add a new integer reloption
393 add_int_reloption(bits32 kinds
, char *name
, char *desc
, int default_val
,
394 int min_val
, int max_val
)
396 relopt_int
*newoption
;
398 newoption
= (relopt_int
*) allocate_reloption(kinds
, RELOPT_TYPE_INT
,
400 newoption
->default_val
= default_val
;
401 newoption
->min
= min_val
;
402 newoption
->max
= max_val
;
404 add_reloption((relopt_gen
*) newoption
);
409 * Add a new float reloption
412 add_real_reloption(bits32 kinds
, char *name
, char *desc
, double default_val
,
413 double min_val
, double max_val
)
415 relopt_real
*newoption
;
417 newoption
= (relopt_real
*) allocate_reloption(kinds
, RELOPT_TYPE_REAL
,
419 newoption
->default_val
= default_val
;
420 newoption
->min
= min_val
;
421 newoption
->max
= max_val
;
423 add_reloption((relopt_gen
*) newoption
);
427 * add_string_reloption
428 * Add a new string reloption
430 * "validator" is an optional function pointer that can be used to test the
431 * validity of the values. It must elog(ERROR) when the argument string is
432 * not acceptable for the variable. Note that the default value must pass
436 add_string_reloption(bits32 kinds
, char *name
, char *desc
, char *default_val
,
437 validate_string_relopt validator
)
439 MemoryContext oldcxt
;
440 relopt_string
*newoption
;
443 oldcxt
= MemoryContextSwitchTo(TopMemoryContext
);
446 default_len
= strlen(default_val
);
448 newoption
= palloc0(sizeof(relopt_string
) + default_len
);
450 newoption
->gen
.name
= pstrdup(name
);
452 newoption
->gen
.desc
= pstrdup(desc
);
454 newoption
->gen
.desc
= NULL
;
455 newoption
->gen
.kinds
= kinds
;
456 newoption
->gen
.namelen
= strlen(name
);
457 newoption
->gen
.type
= RELOPT_TYPE_STRING
;
458 newoption
->validate_cb
= validator
;
461 strcpy(newoption
->default_val
, default_val
);
462 newoption
->default_len
= default_len
;
463 newoption
->default_isnull
= false;
467 newoption
->default_val
[0] = '\0';
468 newoption
->default_len
= 0;
469 newoption
->default_isnull
= true;
472 /* make sure the validator/default combination is sane */
473 if (newoption
->validate_cb
)
474 (newoption
->validate_cb
) (newoption
->default_val
);
476 MemoryContextSwitchTo(oldcxt
);
478 add_reloption((relopt_gen
*) newoption
);
482 * Transform a relation options list (list of DefElem) into the text array
483 * format that is kept in pg_class.reloptions, including only those options
484 * that are in the passed namespace. The output values do not include the
487 * This is used for three cases: CREATE TABLE/INDEX, ALTER TABLE SET, and
488 * ALTER TABLE RESET. In the ALTER cases, oldOptions is the existing
489 * reloptions value (possibly NULL), and we replace or remove entries
492 * If ignoreOids is true, then we should ignore any occurrence of "oids"
493 * in the list (it will be or has been handled by interpretOidsOption()).
495 * Note that this is not responsible for determining whether the options
496 * are valid, but it does check that namespaces for all the options given are
497 * listed in validnsps. The NULL namespace is always valid and needs not be
498 * explicitely listed. Passing a NULL pointer means that only the NULL
499 * namespace is valid.
501 * Both oldOptions and the result are text arrays (or NULL for "default"),
502 * but we declare them as Datums to avoid including array.h in reloptions.h.
505 transformRelOptions(Datum oldOptions
, List
*defList
, char *namspace
,
506 char *validnsps
[], bool ignoreOids
, bool isReset
)
509 ArrayBuildState
*astate
;
512 /* no change if empty list */
516 /* We build new array using accumArrayResult */
519 /* Copy any oldOptions that aren't to be replaced */
520 if (PointerIsValid(DatumGetPointer(oldOptions
)))
522 ArrayType
*array
= DatumGetArrayTypeP(oldOptions
);
527 Assert(ARR_ELEMTYPE(array
) == TEXTOID
);
529 deconstruct_array(array
, TEXTOID
, -1, false, 'i',
530 &oldoptions
, NULL
, &noldoptions
);
532 for (i
= 0; i
< noldoptions
; i
++)
534 text
*oldoption
= DatumGetTextP(oldoptions
[i
]);
535 char *text_str
= VARDATA(oldoption
);
536 int text_len
= VARSIZE(oldoption
) - VARHDRSZ
;
538 /* Search for a match in defList */
539 foreach(cell
, defList
)
541 DefElem
*def
= (DefElem
*) lfirst(cell
);
544 /* ignore if not in the same namespace */
545 if (namspace
== NULL
)
547 if (def
->defnamespace
!= NULL
)
550 else if (def
->defnamespace
== NULL
)
552 else if (pg_strcasecmp(def
->defnamespace
, namspace
) != 0)
555 kw_len
= strlen(def
->defname
);
556 if (text_len
> kw_len
&& text_str
[kw_len
] == '=' &&
557 pg_strncasecmp(text_str
, def
->defname
, kw_len
) == 0)
562 /* No match, so keep old option */
563 astate
= accumArrayResult(astate
, oldoptions
[i
],
565 CurrentMemoryContext
);
571 * If CREATE/SET, add new options to array; if RESET, just check that the
572 * user didn't say RESET (option=val). (Must do this because the grammar
573 * doesn't enforce it.)
575 foreach(cell
, defList
)
577 DefElem
*def
= (DefElem
*) lfirst(cell
);
581 if (def
->arg
!= NULL
)
583 (errcode(ERRCODE_SYNTAX_ERROR
),
584 errmsg("RESET must not include values for parameters")));
593 * Error out if the namespace is not valid. A NULL namespace is
596 if (def
->defnamespace
!= NULL
)
603 for (i
= 0; validnsps
[i
]; i
++)
605 if (pg_strcasecmp(def
->defnamespace
,
616 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
617 errmsg("unrecognized parameter namespace \"%s\"",
618 def
->defnamespace
)));
621 if (ignoreOids
&& pg_strcasecmp(def
->defname
, "oids") == 0)
624 /* ignore if not in the same namespace */
625 if (namspace
== NULL
)
627 if (def
->defnamespace
!= NULL
)
630 else if (def
->defnamespace
== NULL
)
632 else if (pg_strcasecmp(def
->defnamespace
, namspace
) != 0)
636 * Flatten the DefElem into a text string like "name=arg". If we
637 * have just "name", assume "name=true" is meant. Note: the
638 * namespace is not output.
640 if (def
->arg
!= NULL
)
641 value
= defGetString(def
);
644 len
= VARHDRSZ
+ strlen(def
->defname
) + 1 + strlen(value
);
645 /* +1 leaves room for sprintf's trailing null */
646 t
= (text
*) palloc(len
+ 1);
648 sprintf(VARDATA(t
), "%s=%s", def
->defname
, value
);
650 astate
= accumArrayResult(astate
, PointerGetDatum(t
),
652 CurrentMemoryContext
);
657 result
= makeArrayResult(astate
, CurrentMemoryContext
);
666 * Convert the text-array format of reloptions into a List of DefElem.
667 * This is the inverse of transformRelOptions().
670 untransformRelOptions(Datum options
)
678 /* Nothing to do if no options */
679 if (!PointerIsValid(DatumGetPointer(options
)))
682 array
= DatumGetArrayTypeP(options
);
684 Assert(ARR_ELEMTYPE(array
) == TEXTOID
);
686 deconstruct_array(array
, TEXTOID
, -1, false, 'i',
687 &optiondatums
, NULL
, &noptions
);
689 for (i
= 0; i
< noptions
; i
++)
695 s
= TextDatumGetCString(optiondatums
[i
]);
700 val
= (Node
*) makeString(pstrdup(p
));
702 result
= lappend(result
, makeDefElem(pstrdup(s
), val
));
709 * Extract and parse reloptions from a pg_class tuple.
711 * This is a low-level routine, expected to be used by relcache code and
712 * callers that do not have a table's relcache entry (e.g. autovacuum). For
713 * other uses, consider grabbing the rd_options pointer from the relcache entry
716 * tupdesc is pg_class' tuple descriptor. amoptions is the amoptions regproc
717 * in the case of the tuple corresponding to an index, or InvalidOid otherwise.
720 extractRelOptions(HeapTuple tuple
, TupleDesc tupdesc
, Oid amoptions
)
725 Form_pg_class classForm
;
727 datum
= fastgetattr(tuple
,
728 Anum_pg_class_reloptions
,
734 classForm
= (Form_pg_class
) GETSTRUCT(tuple
);
736 /* Parse into appropriate format; don't error out here */
737 switch (classForm
->relkind
)
739 case RELKIND_RELATION
:
740 case RELKIND_TOASTVALUE
:
741 case RELKIND_UNCATALOGED
:
742 options
= heap_reloptions(classForm
->relkind
, datum
, false);
745 options
= index_reloptions(amoptions
, datum
, false);
748 Assert(false); /* can't get here */
749 options
= NULL
; /* keep compiler quiet */
757 * Interpret reloptions that are given in text-array format.
759 * options is a reloption text array as constructed by transformRelOptions.
760 * kind specifies the family of options to be processed.
762 * The return value is a relopt_value * array on which the options actually
763 * set in the options array are marked with isset=true. The length of this
764 * array is returned in *numrelopts. Options not set are also present in the
765 * array; this is so that the caller can easily locate the default values.
767 * If there are no options of the given kind, numrelopts is set to 0 and NULL
770 * Note: values of type int, bool and real are allocated as part of the
771 * returned array. Values of type string are allocated separately and must
772 * be freed by the caller.
775 parseRelOptions(Datum options
, bool validate
, relopt_kind kind
,
778 relopt_value
*reloptions
;
783 if (need_initialization
)
784 initialize_reloptions();
786 /* Build a list of expected options, based on kind */
788 for (i
= 0; relOpts
[i
]; i
++)
789 if (relOpts
[i
]->kinds
& kind
)
798 reloptions
= palloc(numoptions
* sizeof(relopt_value
));
800 for (i
= 0, j
= 0; relOpts
[i
]; i
++)
802 if (relOpts
[i
]->kinds
& kind
)
804 reloptions
[j
].gen
= relOpts
[i
];
805 reloptions
[j
].isset
= false;
810 /* Done if no options */
811 if (PointerIsValid(DatumGetPointer(options
)))
817 array
= DatumGetArrayTypeP(options
);
819 Assert(ARR_ELEMTYPE(array
) == TEXTOID
);
821 deconstruct_array(array
, TEXTOID
, -1, false, 'i',
822 &optiondatums
, NULL
, &noptions
);
824 for (i
= 0; i
< noptions
; i
++)
826 text
*optiontext
= DatumGetTextP(optiondatums
[i
]);
827 char *text_str
= VARDATA(optiontext
);
828 int text_len
= VARSIZE(optiontext
) - VARHDRSZ
;
831 /* Search for a match in reloptions */
832 for (j
= 0; j
< numoptions
; j
++)
834 int kw_len
= reloptions
[j
].gen
->namelen
;
836 if (text_len
> kw_len
&& text_str
[kw_len
] == '=' &&
837 pg_strncasecmp(text_str
, reloptions
[j
].gen
->name
,
840 parse_one_reloption(&reloptions
[j
], text_str
, text_len
,
846 if (j
>= numoptions
&& validate
)
851 s
= TextDatumGetCString(optiondatums
[i
]);
856 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
857 errmsg("unrecognized parameter \"%s\"", s
)));
862 *numrelopts
= numoptions
;
867 * Subroutine for parseRelOptions, to parse and validate a single option's
871 parse_one_reloption(relopt_value
*option
, char *text_str
, int text_len
,
879 if (option
->isset
&& validate
)
881 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
882 errmsg("parameter \"%s\" specified more than once",
883 option
->gen
->name
)));
885 value_len
= text_len
- option
->gen
->namelen
- 1;
886 value
= (char *) palloc(value_len
+ 1);
887 memcpy(value
, text_str
+ option
->gen
->namelen
+ 1, value_len
);
888 value
[value_len
] = '\0';
890 switch (option
->gen
->type
)
892 case RELOPT_TYPE_BOOL
:
894 parsed
= parse_bool(value
, &option
->values
.bool_val
);
895 if (validate
&& !parsed
)
897 (errmsg("invalid value for boolean option \"%s\": %s",
898 option
->gen
->name
, value
)));
901 case RELOPT_TYPE_INT
:
903 relopt_int
*optint
= (relopt_int
*) option
->gen
;
905 parsed
= parse_int(value
, &option
->values
.int_val
, 0, NULL
);
906 if (validate
&& !parsed
)
908 (errmsg("invalid value for integer option \"%s\": %s",
909 option
->gen
->name
, value
)));
910 if (validate
&& (option
->values
.int_val
< optint
->min
||
911 option
->values
.int_val
> optint
->max
))
913 (errmsg("value %s out of bounds for option \"%s\"",
914 value
, option
->gen
->name
),
915 errdetail("Valid values are between \"%d\" and \"%d\".",
916 optint
->min
, optint
->max
)));
919 case RELOPT_TYPE_REAL
:
921 relopt_real
*optreal
= (relopt_real
*) option
->gen
;
923 parsed
= parse_real(value
, &option
->values
.real_val
);
924 if (validate
&& !parsed
)
926 (errmsg("invalid value for floating point option \"%s\": %s",
927 option
->gen
->name
, value
)));
928 if (validate
&& (option
->values
.real_val
< optreal
->min
||
929 option
->values
.real_val
> optreal
->max
))
931 (errmsg("value %s out of bounds for option \"%s\"",
932 value
, option
->gen
->name
),
933 errdetail("Valid values are between \"%f\" and \"%f\".",
934 optreal
->min
, optreal
->max
)));
937 case RELOPT_TYPE_STRING
:
939 relopt_string
*optstring
= (relopt_string
*) option
->gen
;
941 option
->values
.string_val
= value
;
943 if (validate
&& optstring
->validate_cb
)
944 (optstring
->validate_cb
) (value
);
949 elog(ERROR
, "unsupported reloption type %d", option
->gen
->type
);
950 parsed
= true; /* quiet compiler */
955 option
->isset
= true;
961 * Given the result from parseRelOptions, allocate a struct that's of the
962 * specified base size plus any extra space that's needed for string variables.
964 * "base" should be sizeof(struct) of the reloptions struct (StdRdOptions or
968 allocateReloptStruct(Size base
, relopt_value
*options
, int numoptions
)
973 for (i
= 0; i
< numoptions
; i
++)
974 if (options
[i
].gen
->type
== RELOPT_TYPE_STRING
)
975 size
+= GET_STRING_RELOPTION_LEN(options
[i
]) + 1;
977 return palloc0(size
);
981 * Given the result of parseRelOptions and a parsing table, fill in the
982 * struct (previously allocated with allocateReloptStruct) with the parsed
985 * rdopts is the pointer to the allocated struct to be filled.
986 * basesize is the sizeof(struct) that was passed to allocateReloptStruct.
987 * options, of length numoptions, is parseRelOptions' output.
988 * elems, of length numelems, is the table describing the allowed options.
989 * When validate is true, it is expected that all options appear in elems.
992 fillRelOptions(void *rdopts
, Size basesize
,
993 relopt_value
*options
, int numoptions
,
995 const relopt_parse_elt
*elems
, int numelems
)
998 int offset
= basesize
;
1000 for (i
= 0; i
< numoptions
; i
++)
1005 for (j
= 0; j
< numelems
; j
++)
1007 if (pg_strcasecmp(options
[i
].gen
->name
, elems
[j
].optname
) == 0)
1009 relopt_string
*optstring
;
1010 char *itempos
= ((char *) rdopts
) + elems
[j
].offset
;
1013 switch (options
[i
].gen
->type
)
1015 case RELOPT_TYPE_BOOL
:
1016 *(bool *) itempos
= options
[i
].isset
?
1017 options
[i
].values
.bool_val
:
1018 ((relopt_bool
*) options
[i
].gen
)->default_val
;
1020 case RELOPT_TYPE_INT
:
1021 *(int *) itempos
= options
[i
].isset
?
1022 options
[i
].values
.int_val
:
1023 ((relopt_int
*) options
[i
].gen
)->default_val
;
1025 case RELOPT_TYPE_REAL
:
1026 *(double *) itempos
= options
[i
].isset
?
1027 options
[i
].values
.real_val
:
1028 ((relopt_real
*) options
[i
].gen
)->default_val
;
1030 case RELOPT_TYPE_STRING
:
1031 optstring
= (relopt_string
*) options
[i
].gen
;
1032 if (options
[i
].isset
)
1033 string_val
= options
[i
].values
.string_val
;
1034 else if (!optstring
->default_isnull
)
1035 string_val
= optstring
->default_val
;
1039 if (string_val
== NULL
)
1040 *(int *) itempos
= 0;
1043 strcpy((char *) rdopts
+ offset
, string_val
);
1044 *(int *) itempos
= offset
;
1045 offset
+= strlen(string_val
) + 1;
1049 elog(ERROR
, "unrecognized reloption type %c",
1050 options
[i
].gen
->type
);
1057 if (validate
&& !found
)
1058 elog(ERROR
, "reloption \"%s\" not found in parse table",
1059 options
[i
].gen
->name
);
1061 SET_VARSIZE(rdopts
, offset
);
1066 * Option parser for anything that uses StdRdOptions (i.e. fillfactor and
1070 default_reloptions(Datum reloptions
, bool validate
, relopt_kind kind
)
1072 relopt_value
*options
;
1073 StdRdOptions
*rdopts
;
1075 static const relopt_parse_elt tab
[] = {
1076 {"fillfactor", RELOPT_TYPE_INT
, offsetof(StdRdOptions
, fillfactor
)},
1077 {"autovacuum_enabled", RELOPT_TYPE_BOOL
,
1078 offsetof(StdRdOptions
, autovacuum
) +offsetof(AutoVacOpts
, enabled
)},
1079 {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT
,
1080 offsetof(StdRdOptions
, autovacuum
) +offsetof(AutoVacOpts
, vacuum_threshold
)},
1081 {"autovacuum_analyze_threshold", RELOPT_TYPE_INT
,
1082 offsetof(StdRdOptions
, autovacuum
) +offsetof(AutoVacOpts
, analyze_threshold
)},
1083 {"autovacuum_vacuum_cost_delay", RELOPT_TYPE_INT
,
1084 offsetof(StdRdOptions
, autovacuum
) +offsetof(AutoVacOpts
, vacuum_cost_delay
)},
1085 {"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT
,
1086 offsetof(StdRdOptions
, autovacuum
) +offsetof(AutoVacOpts
, vacuum_cost_limit
)},
1087 {"autovacuum_freeze_min_age", RELOPT_TYPE_INT
,
1088 offsetof(StdRdOptions
, autovacuum
) +offsetof(AutoVacOpts
, freeze_min_age
)},
1089 {"autovacuum_freeze_max_age", RELOPT_TYPE_INT
,
1090 offsetof(StdRdOptions
, autovacuum
) +offsetof(AutoVacOpts
, freeze_max_age
)},
1091 {"autovacuum_freeze_table_age", RELOPT_TYPE_INT
,
1092 offsetof(StdRdOptions
, autovacuum
) +offsetof(AutoVacOpts
, freeze_table_age
)},
1093 {"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL
,
1094 offsetof(StdRdOptions
, autovacuum
) +offsetof(AutoVacOpts
, vacuum_scale_factor
)},
1095 {"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL
,
1096 offsetof(StdRdOptions
, autovacuum
) +offsetof(AutoVacOpts
, analyze_scale_factor
)}
1099 options
= parseRelOptions(reloptions
, validate
, kind
, &numoptions
);
1101 /* if none set, we're done */
1102 if (numoptions
== 0)
1105 rdopts
= allocateReloptStruct(sizeof(StdRdOptions
), options
, numoptions
);
1107 fillRelOptions((void *) rdopts
, sizeof(StdRdOptions
), options
, numoptions
,
1108 validate
, tab
, lengthof(tab
));
1112 return (bytea
*) rdopts
;
1116 * Parse options for heaps and toast tables.
1119 heap_reloptions(char relkind
, Datum reloptions
, bool validate
)
1123 case RELKIND_TOASTVALUE
:
1124 return default_reloptions(reloptions
, validate
, RELOPT_KIND_TOAST
);
1125 case RELKIND_RELATION
:
1126 return default_reloptions(reloptions
, validate
, RELOPT_KIND_HEAP
);
1128 /* sequences, composite types and views are not supported */
1135 * Parse options for indexes.
1137 * amoptions Oid of option parser
1138 * reloptions options as text[] datum
1139 * validate error flag
1142 index_reloptions(RegProcedure amoptions
, Datum reloptions
, bool validate
)
1145 FunctionCallInfoData fcinfo
;
1148 Assert(RegProcedureIsValid(amoptions
));
1150 /* Assume function is strict */
1151 if (!PointerIsValid(DatumGetPointer(reloptions
)))
1154 /* Can't use OidFunctionCallN because we might get a NULL result */
1155 fmgr_info(amoptions
, &flinfo
);
1157 InitFunctionCallInfoData(fcinfo
, &flinfo
, 2, NULL
, NULL
);
1159 fcinfo
.arg
[0] = reloptions
;
1160 fcinfo
.arg
[1] = BoolGetDatum(validate
);
1161 fcinfo
.argnull
[0] = false;
1162 fcinfo
.argnull
[1] = false;
1164 result
= FunctionCallInvoke(&fcinfo
);
1166 if (fcinfo
.isnull
|| DatumGetPointer(result
) == NULL
)
1169 return DatumGetByteaP(result
);