1 /*-------------------------------------------------------------------------
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
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 "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
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
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
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
[] =
101 "Enables automatic summarization on this BRIN index",
109 "autovacuum_enabled",
110 "Enables autovacuum in this relation",
111 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
112 ShareUpdateExclusiveLock
118 "user_catalog_table",
119 "Declare a table as an additional catalog table, e.g. for the purpose of logical replication",
128 "Enables \"fast update\" feature for this GIN index",
137 "View acts as a row security barrier",
146 "Privileges on underlying relations are checked as the invoking user, not the view owner",
155 "Enables vacuum to truncate empty pages at the end of this table",
156 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
157 ShareUpdateExclusiveLock
164 "Enables \"deduplicate items\" feature for this btree index",
166 ShareUpdateExclusiveLock
/* since it applies only to later
171 /* list terminator */
175 static relopt_int intRelOpts
[] =
180 "Packs table pages only to this percentage",
182 ShareUpdateExclusiveLock
/* since it applies only to later
185 HEAP_DEFAULT_FILLFACTOR
, HEAP_MIN_FILLFACTOR
, 100
190 "Packs btree index pages only to this percentage",
192 ShareUpdateExclusiveLock
/* since it applies only to later
195 BTREE_DEFAULT_FILLFACTOR
, BTREE_MIN_FILLFACTOR
, 100
200 "Packs hash index pages only to this percentage",
202 ShareUpdateExclusiveLock
/* since it applies only to later
205 HASH_DEFAULT_FILLFACTOR
, HASH_MIN_FILLFACTOR
, 100
210 "Packs gist index pages only to this percentage",
212 ShareUpdateExclusiveLock
/* since it applies only to later
215 GIST_DEFAULT_FILLFACTOR
, GIST_MIN_FILLFACTOR
, 100
220 "Packs spgist index pages only to this percentage",
222 ShareUpdateExclusiveLock
/* since it applies only to later
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
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
247 "autovacuum_analyze_threshold",
248 "Minimum number of tuple inserts, updates or deletes prior to analyze",
250 ShareUpdateExclusiveLock
256 "autovacuum_vacuum_cost_limit",
257 "Vacuum cost amount available before napping, for autovacuum",
258 RELOPT_KIND_HEAP
| RELOPT_KIND_TOAST
,
259 ShareUpdateExclusiveLock
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
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
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
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
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
334 "toast_tuple_target",
335 "Sets the target tuple length at which external columns will be toasted",
337 ShareUpdateExclusiveLock
339 TOAST_TUPLE_TARGET
, 128, TOAST_TUPLE_TARGET_MAIN
344 "Number of pages that each page range covers in a BRIN index",
351 "gin_pending_list_limit",
352 "Maximum size of the pending list for this GIN index, in kilobytes.",
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
366 -1, 0, MAX_IO_CONCURRENCY
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
379 -1, 0, MAX_IO_CONCURRENCY
387 "Number of parallel processes that can be used per executor node for this relation.",
389 ShareUpdateExclusiveLock
394 /* list terminator */
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
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
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
429 "autovacuum_analyze_scale_factor",
430 "Number of tuple inserts, updates or deletes prior to analyze as a fraction of reltuples",
432 ShareUpdateExclusiveLock
439 "Sets the planner's estimate of the cost of a sequentially fetched disk page.",
440 RELOPT_KIND_TABLESPACE
,
441 ShareUpdateExclusiveLock
448 "Sets the planner's estimate of the cost of a nonsequentially fetched disk page.",
449 RELOPT_KIND_TABLESPACE
,
450 ShareUpdateExclusiveLock
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
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
474 "vacuum_cleanup_index_scale_factor",
475 "Deprecated B-Tree parameter.",
477 ShareUpdateExclusiveLock
481 /* list terminator */
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\".")
534 "Enables buffering build for this GiST index",
538 gistBufferingOptValues
,
539 GIST_OPTION_BUFFERING_AUTO
,
540 gettext_noop("Valid values are \"on\", \"off\", and \"auto\".")
545 "View has WITH CHECK OPTION defined (local or cascaded).",
550 VIEW_OPTION_CHECK_OPTION_NOT_SET
,
551 gettext_noop("Valid values are \"local\" and \"cascaded\".")
553 /* list terminator */
557 static relopt_string stringRelOpts
[] =
559 /* list terminator */
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
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.
590 initialize_reloptions(void)
596 for (i
= 0; boolRelOpts
[i
].gen
.name
; i
++)
598 Assert(DoLockModesConflict(boolRelOpts
[i
].gen
.lockmode
,
599 boolRelOpts
[i
].gen
.lockmode
));
602 for (i
= 0; intRelOpts
[i
].gen
.name
; i
++)
604 Assert(DoLockModesConflict(intRelOpts
[i
].gen
.lockmode
,
605 intRelOpts
[i
].gen
.lockmode
));
608 for (i
= 0; realRelOpts
[i
].gen
.name
; i
++)
610 Assert(DoLockModesConflict(realRelOpts
[i
].gen
.lockmode
,
611 realRelOpts
[i
].gen
.lockmode
));
614 for (i
= 0; enumRelOpts
[i
].gen
.name
; i
++)
616 Assert(DoLockModesConflict(enumRelOpts
[i
].gen
.lockmode
,
617 enumRelOpts
[i
].gen
.lockmode
));
620 for (i
= 0; stringRelOpts
[i
].gen
.name
; i
++)
622 Assert(DoLockModesConflict(stringRelOpts
[i
].gen
.lockmode
,
623 stringRelOpts
[i
].gen
.lockmode
));
626 j
+= num_custom_options
;
630 relOpts
= MemoryContextAlloc(TopMemoryContext
,
631 (j
+ 1) * sizeof(relopt_gen
*));
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
);
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
);
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
);
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
);
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
);
674 for (i
= 0; i
< num_custom_options
; i
++)
676 relOpts
[j
] = custom_options
[i
];
680 /* add a list terminator */
683 /* flag the work is complete */
684 need_initialization
= false;
689 * Create a new relopt_kind value, to be used in custom reloptions by
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
)
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
;
706 * Add an already-created custom reloption to the list, and recompute the
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
*));
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'.
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().
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.
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
);
781 * Allocate a new reloption and initialize the type-agnostic fields
782 * (for types other than string)
785 allocate_reloption(bits32 kinds
, int type
, const char *name
, const char *desc
,
788 MemoryContext oldcxt
;
790 relopt_gen
*newoption
;
792 if (kinds
!= RELOPT_KIND_LOCAL
)
793 oldcxt
= MemoryContextSwitchTo(TopMemoryContext
);
799 case RELOPT_TYPE_BOOL
:
800 size
= sizeof(relopt_bool
);
802 case RELOPT_TYPE_INT
:
803 size
= sizeof(relopt_int
);
805 case RELOPT_TYPE_REAL
:
806 size
= sizeof(relopt_real
);
808 case RELOPT_TYPE_ENUM
:
809 size
= sizeof(relopt_enum
);
811 case RELOPT_TYPE_STRING
:
812 size
= sizeof(relopt_string
);
815 elog(ERROR
, "unsupported reloption type %d", type
);
816 return NULL
; /* keep compiler quiet */
819 newoption
= palloc(size
);
821 newoption
->name
= pstrdup(name
);
823 newoption
->desc
= pstrdup(desc
);
825 newoption
->desc
= NULL
;
826 newoption
->kinds
= kinds
;
827 newoption
->namelen
= strlen(name
);
828 newoption
->type
= type
;
829 newoption
->lockmode
= lockmode
;
832 MemoryContextSwitchTo(oldcxt
);
838 * init_bool_reloption
839 * Allocate and initialize a new boolean reloption
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
;
856 * Add a new boolean reloption
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.
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
,
882 add_local_reloption(relopts
, (relopt_gen
*) newoption
, offset
);
887 * init_real_reloption
888 * Allocate and initialize a new integer reloption
891 init_int_reloption(bits32 kinds
, const char *name
, const char *desc
,
892 int default_val
, int min_val
, int max_val
,
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
;
908 * Add a new integer reloption
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
,
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.
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
944 init_real_reloption(bits32 kinds
, const char *name
, const char *desc
,
945 double default_val
, double min_val
, double max_val
,
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
;
961 * Add a new float reloption
964 add_real_reloption(bits32 kinds
, const char *name
, const char *desc
,
965 double default_val
, double min_val
, double max_val
,
968 relopt_real
*newoption
= init_real_reloption(kinds
, name
, desc
,
969 default_val
, min_val
,
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.
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
,
988 default_val
, min_val
,
991 add_local_reloption(relopts
, (relopt_gen
*) newoption
, offset
);
995 * init_enum_reloption
996 * Allocate and initialize a new enum reloption
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
;
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.
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.
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
,
1052 members
, default_val
,
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
,
1069 relopt_string
*newoption
;
1071 /* make sure the validator/default combination is sane */
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
;
1081 if (kinds
== RELOPT_KIND_LOCAL
)
1082 newoption
->default_val
= strdup(default_val
);
1084 newoption
->default_val
= MemoryContextStrdup(TopMemoryContext
, default_val
);
1085 newoption
->default_len
= strlen(default_val
);
1086 newoption
->default_isnull
= false;
1090 newoption
->default_val
= "";
1091 newoption
->default_len
= 0;
1092 newoption
->default_isnull
= true;
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
1108 add_string_reloption(bits32 kinds
, const char *name
, const char *desc
,
1109 const char *default_val
, validate_string_relopt validator
,
1112 relopt_string
*newoption
= init_string_reloption(kinds
, name
, desc
,
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.
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
,
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
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
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.
1166 transformRelOptions(Datum oldOptions
, List
*defList
, const char *namspace
,
1167 char *validnsps
[], bool acceptOidsOff
, bool isReset
)
1170 ArrayBuildState
*astate
;
1173 /* no change if empty list */
1177 /* We build new array using accumArrayResult */
1180 /* Copy any oldOptions that aren't to be replaced */
1181 if (PointerIsValid(DatumGetPointer(oldOptions
)))
1183 ArrayType
*array
= DatumGetArrayTypeP(oldOptions
);
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
);
1201 /* ignore if not in the same namespace */
1202 if (namspace
== NULL
)
1204 if (def
->defnamespace
!= NULL
)
1207 else if (def
->defnamespace
== NULL
)
1209 else if (strcmp(def
->defnamespace
, namspace
) != 0)
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)
1219 /* No match, so keep old option */
1220 astate
= accumArrayResult(astate
, oldoptions
[i
],
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
);
1238 if (def
->arg
!= NULL
)
1240 (errcode(ERRCODE_SYNTAX_ERROR
),
1241 errmsg("RESET must not include values for parameters")));
1250 * Error out if the namespace is not valid. A NULL namespace is
1253 if (def
->defnamespace
!= NULL
)
1260 for (i
= 0; validnsps
[i
]; i
++)
1262 if (strcmp(def
->defnamespace
, validnsps
[i
]) == 0)
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
)
1283 else if (def
->defnamespace
== NULL
)
1285 else if (strcmp(def
->defnamespace
, namspace
) != 0)
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
);
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
1304 if (acceptOidsOff
&& def
->defnamespace
== NULL
&&
1305 strcmp(def
->defname
, "oids") == 0)
1307 if (defGetBoolean(def
))
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 */
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
),
1323 CurrentMemoryContext
);
1328 result
= makeArrayResult(astate
, CurrentMemoryContext
);
1337 * Convert the text-array format of reloptions into a List of DefElem.
1338 * This is the inverse of transformRelOptions().
1341 untransformRelOptions(Datum options
)
1345 Datum
*optiondatums
;
1349 /* Nothing to do if no options */
1350 if (!PointerIsValid(DatumGetPointer(options
)))
1353 array
= DatumGetArrayTypeP(options
);
1355 deconstruct_array_builtin(array
, TEXTOID
, &optiondatums
, NULL
, &noptions
);
1357 for (i
= 0; i
< noptions
; i
++)
1363 s
= TextDatumGetCString(optiondatums
[i
]);
1368 val
= (Node
*) makeString(p
);
1370 result
= lappend(result
, makeDefElem(s
, val
, -1));
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
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.
1389 extractRelOptions(HeapTuple tuple
, TupleDesc tupdesc
,
1390 amoptions_function amoptions
)
1395 Form_pg_class classForm
;
1397 datum
= fastgetattr(tuple
,
1398 Anum_pg_class_reloptions
,
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);
1414 case RELKIND_PARTITIONED_TABLE
:
1415 options
= partitioned_table_reloptions(datum
, false);
1418 options
= view_reloptions(datum
, false);
1421 case RELKIND_PARTITIONED_INDEX
:
1422 options
= index_reloptions(amoptions
, datum
, false);
1424 case RELKIND_FOREIGN_TABLE
:
1428 Assert(false); /* can't get here */
1429 options
= NULL
; /* keep compiler quiet */
1437 parseRelOptionsInternal(Datum options
, bool validate
,
1438 relopt_value
*reloptions
, int numoptions
)
1440 ArrayType
*array
= DatumGetArrayTypeP(options
);
1441 Datum
*optiondatums
;
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
;
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
,
1467 if (j
>= numoptions
&& validate
)
1472 s
= TextDatumGetCString(optiondatums
[i
]);
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
))
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
,
1512 relopt_value
*reloptions
= NULL
;
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
)
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;
1541 /* Done if no options */
1542 if (PointerIsValid(DatumGetPointer(options
)))
1543 parseRelOptionsInternal(options
, validate
, reloptions
, numoptions
);
1545 *numrelopts
= numoptions
;
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
);
1558 foreach(lc
, relopts
->options
)
1560 local_relopt
*opt
= lfirst(lc
);
1562 values
[i
].gen
= opt
->option
;
1563 values
[i
].isset
= false;
1568 if (options
!= (Datum
) 0)
1569 parseRelOptionsInternal(options
, validate
, values
, nopts
);
1575 * Subroutine for parseRelOptions, to parse and validate a single option's
1579 parse_one_reloption(relopt_value
*option
, char *text_str
, int text_len
,
1585 bool nofree
= false;
1587 if (option
->isset
&& validate
)
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
)
1605 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1606 errmsg("invalid value for boolean option \"%s\": %s",
1607 option
->gen
->name
, value
)));
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
)
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
))
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
)));
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
)
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
))
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
)));
1650 case RELOPT_TYPE_ENUM
:
1652 relopt_enum
*optenum
= (relopt_enum
*) option
->gen
;
1653 relopt_enum_elt_def
*elt
;
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
;
1665 if (validate
&& !parsed
)
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.
1678 option
->values
.enum_val
= optenum
->default_val
;
1681 case RELOPT_TYPE_STRING
:
1683 relopt_string
*optstring
= (relopt_string
*) option
->gen
;
1685 option
->values
.string_val
= value
;
1687 if (validate
&& optstring
->validate_cb
)
1688 (optstring
->validate_cb
) (value
);
1693 elog(ERROR
, "unsupported reloption type %d", option
->gen
->type
);
1694 parsed
= true; /* quiet compiler */
1699 option
->isset
= true;
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
1712 allocateReloptStruct(Size base
, relopt_value
*options
, int numoptions
)
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
);
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
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.
1752 fillRelOptions(void *rdopts
, Size basesize
,
1753 relopt_value
*options
, int numoptions
,
1755 const relopt_parse_elt
*elems
, int numelems
)
1758 int offset
= basesize
;
1760 for (i
= 0; i
< numoptions
; i
++)
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
;
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
;
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
;
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
;
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
;
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
;
1804 if (optstring
->fill_cb
)
1807 optstring
->fill_cb(string_val
,
1808 (char *) rdopts
+ offset
);
1812 *(int *) itempos
= offset
;
1816 *(int *) itempos
= 0;
1818 else if (string_val
== NULL
)
1819 *(int *) itempos
= 0;
1822 strcpy((char *) rdopts
+ offset
, string_val
);
1823 *(int *) itempos
= offset
;
1824 offset
+= strlen(string_val
) + 1;
1828 elog(ERROR
, "unsupported reloption type %d",
1829 options
[i
].gen
->type
);
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.
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
));
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
1920 build_reloptions(Datum reloptions
, bool validate
,
1922 Size relopt_struct_size
,
1923 const relopt_parse_elt
*relopt_elems
,
1924 int num_relopt_elems
)
1927 relopt_value
*options
;
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
);
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
);
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.
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
);
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
;
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
,
1982 foreach(lc
, relopts
->validators
)
1983 ((relopts_validator
) lfirst(lc
)) (opts
, vals
, noptions
);
1992 * Option parser for partitioned tables
1995 partitioned_table_reloptions(Datum reloptions
, bool validate
)
1997 if (validate
&& reloptions
)
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."));
2006 * Option parser for views
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
,
2022 sizeof(ViewOptions
),
2023 tab
, lengthof(tab
));
2027 * Parse options for heaps, views and toast tables.
2030 heap_reloptions(char relkind
, Datum reloptions
, bool validate
)
2032 StdRdOptions
*rdopts
;
2036 case RELKIND_TOASTVALUE
:
2037 rdopts
= (StdRdOptions
*)
2038 default_reloptions(reloptions
, validate
, RELOPT_KIND_TOAST
);
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
);
2051 /* other relkinds are not supported */
2058 * Parse options for indexes.
2060 * amoptions index AM's option parser function
2061 * reloptions options as text[] datum
2062 * validate error flag
2065 index_reloptions(amoptions_function amoptions
, Datum reloptions
, bool validate
)
2067 Assert(amoptions
!= NULL
);
2069 /* Assume function is strict */
2070 if (!PointerIsValid(DatumGetPointer(reloptions
)))
2073 return amoptions(reloptions
, validate
);
2077 * Option parser for attribute reloptions
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
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.
2119 AlterTableGetRelOptionsLockLevel(List
*defList
)
2121 LOCKMODE lockmode
= NoLock
;
2125 return AccessExclusiveLock
;
2127 if (need_initialization
)
2128 initialize_reloptions();
2130 foreach(cell
, defList
)
2132 DefElem
*def
= (DefElem
*) lfirst(cell
);
2135 for (i
= 0; relOpts
[i
]; i
++)
2137 if (strncmp(relOpts
[i
]->name
,
2139 relOpts
[i
]->namelen
+ 1) == 0)
2141 if (lockmode
< relOpts
[i
]->lockmode
)
2142 lockmode
= relOpts
[i
]->lockmode
;