Fix xslt_process() to ensure that it inserts a NULL terminator after the
[PostgreSQL.git] / src / backend / access / common / reloptions.c
blob4ee53d178a22101497e1be8a6f26dd6ed09672b8
1 /*-------------------------------------------------------------------------
3 * reloptions.c
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
10 * IDENTIFICATION
11 * $PostgreSQL$
13 *-------------------------------------------------------------------------
16 #include "postgres.h"
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
34 * To add an option:
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
38 * routine.
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
42 * default_reloptions)
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[] =
53 "autovacuum_enabled",
54 "Enables autovacuum in this relation",
55 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST
57 true
61 "fastupdate",
62 "Enables \"fast update\" feature for this GIN index",
63 RELOPT_KIND_GIN
65 true
67 /* list terminator */
68 {{NULL}}
71 static relopt_int intRelOpts[] =
75 "fillfactor",
76 "Packs table pages only to this percentage",
77 RELOPT_KIND_HEAP
79 HEAP_DEFAULT_FILLFACTOR, HEAP_MIN_FILLFACTOR, 100
83 "fillfactor",
84 "Packs btree index pages only to this percentage",
85 RELOPT_KIND_BTREE
87 BTREE_DEFAULT_FILLFACTOR, BTREE_MIN_FILLFACTOR, 100
91 "fillfactor",
92 "Packs hash index pages only to this percentage",
93 RELOPT_KIND_HASH
95 HASH_DEFAULT_FILLFACTOR, HASH_MIN_FILLFACTOR, 100
99 "fillfactor",
100 "Packs gist index pages only to this percentage",
101 RELOPT_KIND_GIST
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
111 50, 0, INT_MAX
115 "autovacuum_analyze_threshold",
116 "Minimum number of tuple inserts, updates or deletes prior to analyze",
117 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST
119 50, 0, INT_MAX
123 "autovacuum_vacuum_cost_delay",
124 "Vacuum cost delay in milliseconds, for autovacuum",
125 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST
127 20, 0, 100
131 "autovacuum_vacuum_cost_limit",
132 "Vacuum cost amount available before napping, for autovacuum",
133 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST
135 200, 1, 10000
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 */
161 {{NULL}}
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
172 0.2, 0.0, 100.0
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
180 0.1, 0.0, 100.0
182 /* list terminator */
183 {{NULL}}
186 static relopt_string stringRelOpts[] =
188 /* list terminator */
189 {{NULL}}
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.
209 static void
210 initialize_reloptions(void)
212 int i;
213 int j = 0;
215 for (i = 0; boolRelOpts[i].gen.name; i++)
216 j++;
217 for (i = 0; intRelOpts[i].gen.name; i++)
218 j++;
219 for (i = 0; realRelOpts[i].gen.name; i++)
220 j++;
221 for (i = 0; stringRelOpts[i].gen.name; i++)
222 j++;
223 j += num_custom_options;
225 if (relOpts)
226 pfree(relOpts);
227 relOpts = MemoryContextAlloc(TopMemoryContext,
228 (j + 1) * sizeof(relopt_gen *));
230 j = 0;
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);
236 j++;
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);
244 j++;
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);
252 j++;
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);
260 j++;
263 for (i = 0; i < num_custom_options; i++)
265 relOpts[j] = custom_options[i];
266 j++;
269 /* add a list terminator */
270 relOpts[j] = NULL;
274 * add_reloption_kind
275 * Create a new relopt_kind value, to be used in custom reloptions by
276 * user-defined AMs.
278 relopt_kind
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)
283 ereport(ERROR,
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;
291 * add_reloption
292 * Add an already-created custom reloption to the list, and recompute the
293 * main parser table.
295 static void
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 *));
311 else
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;
325 * allocate_reloption
326 * Allocate a new reloption and initialize the type-agnostic fields
327 * (for types other than string)
329 static relopt_gen *
330 allocate_reloption(bits32 kinds, int type, char *name, char *desc)
332 MemoryContext oldcxt;
333 size_t size;
334 relopt_gen *newoption;
336 Assert(type != RELOPT_TYPE_STRING);
338 oldcxt = MemoryContextSwitchTo(TopMemoryContext);
340 switch (type)
342 case RELOPT_TYPE_BOOL:
343 size = sizeof(relopt_bool);
344 break;
345 case RELOPT_TYPE_INT:
346 size = sizeof(relopt_int);
347 break;
348 case RELOPT_TYPE_REAL:
349 size = sizeof(relopt_real);
350 break;
351 default:
352 elog(ERROR, "unsupported option type");
353 return NULL; /* keep compiler quiet */
356 newoption = palloc(size);
358 newoption->name = pstrdup(name);
359 if (desc)
360 newoption->desc = pstrdup(desc);
361 else
362 newoption->desc = NULL;
363 newoption->kinds = kinds;
364 newoption->namelen = strlen(name);
365 newoption->type = type;
367 MemoryContextSwitchTo(oldcxt);
369 return newoption;
373 * add_bool_reloption
374 * Add a new boolean reloption
376 void
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,
382 name, desc);
383 newoption->default_val = default_val;
385 add_reloption((relopt_gen *) newoption);
389 * add_int_reloption
390 * Add a new integer reloption
392 void
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,
399 name, desc);
400 newoption->default_val = default_val;
401 newoption->min = min_val;
402 newoption->max = max_val;
404 add_reloption((relopt_gen *) newoption);
408 * add_real_reloption
409 * Add a new float reloption
411 void
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,
418 name, desc);
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
433 * the validation.
435 void
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;
441 int default_len = 0;
443 oldcxt = MemoryContextSwitchTo(TopMemoryContext);
445 if (default_val)
446 default_len = strlen(default_val);
448 newoption = palloc0(sizeof(relopt_string) + default_len);
450 newoption->gen.name = pstrdup(name);
451 if (desc)
452 newoption->gen.desc = pstrdup(desc);
453 else
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;
459 if (default_val)
461 strcpy(newoption->default_val, default_val);
462 newoption->default_len = default_len;
463 newoption->default_isnull = false;
465 else
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
485 * namespace.
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
490 * as needed.
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.
504 Datum
505 transformRelOptions(Datum oldOptions, List *defList, char *namspace,
506 char *validnsps[], bool ignoreOids, bool isReset)
508 Datum result;
509 ArrayBuildState *astate;
510 ListCell *cell;
512 /* no change if empty list */
513 if (defList == NIL)
514 return oldOptions;
516 /* We build new array using accumArrayResult */
517 astate = NULL;
519 /* Copy any oldOptions that aren't to be replaced */
520 if (PointerIsValid(DatumGetPointer(oldOptions)))
522 ArrayType *array = DatumGetArrayTypeP(oldOptions);
523 Datum *oldoptions;
524 int noldoptions;
525 int i;
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);
542 int kw_len;
544 /* ignore if not in the same namespace */
545 if (namspace == NULL)
547 if (def->defnamespace != NULL)
548 continue;
550 else if (def->defnamespace == NULL)
551 continue;
552 else if (pg_strcasecmp(def->defnamespace, namspace) != 0)
553 continue;
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)
558 break;
560 if (!cell)
562 /* No match, so keep old option */
563 astate = accumArrayResult(astate, oldoptions[i],
564 false, TEXTOID,
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);
579 if (isReset)
581 if (def->arg != NULL)
582 ereport(ERROR,
583 (errcode(ERRCODE_SYNTAX_ERROR),
584 errmsg("RESET must not include values for parameters")));
586 else
588 text *t;
589 const char *value;
590 Size len;
593 * Error out if the namespace is not valid. A NULL namespace is
594 * always valid.
596 if (def->defnamespace != NULL)
598 bool valid = false;
599 int i;
601 if (validnsps)
603 for (i = 0; validnsps[i]; i++)
605 if (pg_strcasecmp(def->defnamespace,
606 validnsps[i]) == 0)
608 valid = true;
609 break;
614 if (!valid)
615 ereport(ERROR,
616 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
617 errmsg("unrecognized parameter namespace \"%s\"",
618 def->defnamespace)));
621 if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0)
622 continue;
624 /* ignore if not in the same namespace */
625 if (namspace == NULL)
627 if (def->defnamespace != NULL)
628 continue;
630 else if (def->defnamespace == NULL)
631 continue;
632 else if (pg_strcasecmp(def->defnamespace, namspace) != 0)
633 continue;
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);
642 else
643 value = "true";
644 len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
645 /* +1 leaves room for sprintf's trailing null */
646 t = (text *) palloc(len + 1);
647 SET_VARSIZE(t, len);
648 sprintf(VARDATA(t), "%s=%s", def->defname, value);
650 astate = accumArrayResult(astate, PointerGetDatum(t),
651 false, TEXTOID,
652 CurrentMemoryContext);
656 if (astate)
657 result = makeArrayResult(astate, CurrentMemoryContext);
658 else
659 result = (Datum) 0;
661 return result;
666 * Convert the text-array format of reloptions into a List of DefElem.
667 * This is the inverse of transformRelOptions().
669 List *
670 untransformRelOptions(Datum options)
672 List *result = NIL;
673 ArrayType *array;
674 Datum *optiondatums;
675 int noptions;
676 int i;
678 /* Nothing to do if no options */
679 if (!PointerIsValid(DatumGetPointer(options)))
680 return result;
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++)
691 char *s;
692 char *p;
693 Node *val = NULL;
695 s = TextDatumGetCString(optiondatums[i]);
696 p = strchr(s, '=');
697 if (p)
699 *p++ = '\0';
700 val = (Node *) makeString(pstrdup(p));
702 result = lappend(result, makeDefElem(pstrdup(s), val));
705 return result;
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
714 * instead.
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.
719 bytea *
720 extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, Oid amoptions)
722 bytea *options;
723 bool isnull;
724 Datum datum;
725 Form_pg_class classForm;
727 datum = fastgetattr(tuple,
728 Anum_pg_class_reloptions,
729 tupdesc,
730 &isnull);
731 if (isnull)
732 return NULL;
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);
743 break;
744 case RELKIND_INDEX:
745 options = index_reloptions(amoptions, datum, false);
746 break;
747 default:
748 Assert(false); /* can't get here */
749 options = NULL; /* keep compiler quiet */
750 break;
753 return options;
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
768 * is returned.
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.
774 relopt_value *
775 parseRelOptions(Datum options, bool validate, relopt_kind kind,
776 int *numrelopts)
778 relopt_value *reloptions;
779 int numoptions = 0;
780 int i;
781 int j;
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)
790 numoptions++;
792 if (numoptions == 0)
794 *numrelopts = 0;
795 return NULL;
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;
806 j++;
810 /* Done if no options */
811 if (PointerIsValid(DatumGetPointer(options)))
813 ArrayType *array;
814 Datum *optiondatums;
815 int noptions;
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;
829 int j;
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,
838 kw_len) == 0)
840 parse_one_reloption(&reloptions[j], text_str, text_len,
841 validate);
842 break;
846 if (j >= numoptions && validate)
848 char *s;
849 char *p;
851 s = TextDatumGetCString(optiondatums[i]);
852 p = strchr(s, '=');
853 if (p)
854 *p = '\0';
855 ereport(ERROR,
856 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
857 errmsg("unrecognized parameter \"%s\"", s)));
862 *numrelopts = numoptions;
863 return reloptions;
867 * Subroutine for parseRelOptions, to parse and validate a single option's
868 * value
870 static void
871 parse_one_reloption(relopt_value *option, char *text_str, int text_len,
872 bool validate)
874 char *value;
875 int value_len;
876 bool parsed;
877 bool nofree = false;
879 if (option->isset && validate)
880 ereport(ERROR,
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)
896 ereport(ERROR,
897 (errmsg("invalid value for boolean option \"%s\": %s",
898 option->gen->name, value)));
900 break;
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)
907 ereport(ERROR,
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))
912 ereport(ERROR,
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)));
918 break;
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)
925 ereport(ERROR,
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))
930 ereport(ERROR,
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)));
936 break;
937 case RELOPT_TYPE_STRING:
939 relopt_string *optstring = (relopt_string *) option->gen;
941 option->values.string_val = value;
942 nofree = true;
943 if (validate && optstring->validate_cb)
944 (optstring->validate_cb) (value);
945 parsed = true;
947 break;
948 default:
949 elog(ERROR, "unsupported reloption type %d", option->gen->type);
950 parsed = true; /* quiet compiler */
951 break;
954 if (parsed)
955 option->isset = true;
956 if (!nofree)
957 pfree(value);
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
965 * equivalent).
967 void *
968 allocateReloptStruct(Size base, relopt_value *options, int numoptions)
970 Size size = base;
971 int i;
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
983 * values.
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.
991 void
992 fillRelOptions(void *rdopts, Size basesize,
993 relopt_value *options, int numoptions,
994 bool validate,
995 const relopt_parse_elt *elems, int numelems)
997 int i;
998 int offset = basesize;
1000 for (i = 0; i < numoptions; i++)
1002 int j;
1003 bool found = false;
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;
1011 char *string_val;
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;
1019 break;
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;
1024 break;
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;
1029 break;
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;
1036 else
1037 string_val = NULL;
1039 if (string_val == NULL)
1040 *(int *) itempos = 0;
1041 else
1043 strcpy((char *) rdopts + offset, string_val);
1044 *(int *) itempos = offset;
1045 offset += strlen(string_val) + 1;
1047 break;
1048 default:
1049 elog(ERROR, "unrecognized reloption type %c",
1050 options[i].gen->type);
1051 break;
1053 found = true;
1054 break;
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
1067 * autovacuum)
1069 bytea *
1070 default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
1072 relopt_value *options;
1073 StdRdOptions *rdopts;
1074 int numoptions;
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)
1103 return NULL;
1105 rdopts = allocateReloptStruct(sizeof(StdRdOptions), options, numoptions);
1107 fillRelOptions((void *) rdopts, sizeof(StdRdOptions), options, numoptions,
1108 validate, tab, lengthof(tab));
1110 pfree(options);
1112 return (bytea *) rdopts;
1116 * Parse options for heaps and toast tables.
1118 bytea *
1119 heap_reloptions(char relkind, Datum reloptions, bool validate)
1121 switch (relkind)
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);
1127 default:
1128 /* sequences, composite types and views are not supported */
1129 return NULL;
1135 * Parse options for indexes.
1137 * amoptions Oid of option parser
1138 * reloptions options as text[] datum
1139 * validate error flag
1141 bytea *
1142 index_reloptions(RegProcedure amoptions, Datum reloptions, bool validate)
1144 FmgrInfo flinfo;
1145 FunctionCallInfoData fcinfo;
1146 Datum result;
1148 Assert(RegProcedureIsValid(amoptions));
1150 /* Assume function is strict */
1151 if (!PointerIsValid(DatumGetPointer(reloptions)))
1152 return NULL;
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)
1167 return NULL;
1169 return DatumGetByteaP(result);