1 /*-------------------------------------------------------------------------
4 * Core support for relation options (pg_class.reloptions)
6 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/access/common/reloptions.c
13 *-------------------------------------------------------------------------
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 "nodes/makefuncs.h"
31 #include "utils/array.h"
32 #include "utils/attoptcache.h"
33 #include "utils/builtins.h"
34 #include "utils/guc.h"
35 #include "utils/memutils.h"
36 #include "utils/rel.h"
39 * Contents of pg_class.reloptions
43 * (i) decide on a type (bool, integer, real, enum, string), name, default
44 * value, upper and lower bounds (if applicable); for strings, consider a
46 * (ii) add a record below (or use add_<type>_reloption).
47 * (iii) add it to the appropriate options struct (perhaps StdRdOptions)
48 * (iv) add it to the appropriate handling routine (perhaps
50 * (v) make sure the lock level is set correctly for that operation
51 * (vi) don't forget to document the option
53 * The default choice for any new option should be AccessExclusiveLock.
54 * In some cases the lock level can be reduced from there, but the lock
55 * level chosen should always conflict with itself to ensure that multiple
56 * changes aren't lost when we attempt concurrent changes.
57 * The choice of lock level depends completely upon how that parameter
58 * is used within the server, not upon how and when you'd like to change it.
59 * Safety first. Existing choices are documented here, and elsewhere in
60 * backend code where the parameters are used.
62 * In general, anything that affects the results obtained from a SELECT must be
63 * protected by AccessExclusiveLock.
65 * Autovacuum related parameters can be set at ShareUpdateExclusiveLock
66 * since they are only used by the AV procs and don't change anything
67 * currently executing.
69 * Fillfactor can be set at ShareUpdateExclusiveLock because it applies only to
70 * subsequent changes made to data blocks, as documented in hio.c
72 * n_distinct options can be set at ShareUpdateExclusiveLock because they
73 * are only used during ANALYZE, which uses a ShareUpdateExclusiveLock,
74 * so the ANALYZE will not be affected by in-flight changes. Changing those
75 * values has no effect until the next ANALYZE, so no need for stronger lock.
77 * Planner-related parameters can be set at ShareUpdateExclusiveLock because
78 * they only affect planning and not the correctness of the execution. Plans
79 * cannot be changed in mid-flight, so changes here could not easily result in
80 * new improved plans in any case. So we allow existing queries to continue
81 * and existing plans to survive, a small price to pay for allowing better
82 * plans to be introduced concurrently without interfering with users.
84 * Setting parallel_workers at ShareUpdateExclusiveLock is safe, since it acts
85 * the same as max_parallel_workers_per_gather which is a USERSET parameter
86 * that doesn't affect existing plans or queries.
88 * vacuum_truncate can be set at ShareUpdateExclusiveLock because it
89 * is only used during VACUUM, which uses a ShareUpdateExclusiveLock,
90 * so the VACUUM will not be affected by in-flight changes. Changing its
91 * value has no effect until the next VACUUM, so no need for stronger lock.
94 static relopt_bool boolRelOpts
[] =
99 "Enables automatic summarization on this BRIN index",
107 "autovacuum_enabled",
108 "Enables autovacuum in this relation",
109 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
110 ShareUpdateExclusiveLock
116 "user_catalog_table",
117 "Declare a table as an additional catalog table, e.g. for the purpose of logical replication",
126 "Enables \"fast update\" feature for this GIN index",
135 "View acts as a row security barrier",
144 "Privileges on underlying relations are checked as the invoking user, not the view owner",
153 "Enables vacuum to truncate empty pages at the end of this table",
154 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
155 ShareUpdateExclusiveLock
162 "Enables \"deduplicate items\" feature for this btree index",
164 ShareUpdateExclusiveLock
/* since it applies only to later
169 /* list terminator */
173 static relopt_int intRelOpts
[] =
178 "Packs table pages only to this percentage",
180 ShareUpdateExclusiveLock
/* since it applies only to later
183 HEAP_DEFAULT_FILLFACTOR
, HEAP_MIN_FILLFACTOR
, 100
188 "Packs btree index pages only to this percentage",
190 ShareUpdateExclusiveLock
/* since it applies only to later
193 BTREE_DEFAULT_FILLFACTOR
, BTREE_MIN_FILLFACTOR
, 100
198 "Packs hash index pages only to this percentage",
200 ShareUpdateExclusiveLock
/* since it applies only to later
203 HASH_DEFAULT_FILLFACTOR
, HASH_MIN_FILLFACTOR
, 100
208 "Packs gist index pages only to this percentage",
210 ShareUpdateExclusiveLock
/* since it applies only to later
213 GIST_DEFAULT_FILLFACTOR
, GIST_MIN_FILLFACTOR
, 100
218 "Packs spgist index pages only to this percentage",
220 ShareUpdateExclusiveLock
/* since it applies only to later
223 SPGIST_DEFAULT_FILLFACTOR
, SPGIST_MIN_FILLFACTOR
, 100
227 "autovacuum_vacuum_threshold",
228 "Minimum number of tuple updates or deletes prior to vacuum",
229 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
230 ShareUpdateExclusiveLock
236 "autovacuum_vacuum_insert_threshold",
237 "Minimum number of tuple inserts prior to vacuum, or -1 to disable insert vacuums",
238 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
239 ShareUpdateExclusiveLock
245 "autovacuum_analyze_threshold",
246 "Minimum number of tuple inserts, updates or deletes prior to analyze",
248 ShareUpdateExclusiveLock
254 "autovacuum_vacuum_cost_limit",
255 "Vacuum cost amount available before napping, for autovacuum",
256 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
257 ShareUpdateExclusiveLock
263 "autovacuum_freeze_min_age",
264 "Minimum age at which VACUUM should freeze a table row, for autovacuum",
265 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
266 ShareUpdateExclusiveLock
272 "autovacuum_multixact_freeze_min_age",
273 "Minimum multixact age at which VACUUM should freeze a row multixact's, for autovacuum",
274 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
275 ShareUpdateExclusiveLock
281 "autovacuum_freeze_max_age",
282 "Age at which to autovacuum a table to prevent transaction ID wraparound",
283 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
284 ShareUpdateExclusiveLock
286 -1, 100000, 2000000000
290 "autovacuum_multixact_freeze_max_age",
291 "Multixact age at which to autovacuum a table to prevent multixact wraparound",
292 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
293 ShareUpdateExclusiveLock
295 -1, 10000, 2000000000
299 "autovacuum_freeze_table_age",
300 "Age at which VACUUM should perform a full table sweep to freeze row versions",
301 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
302 ShareUpdateExclusiveLock
307 "autovacuum_multixact_freeze_table_age",
308 "Age of multixact at which VACUUM should perform a full table sweep to freeze row versions",
309 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
310 ShareUpdateExclusiveLock
315 "log_autovacuum_min_duration",
316 "Sets the minimum execution time above which autovacuum actions will be logged",
317 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
318 ShareUpdateExclusiveLock
324 "toast_tuple_target",
325 "Sets the target tuple length at which external columns will be toasted",
327 ShareUpdateExclusiveLock
329 TOAST_TUPLE_TARGET
, 128, TOAST_TUPLE_TARGET_MAIN
334 "Number of pages that each page range covers in a BRIN index",
341 "gin_pending_list_limit",
342 "Maximum size of the pending list for this GIN index, in kilobytes.",
346 -1, 64, MAX_KILOBYTES
350 "effective_io_concurrency",
351 "Number of simultaneous requests that can be handled efficiently by the disk subsystem.",
352 RELOPT_KIND_TABLESPACE
,
353 ShareUpdateExclusiveLock
356 -1, 0, MAX_IO_CONCURRENCY
363 "maintenance_io_concurrency",
364 "Number of simultaneous requests that can be handled efficiently by the disk subsystem for maintenance work.",
365 RELOPT_KIND_TABLESPACE
,
366 ShareUpdateExclusiveLock
369 -1, 0, MAX_IO_CONCURRENCY
377 "Number of parallel processes that can be used per executor node for this relation.",
379 ShareUpdateExclusiveLock
384 /* list terminator */
388 static relopt_real realRelOpts
[] =
392 "autovacuum_vacuum_cost_delay",
393 "Vacuum cost delay in milliseconds, for autovacuum",
394 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
395 ShareUpdateExclusiveLock
401 "autovacuum_vacuum_scale_factor",
402 "Number of tuple updates or deletes prior to vacuum as a fraction of reltuples",
403 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
404 ShareUpdateExclusiveLock
410 "autovacuum_vacuum_insert_scale_factor",
411 "Number of tuple inserts prior to vacuum as a fraction of reltuples",
412 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
413 ShareUpdateExclusiveLock
419 "autovacuum_analyze_scale_factor",
420 "Number of tuple inserts, updates or deletes prior to analyze as a fraction of reltuples",
422 ShareUpdateExclusiveLock
429 "Sets the planner's estimate of the cost of a sequentially fetched disk page.",
430 RELOPT_KIND_TABLESPACE
,
431 ShareUpdateExclusiveLock
438 "Sets the planner's estimate of the cost of a nonsequentially fetched disk page.",
439 RELOPT_KIND_TABLESPACE
,
440 ShareUpdateExclusiveLock
447 "Sets the planner's estimate of the number of distinct values appearing in a column (excluding child relations).",
448 RELOPT_KIND_ATTRIBUTE
,
449 ShareUpdateExclusiveLock
455 "n_distinct_inherited",
456 "Sets the planner's estimate of the number of distinct values appearing in a column (including child relations).",
457 RELOPT_KIND_ATTRIBUTE
,
458 ShareUpdateExclusiveLock
464 "vacuum_cleanup_index_scale_factor",
465 "Deprecated B-Tree parameter.",
467 ShareUpdateExclusiveLock
471 /* list terminator */
475 /* values from StdRdOptIndexCleanup */
476 static relopt_enum_elt_def StdRdOptIndexCleanupValues
[] =
478 {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO
},
479 {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON
},
480 {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF
},
481 {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON
},
482 {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF
},
483 {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON
},
484 {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF
},
485 {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON
},
486 {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF
},
487 {(const char *) NULL
} /* list terminator */
490 /* values from GistOptBufferingMode */
491 static relopt_enum_elt_def gistBufferingOptValues
[] =
493 {"auto", GIST_OPTION_BUFFERING_AUTO
},
494 {"on", GIST_OPTION_BUFFERING_ON
},
495 {"off", GIST_OPTION_BUFFERING_OFF
},
496 {(const char *) NULL
} /* list terminator */
499 /* values from ViewOptCheckOption */
500 static relopt_enum_elt_def viewCheckOptValues
[] =
502 /* no value for NOT_SET */
503 {"local", VIEW_OPTION_CHECK_OPTION_LOCAL
},
504 {"cascaded", VIEW_OPTION_CHECK_OPTION_CASCADED
},
505 {(const char *) NULL
} /* list terminator */
508 static relopt_enum enumRelOpts
[] =
512 "vacuum_index_cleanup",
513 "Controls index vacuuming and index cleanup",
514 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
515 ShareUpdateExclusiveLock
517 StdRdOptIndexCleanupValues
,
518 STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO
,
519 gettext_noop("Valid values are \"on\", \"off\", and \"auto\".")
524 "Enables buffering build for this GiST index",
528 gistBufferingOptValues
,
529 GIST_OPTION_BUFFERING_AUTO
,
530 gettext_noop("Valid values are \"on\", \"off\", and \"auto\".")
535 "View has WITH CHECK OPTION defined (local or cascaded).",
540 VIEW_OPTION_CHECK_OPTION_NOT_SET
,
541 gettext_noop("Valid values are \"local\" and \"cascaded\".")
543 /* list terminator */
547 static relopt_string stringRelOpts
[] =
549 /* list terminator */
553 static relopt_gen
**relOpts
= NULL
;
554 static bits32 last_assigned_kind
= RELOPT_KIND_LAST_DEFAULT
;
556 static int num_custom_options
= 0;
557 static relopt_gen
**custom_options
= NULL
;
558 static bool need_initialization
= true;
560 static void initialize_reloptions(void);
561 static void parse_one_reloption(relopt_value
*option
, char *text_str
,
562 int text_len
, bool validate
);
565 * Get the length of a string reloption (either default or the user-defined
566 * value). This is used for allocation purposes when building a set of
569 #define GET_STRING_RELOPTION_LEN(option) \
570 ((option).isset ? strlen((option).values.string_val) : \
571 ((relopt_string *) (option).gen)->default_len)
574 * initialize_reloptions
575 * initialization routine, must be called before parsing
577 * Initialize the relOpts array and fill each variable's type and name length.
580 initialize_reloptions(void)
586 for (i
= 0; boolRelOpts
[i
].gen
.name
; i
++)
588 Assert(DoLockModesConflict(boolRelOpts
[i
].gen
.lockmode
,
589 boolRelOpts
[i
].gen
.lockmode
));
592 for (i
= 0; intRelOpts
[i
].gen
.name
; i
++)
594 Assert(DoLockModesConflict(intRelOpts
[i
].gen
.lockmode
,
595 intRelOpts
[i
].gen
.lockmode
));
598 for (i
= 0; realRelOpts
[i
].gen
.name
; i
++)
600 Assert(DoLockModesConflict(realRelOpts
[i
].gen
.lockmode
,
601 realRelOpts
[i
].gen
.lockmode
));
604 for (i
= 0; enumRelOpts
[i
].gen
.name
; i
++)
606 Assert(DoLockModesConflict(enumRelOpts
[i
].gen
.lockmode
,
607 enumRelOpts
[i
].gen
.lockmode
));
610 for (i
= 0; stringRelOpts
[i
].gen
.name
; i
++)
612 Assert(DoLockModesConflict(stringRelOpts
[i
].gen
.lockmode
,
613 stringRelOpts
[i
].gen
.lockmode
));
616 j
+= num_custom_options
;
620 relOpts
= MemoryContextAlloc(TopMemoryContext
,
621 (j
+ 1) * sizeof(relopt_gen
*));
624 for (i
= 0; boolRelOpts
[i
].gen
.name
; i
++)
626 relOpts
[j
] = &boolRelOpts
[i
].gen
;
627 relOpts
[j
]->type
= RELOPT_TYPE_BOOL
;
628 relOpts
[j
]->namelen
= strlen(relOpts
[j
]->name
);
632 for (i
= 0; intRelOpts
[i
].gen
.name
; i
++)
634 relOpts
[j
] = &intRelOpts
[i
].gen
;
635 relOpts
[j
]->type
= RELOPT_TYPE_INT
;
636 relOpts
[j
]->namelen
= strlen(relOpts
[j
]->name
);
640 for (i
= 0; realRelOpts
[i
].gen
.name
; i
++)
642 relOpts
[j
] = &realRelOpts
[i
].gen
;
643 relOpts
[j
]->type
= RELOPT_TYPE_REAL
;
644 relOpts
[j
]->namelen
= strlen(relOpts
[j
]->name
);
648 for (i
= 0; enumRelOpts
[i
].gen
.name
; i
++)
650 relOpts
[j
] = &enumRelOpts
[i
].gen
;
651 relOpts
[j
]->type
= RELOPT_TYPE_ENUM
;
652 relOpts
[j
]->namelen
= strlen(relOpts
[j
]->name
);
656 for (i
= 0; stringRelOpts
[i
].gen
.name
; i
++)
658 relOpts
[j
] = &stringRelOpts
[i
].gen
;
659 relOpts
[j
]->type
= RELOPT_TYPE_STRING
;
660 relOpts
[j
]->namelen
= strlen(relOpts
[j
]->name
);
664 for (i
= 0; i
< num_custom_options
; i
++)
666 relOpts
[j
] = custom_options
[i
];
670 /* add a list terminator */
673 /* flag the work is complete */
674 need_initialization
= false;
679 * Create a new relopt_kind value, to be used in custom reloptions by
683 add_reloption_kind(void)
685 /* don't hand out the last bit so that the enum's behavior is portable */
686 if (last_assigned_kind
>= RELOPT_KIND_MAX
)
688 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED
),
689 errmsg("user-defined relation parameter types limit exceeded")));
690 last_assigned_kind
<<= 1;
691 return (relopt_kind
) last_assigned_kind
;
696 * Add an already-created custom reloption to the list, and recompute the
700 add_reloption(relopt_gen
*newoption
)
702 static int max_custom_options
= 0;
704 if (num_custom_options
>= max_custom_options
)
706 MemoryContext oldcxt
;
708 oldcxt
= MemoryContextSwitchTo(TopMemoryContext
);
710 if (max_custom_options
== 0)
712 max_custom_options
= 8;
713 custom_options
= palloc(max_custom_options
* sizeof(relopt_gen
*));
717 max_custom_options
*= 2;
718 custom_options
= repalloc(custom_options
,
719 max_custom_options
* sizeof(relopt_gen
*));
721 MemoryContextSwitchTo(oldcxt
);
723 custom_options
[num_custom_options
++] = newoption
;
725 need_initialization
= true;
729 * init_local_reloptions
730 * Initialize local reloptions that will parsed into bytea structure of
731 * 'relopt_struct_size'.
734 init_local_reloptions(local_relopts
*relopts
, Size relopt_struct_size
)
736 relopts
->options
= NIL
;
737 relopts
->validators
= NIL
;
738 relopts
->relopt_struct_size
= relopt_struct_size
;
742 * register_reloptions_validator
743 * Register custom validation callback that will be called at the end of
744 * build_local_reloptions().
747 register_reloptions_validator(local_relopts
*relopts
, relopts_validator validator
)
749 relopts
->validators
= lappend(relopts
->validators
, validator
);
753 * add_local_reloption
754 * Add an already-created custom reloption to the local list.
757 add_local_reloption(local_relopts
*relopts
, relopt_gen
*newoption
, int offset
)
759 local_relopt
*opt
= palloc(sizeof(*opt
));
761 Assert(offset
< relopts
->relopt_struct_size
);
763 opt
->option
= newoption
;
764 opt
->offset
= offset
;
766 relopts
->options
= lappend(relopts
->options
, opt
);
771 * Allocate a new reloption and initialize the type-agnostic fields
772 * (for types other than string)
775 allocate_reloption(bits32 kinds
, int type
, const char *name
, const char *desc
,
778 MemoryContext oldcxt
;
780 relopt_gen
*newoption
;
782 if (kinds
!= RELOPT_KIND_LOCAL
)
783 oldcxt
= MemoryContextSwitchTo(TopMemoryContext
);
789 case RELOPT_TYPE_BOOL
:
790 size
= sizeof(relopt_bool
);
792 case RELOPT_TYPE_INT
:
793 size
= sizeof(relopt_int
);
795 case RELOPT_TYPE_REAL
:
796 size
= sizeof(relopt_real
);
798 case RELOPT_TYPE_ENUM
:
799 size
= sizeof(relopt_enum
);
801 case RELOPT_TYPE_STRING
:
802 size
= sizeof(relopt_string
);
805 elog(ERROR
, "unsupported reloption type %d", type
);
806 return NULL
; /* keep compiler quiet */
809 newoption
= palloc(size
);
811 newoption
->name
= pstrdup(name
);
813 newoption
->desc
= pstrdup(desc
);
815 newoption
->desc
= NULL
;
816 newoption
->kinds
= kinds
;
817 newoption
->namelen
= strlen(name
);
818 newoption
->type
= type
;
819 newoption
->lockmode
= lockmode
;
822 MemoryContextSwitchTo(oldcxt
);
828 * init_bool_reloption
829 * Allocate and initialize a new boolean reloption
832 init_bool_reloption(bits32 kinds
, const char *name
, const char *desc
,
833 bool default_val
, LOCKMODE lockmode
)
835 relopt_bool
*newoption
;
837 newoption
= (relopt_bool
*) allocate_reloption(kinds
, RELOPT_TYPE_BOOL
,
838 name
, desc
, lockmode
);
839 newoption
->default_val
= default_val
;
846 * Add a new boolean reloption
849 add_bool_reloption(bits32 kinds
, const char *name
, const char *desc
,
850 bool default_val
, LOCKMODE lockmode
)
852 relopt_bool
*newoption
= init_bool_reloption(kinds
, name
, desc
,
853 default_val
, lockmode
);
855 add_reloption((relopt_gen
*) newoption
);
859 * add_local_bool_reloption
860 * Add a new boolean local reloption
862 * 'offset' is offset of bool-typed field.
865 add_local_bool_reloption(local_relopts
*relopts
, const char *name
,
866 const char *desc
, bool default_val
, int offset
)
868 relopt_bool
*newoption
= init_bool_reloption(RELOPT_KIND_LOCAL
,
872 add_local_reloption(relopts
, (relopt_gen
*) newoption
, offset
);
877 * init_real_reloption
878 * Allocate and initialize a new integer reloption
881 init_int_reloption(bits32 kinds
, const char *name
, const char *desc
,
882 int default_val
, int min_val
, int max_val
,
885 relopt_int
*newoption
;
887 newoption
= (relopt_int
*) allocate_reloption(kinds
, RELOPT_TYPE_INT
,
888 name
, desc
, lockmode
);
889 newoption
->default_val
= default_val
;
890 newoption
->min
= min_val
;
891 newoption
->max
= max_val
;
898 * Add a new integer reloption
901 add_int_reloption(bits32 kinds
, const char *name
, const char *desc
, int default_val
,
902 int min_val
, int max_val
, LOCKMODE lockmode
)
904 relopt_int
*newoption
= init_int_reloption(kinds
, name
, desc
,
905 default_val
, min_val
,
908 add_reloption((relopt_gen
*) newoption
);
912 * add_local_int_reloption
913 * Add a new local integer reloption
915 * 'offset' is offset of int-typed field.
918 add_local_int_reloption(local_relopts
*relopts
, const char *name
,
919 const char *desc
, int default_val
, int min_val
,
920 int max_val
, int offset
)
922 relopt_int
*newoption
= init_int_reloption(RELOPT_KIND_LOCAL
,
923 name
, desc
, default_val
,
924 min_val
, max_val
, 0);
926 add_local_reloption(relopts
, (relopt_gen
*) newoption
, offset
);
930 * init_real_reloption
931 * Allocate and initialize a new real reloption
934 init_real_reloption(bits32 kinds
, const char *name
, const char *desc
,
935 double default_val
, double min_val
, double max_val
,
938 relopt_real
*newoption
;
940 newoption
= (relopt_real
*) allocate_reloption(kinds
, RELOPT_TYPE_REAL
,
941 name
, desc
, lockmode
);
942 newoption
->default_val
= default_val
;
943 newoption
->min
= min_val
;
944 newoption
->max
= max_val
;
951 * Add a new float reloption
954 add_real_reloption(bits32 kinds
, const char *name
, const char *desc
,
955 double default_val
, double min_val
, double max_val
,
958 relopt_real
*newoption
= init_real_reloption(kinds
, name
, desc
,
959 default_val
, min_val
,
962 add_reloption((relopt_gen
*) newoption
);
966 * add_local_real_reloption
967 * Add a new local float reloption
969 * 'offset' is offset of double-typed field.
972 add_local_real_reloption(local_relopts
*relopts
, const char *name
,
973 const char *desc
, double default_val
,
974 double min_val
, double max_val
, int offset
)
976 relopt_real
*newoption
= init_real_reloption(RELOPT_KIND_LOCAL
,
978 default_val
, min_val
,
981 add_local_reloption(relopts
, (relopt_gen
*) newoption
, offset
);
985 * init_enum_reloption
986 * Allocate and initialize a new enum reloption
989 init_enum_reloption(bits32 kinds
, const char *name
, const char *desc
,
990 relopt_enum_elt_def
*members
, int default_val
,
991 const char *detailmsg
, LOCKMODE lockmode
)
993 relopt_enum
*newoption
;
995 newoption
= (relopt_enum
*) allocate_reloption(kinds
, RELOPT_TYPE_ENUM
,
996 name
, desc
, lockmode
);
997 newoption
->members
= members
;
998 newoption
->default_val
= default_val
;
999 newoption
->detailmsg
= detailmsg
;
1006 * add_enum_reloption
1007 * Add a new enum reloption
1009 * The members array must have a terminating NULL entry.
1011 * The detailmsg is shown when unsupported values are passed, and has this
1012 * form: "Valid values are \"foo\", \"bar\", and \"bar\"."
1014 * The members array and detailmsg are not copied -- caller must ensure that
1015 * they are valid throughout the life of the process.
1018 add_enum_reloption(bits32 kinds
, const char *name
, const char *desc
,
1019 relopt_enum_elt_def
*members
, int default_val
,
1020 const char *detailmsg
, LOCKMODE lockmode
)
1022 relopt_enum
*newoption
= init_enum_reloption(kinds
, name
, desc
,
1023 members
, default_val
,
1024 detailmsg
, lockmode
);
1026 add_reloption((relopt_gen
*) newoption
);
1030 * add_local_enum_reloption
1031 * Add a new local enum reloption
1033 * 'offset' is offset of int-typed field.
1036 add_local_enum_reloption(local_relopts
*relopts
, const char *name
,
1037 const char *desc
, relopt_enum_elt_def
*members
,
1038 int default_val
, const char *detailmsg
, int offset
)
1040 relopt_enum
*newoption
= init_enum_reloption(RELOPT_KIND_LOCAL
,
1042 members
, default_val
,
1045 add_local_reloption(relopts
, (relopt_gen
*) newoption
, offset
);
1049 * init_string_reloption
1050 * Allocate and initialize a new string reloption
1052 static relopt_string
*
1053 init_string_reloption(bits32 kinds
, const char *name
, const char *desc
,
1054 const char *default_val
,
1055 validate_string_relopt validator
,
1056 fill_string_relopt filler
,
1059 relopt_string
*newoption
;
1061 /* make sure the validator/default combination is sane */
1063 (validator
) (default_val
);
1065 newoption
= (relopt_string
*) allocate_reloption(kinds
, RELOPT_TYPE_STRING
,
1066 name
, desc
, lockmode
);
1067 newoption
->validate_cb
= validator
;
1068 newoption
->fill_cb
= filler
;
1071 if (kinds
== RELOPT_KIND_LOCAL
)
1072 newoption
->default_val
= strdup(default_val
);
1074 newoption
->default_val
= MemoryContextStrdup(TopMemoryContext
, default_val
);
1075 newoption
->default_len
= strlen(default_val
);
1076 newoption
->default_isnull
= false;
1080 newoption
->default_val
= "";
1081 newoption
->default_len
= 0;
1082 newoption
->default_isnull
= true;
1089 * add_string_reloption
1090 * Add a new string reloption
1092 * "validator" is an optional function pointer that can be used to test the
1093 * validity of the values. It must elog(ERROR) when the argument string is
1094 * not acceptable for the variable. Note that the default value must pass
1098 add_string_reloption(bits32 kinds
, const char *name
, const char *desc
,
1099 const char *default_val
, validate_string_relopt validator
,
1102 relopt_string
*newoption
= init_string_reloption(kinds
, name
, desc
,
1107 add_reloption((relopt_gen
*) newoption
);
1111 * add_local_string_reloption
1112 * Add a new local string reloption
1114 * 'offset' is offset of int-typed field that will store offset of string value
1115 * in the resulting bytea structure.
1118 add_local_string_reloption(local_relopts
*relopts
, const char *name
,
1119 const char *desc
, const char *default_val
,
1120 validate_string_relopt validator
,
1121 fill_string_relopt filler
, int offset
)
1123 relopt_string
*newoption
= init_string_reloption(RELOPT_KIND_LOCAL
,
1129 add_local_reloption(relopts
, (relopt_gen
*) newoption
, offset
);
1133 * Transform a relation options list (list of DefElem) into the text array
1134 * format that is kept in pg_class.reloptions, including only those options
1135 * that are in the passed namespace. The output values do not include the
1138 * This is used for three cases: CREATE TABLE/INDEX, ALTER TABLE SET, and
1139 * ALTER TABLE RESET. In the ALTER cases, oldOptions is the existing
1140 * reloptions value (possibly NULL), and we replace or remove entries
1143 * If acceptOidsOff is true, then we allow oids = false, but throw error when
1144 * on. This is solely needed for backwards compatibility.
1146 * Note that this is not responsible for determining whether the options
1147 * are valid, but it does check that namespaces for all the options given are
1148 * listed in validnsps. The NULL namespace is always valid and need not be
1149 * explicitly listed. Passing a NULL pointer means that only the NULL
1150 * namespace is valid.
1152 * Both oldOptions and the result are text arrays (or NULL for "default"),
1153 * but we declare them as Datums to avoid including array.h in reloptions.h.
1156 transformRelOptions(Datum oldOptions
, List
*defList
, const char *namspace
,
1157 const char *const validnsps
[], bool acceptOidsOff
, bool isReset
)
1160 ArrayBuildState
*astate
;
1163 /* no change if empty list */
1167 /* We build new array using accumArrayResult */
1170 /* Copy any oldOptions that aren't to be replaced */
1171 if (PointerIsValid(DatumGetPointer(oldOptions
)))
1173 ArrayType
*array
= DatumGetArrayTypeP(oldOptions
);
1178 deconstruct_array_builtin(array
, TEXTOID
, &oldoptions
, NULL
, &noldoptions
);
1180 for (i
= 0; i
< noldoptions
; i
++)
1182 char *text_str
= VARDATA(oldoptions
[i
]);
1183 int text_len
= VARSIZE(oldoptions
[i
]) - VARHDRSZ
;
1185 /* Search for a match in defList */
1186 foreach(cell
, defList
)
1188 DefElem
*def
= (DefElem
*) lfirst(cell
);
1191 /* ignore if not in the same namespace */
1192 if (namspace
== NULL
)
1194 if (def
->defnamespace
!= NULL
)
1197 else if (def
->defnamespace
== NULL
)
1199 else if (strcmp(def
->defnamespace
, namspace
) != 0)
1202 kw_len
= strlen(def
->defname
);
1203 if (text_len
> kw_len
&& text_str
[kw_len
] == '=' &&
1204 strncmp(text_str
, def
->defname
, kw_len
) == 0)
1209 /* No match, so keep old option */
1210 astate
= accumArrayResult(astate
, oldoptions
[i
],
1212 CurrentMemoryContext
);
1218 * If CREATE/SET, add new options to array; if RESET, just check that the
1219 * user didn't say RESET (option=val). (Must do this because the grammar
1220 * doesn't enforce it.)
1222 foreach(cell
, defList
)
1224 DefElem
*def
= (DefElem
*) lfirst(cell
);
1228 if (def
->arg
!= NULL
)
1230 (errcode(ERRCODE_SYNTAX_ERROR
),
1231 errmsg("RESET must not include values for parameters")));
1240 * Error out if the namespace is not valid. A NULL namespace is
1243 if (def
->defnamespace
!= NULL
)
1250 for (i
= 0; validnsps
[i
]; i
++)
1252 if (strcmp(def
->defnamespace
, validnsps
[i
]) == 0)
1262 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1263 errmsg("unrecognized parameter namespace \"%s\"",
1264 def
->defnamespace
)));
1267 /* ignore if not in the same namespace */
1268 if (namspace
== NULL
)
1270 if (def
->defnamespace
!= NULL
)
1273 else if (def
->defnamespace
== NULL
)
1275 else if (strcmp(def
->defnamespace
, namspace
) != 0)
1279 * Flatten the DefElem into a text string like "name=arg". If we
1280 * have just "name", assume "name=true" is meant. Note: the
1281 * namespace is not output.
1283 if (def
->arg
!= NULL
)
1284 value
= defGetString(def
);
1289 * This is not a great place for this test, but there's no other
1290 * convenient place to filter the option out. As WITH (oids =
1291 * false) will be removed someday, this seems like an acceptable
1294 if (acceptOidsOff
&& def
->defnamespace
== NULL
&&
1295 strcmp(def
->defname
, "oids") == 0)
1297 if (defGetBoolean(def
))
1299 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED
),
1300 errmsg("tables declared WITH OIDS are not supported")));
1301 /* skip over option, reloptions machinery doesn't know it */
1305 len
= VARHDRSZ
+ strlen(def
->defname
) + 1 + strlen(value
);
1306 /* +1 leaves room for sprintf's trailing null */
1307 t
= (text
*) palloc(len
+ 1);
1308 SET_VARSIZE(t
, len
);
1309 sprintf(VARDATA(t
), "%s=%s", def
->defname
, value
);
1311 astate
= accumArrayResult(astate
, PointerGetDatum(t
),
1313 CurrentMemoryContext
);
1318 result
= makeArrayResult(astate
, CurrentMemoryContext
);
1327 * Convert the text-array format of reloptions into a List of DefElem.
1328 * This is the inverse of transformRelOptions().
1331 untransformRelOptions(Datum options
)
1335 Datum
*optiondatums
;
1339 /* Nothing to do if no options */
1340 if (!PointerIsValid(DatumGetPointer(options
)))
1343 array
= DatumGetArrayTypeP(options
);
1345 deconstruct_array_builtin(array
, TEXTOID
, &optiondatums
, NULL
, &noptions
);
1347 for (i
= 0; i
< noptions
; i
++)
1353 s
= TextDatumGetCString(optiondatums
[i
]);
1358 val
= (Node
*) makeString(p
);
1360 result
= lappend(result
, makeDefElem(s
, val
, -1));
1367 * Extract and parse reloptions from a pg_class tuple.
1369 * This is a low-level routine, expected to be used by relcache code and
1370 * callers that do not have a table's relcache entry (e.g. autovacuum). For
1371 * other uses, consider grabbing the rd_options pointer from the relcache entry
1374 * tupdesc is pg_class' tuple descriptor. amoptions is a pointer to the index
1375 * AM's options parser function in the case of a tuple corresponding to an
1376 * index, or NULL otherwise.
1379 extractRelOptions(HeapTuple tuple
, TupleDesc tupdesc
,
1380 amoptions_function amoptions
)
1385 Form_pg_class classForm
;
1387 datum
= fastgetattr(tuple
,
1388 Anum_pg_class_reloptions
,
1394 classForm
= (Form_pg_class
) GETSTRUCT(tuple
);
1396 /* Parse into appropriate format; don't error out here */
1397 switch (classForm
->relkind
)
1399 case RELKIND_RELATION
:
1400 case RELKIND_TOASTVALUE
:
1401 case RELKIND_MATVIEW
:
1402 options
= heap_reloptions(classForm
->relkind
, datum
, false);
1404 case RELKIND_PARTITIONED_TABLE
:
1405 options
= partitioned_table_reloptions(datum
, false);
1408 options
= view_reloptions(datum
, false);
1411 case RELKIND_PARTITIONED_INDEX
:
1412 options
= index_reloptions(amoptions
, datum
, false);
1414 case RELKIND_FOREIGN_TABLE
:
1418 Assert(false); /* can't get here */
1419 options
= NULL
; /* keep compiler quiet */
1427 parseRelOptionsInternal(Datum options
, bool validate
,
1428 relopt_value
*reloptions
, int numoptions
)
1430 ArrayType
*array
= DatumGetArrayTypeP(options
);
1431 Datum
*optiondatums
;
1435 deconstruct_array_builtin(array
, TEXTOID
, &optiondatums
, NULL
, &noptions
);
1437 for (i
= 0; i
< noptions
; i
++)
1439 char *text_str
= VARDATA(optiondatums
[i
]);
1440 int text_len
= VARSIZE(optiondatums
[i
]) - VARHDRSZ
;
1443 /* Search for a match in reloptions */
1444 for (j
= 0; j
< numoptions
; j
++)
1446 int kw_len
= reloptions
[j
].gen
->namelen
;
1448 if (text_len
> kw_len
&& text_str
[kw_len
] == '=' &&
1449 strncmp(text_str
, reloptions
[j
].gen
->name
, kw_len
) == 0)
1451 parse_one_reloption(&reloptions
[j
], text_str
, text_len
,
1457 if (j
>= numoptions
&& validate
)
1462 s
= TextDatumGetCString(optiondatums
[i
]);
1467 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1468 errmsg("unrecognized parameter \"%s\"", s
)));
1472 /* It's worth avoiding memory leaks in this function */
1473 pfree(optiondatums
);
1475 if (((void *) array
) != DatumGetPointer(options
))
1480 * Interpret reloptions that are given in text-array format.
1482 * options is a reloption text array as constructed by transformRelOptions.
1483 * kind specifies the family of options to be processed.
1485 * The return value is a relopt_value * array on which the options actually
1486 * set in the options array are marked with isset=true. The length of this
1487 * array is returned in *numrelopts. Options not set are also present in the
1488 * array; this is so that the caller can easily locate the default values.
1490 * If there are no options of the given kind, numrelopts is set to 0 and NULL
1491 * is returned (unless options are illegally supplied despite none being
1492 * defined, in which case an error occurs).
1494 * Note: values of type int, bool and real are allocated as part of the
1495 * returned array. Values of type string are allocated separately and must
1496 * be freed by the caller.
1498 static relopt_value
*
1499 parseRelOptions(Datum options
, bool validate
, relopt_kind kind
,
1502 relopt_value
*reloptions
= NULL
;
1507 if (need_initialization
)
1508 initialize_reloptions();
1510 /* Build a list of expected options, based on kind */
1512 for (i
= 0; relOpts
[i
]; i
++)
1513 if (relOpts
[i
]->kinds
& kind
)
1518 reloptions
= palloc(numoptions
* sizeof(relopt_value
));
1520 for (i
= 0, j
= 0; relOpts
[i
]; i
++)
1522 if (relOpts
[i
]->kinds
& kind
)
1524 reloptions
[j
].gen
= relOpts
[i
];
1525 reloptions
[j
].isset
= false;
1531 /* Done if no options */
1532 if (PointerIsValid(DatumGetPointer(options
)))
1533 parseRelOptionsInternal(options
, validate
, reloptions
, numoptions
);
1535 *numrelopts
= numoptions
;
1539 /* Parse local unregistered options. */
1540 static relopt_value
*
1541 parseLocalRelOptions(local_relopts
*relopts
, Datum options
, bool validate
)
1543 int nopts
= list_length(relopts
->options
);
1544 relopt_value
*values
= palloc(sizeof(*values
) * nopts
);
1548 foreach(lc
, relopts
->options
)
1550 local_relopt
*opt
= lfirst(lc
);
1552 values
[i
].gen
= opt
->option
;
1553 values
[i
].isset
= false;
1558 if (options
!= (Datum
) 0)
1559 parseRelOptionsInternal(options
, validate
, values
, nopts
);
1565 * Subroutine for parseRelOptions, to parse and validate a single option's
1569 parse_one_reloption(relopt_value
*option
, char *text_str
, int text_len
,
1575 bool nofree
= false;
1577 if (option
->isset
&& validate
)
1579 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1580 errmsg("parameter \"%s\" specified more than once",
1581 option
->gen
->name
)));
1583 value_len
= text_len
- option
->gen
->namelen
- 1;
1584 value
= (char *) palloc(value_len
+ 1);
1585 memcpy(value
, text_str
+ option
->gen
->namelen
+ 1, value_len
);
1586 value
[value_len
] = '\0';
1588 switch (option
->gen
->type
)
1590 case RELOPT_TYPE_BOOL
:
1592 parsed
= parse_bool(value
, &option
->values
.bool_val
);
1593 if (validate
&& !parsed
)
1595 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1596 errmsg("invalid value for boolean option \"%s\": %s",
1597 option
->gen
->name
, value
)));
1600 case RELOPT_TYPE_INT
:
1602 relopt_int
*optint
= (relopt_int
*) option
->gen
;
1604 parsed
= parse_int(value
, &option
->values
.int_val
, 0, NULL
);
1605 if (validate
&& !parsed
)
1607 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1608 errmsg("invalid value for integer option \"%s\": %s",
1609 option
->gen
->name
, value
)));
1610 if (validate
&& (option
->values
.int_val
< optint
->min
||
1611 option
->values
.int_val
> optint
->max
))
1613 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1614 errmsg("value %s out of bounds for option \"%s\"",
1615 value
, option
->gen
->name
),
1616 errdetail("Valid values are between \"%d\" and \"%d\".",
1617 optint
->min
, optint
->max
)));
1620 case RELOPT_TYPE_REAL
:
1622 relopt_real
*optreal
= (relopt_real
*) option
->gen
;
1624 parsed
= parse_real(value
, &option
->values
.real_val
, 0, NULL
);
1625 if (validate
&& !parsed
)
1627 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1628 errmsg("invalid value for floating point option \"%s\": %s",
1629 option
->gen
->name
, value
)));
1630 if (validate
&& (option
->values
.real_val
< optreal
->min
||
1631 option
->values
.real_val
> optreal
->max
))
1633 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1634 errmsg("value %s out of bounds for option \"%s\"",
1635 value
, option
->gen
->name
),
1636 errdetail("Valid values are between \"%f\" and \"%f\".",
1637 optreal
->min
, optreal
->max
)));
1640 case RELOPT_TYPE_ENUM
:
1642 relopt_enum
*optenum
= (relopt_enum
*) option
->gen
;
1643 relopt_enum_elt_def
*elt
;
1646 for (elt
= optenum
->members
; elt
->string_val
; elt
++)
1648 if (pg_strcasecmp(value
, elt
->string_val
) == 0)
1650 option
->values
.enum_val
= elt
->symbol_val
;
1655 if (validate
&& !parsed
)
1657 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1658 errmsg("invalid value for enum option \"%s\": %s",
1659 option
->gen
->name
, value
),
1660 optenum
->detailmsg
?
1661 errdetail_internal("%s", _(optenum
->detailmsg
)) : 0));
1664 * If value is not among the allowed string values, but we are
1665 * not asked to validate, just use the default numeric value.
1668 option
->values
.enum_val
= optenum
->default_val
;
1671 case RELOPT_TYPE_STRING
:
1673 relopt_string
*optstring
= (relopt_string
*) option
->gen
;
1675 option
->values
.string_val
= value
;
1677 if (validate
&& optstring
->validate_cb
)
1678 (optstring
->validate_cb
) (value
);
1683 elog(ERROR
, "unsupported reloption type %d", option
->gen
->type
);
1684 parsed
= true; /* quiet compiler */
1689 option
->isset
= true;
1695 * Given the result from parseRelOptions, allocate a struct that's of the
1696 * specified base size plus any extra space that's needed for string variables.
1698 * "base" should be sizeof(struct) of the reloptions struct (StdRdOptions or
1702 allocateReloptStruct(Size base
, relopt_value
*options
, int numoptions
)
1707 for (i
= 0; i
< numoptions
; i
++)
1709 relopt_value
*optval
= &options
[i
];
1711 if (optval
->gen
->type
== RELOPT_TYPE_STRING
)
1713 relopt_string
*optstr
= (relopt_string
*) optval
->gen
;
1715 if (optstr
->fill_cb
)
1717 const char *val
= optval
->isset
? optval
->values
.string_val
:
1718 optstr
->default_isnull
? NULL
: optstr
->default_val
;
1720 size
+= optstr
->fill_cb(val
, NULL
);
1723 size
+= GET_STRING_RELOPTION_LEN(*optval
) + 1;
1727 return palloc0(size
);
1731 * Given the result of parseRelOptions and a parsing table, fill in the
1732 * struct (previously allocated with allocateReloptStruct) with the parsed
1735 * rdopts is the pointer to the allocated struct to be filled.
1736 * basesize is the sizeof(struct) that was passed to allocateReloptStruct.
1737 * options, of length numoptions, is parseRelOptions' output.
1738 * elems, of length numelems, is the table describing the allowed options.
1739 * When validate is true, it is expected that all options appear in elems.
1742 fillRelOptions(void *rdopts
, Size basesize
,
1743 relopt_value
*options
, int numoptions
,
1745 const relopt_parse_elt
*elems
, int numelems
)
1748 int offset
= basesize
;
1750 for (i
= 0; i
< numoptions
; i
++)
1755 for (j
= 0; j
< numelems
; j
++)
1757 if (strcmp(options
[i
].gen
->name
, elems
[j
].optname
) == 0)
1759 relopt_string
*optstring
;
1760 char *itempos
= ((char *) rdopts
) + elems
[j
].offset
;
1763 switch (options
[i
].gen
->type
)
1765 case RELOPT_TYPE_BOOL
:
1766 *(bool *) itempos
= options
[i
].isset
?
1767 options
[i
].values
.bool_val
:
1768 ((relopt_bool
*) options
[i
].gen
)->default_val
;
1770 case RELOPT_TYPE_INT
:
1771 *(int *) itempos
= options
[i
].isset
?
1772 options
[i
].values
.int_val
:
1773 ((relopt_int
*) options
[i
].gen
)->default_val
;
1775 case RELOPT_TYPE_REAL
:
1776 *(double *) itempos
= options
[i
].isset
?
1777 options
[i
].values
.real_val
:
1778 ((relopt_real
*) options
[i
].gen
)->default_val
;
1780 case RELOPT_TYPE_ENUM
:
1781 *(int *) itempos
= options
[i
].isset
?
1782 options
[i
].values
.enum_val
:
1783 ((relopt_enum
*) options
[i
].gen
)->default_val
;
1785 case RELOPT_TYPE_STRING
:
1786 optstring
= (relopt_string
*) options
[i
].gen
;
1787 if (options
[i
].isset
)
1788 string_val
= options
[i
].values
.string_val
;
1789 else if (!optstring
->default_isnull
)
1790 string_val
= optstring
->default_val
;
1794 if (optstring
->fill_cb
)
1797 optstring
->fill_cb(string_val
,
1798 (char *) rdopts
+ offset
);
1802 *(int *) itempos
= offset
;
1806 *(int *) itempos
= 0;
1808 else if (string_val
== NULL
)
1809 *(int *) itempos
= 0;
1812 strcpy((char *) rdopts
+ offset
, string_val
);
1813 *(int *) itempos
= offset
;
1814 offset
+= strlen(string_val
) + 1;
1818 elog(ERROR
, "unsupported reloption type %d",
1819 options
[i
].gen
->type
);
1826 if (validate
&& !found
)
1827 elog(ERROR
, "reloption \"%s\" not found in parse table",
1828 options
[i
].gen
->name
);
1830 SET_VARSIZE(rdopts
, offset
);
1835 * Option parser for anything that uses StdRdOptions.
1838 default_reloptions(Datum reloptions
, bool validate
, relopt_kind kind
)
1840 static const relopt_parse_elt tab
[] = {
1841 {"fillfactor", RELOPT_TYPE_INT
, offsetof(StdRdOptions
, fillfactor
)},
1842 {"autovacuum_enabled", RELOPT_TYPE_BOOL
,
1843 offsetof(StdRdOptions
, autovacuum
) + offsetof(AutoVacOpts
, enabled
)},
1844 {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT
,
1845 offsetof(StdRdOptions
, autovacuum
) + offsetof(AutoVacOpts
, vacuum_threshold
)},
1846 {"autovacuum_vacuum_insert_threshold", RELOPT_TYPE_INT
,
1847 offsetof(StdRdOptions
, autovacuum
) + offsetof(AutoVacOpts
, vacuum_ins_threshold
)},
1848 {"autovacuum_analyze_threshold", RELOPT_TYPE_INT
,
1849 offsetof(StdRdOptions
, autovacuum
) + offsetof(AutoVacOpts
, analyze_threshold
)},
1850 {"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT
,
1851 offsetof(StdRdOptions
, autovacuum
) + offsetof(AutoVacOpts
, vacuum_cost_limit
)},
1852 {"autovacuum_freeze_min_age", RELOPT_TYPE_INT
,
1853 offsetof(StdRdOptions
, autovacuum
) + offsetof(AutoVacOpts
, freeze_min_age
)},
1854 {"autovacuum_freeze_max_age", RELOPT_TYPE_INT
,
1855 offsetof(StdRdOptions
, autovacuum
) + offsetof(AutoVacOpts
, freeze_max_age
)},
1856 {"autovacuum_freeze_table_age", RELOPT_TYPE_INT
,
1857 offsetof(StdRdOptions
, autovacuum
) + offsetof(AutoVacOpts
, freeze_table_age
)},
1858 {"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT
,
1859 offsetof(StdRdOptions
, autovacuum
) + offsetof(AutoVacOpts
, multixact_freeze_min_age
)},
1860 {"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT
,
1861 offsetof(StdRdOptions
, autovacuum
) + offsetof(AutoVacOpts
, multixact_freeze_max_age
)},
1862 {"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT
,
1863 offsetof(StdRdOptions
, autovacuum
) + offsetof(AutoVacOpts
, multixact_freeze_table_age
)},
1864 {"log_autovacuum_min_duration", RELOPT_TYPE_INT
,
1865 offsetof(StdRdOptions
, autovacuum
) + offsetof(AutoVacOpts
, log_min_duration
)},
1866 {"toast_tuple_target", RELOPT_TYPE_INT
,
1867 offsetof(StdRdOptions
, toast_tuple_target
)},
1868 {"autovacuum_vacuum_cost_delay", RELOPT_TYPE_REAL
,
1869 offsetof(StdRdOptions
, autovacuum
) + offsetof(AutoVacOpts
, vacuum_cost_delay
)},
1870 {"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL
,
1871 offsetof(StdRdOptions
, autovacuum
) + offsetof(AutoVacOpts
, vacuum_scale_factor
)},
1872 {"autovacuum_vacuum_insert_scale_factor", RELOPT_TYPE_REAL
,
1873 offsetof(StdRdOptions
, autovacuum
) + offsetof(AutoVacOpts
, vacuum_ins_scale_factor
)},
1874 {"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL
,
1875 offsetof(StdRdOptions
, autovacuum
) + offsetof(AutoVacOpts
, analyze_scale_factor
)},
1876 {"user_catalog_table", RELOPT_TYPE_BOOL
,
1877 offsetof(StdRdOptions
, user_catalog_table
)},
1878 {"parallel_workers", RELOPT_TYPE_INT
,
1879 offsetof(StdRdOptions
, parallel_workers
)},
1880 {"vacuum_index_cleanup", RELOPT_TYPE_ENUM
,
1881 offsetof(StdRdOptions
, vacuum_index_cleanup
)},
1882 {"vacuum_truncate", RELOPT_TYPE_BOOL
,
1883 offsetof(StdRdOptions
, vacuum_truncate
)}
1886 return (bytea
*) build_reloptions(reloptions
, validate
, kind
,
1887 sizeof(StdRdOptions
),
1888 tab
, lengthof(tab
));
1894 * Parses "reloptions" provided by the caller, returning them in a
1895 * structure containing the parsed options. The parsing is done with
1896 * the help of a parsing table describing the allowed options, defined
1897 * by "relopt_elems" of length "num_relopt_elems".
1899 * "validate" must be true if reloptions value is freshly built by
1900 * transformRelOptions(), as opposed to being read from the catalog, in which
1901 * case the values contained in it must already be valid.
1903 * NULL is returned if the passed-in options did not match any of the options
1904 * in the parsing table, unless validate is true in which case an error would
1908 build_reloptions(Datum reloptions
, bool validate
,
1910 Size relopt_struct_size
,
1911 const relopt_parse_elt
*relopt_elems
,
1912 int num_relopt_elems
)
1915 relopt_value
*options
;
1918 /* parse options specific to given relation option kind */
1919 options
= parseRelOptions(reloptions
, validate
, kind
, &numoptions
);
1920 Assert(numoptions
<= num_relopt_elems
);
1922 /* if none set, we're done */
1923 if (numoptions
== 0)
1925 Assert(options
== NULL
);
1929 /* allocate and fill the structure */
1930 rdopts
= allocateReloptStruct(relopt_struct_size
, options
, numoptions
);
1931 fillRelOptions(rdopts
, relopt_struct_size
, options
, numoptions
,
1932 validate
, relopt_elems
, num_relopt_elems
);
1940 * Parse local options, allocate a bytea struct that's of the specified
1941 * 'base_size' plus any extra space that's needed for string variables,
1942 * fill its option's fields located at the given offsets and return it.
1945 build_local_reloptions(local_relopts
*relopts
, Datum options
, bool validate
)
1947 int noptions
= list_length(relopts
->options
);
1948 relopt_parse_elt
*elems
= palloc(sizeof(*elems
) * noptions
);
1954 foreach(lc
, relopts
->options
)
1956 local_relopt
*opt
= lfirst(lc
);
1958 elems
[i
].optname
= opt
->option
->name
;
1959 elems
[i
].opttype
= opt
->option
->type
;
1960 elems
[i
].offset
= opt
->offset
;
1965 vals
= parseLocalRelOptions(relopts
, options
, validate
);
1966 opts
= allocateReloptStruct(relopts
->relopt_struct_size
, vals
, noptions
);
1967 fillRelOptions(opts
, relopts
->relopt_struct_size
, vals
, noptions
, validate
,
1971 foreach(lc
, relopts
->validators
)
1972 ((relopts_validator
) lfirst(lc
)) (opts
, vals
, noptions
);
1981 * Option parser for partitioned tables
1984 partitioned_table_reloptions(Datum reloptions
, bool validate
)
1986 if (validate
&& reloptions
)
1988 errcode(ERRCODE_WRONG_OBJECT_TYPE
),
1989 errmsg("cannot specify storage parameters for a partitioned table"),
1990 errhint("Specify storage parameters for its leaf partitions instead."));
1995 * Option parser for views
1998 view_reloptions(Datum reloptions
, bool validate
)
2000 static const relopt_parse_elt tab
[] = {
2001 {"security_barrier", RELOPT_TYPE_BOOL
,
2002 offsetof(ViewOptions
, security_barrier
)},
2003 {"security_invoker", RELOPT_TYPE_BOOL
,
2004 offsetof(ViewOptions
, security_invoker
)},
2005 {"check_option", RELOPT_TYPE_ENUM
,
2006 offsetof(ViewOptions
, check_option
)}
2009 return (bytea
*) build_reloptions(reloptions
, validate
,
2011 sizeof(ViewOptions
),
2012 tab
, lengthof(tab
));
2016 * Parse options for heaps, views and toast tables.
2019 heap_reloptions(char relkind
, Datum reloptions
, bool validate
)
2021 StdRdOptions
*rdopts
;
2025 case RELKIND_TOASTVALUE
:
2026 rdopts
= (StdRdOptions
*)
2027 default_reloptions(reloptions
, validate
, RELOPT_KIND_TOAST
);
2030 /* adjust default-only parameters for TOAST relations */
2031 rdopts
->fillfactor
= 100;
2032 rdopts
->autovacuum
.analyze_threshold
= -1;
2033 rdopts
->autovacuum
.analyze_scale_factor
= -1;
2035 return (bytea
*) rdopts
;
2036 case RELKIND_RELATION
:
2037 case RELKIND_MATVIEW
:
2038 return default_reloptions(reloptions
, validate
, RELOPT_KIND_HEAP
);
2040 /* other relkinds are not supported */
2047 * Parse options for indexes.
2049 * amoptions index AM's option parser function
2050 * reloptions options as text[] datum
2051 * validate error flag
2054 index_reloptions(amoptions_function amoptions
, Datum reloptions
, bool validate
)
2056 Assert(amoptions
!= NULL
);
2058 /* Assume function is strict */
2059 if (!PointerIsValid(DatumGetPointer(reloptions
)))
2062 return amoptions(reloptions
, validate
);
2066 * Option parser for attribute reloptions
2069 attribute_reloptions(Datum reloptions
, bool validate
)
2071 static const relopt_parse_elt tab
[] = {
2072 {"n_distinct", RELOPT_TYPE_REAL
, offsetof(AttributeOpts
, n_distinct
)},
2073 {"n_distinct_inherited", RELOPT_TYPE_REAL
, offsetof(AttributeOpts
, n_distinct_inherited
)}
2076 return (bytea
*) build_reloptions(reloptions
, validate
,
2077 RELOPT_KIND_ATTRIBUTE
,
2078 sizeof(AttributeOpts
),
2079 tab
, lengthof(tab
));
2083 * Option parser for tablespace reloptions
2086 tablespace_reloptions(Datum reloptions
, bool validate
)
2088 static const relopt_parse_elt tab
[] = {
2089 {"random_page_cost", RELOPT_TYPE_REAL
, offsetof(TableSpaceOpts
, random_page_cost
)},
2090 {"seq_page_cost", RELOPT_TYPE_REAL
, offsetof(TableSpaceOpts
, seq_page_cost
)},
2091 {"effective_io_concurrency", RELOPT_TYPE_INT
, offsetof(TableSpaceOpts
, effective_io_concurrency
)},
2092 {"maintenance_io_concurrency", RELOPT_TYPE_INT
, offsetof(TableSpaceOpts
, maintenance_io_concurrency
)}
2095 return (bytea
*) build_reloptions(reloptions
, validate
,
2096 RELOPT_KIND_TABLESPACE
,
2097 sizeof(TableSpaceOpts
),
2098 tab
, lengthof(tab
));
2102 * Determine the required LOCKMODE from an option list.
2104 * Called from AlterTableGetLockLevel(), see that function
2105 * for a longer explanation of how this works.
2108 AlterTableGetRelOptionsLockLevel(List
*defList
)
2110 LOCKMODE lockmode
= NoLock
;
2114 return AccessExclusiveLock
;
2116 if (need_initialization
)
2117 initialize_reloptions();
2119 foreach(cell
, defList
)
2121 DefElem
*def
= (DefElem
*) lfirst(cell
);
2124 for (i
= 0; relOpts
[i
]; i
++)
2126 if (strncmp(relOpts
[i
]->name
,
2128 relOpts
[i
]->namelen
+ 1) == 0)
2130 if (lockmode
< relOpts
[i
]->lockmode
)
2131 lockmode
= relOpts
[i
]->lockmode
;