Add eager and lazy freezing strategies to VACUUM.
[pgsql.git] / src / backend / access / common / reloptions.c
blobdfa802416fc9c47715b2276d3ed77a723a78e853
1 /*-------------------------------------------------------------------------
3 * reloptions.c
4 * Core support for relation options (pg_class.reloptions)
6 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * src/backend/access/common/reloptions.c
13 *-------------------------------------------------------------------------
16 #include "postgres.h"
18 #include <float.h>
20 #include "access/gist_private.h"
21 #include "access/hash.h"
22 #include "access/heaptoast.h"
23 #include "access/htup_details.h"
24 #include "access/nbtree.h"
25 #include "access/reloptions.h"
26 #include "access/spgist_private.h"
27 #include "catalog/pg_type.h"
28 #include "commands/defrem.h"
29 #include "commands/tablespace.h"
30 #include "commands/view.h"
31 #include "nodes/makefuncs.h"
32 #include "postmaster/postmaster.h"
33 #include "utils/array.h"
34 #include "utils/attoptcache.h"
35 #include "utils/builtins.h"
36 #include "utils/guc.h"
37 #include "utils/memutils.h"
38 #include "utils/rel.h"
41 * Contents of pg_class.reloptions
43 * To add an option:
45 * (i) decide on a type (integer, real, bool, string), name, default value,
46 * upper and lower bounds (if applicable); for strings, consider a validation
47 * routine.
48 * (ii) add a record below (or use add_<type>_reloption).
49 * (iii) add it to the appropriate options struct (perhaps StdRdOptions)
50 * (iv) add it to the appropriate handling routine (perhaps
51 * default_reloptions)
52 * (v) make sure the lock level is set correctly for that operation
53 * (vi) don't forget to document the option
55 * The default choice for any new option should be AccessExclusiveLock.
56 * In some cases the lock level can be reduced from there, but the lock
57 * level chosen should always conflict with itself to ensure that multiple
58 * changes aren't lost when we attempt concurrent changes.
59 * The choice of lock level depends completely upon how that parameter
60 * is used within the server, not upon how and when you'd like to change it.
61 * Safety first. Existing choices are documented here, and elsewhere in
62 * backend code where the parameters are used.
64 * In general, anything that affects the results obtained from a SELECT must be
65 * protected by AccessExclusiveLock.
67 * Autovacuum related parameters can be set at ShareUpdateExclusiveLock
68 * since they are only used by the AV procs and don't change anything
69 * currently executing.
71 * Fillfactor can be set because it applies only to subsequent changes made to
72 * data blocks, as documented in hio.c
74 * n_distinct options can be set at ShareUpdateExclusiveLock because they
75 * are only used during ANALYZE, which uses a ShareUpdateExclusiveLock,
76 * so the ANALYZE will not be affected by in-flight changes. Changing those
77 * values has no effect until the next ANALYZE, so no need for stronger lock.
79 * Planner-related parameters can be set with ShareUpdateExclusiveLock because
80 * they only affect planning and not the correctness of the execution. Plans
81 * cannot be changed in mid-flight, so changes here could not easily result in
82 * new improved plans in any case. So we allow existing queries to continue
83 * and existing plans to survive, a small price to pay for allowing better
84 * plans to be introduced concurrently without interfering with users.
86 * Setting parallel_workers is safe, since it acts the same as
87 * max_parallel_workers_per_gather which is a USERSET parameter that doesn't
88 * affect existing plans or queries.
90 * vacuum_truncate can be set at ShareUpdateExclusiveLock because it
91 * is only used during VACUUM, which uses a ShareUpdateExclusiveLock,
92 * so the VACUUM will not be affected by in-flight changes. Changing its
93 * value has no effect until the next VACUUM, so no need for stronger lock.
96 static relopt_bool boolRelOpts[] =
100 "autosummarize",
101 "Enables automatic summarization on this BRIN index",
102 RELOPT_KIND_BRIN,
103 AccessExclusiveLock
105 false
109 "autovacuum_enabled",
110 "Enables autovacuum in this relation",
111 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
112 ShareUpdateExclusiveLock
114 true
118 "user_catalog_table",
119 "Declare a table as an additional catalog table, e.g. for the purpose of logical replication",
120 RELOPT_KIND_HEAP,
121 AccessExclusiveLock
123 false
127 "fastupdate",
128 "Enables \"fast update\" feature for this GIN index",
129 RELOPT_KIND_GIN,
130 AccessExclusiveLock
132 true
136 "security_barrier",
137 "View acts as a row security barrier",
138 RELOPT_KIND_VIEW,
139 AccessExclusiveLock
141 false
145 "security_invoker",
146 "Privileges on underlying relations are checked as the invoking user, not the view owner",
147 RELOPT_KIND_VIEW,
148 AccessExclusiveLock
150 false
154 "vacuum_truncate",
155 "Enables vacuum to truncate empty pages at the end of this table",
156 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
157 ShareUpdateExclusiveLock
159 true
163 "deduplicate_items",
164 "Enables \"deduplicate items\" feature for this btree index",
165 RELOPT_KIND_BTREE,
166 ShareUpdateExclusiveLock /* since it applies only to later
167 * inserts */
169 true
171 /* list terminator */
172 {{NULL}}
175 static relopt_int intRelOpts[] =
179 "fillfactor",
180 "Packs table pages only to this percentage",
181 RELOPT_KIND_HEAP,
182 ShareUpdateExclusiveLock /* since it applies only to later
183 * inserts */
185 HEAP_DEFAULT_FILLFACTOR, HEAP_MIN_FILLFACTOR, 100
189 "fillfactor",
190 "Packs btree index pages only to this percentage",
191 RELOPT_KIND_BTREE,
192 ShareUpdateExclusiveLock /* since it applies only to later
193 * inserts */
195 BTREE_DEFAULT_FILLFACTOR, BTREE_MIN_FILLFACTOR, 100
199 "fillfactor",
200 "Packs hash index pages only to this percentage",
201 RELOPT_KIND_HASH,
202 ShareUpdateExclusiveLock /* since it applies only to later
203 * inserts */
205 HASH_DEFAULT_FILLFACTOR, HASH_MIN_FILLFACTOR, 100
209 "fillfactor",
210 "Packs gist index pages only to this percentage",
211 RELOPT_KIND_GIST,
212 ShareUpdateExclusiveLock /* since it applies only to later
213 * inserts */
215 GIST_DEFAULT_FILLFACTOR, GIST_MIN_FILLFACTOR, 100
219 "fillfactor",
220 "Packs spgist index pages only to this percentage",
221 RELOPT_KIND_SPGIST,
222 ShareUpdateExclusiveLock /* since it applies only to later
223 * inserts */
225 SPGIST_DEFAULT_FILLFACTOR, SPGIST_MIN_FILLFACTOR, 100
229 "autovacuum_vacuum_threshold",
230 "Minimum number of tuple updates or deletes prior to vacuum",
231 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
232 ShareUpdateExclusiveLock
234 -1, 0, INT_MAX
238 "autovacuum_vacuum_insert_threshold",
239 "Minimum number of tuple inserts prior to vacuum, or -1 to disable insert vacuums",
240 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
241 ShareUpdateExclusiveLock
243 -2, -1, INT_MAX
247 "autovacuum_analyze_threshold",
248 "Minimum number of tuple inserts, updates or deletes prior to analyze",
249 RELOPT_KIND_HEAP,
250 ShareUpdateExclusiveLock
252 -1, 0, INT_MAX
256 "autovacuum_vacuum_cost_limit",
257 "Vacuum cost amount available before napping, for autovacuum",
258 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
259 ShareUpdateExclusiveLock
261 -1, 1, 10000
265 "autovacuum_freeze_min_age",
266 "Minimum age at which VACUUM should freeze a table row, for autovacuum",
267 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
268 ShareUpdateExclusiveLock
270 -1, 0, 1000000000
274 "autovacuum_multixact_freeze_min_age",
275 "Minimum multixact age at which VACUUM should freeze a row multixact's, for autovacuum",
276 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
277 ShareUpdateExclusiveLock
279 -1, 0, 1000000000
283 "autovacuum_freeze_max_age",
284 "Age at which to autovacuum a table to prevent transaction ID wraparound",
285 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
286 ShareUpdateExclusiveLock
288 -1, 100000, 2000000000
292 "autovacuum_multixact_freeze_max_age",
293 "Multixact age at which to autovacuum a table to prevent multixact wraparound",
294 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
295 ShareUpdateExclusiveLock
297 -1, 10000, 2000000000
301 "autovacuum_freeze_table_age",
302 "Age at which VACUUM should perform a full table sweep to freeze row versions",
303 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
304 ShareUpdateExclusiveLock
305 }, -1, 0, 2000000000
309 "autovacuum_multixact_freeze_table_age",
310 "Age of multixact at which VACUUM should perform a full table sweep to freeze row versions",
311 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
312 ShareUpdateExclusiveLock
313 }, -1, 0, 2000000000
317 "autovacuum_freeze_strategy_threshold",
318 "Table size at which VACUUM freezes using eager strategy, in megabytes.",
319 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
320 ShareUpdateExclusiveLock
321 }, -1, 0, MAX_KILOBYTES
325 "log_autovacuum_min_duration",
326 "Sets the minimum execution time above which autovacuum actions will be logged",
327 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
328 ShareUpdateExclusiveLock
330 -1, -1, INT_MAX
334 "toast_tuple_target",
335 "Sets the target tuple length at which external columns will be toasted",
336 RELOPT_KIND_HEAP,
337 ShareUpdateExclusiveLock
339 TOAST_TUPLE_TARGET, 128, TOAST_TUPLE_TARGET_MAIN
343 "pages_per_range",
344 "Number of pages that each page range covers in a BRIN index",
345 RELOPT_KIND_BRIN,
346 AccessExclusiveLock
347 }, 128, 1, 131072
351 "gin_pending_list_limit",
352 "Maximum size of the pending list for this GIN index, in kilobytes.",
353 RELOPT_KIND_GIN,
354 AccessExclusiveLock
356 -1, 64, MAX_KILOBYTES
360 "effective_io_concurrency",
361 "Number of simultaneous requests that can be handled efficiently by the disk subsystem.",
362 RELOPT_KIND_TABLESPACE,
363 ShareUpdateExclusiveLock
365 #ifdef USE_PREFETCH
366 -1, 0, MAX_IO_CONCURRENCY
367 #else
368 0, 0, 0
369 #endif
373 "maintenance_io_concurrency",
374 "Number of simultaneous requests that can be handled efficiently by the disk subsystem for maintenance work.",
375 RELOPT_KIND_TABLESPACE,
376 ShareUpdateExclusiveLock
378 #ifdef USE_PREFETCH
379 -1, 0, MAX_IO_CONCURRENCY
380 #else
381 0, 0, 0
382 #endif
386 "parallel_workers",
387 "Number of parallel processes that can be used per executor node for this relation.",
388 RELOPT_KIND_HEAP,
389 ShareUpdateExclusiveLock
391 -1, 0, 1024
394 /* list terminator */
395 {{NULL}}
398 static relopt_real realRelOpts[] =
402 "autovacuum_vacuum_cost_delay",
403 "Vacuum cost delay in milliseconds, for autovacuum",
404 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
405 ShareUpdateExclusiveLock
407 -1, 0.0, 100.0
411 "autovacuum_vacuum_scale_factor",
412 "Number of tuple updates or deletes prior to vacuum as a fraction of reltuples",
413 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
414 ShareUpdateExclusiveLock
416 -1, 0.0, 100.0
420 "autovacuum_vacuum_insert_scale_factor",
421 "Number of tuple inserts prior to vacuum as a fraction of reltuples",
422 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
423 ShareUpdateExclusiveLock
425 -1, 0.0, 100.0
429 "autovacuum_analyze_scale_factor",
430 "Number of tuple inserts, updates or deletes prior to analyze as a fraction of reltuples",
431 RELOPT_KIND_HEAP,
432 ShareUpdateExclusiveLock
434 -1, 0.0, 100.0
438 "seq_page_cost",
439 "Sets the planner's estimate of the cost of a sequentially fetched disk page.",
440 RELOPT_KIND_TABLESPACE,
441 ShareUpdateExclusiveLock
443 -1, 0.0, DBL_MAX
447 "random_page_cost",
448 "Sets the planner's estimate of the cost of a nonsequentially fetched disk page.",
449 RELOPT_KIND_TABLESPACE,
450 ShareUpdateExclusiveLock
452 -1, 0.0, DBL_MAX
456 "n_distinct",
457 "Sets the planner's estimate of the number of distinct values appearing in a column (excluding child relations).",
458 RELOPT_KIND_ATTRIBUTE,
459 ShareUpdateExclusiveLock
461 0, -1.0, DBL_MAX
465 "n_distinct_inherited",
466 "Sets the planner's estimate of the number of distinct values appearing in a column (including child relations).",
467 RELOPT_KIND_ATTRIBUTE,
468 ShareUpdateExclusiveLock
470 0, -1.0, DBL_MAX
474 "vacuum_cleanup_index_scale_factor",
475 "Deprecated B-Tree parameter.",
476 RELOPT_KIND_BTREE,
477 ShareUpdateExclusiveLock
479 -1, 0.0, 1e10
481 /* list terminator */
482 {{NULL}}
485 /* values from StdRdOptIndexCleanup */
486 static relopt_enum_elt_def StdRdOptIndexCleanupValues[] =
488 {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO},
489 {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON},
490 {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF},
491 {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON},
492 {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF},
493 {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON},
494 {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF},
495 {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON},
496 {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF},
497 {(const char *) NULL} /* list terminator */
500 /* values from GistOptBufferingMode */
501 static relopt_enum_elt_def gistBufferingOptValues[] =
503 {"auto", GIST_OPTION_BUFFERING_AUTO},
504 {"on", GIST_OPTION_BUFFERING_ON},
505 {"off", GIST_OPTION_BUFFERING_OFF},
506 {(const char *) NULL} /* list terminator */
509 /* values from ViewOptCheckOption */
510 static relopt_enum_elt_def viewCheckOptValues[] =
512 /* no value for NOT_SET */
513 {"local", VIEW_OPTION_CHECK_OPTION_LOCAL},
514 {"cascaded", VIEW_OPTION_CHECK_OPTION_CASCADED},
515 {(const char *) NULL} /* list terminator */
518 static relopt_enum enumRelOpts[] =
522 "vacuum_index_cleanup",
523 "Controls index vacuuming and index cleanup",
524 RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
525 ShareUpdateExclusiveLock
527 StdRdOptIndexCleanupValues,
528 STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO,
529 gettext_noop("Valid values are \"on\", \"off\", and \"auto\".")
533 "buffering",
534 "Enables buffering build for this GiST index",
535 RELOPT_KIND_GIST,
536 AccessExclusiveLock
538 gistBufferingOptValues,
539 GIST_OPTION_BUFFERING_AUTO,
540 gettext_noop("Valid values are \"on\", \"off\", and \"auto\".")
544 "check_option",
545 "View has WITH CHECK OPTION defined (local or cascaded).",
546 RELOPT_KIND_VIEW,
547 AccessExclusiveLock
549 viewCheckOptValues,
550 VIEW_OPTION_CHECK_OPTION_NOT_SET,
551 gettext_noop("Valid values are \"local\" and \"cascaded\".")
553 /* list terminator */
554 {{NULL}}
557 static relopt_string stringRelOpts[] =
559 /* list terminator */
560 {{NULL}}
563 static relopt_gen **relOpts = NULL;
564 static bits32 last_assigned_kind = RELOPT_KIND_LAST_DEFAULT;
566 static int num_custom_options = 0;
567 static relopt_gen **custom_options = NULL;
568 static bool need_initialization = true;
570 static void initialize_reloptions(void);
571 static void parse_one_reloption(relopt_value *option, char *text_str,
572 int text_len, bool validate);
575 * Get the length of a string reloption (either default or the user-defined
576 * value). This is used for allocation purposes when building a set of
577 * relation options.
579 #define GET_STRING_RELOPTION_LEN(option) \
580 ((option).isset ? strlen((option).values.string_val) : \
581 ((relopt_string *) (option).gen)->default_len)
584 * initialize_reloptions
585 * initialization routine, must be called before parsing
587 * Initialize the relOpts array and fill each variable's type and name length.
589 static void
590 initialize_reloptions(void)
592 int i;
593 int j;
595 j = 0;
596 for (i = 0; boolRelOpts[i].gen.name; i++)
598 Assert(DoLockModesConflict(boolRelOpts[i].gen.lockmode,
599 boolRelOpts[i].gen.lockmode));
600 j++;
602 for (i = 0; intRelOpts[i].gen.name; i++)
604 Assert(DoLockModesConflict(intRelOpts[i].gen.lockmode,
605 intRelOpts[i].gen.lockmode));
606 j++;
608 for (i = 0; realRelOpts[i].gen.name; i++)
610 Assert(DoLockModesConflict(realRelOpts[i].gen.lockmode,
611 realRelOpts[i].gen.lockmode));
612 j++;
614 for (i = 0; enumRelOpts[i].gen.name; i++)
616 Assert(DoLockModesConflict(enumRelOpts[i].gen.lockmode,
617 enumRelOpts[i].gen.lockmode));
618 j++;
620 for (i = 0; stringRelOpts[i].gen.name; i++)
622 Assert(DoLockModesConflict(stringRelOpts[i].gen.lockmode,
623 stringRelOpts[i].gen.lockmode));
624 j++;
626 j += num_custom_options;
628 if (relOpts)
629 pfree(relOpts);
630 relOpts = MemoryContextAlloc(TopMemoryContext,
631 (j + 1) * sizeof(relopt_gen *));
633 j = 0;
634 for (i = 0; boolRelOpts[i].gen.name; i++)
636 relOpts[j] = &boolRelOpts[i].gen;
637 relOpts[j]->type = RELOPT_TYPE_BOOL;
638 relOpts[j]->namelen = strlen(relOpts[j]->name);
639 j++;
642 for (i = 0; intRelOpts[i].gen.name; i++)
644 relOpts[j] = &intRelOpts[i].gen;
645 relOpts[j]->type = RELOPT_TYPE_INT;
646 relOpts[j]->namelen = strlen(relOpts[j]->name);
647 j++;
650 for (i = 0; realRelOpts[i].gen.name; i++)
652 relOpts[j] = &realRelOpts[i].gen;
653 relOpts[j]->type = RELOPT_TYPE_REAL;
654 relOpts[j]->namelen = strlen(relOpts[j]->name);
655 j++;
658 for (i = 0; enumRelOpts[i].gen.name; i++)
660 relOpts[j] = &enumRelOpts[i].gen;
661 relOpts[j]->type = RELOPT_TYPE_ENUM;
662 relOpts[j]->namelen = strlen(relOpts[j]->name);
663 j++;
666 for (i = 0; stringRelOpts[i].gen.name; i++)
668 relOpts[j] = &stringRelOpts[i].gen;
669 relOpts[j]->type = RELOPT_TYPE_STRING;
670 relOpts[j]->namelen = strlen(relOpts[j]->name);
671 j++;
674 for (i = 0; i < num_custom_options; i++)
676 relOpts[j] = custom_options[i];
677 j++;
680 /* add a list terminator */
681 relOpts[j] = NULL;
683 /* flag the work is complete */
684 need_initialization = false;
688 * add_reloption_kind
689 * Create a new relopt_kind value, to be used in custom reloptions by
690 * user-defined AMs.
692 relopt_kind
693 add_reloption_kind(void)
695 /* don't hand out the last bit so that the enum's behavior is portable */
696 if (last_assigned_kind >= RELOPT_KIND_MAX)
697 ereport(ERROR,
698 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
699 errmsg("user-defined relation parameter types limit exceeded")));
700 last_assigned_kind <<= 1;
701 return (relopt_kind) last_assigned_kind;
705 * add_reloption
706 * Add an already-created custom reloption to the list, and recompute the
707 * main parser table.
709 static void
710 add_reloption(relopt_gen *newoption)
712 static int max_custom_options = 0;
714 if (num_custom_options >= max_custom_options)
716 MemoryContext oldcxt;
718 oldcxt = MemoryContextSwitchTo(TopMemoryContext);
720 if (max_custom_options == 0)
722 max_custom_options = 8;
723 custom_options = palloc(max_custom_options * sizeof(relopt_gen *));
725 else
727 max_custom_options *= 2;
728 custom_options = repalloc(custom_options,
729 max_custom_options * sizeof(relopt_gen *));
731 MemoryContextSwitchTo(oldcxt);
733 custom_options[num_custom_options++] = newoption;
735 need_initialization = true;
739 * init_local_reloptions
740 * Initialize local reloptions that will parsed into bytea structure of
741 * 'relopt_struct_size'.
743 void
744 init_local_reloptions(local_relopts *relopts, Size relopt_struct_size)
746 relopts->options = NIL;
747 relopts->validators = NIL;
748 relopts->relopt_struct_size = relopt_struct_size;
752 * register_reloptions_validator
753 * Register custom validation callback that will be called at the end of
754 * build_local_reloptions().
756 void
757 register_reloptions_validator(local_relopts *relopts, relopts_validator validator)
759 relopts->validators = lappend(relopts->validators, validator);
763 * add_local_reloption
764 * Add an already-created custom reloption to the local list.
766 static void
767 add_local_reloption(local_relopts *relopts, relopt_gen *newoption, int offset)
769 local_relopt *opt = palloc(sizeof(*opt));
771 Assert(offset < relopts->relopt_struct_size);
773 opt->option = newoption;
774 opt->offset = offset;
776 relopts->options = lappend(relopts->options, opt);
780 * allocate_reloption
781 * Allocate a new reloption and initialize the type-agnostic fields
782 * (for types other than string)
784 static relopt_gen *
785 allocate_reloption(bits32 kinds, int type, const char *name, const char *desc,
786 LOCKMODE lockmode)
788 MemoryContext oldcxt;
789 size_t size;
790 relopt_gen *newoption;
792 if (kinds != RELOPT_KIND_LOCAL)
793 oldcxt = MemoryContextSwitchTo(TopMemoryContext);
794 else
795 oldcxt = NULL;
797 switch (type)
799 case RELOPT_TYPE_BOOL:
800 size = sizeof(relopt_bool);
801 break;
802 case RELOPT_TYPE_INT:
803 size = sizeof(relopt_int);
804 break;
805 case RELOPT_TYPE_REAL:
806 size = sizeof(relopt_real);
807 break;
808 case RELOPT_TYPE_ENUM:
809 size = sizeof(relopt_enum);
810 break;
811 case RELOPT_TYPE_STRING:
812 size = sizeof(relopt_string);
813 break;
814 default:
815 elog(ERROR, "unsupported reloption type %d", type);
816 return NULL; /* keep compiler quiet */
819 newoption = palloc(size);
821 newoption->name = pstrdup(name);
822 if (desc)
823 newoption->desc = pstrdup(desc);
824 else
825 newoption->desc = NULL;
826 newoption->kinds = kinds;
827 newoption->namelen = strlen(name);
828 newoption->type = type;
829 newoption->lockmode = lockmode;
831 if (oldcxt != NULL)
832 MemoryContextSwitchTo(oldcxt);
834 return newoption;
838 * init_bool_reloption
839 * Allocate and initialize a new boolean reloption
841 static relopt_bool *
842 init_bool_reloption(bits32 kinds, const char *name, const char *desc,
843 bool default_val, LOCKMODE lockmode)
845 relopt_bool *newoption;
847 newoption = (relopt_bool *) allocate_reloption(kinds, RELOPT_TYPE_BOOL,
848 name, desc, lockmode);
849 newoption->default_val = default_val;
851 return newoption;
855 * add_bool_reloption
856 * Add a new boolean reloption
858 void
859 add_bool_reloption(bits32 kinds, const char *name, const char *desc,
860 bool default_val, LOCKMODE lockmode)
862 relopt_bool *newoption = init_bool_reloption(kinds, name, desc,
863 default_val, lockmode);
865 add_reloption((relopt_gen *) newoption);
869 * add_local_bool_reloption
870 * Add a new boolean local reloption
872 * 'offset' is offset of bool-typed field.
874 void
875 add_local_bool_reloption(local_relopts *relopts, const char *name,
876 const char *desc, bool default_val, int offset)
878 relopt_bool *newoption = init_bool_reloption(RELOPT_KIND_LOCAL,
879 name, desc,
880 default_val, 0);
882 add_local_reloption(relopts, (relopt_gen *) newoption, offset);
887 * init_real_reloption
888 * Allocate and initialize a new integer reloption
890 static relopt_int *
891 init_int_reloption(bits32 kinds, const char *name, const char *desc,
892 int default_val, int min_val, int max_val,
893 LOCKMODE lockmode)
895 relopt_int *newoption;
897 newoption = (relopt_int *) allocate_reloption(kinds, RELOPT_TYPE_INT,
898 name, desc, lockmode);
899 newoption->default_val = default_val;
900 newoption->min = min_val;
901 newoption->max = max_val;
903 return newoption;
907 * add_int_reloption
908 * Add a new integer reloption
910 void
911 add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val,
912 int min_val, int max_val, LOCKMODE lockmode)
914 relopt_int *newoption = init_int_reloption(kinds, name, desc,
915 default_val, min_val,
916 max_val, lockmode);
918 add_reloption((relopt_gen *) newoption);
922 * add_local_int_reloption
923 * Add a new local integer reloption
925 * 'offset' is offset of int-typed field.
927 void
928 add_local_int_reloption(local_relopts *relopts, const char *name,
929 const char *desc, int default_val, int min_val,
930 int max_val, int offset)
932 relopt_int *newoption = init_int_reloption(RELOPT_KIND_LOCAL,
933 name, desc, default_val,
934 min_val, max_val, 0);
936 add_local_reloption(relopts, (relopt_gen *) newoption, offset);
940 * init_real_reloption
941 * Allocate and initialize a new real reloption
943 static relopt_real *
944 init_real_reloption(bits32 kinds, const char *name, const char *desc,
945 double default_val, double min_val, double max_val,
946 LOCKMODE lockmode)
948 relopt_real *newoption;
950 newoption = (relopt_real *) allocate_reloption(kinds, RELOPT_TYPE_REAL,
951 name, desc, lockmode);
952 newoption->default_val = default_val;
953 newoption->min = min_val;
954 newoption->max = max_val;
956 return newoption;
960 * add_real_reloption
961 * Add a new float reloption
963 void
964 add_real_reloption(bits32 kinds, const char *name, const char *desc,
965 double default_val, double min_val, double max_val,
966 LOCKMODE lockmode)
968 relopt_real *newoption = init_real_reloption(kinds, name, desc,
969 default_val, min_val,
970 max_val, lockmode);
972 add_reloption((relopt_gen *) newoption);
976 * add_local_real_reloption
977 * Add a new local float reloption
979 * 'offset' is offset of double-typed field.
981 void
982 add_local_real_reloption(local_relopts *relopts, const char *name,
983 const char *desc, double default_val,
984 double min_val, double max_val, int offset)
986 relopt_real *newoption = init_real_reloption(RELOPT_KIND_LOCAL,
987 name, desc,
988 default_val, min_val,
989 max_val, 0);
991 add_local_reloption(relopts, (relopt_gen *) newoption, offset);
995 * init_enum_reloption
996 * Allocate and initialize a new enum reloption
998 static relopt_enum *
999 init_enum_reloption(bits32 kinds, const char *name, const char *desc,
1000 relopt_enum_elt_def *members, int default_val,
1001 const char *detailmsg, LOCKMODE lockmode)
1003 relopt_enum *newoption;
1005 newoption = (relopt_enum *) allocate_reloption(kinds, RELOPT_TYPE_ENUM,
1006 name, desc, lockmode);
1007 newoption->members = members;
1008 newoption->default_val = default_val;
1009 newoption->detailmsg = detailmsg;
1011 return newoption;
1016 * add_enum_reloption
1017 * Add a new enum reloption
1019 * The members array must have a terminating NULL entry.
1021 * The detailmsg is shown when unsupported values are passed, and has this
1022 * form: "Valid values are \"foo\", \"bar\", and \"bar\"."
1024 * The members array and detailmsg are not copied -- caller must ensure that
1025 * they are valid throughout the life of the process.
1027 void
1028 add_enum_reloption(bits32 kinds, const char *name, const char *desc,
1029 relopt_enum_elt_def *members, int default_val,
1030 const char *detailmsg, LOCKMODE lockmode)
1032 relopt_enum *newoption = init_enum_reloption(kinds, name, desc,
1033 members, default_val,
1034 detailmsg, lockmode);
1036 add_reloption((relopt_gen *) newoption);
1040 * add_local_enum_reloption
1041 * Add a new local enum reloption
1043 * 'offset' is offset of int-typed field.
1045 void
1046 add_local_enum_reloption(local_relopts *relopts, const char *name,
1047 const char *desc, relopt_enum_elt_def *members,
1048 int default_val, const char *detailmsg, int offset)
1050 relopt_enum *newoption = init_enum_reloption(RELOPT_KIND_LOCAL,
1051 name, desc,
1052 members, default_val,
1053 detailmsg, 0);
1055 add_local_reloption(relopts, (relopt_gen *) newoption, offset);
1059 * init_string_reloption
1060 * Allocate and initialize a new string reloption
1062 static relopt_string *
1063 init_string_reloption(bits32 kinds, const char *name, const char *desc,
1064 const char *default_val,
1065 validate_string_relopt validator,
1066 fill_string_relopt filler,
1067 LOCKMODE lockmode)
1069 relopt_string *newoption;
1071 /* make sure the validator/default combination is sane */
1072 if (validator)
1073 (validator) (default_val);
1075 newoption = (relopt_string *) allocate_reloption(kinds, RELOPT_TYPE_STRING,
1076 name, desc, lockmode);
1077 newoption->validate_cb = validator;
1078 newoption->fill_cb = filler;
1079 if (default_val)
1081 if (kinds == RELOPT_KIND_LOCAL)
1082 newoption->default_val = strdup(default_val);
1083 else
1084 newoption->default_val = MemoryContextStrdup(TopMemoryContext, default_val);
1085 newoption->default_len = strlen(default_val);
1086 newoption->default_isnull = false;
1088 else
1090 newoption->default_val = "";
1091 newoption->default_len = 0;
1092 newoption->default_isnull = true;
1095 return newoption;
1099 * add_string_reloption
1100 * Add a new string reloption
1102 * "validator" is an optional function pointer that can be used to test the
1103 * validity of the values. It must elog(ERROR) when the argument string is
1104 * not acceptable for the variable. Note that the default value must pass
1105 * the validation.
1107 void
1108 add_string_reloption(bits32 kinds, const char *name, const char *desc,
1109 const char *default_val, validate_string_relopt validator,
1110 LOCKMODE lockmode)
1112 relopt_string *newoption = init_string_reloption(kinds, name, desc,
1113 default_val,
1114 validator, NULL,
1115 lockmode);
1117 add_reloption((relopt_gen *) newoption);
1121 * add_local_string_reloption
1122 * Add a new local string reloption
1124 * 'offset' is offset of int-typed field that will store offset of string value
1125 * in the resulting bytea structure.
1127 void
1128 add_local_string_reloption(local_relopts *relopts, const char *name,
1129 const char *desc, const char *default_val,
1130 validate_string_relopt validator,
1131 fill_string_relopt filler, int offset)
1133 relopt_string *newoption = init_string_reloption(RELOPT_KIND_LOCAL,
1134 name, desc,
1135 default_val,
1136 validator, filler,
1139 add_local_reloption(relopts, (relopt_gen *) newoption, offset);
1143 * Transform a relation options list (list of DefElem) into the text array
1144 * format that is kept in pg_class.reloptions, including only those options
1145 * that are in the passed namespace. The output values do not include the
1146 * namespace.
1148 * This is used for three cases: CREATE TABLE/INDEX, ALTER TABLE SET, and
1149 * ALTER TABLE RESET. In the ALTER cases, oldOptions is the existing
1150 * reloptions value (possibly NULL), and we replace or remove entries
1151 * as needed.
1153 * If acceptOidsOff is true, then we allow oids = false, but throw error when
1154 * on. This is solely needed for backwards compatibility.
1156 * Note that this is not responsible for determining whether the options
1157 * are valid, but it does check that namespaces for all the options given are
1158 * listed in validnsps. The NULL namespace is always valid and need not be
1159 * explicitly listed. Passing a NULL pointer means that only the NULL
1160 * namespace is valid.
1162 * Both oldOptions and the result are text arrays (or NULL for "default"),
1163 * but we declare them as Datums to avoid including array.h in reloptions.h.
1165 Datum
1166 transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
1167 char *validnsps[], bool acceptOidsOff, bool isReset)
1169 Datum result;
1170 ArrayBuildState *astate;
1171 ListCell *cell;
1173 /* no change if empty list */
1174 if (defList == NIL)
1175 return oldOptions;
1177 /* We build new array using accumArrayResult */
1178 astate = NULL;
1180 /* Copy any oldOptions that aren't to be replaced */
1181 if (PointerIsValid(DatumGetPointer(oldOptions)))
1183 ArrayType *array = DatumGetArrayTypeP(oldOptions);
1184 Datum *oldoptions;
1185 int noldoptions;
1186 int i;
1188 deconstruct_array_builtin(array, TEXTOID, &oldoptions, NULL, &noldoptions);
1190 for (i = 0; i < noldoptions; i++)
1192 char *text_str = VARDATA(oldoptions[i]);
1193 int text_len = VARSIZE(oldoptions[i]) - VARHDRSZ;
1195 /* Search for a match in defList */
1196 foreach(cell, defList)
1198 DefElem *def = (DefElem *) lfirst(cell);
1199 int kw_len;
1201 /* ignore if not in the same namespace */
1202 if (namspace == NULL)
1204 if (def->defnamespace != NULL)
1205 continue;
1207 else if (def->defnamespace == NULL)
1208 continue;
1209 else if (strcmp(def->defnamespace, namspace) != 0)
1210 continue;
1212 kw_len = strlen(def->defname);
1213 if (text_len > kw_len && text_str[kw_len] == '=' &&
1214 strncmp(text_str, def->defname, kw_len) == 0)
1215 break;
1217 if (!cell)
1219 /* No match, so keep old option */
1220 astate = accumArrayResult(astate, oldoptions[i],
1221 false, TEXTOID,
1222 CurrentMemoryContext);
1228 * If CREATE/SET, add new options to array; if RESET, just check that the
1229 * user didn't say RESET (option=val). (Must do this because the grammar
1230 * doesn't enforce it.)
1232 foreach(cell, defList)
1234 DefElem *def = (DefElem *) lfirst(cell);
1236 if (isReset)
1238 if (def->arg != NULL)
1239 ereport(ERROR,
1240 (errcode(ERRCODE_SYNTAX_ERROR),
1241 errmsg("RESET must not include values for parameters")));
1243 else
1245 text *t;
1246 const char *value;
1247 Size len;
1250 * Error out if the namespace is not valid. A NULL namespace is
1251 * always valid.
1253 if (def->defnamespace != NULL)
1255 bool valid = false;
1256 int i;
1258 if (validnsps)
1260 for (i = 0; validnsps[i]; i++)
1262 if (strcmp(def->defnamespace, validnsps[i]) == 0)
1264 valid = true;
1265 break;
1270 if (!valid)
1271 ereport(ERROR,
1272 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1273 errmsg("unrecognized parameter namespace \"%s\"",
1274 def->defnamespace)));
1277 /* ignore if not in the same namespace */
1278 if (namspace == NULL)
1280 if (def->defnamespace != NULL)
1281 continue;
1283 else if (def->defnamespace == NULL)
1284 continue;
1285 else if (strcmp(def->defnamespace, namspace) != 0)
1286 continue;
1289 * Flatten the DefElem into a text string like "name=arg". If we
1290 * have just "name", assume "name=true" is meant. Note: the
1291 * namespace is not output.
1293 if (def->arg != NULL)
1294 value = defGetString(def);
1295 else
1296 value = "true";
1299 * This is not a great place for this test, but there's no other
1300 * convenient place to filter the option out. As WITH (oids =
1301 * false) will be removed someday, this seems like an acceptable
1302 * amount of ugly.
1304 if (acceptOidsOff && def->defnamespace == NULL &&
1305 strcmp(def->defname, "oids") == 0)
1307 if (defGetBoolean(def))
1308 ereport(ERROR,
1309 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1310 errmsg("tables declared WITH OIDS are not supported")));
1311 /* skip over option, reloptions machinery doesn't know it */
1312 continue;
1315 len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
1316 /* +1 leaves room for sprintf's trailing null */
1317 t = (text *) palloc(len + 1);
1318 SET_VARSIZE(t, len);
1319 sprintf(VARDATA(t), "%s=%s", def->defname, value);
1321 astate = accumArrayResult(astate, PointerGetDatum(t),
1322 false, TEXTOID,
1323 CurrentMemoryContext);
1327 if (astate)
1328 result = makeArrayResult(astate, CurrentMemoryContext);
1329 else
1330 result = (Datum) 0;
1332 return result;
1337 * Convert the text-array format of reloptions into a List of DefElem.
1338 * This is the inverse of transformRelOptions().
1340 List *
1341 untransformRelOptions(Datum options)
1343 List *result = NIL;
1344 ArrayType *array;
1345 Datum *optiondatums;
1346 int noptions;
1347 int i;
1349 /* Nothing to do if no options */
1350 if (!PointerIsValid(DatumGetPointer(options)))
1351 return result;
1353 array = DatumGetArrayTypeP(options);
1355 deconstruct_array_builtin(array, TEXTOID, &optiondatums, NULL, &noptions);
1357 for (i = 0; i < noptions; i++)
1359 char *s;
1360 char *p;
1361 Node *val = NULL;
1363 s = TextDatumGetCString(optiondatums[i]);
1364 p = strchr(s, '=');
1365 if (p)
1367 *p++ = '\0';
1368 val = (Node *) makeString(p);
1370 result = lappend(result, makeDefElem(s, val, -1));
1373 return result;
1377 * Extract and parse reloptions from a pg_class tuple.
1379 * This is a low-level routine, expected to be used by relcache code and
1380 * callers that do not have a table's relcache entry (e.g. autovacuum). For
1381 * other uses, consider grabbing the rd_options pointer from the relcache entry
1382 * instead.
1384 * tupdesc is pg_class' tuple descriptor. amoptions is a pointer to the index
1385 * AM's options parser function in the case of a tuple corresponding to an
1386 * index, or NULL otherwise.
1388 bytea *
1389 extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
1390 amoptions_function amoptions)
1392 bytea *options;
1393 bool isnull;
1394 Datum datum;
1395 Form_pg_class classForm;
1397 datum = fastgetattr(tuple,
1398 Anum_pg_class_reloptions,
1399 tupdesc,
1400 &isnull);
1401 if (isnull)
1402 return NULL;
1404 classForm = (Form_pg_class) GETSTRUCT(tuple);
1406 /* Parse into appropriate format; don't error out here */
1407 switch (classForm->relkind)
1409 case RELKIND_RELATION:
1410 case RELKIND_TOASTVALUE:
1411 case RELKIND_MATVIEW:
1412 options = heap_reloptions(classForm->relkind, datum, false);
1413 break;
1414 case RELKIND_PARTITIONED_TABLE:
1415 options = partitioned_table_reloptions(datum, false);
1416 break;
1417 case RELKIND_VIEW:
1418 options = view_reloptions(datum, false);
1419 break;
1420 case RELKIND_INDEX:
1421 case RELKIND_PARTITIONED_INDEX:
1422 options = index_reloptions(amoptions, datum, false);
1423 break;
1424 case RELKIND_FOREIGN_TABLE:
1425 options = NULL;
1426 break;
1427 default:
1428 Assert(false); /* can't get here */
1429 options = NULL; /* keep compiler quiet */
1430 break;
1433 return options;
1436 static void
1437 parseRelOptionsInternal(Datum options, bool validate,
1438 relopt_value *reloptions, int numoptions)
1440 ArrayType *array = DatumGetArrayTypeP(options);
1441 Datum *optiondatums;
1442 int noptions;
1443 int i;
1445 deconstruct_array_builtin(array, TEXTOID, &optiondatums, NULL, &noptions);
1447 for (i = 0; i < noptions; i++)
1449 char *text_str = VARDATA(optiondatums[i]);
1450 int text_len = VARSIZE(optiondatums[i]) - VARHDRSZ;
1451 int j;
1453 /* Search for a match in reloptions */
1454 for (j = 0; j < numoptions; j++)
1456 int kw_len = reloptions[j].gen->namelen;
1458 if (text_len > kw_len && text_str[kw_len] == '=' &&
1459 strncmp(text_str, reloptions[j].gen->name, kw_len) == 0)
1461 parse_one_reloption(&reloptions[j], text_str, text_len,
1462 validate);
1463 break;
1467 if (j >= numoptions && validate)
1469 char *s;
1470 char *p;
1472 s = TextDatumGetCString(optiondatums[i]);
1473 p = strchr(s, '=');
1474 if (p)
1475 *p = '\0';
1476 ereport(ERROR,
1477 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1478 errmsg("unrecognized parameter \"%s\"", s)));
1482 /* It's worth avoiding memory leaks in this function */
1483 pfree(optiondatums);
1485 if (((void *) array) != DatumGetPointer(options))
1486 pfree(array);
1490 * Interpret reloptions that are given in text-array format.
1492 * options is a reloption text array as constructed by transformRelOptions.
1493 * kind specifies the family of options to be processed.
1495 * The return value is a relopt_value * array on which the options actually
1496 * set in the options array are marked with isset=true. The length of this
1497 * array is returned in *numrelopts. Options not set are also present in the
1498 * array; this is so that the caller can easily locate the default values.
1500 * If there are no options of the given kind, numrelopts is set to 0 and NULL
1501 * is returned (unless options are illegally supplied despite none being
1502 * defined, in which case an error occurs).
1504 * Note: values of type int, bool and real are allocated as part of the
1505 * returned array. Values of type string are allocated separately and must
1506 * be freed by the caller.
1508 static relopt_value *
1509 parseRelOptions(Datum options, bool validate, relopt_kind kind,
1510 int *numrelopts)
1512 relopt_value *reloptions = NULL;
1513 int numoptions = 0;
1514 int i;
1515 int j;
1517 if (need_initialization)
1518 initialize_reloptions();
1520 /* Build a list of expected options, based on kind */
1522 for (i = 0; relOpts[i]; i++)
1523 if (relOpts[i]->kinds & kind)
1524 numoptions++;
1526 if (numoptions > 0)
1528 reloptions = palloc(numoptions * sizeof(relopt_value));
1530 for (i = 0, j = 0; relOpts[i]; i++)
1532 if (relOpts[i]->kinds & kind)
1534 reloptions[j].gen = relOpts[i];
1535 reloptions[j].isset = false;
1536 j++;
1541 /* Done if no options */
1542 if (PointerIsValid(DatumGetPointer(options)))
1543 parseRelOptionsInternal(options, validate, reloptions, numoptions);
1545 *numrelopts = numoptions;
1546 return reloptions;
1549 /* Parse local unregistered options. */
1550 static relopt_value *
1551 parseLocalRelOptions(local_relopts *relopts, Datum options, bool validate)
1553 int nopts = list_length(relopts->options);
1554 relopt_value *values = palloc(sizeof(*values) * nopts);
1555 ListCell *lc;
1556 int i = 0;
1558 foreach(lc, relopts->options)
1560 local_relopt *opt = lfirst(lc);
1562 values[i].gen = opt->option;
1563 values[i].isset = false;
1565 i++;
1568 if (options != (Datum) 0)
1569 parseRelOptionsInternal(options, validate, values, nopts);
1571 return values;
1575 * Subroutine for parseRelOptions, to parse and validate a single option's
1576 * value
1578 static void
1579 parse_one_reloption(relopt_value *option, char *text_str, int text_len,
1580 bool validate)
1582 char *value;
1583 int value_len;
1584 bool parsed;
1585 bool nofree = false;
1587 if (option->isset && validate)
1588 ereport(ERROR,
1589 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1590 errmsg("parameter \"%s\" specified more than once",
1591 option->gen->name)));
1593 value_len = text_len - option->gen->namelen - 1;
1594 value = (char *) palloc(value_len + 1);
1595 memcpy(value, text_str + option->gen->namelen + 1, value_len);
1596 value[value_len] = '\0';
1598 switch (option->gen->type)
1600 case RELOPT_TYPE_BOOL:
1602 parsed = parse_bool(value, &option->values.bool_val);
1603 if (validate && !parsed)
1604 ereport(ERROR,
1605 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1606 errmsg("invalid value for boolean option \"%s\": %s",
1607 option->gen->name, value)));
1609 break;
1610 case RELOPT_TYPE_INT:
1612 relopt_int *optint = (relopt_int *) option->gen;
1614 parsed = parse_int(value, &option->values.int_val, 0, NULL);
1615 if (validate && !parsed)
1616 ereport(ERROR,
1617 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1618 errmsg("invalid value for integer option \"%s\": %s",
1619 option->gen->name, value)));
1620 if (validate && (option->values.int_val < optint->min ||
1621 option->values.int_val > optint->max))
1622 ereport(ERROR,
1623 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1624 errmsg("value %s out of bounds for option \"%s\"",
1625 value, option->gen->name),
1626 errdetail("Valid values are between \"%d\" and \"%d\".",
1627 optint->min, optint->max)));
1629 break;
1630 case RELOPT_TYPE_REAL:
1632 relopt_real *optreal = (relopt_real *) option->gen;
1634 parsed = parse_real(value, &option->values.real_val, 0, NULL);
1635 if (validate && !parsed)
1636 ereport(ERROR,
1637 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1638 errmsg("invalid value for floating point option \"%s\": %s",
1639 option->gen->name, value)));
1640 if (validate && (option->values.real_val < optreal->min ||
1641 option->values.real_val > optreal->max))
1642 ereport(ERROR,
1643 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1644 errmsg("value %s out of bounds for option \"%s\"",
1645 value, option->gen->name),
1646 errdetail("Valid values are between \"%f\" and \"%f\".",
1647 optreal->min, optreal->max)));
1649 break;
1650 case RELOPT_TYPE_ENUM:
1652 relopt_enum *optenum = (relopt_enum *) option->gen;
1653 relopt_enum_elt_def *elt;
1655 parsed = false;
1656 for (elt = optenum->members; elt->string_val; elt++)
1658 if (pg_strcasecmp(value, elt->string_val) == 0)
1660 option->values.enum_val = elt->symbol_val;
1661 parsed = true;
1662 break;
1665 if (validate && !parsed)
1666 ereport(ERROR,
1667 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1668 errmsg("invalid value for enum option \"%s\": %s",
1669 option->gen->name, value),
1670 optenum->detailmsg ?
1671 errdetail_internal("%s", _(optenum->detailmsg)) : 0));
1674 * If value is not among the allowed string values, but we are
1675 * not asked to validate, just use the default numeric value.
1677 if (!parsed)
1678 option->values.enum_val = optenum->default_val;
1680 break;
1681 case RELOPT_TYPE_STRING:
1683 relopt_string *optstring = (relopt_string *) option->gen;
1685 option->values.string_val = value;
1686 nofree = true;
1687 if (validate && optstring->validate_cb)
1688 (optstring->validate_cb) (value);
1689 parsed = true;
1691 break;
1692 default:
1693 elog(ERROR, "unsupported reloption type %d", option->gen->type);
1694 parsed = true; /* quiet compiler */
1695 break;
1698 if (parsed)
1699 option->isset = true;
1700 if (!nofree)
1701 pfree(value);
1705 * Given the result from parseRelOptions, allocate a struct that's of the
1706 * specified base size plus any extra space that's needed for string variables.
1708 * "base" should be sizeof(struct) of the reloptions struct (StdRdOptions or
1709 * equivalent).
1711 static void *
1712 allocateReloptStruct(Size base, relopt_value *options, int numoptions)
1714 Size size = base;
1715 int i;
1717 for (i = 0; i < numoptions; i++)
1719 relopt_value *optval = &options[i];
1721 if (optval->gen->type == RELOPT_TYPE_STRING)
1723 relopt_string *optstr = (relopt_string *) optval->gen;
1725 if (optstr->fill_cb)
1727 const char *val = optval->isset ? optval->values.string_val :
1728 optstr->default_isnull ? NULL : optstr->default_val;
1730 size += optstr->fill_cb(val, NULL);
1732 else
1733 size += GET_STRING_RELOPTION_LEN(*optval) + 1;
1737 return palloc0(size);
1741 * Given the result of parseRelOptions and a parsing table, fill in the
1742 * struct (previously allocated with allocateReloptStruct) with the parsed
1743 * values.
1745 * rdopts is the pointer to the allocated struct to be filled.
1746 * basesize is the sizeof(struct) that was passed to allocateReloptStruct.
1747 * options, of length numoptions, is parseRelOptions' output.
1748 * elems, of length numelems, is the table describing the allowed options.
1749 * When validate is true, it is expected that all options appear in elems.
1751 static void
1752 fillRelOptions(void *rdopts, Size basesize,
1753 relopt_value *options, int numoptions,
1754 bool validate,
1755 const relopt_parse_elt *elems, int numelems)
1757 int i;
1758 int offset = basesize;
1760 for (i = 0; i < numoptions; i++)
1762 int j;
1763 bool found = false;
1765 for (j = 0; j < numelems; j++)
1767 if (strcmp(options[i].gen->name, elems[j].optname) == 0)
1769 relopt_string *optstring;
1770 char *itempos = ((char *) rdopts) + elems[j].offset;
1771 char *string_val;
1773 switch (options[i].gen->type)
1775 case RELOPT_TYPE_BOOL:
1776 *(bool *) itempos = options[i].isset ?
1777 options[i].values.bool_val :
1778 ((relopt_bool *) options[i].gen)->default_val;
1779 break;
1780 case RELOPT_TYPE_INT:
1781 *(int *) itempos = options[i].isset ?
1782 options[i].values.int_val :
1783 ((relopt_int *) options[i].gen)->default_val;
1784 break;
1785 case RELOPT_TYPE_REAL:
1786 *(double *) itempos = options[i].isset ?
1787 options[i].values.real_val :
1788 ((relopt_real *) options[i].gen)->default_val;
1789 break;
1790 case RELOPT_TYPE_ENUM:
1791 *(int *) itempos = options[i].isset ?
1792 options[i].values.enum_val :
1793 ((relopt_enum *) options[i].gen)->default_val;
1794 break;
1795 case RELOPT_TYPE_STRING:
1796 optstring = (relopt_string *) options[i].gen;
1797 if (options[i].isset)
1798 string_val = options[i].values.string_val;
1799 else if (!optstring->default_isnull)
1800 string_val = optstring->default_val;
1801 else
1802 string_val = NULL;
1804 if (optstring->fill_cb)
1806 Size size =
1807 optstring->fill_cb(string_val,
1808 (char *) rdopts + offset);
1810 if (size)
1812 *(int *) itempos = offset;
1813 offset += size;
1815 else
1816 *(int *) itempos = 0;
1818 else if (string_val == NULL)
1819 *(int *) itempos = 0;
1820 else
1822 strcpy((char *) rdopts + offset, string_val);
1823 *(int *) itempos = offset;
1824 offset += strlen(string_val) + 1;
1826 break;
1827 default:
1828 elog(ERROR, "unsupported reloption type %d",
1829 options[i].gen->type);
1830 break;
1832 found = true;
1833 break;
1836 if (validate && !found)
1837 elog(ERROR, "reloption \"%s\" not found in parse table",
1838 options[i].gen->name);
1840 SET_VARSIZE(rdopts, offset);
1845 * Option parser for anything that uses StdRdOptions.
1847 bytea *
1848 default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
1850 static const relopt_parse_elt tab[] = {
1851 {"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
1852 {"autovacuum_enabled", RELOPT_TYPE_BOOL,
1853 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, enabled)},
1854 {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,
1855 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)},
1856 {"autovacuum_vacuum_insert_threshold", RELOPT_TYPE_INT,
1857 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_threshold)},
1858 {"autovacuum_analyze_threshold", RELOPT_TYPE_INT,
1859 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)},
1860 {"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,
1861 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)},
1862 {"autovacuum_freeze_min_age", RELOPT_TYPE_INT,
1863 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_min_age)},
1864 {"autovacuum_freeze_max_age", RELOPT_TYPE_INT,
1865 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_max_age)},
1866 {"autovacuum_freeze_table_age", RELOPT_TYPE_INT,
1867 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_table_age)},
1868 {"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT,
1869 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_min_age)},
1870 {"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT,
1871 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_max_age)},
1872 {"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT,
1873 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_table_age)},
1874 {"autovacuum_freeze_strategy_threshold", RELOPT_TYPE_INT,
1875 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_strategy_threshold)},
1876 {"log_autovacuum_min_duration", RELOPT_TYPE_INT,
1877 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, log_min_duration)},
1878 {"toast_tuple_target", RELOPT_TYPE_INT,
1879 offsetof(StdRdOptions, toast_tuple_target)},
1880 {"autovacuum_vacuum_cost_delay", RELOPT_TYPE_REAL,
1881 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)},
1882 {"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
1883 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_scale_factor)},
1884 {"autovacuum_vacuum_insert_scale_factor", RELOPT_TYPE_REAL,
1885 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_scale_factor)},
1886 {"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
1887 offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_scale_factor)},
1888 {"user_catalog_table", RELOPT_TYPE_BOOL,
1889 offsetof(StdRdOptions, user_catalog_table)},
1890 {"parallel_workers", RELOPT_TYPE_INT,
1891 offsetof(StdRdOptions, parallel_workers)},
1892 {"vacuum_index_cleanup", RELOPT_TYPE_ENUM,
1893 offsetof(StdRdOptions, vacuum_index_cleanup)},
1894 {"vacuum_truncate", RELOPT_TYPE_BOOL,
1895 offsetof(StdRdOptions, vacuum_truncate)}
1898 return (bytea *) build_reloptions(reloptions, validate, kind,
1899 sizeof(StdRdOptions),
1900 tab, lengthof(tab));
1904 * build_reloptions
1906 * Parses "reloptions" provided by the caller, returning them in a
1907 * structure containing the parsed options. The parsing is done with
1908 * the help of a parsing table describing the allowed options, defined
1909 * by "relopt_elems" of length "num_relopt_elems".
1911 * "validate" must be true if reloptions value is freshly built by
1912 * transformRelOptions(), as opposed to being read from the catalog, in which
1913 * case the values contained in it must already be valid.
1915 * NULL is returned if the passed-in options did not match any of the options
1916 * in the parsing table, unless validate is true in which case an error would
1917 * be reported.
1919 void *
1920 build_reloptions(Datum reloptions, bool validate,
1921 relopt_kind kind,
1922 Size relopt_struct_size,
1923 const relopt_parse_elt *relopt_elems,
1924 int num_relopt_elems)
1926 int numoptions;
1927 relopt_value *options;
1928 void *rdopts;
1930 /* parse options specific to given relation option kind */
1931 options = parseRelOptions(reloptions, validate, kind, &numoptions);
1932 Assert(numoptions <= num_relopt_elems);
1934 /* if none set, we're done */
1935 if (numoptions == 0)
1937 Assert(options == NULL);
1938 return NULL;
1941 /* allocate and fill the structure */
1942 rdopts = allocateReloptStruct(relopt_struct_size, options, numoptions);
1943 fillRelOptions(rdopts, relopt_struct_size, options, numoptions,
1944 validate, relopt_elems, num_relopt_elems);
1946 pfree(options);
1948 return rdopts;
1952 * Parse local options, allocate a bytea struct that's of the specified
1953 * 'base_size' plus any extra space that's needed for string variables,
1954 * fill its option's fields located at the given offsets and return it.
1956 void *
1957 build_local_reloptions(local_relopts *relopts, Datum options, bool validate)
1959 int noptions = list_length(relopts->options);
1960 relopt_parse_elt *elems = palloc(sizeof(*elems) * noptions);
1961 relopt_value *vals;
1962 void *opts;
1963 int i = 0;
1964 ListCell *lc;
1966 foreach(lc, relopts->options)
1968 local_relopt *opt = lfirst(lc);
1970 elems[i].optname = opt->option->name;
1971 elems[i].opttype = opt->option->type;
1972 elems[i].offset = opt->offset;
1974 i++;
1977 vals = parseLocalRelOptions(relopts, options, validate);
1978 opts = allocateReloptStruct(relopts->relopt_struct_size, vals, noptions);
1979 fillRelOptions(opts, relopts->relopt_struct_size, vals, noptions, validate,
1980 elems, noptions);
1982 foreach(lc, relopts->validators)
1983 ((relopts_validator) lfirst(lc)) (opts, vals, noptions);
1985 if (elems)
1986 pfree(elems);
1988 return opts;
1992 * Option parser for partitioned tables
1994 bytea *
1995 partitioned_table_reloptions(Datum reloptions, bool validate)
1997 if (validate && reloptions)
1998 ereport(ERROR,
1999 errcode(ERRCODE_WRONG_OBJECT_TYPE),
2000 errmsg("cannot specify storage parameters for a partitioned table"),
2001 errhint("Specify storage parameters for its leaf partitions, instead."));
2002 return NULL;
2006 * Option parser for views
2008 bytea *
2009 view_reloptions(Datum reloptions, bool validate)
2011 static const relopt_parse_elt tab[] = {
2012 {"security_barrier", RELOPT_TYPE_BOOL,
2013 offsetof(ViewOptions, security_barrier)},
2014 {"security_invoker", RELOPT_TYPE_BOOL,
2015 offsetof(ViewOptions, security_invoker)},
2016 {"check_option", RELOPT_TYPE_ENUM,
2017 offsetof(ViewOptions, check_option)}
2020 return (bytea *) build_reloptions(reloptions, validate,
2021 RELOPT_KIND_VIEW,
2022 sizeof(ViewOptions),
2023 tab, lengthof(tab));
2027 * Parse options for heaps, views and toast tables.
2029 bytea *
2030 heap_reloptions(char relkind, Datum reloptions, bool validate)
2032 StdRdOptions *rdopts;
2034 switch (relkind)
2036 case RELKIND_TOASTVALUE:
2037 rdopts = (StdRdOptions *)
2038 default_reloptions(reloptions, validate, RELOPT_KIND_TOAST);
2039 if (rdopts != NULL)
2041 /* adjust default-only parameters for TOAST relations */
2042 rdopts->fillfactor = 100;
2043 rdopts->autovacuum.analyze_threshold = -1;
2044 rdopts->autovacuum.analyze_scale_factor = -1;
2046 return (bytea *) rdopts;
2047 case RELKIND_RELATION:
2048 case RELKIND_MATVIEW:
2049 return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
2050 default:
2051 /* other relkinds are not supported */
2052 return NULL;
2058 * Parse options for indexes.
2060 * amoptions index AM's option parser function
2061 * reloptions options as text[] datum
2062 * validate error flag
2064 bytea *
2065 index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate)
2067 Assert(amoptions != NULL);
2069 /* Assume function is strict */
2070 if (!PointerIsValid(DatumGetPointer(reloptions)))
2071 return NULL;
2073 return amoptions(reloptions, validate);
2077 * Option parser for attribute reloptions
2079 bytea *
2080 attribute_reloptions(Datum reloptions, bool validate)
2082 static const relopt_parse_elt tab[] = {
2083 {"n_distinct", RELOPT_TYPE_REAL, offsetof(AttributeOpts, n_distinct)},
2084 {"n_distinct_inherited", RELOPT_TYPE_REAL, offsetof(AttributeOpts, n_distinct_inherited)}
2087 return (bytea *) build_reloptions(reloptions, validate,
2088 RELOPT_KIND_ATTRIBUTE,
2089 sizeof(AttributeOpts),
2090 tab, lengthof(tab));
2094 * Option parser for tablespace reloptions
2096 bytea *
2097 tablespace_reloptions(Datum reloptions, bool validate)
2099 static const relopt_parse_elt tab[] = {
2100 {"random_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, random_page_cost)},
2101 {"seq_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, seq_page_cost)},
2102 {"effective_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, effective_io_concurrency)},
2103 {"maintenance_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, maintenance_io_concurrency)}
2106 return (bytea *) build_reloptions(reloptions, validate,
2107 RELOPT_KIND_TABLESPACE,
2108 sizeof(TableSpaceOpts),
2109 tab, lengthof(tab));
2113 * Determine the required LOCKMODE from an option list.
2115 * Called from AlterTableGetLockLevel(), see that function
2116 * for a longer explanation of how this works.
2118 LOCKMODE
2119 AlterTableGetRelOptionsLockLevel(List *defList)
2121 LOCKMODE lockmode = NoLock;
2122 ListCell *cell;
2124 if (defList == NIL)
2125 return AccessExclusiveLock;
2127 if (need_initialization)
2128 initialize_reloptions();
2130 foreach(cell, defList)
2132 DefElem *def = (DefElem *) lfirst(cell);
2133 int i;
2135 for (i = 0; relOpts[i]; i++)
2137 if (strncmp(relOpts[i]->name,
2138 def->defname,
2139 relOpts[i]->namelen + 1) == 0)
2141 if (lockmode < relOpts[i]->lockmode)
2142 lockmode = relOpts[i]->lockmode;
2147 return lockmode;