TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * reloptions.c
4 : * Core support for relation options (pg_class.reloptions)
5 : *
6 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/access/common/reloptions.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 :
16 : #include "postgres.h"
17 :
18 : #include <float.h>
19 :
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"
39 :
40 : /*
41 : * Contents of pg_class.reloptions
42 : *
43 : * To add an option:
44 : *
45 : * (i) decide on a type (integer, real, bool, string), name, default value,
46 : * upper and lower bounds (if applicable); for strings, consider a validation
47 : * routine.
48 : * (ii) add a record below (or use add_<type>_reloption).
49 : * (iii) add it to the appropriate options struct (perhaps StdRdOptions)
50 : * (iv) add it to the appropriate handling routine (perhaps
51 : * default_reloptions)
52 : * (v) make sure the lock level is set correctly for that operation
53 : * (vi) don't forget to document the option
54 : *
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.
63 : *
64 : * In general, anything that affects the results obtained from a SELECT must be
65 : * protected by AccessExclusiveLock.
66 : *
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.
70 : *
71 : * Fillfactor can be set because it applies only to subsequent changes made to
72 : * data blocks, as documented in hio.c
73 : *
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.
78 : *
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.
85 : *
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.
89 : *
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.
94 : */
95 :
96 : static relopt_bool boolRelOpts[] =
97 : {
98 : {
99 : {
100 : "autosummarize",
101 : "Enables automatic summarization on this BRIN index",
102 : RELOPT_KIND_BRIN,
103 : AccessExclusiveLock
104 : },
105 : false
106 : },
107 : {
108 : {
109 : "autovacuum_enabled",
110 : "Enables autovacuum in this relation",
111 : RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
112 : ShareUpdateExclusiveLock
113 : },
114 : true
115 : },
116 : {
117 : {
118 : "user_catalog_table",
119 : "Declare a table as an additional catalog table, e.g. for the purpose of logical replication",
120 : RELOPT_KIND_HEAP,
121 : AccessExclusiveLock
122 : },
123 : false
124 : },
125 : {
126 : {
127 : "fastupdate",
128 : "Enables \"fast update\" feature for this GIN index",
129 : RELOPT_KIND_GIN,
130 : AccessExclusiveLock
131 : },
132 : true
133 : },
134 : {
135 : {
136 : "security_barrier",
137 : "View acts as a row security barrier",
138 : RELOPT_KIND_VIEW,
139 : AccessExclusiveLock
140 : },
141 : false
142 : },
143 : {
144 : {
145 : "security_invoker",
146 : "Privileges on underlying relations are checked as the invoking user, not the view owner",
147 : RELOPT_KIND_VIEW,
148 : AccessExclusiveLock
149 : },
150 : false
151 : },
152 : {
153 : {
154 : "vacuum_truncate",
155 : "Enables vacuum to truncate empty pages at the end of this table",
156 : RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
157 : ShareUpdateExclusiveLock
158 : },
159 : true
160 : },
161 : {
162 : {
163 : "deduplicate_items",
164 : "Enables \"deduplicate items\" feature for this btree index",
165 : RELOPT_KIND_BTREE,
166 : ShareUpdateExclusiveLock /* since it applies only to later
167 : * inserts */
168 : },
169 : true
170 : },
171 : /* list terminator */
172 : {{NULL}}
173 : };
174 :
175 : static relopt_int intRelOpts[] =
176 : {
177 : {
178 : {
179 : "fillfactor",
180 : "Packs table pages only to this percentage",
181 : RELOPT_KIND_HEAP,
182 : ShareUpdateExclusiveLock /* since it applies only to later
183 : * inserts */
184 : },
185 : HEAP_DEFAULT_FILLFACTOR, HEAP_MIN_FILLFACTOR, 100
186 : },
187 : {
188 : {
189 : "fillfactor",
190 : "Packs btree index pages only to this percentage",
191 : RELOPT_KIND_BTREE,
192 : ShareUpdateExclusiveLock /* since it applies only to later
193 : * inserts */
194 : },
195 : BTREE_DEFAULT_FILLFACTOR, BTREE_MIN_FILLFACTOR, 100
196 : },
197 : {
198 : {
199 : "fillfactor",
200 : "Packs hash index pages only to this percentage",
201 : RELOPT_KIND_HASH,
202 : ShareUpdateExclusiveLock /* since it applies only to later
203 : * inserts */
204 : },
205 : HASH_DEFAULT_FILLFACTOR, HASH_MIN_FILLFACTOR, 100
206 : },
207 : {
208 : {
209 : "fillfactor",
210 : "Packs gist index pages only to this percentage",
211 : RELOPT_KIND_GIST,
212 : ShareUpdateExclusiveLock /* since it applies only to later
213 : * inserts */
214 : },
215 : GIST_DEFAULT_FILLFACTOR, GIST_MIN_FILLFACTOR, 100
216 : },
217 : {
218 : {
219 : "fillfactor",
220 : "Packs spgist index pages only to this percentage",
221 : RELOPT_KIND_SPGIST,
222 : ShareUpdateExclusiveLock /* since it applies only to later
223 : * inserts */
224 : },
225 : SPGIST_DEFAULT_FILLFACTOR, SPGIST_MIN_FILLFACTOR, 100
226 : },
227 : {
228 : {
229 : "autovacuum_vacuum_threshold",
230 : "Minimum number of tuple updates or deletes prior to vacuum",
231 : RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
232 : ShareUpdateExclusiveLock
233 : },
234 : -1, 0, INT_MAX
235 : },
236 : {
237 : {
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
242 : },
243 : -2, -1, INT_MAX
244 : },
245 : {
246 : {
247 : "autovacuum_analyze_threshold",
248 : "Minimum number of tuple inserts, updates or deletes prior to analyze",
249 : RELOPT_KIND_HEAP,
250 : ShareUpdateExclusiveLock
251 : },
252 : -1, 0, INT_MAX
253 : },
254 : {
255 : {
256 : "autovacuum_vacuum_cost_limit",
257 : "Vacuum cost amount available before napping, for autovacuum",
258 : RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
259 : ShareUpdateExclusiveLock
260 : },
261 : -1, 1, 10000
262 : },
263 : {
264 : {
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
269 : },
270 : -1, 0, 1000000000
271 : },
272 : {
273 : {
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
278 : },
279 : -1, 0, 1000000000
280 : },
281 : {
282 : {
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
287 : },
288 : -1, 100000, 2000000000
289 : },
290 : {
291 : {
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
296 : },
297 : -1, 10000, 2000000000
298 : },
299 : {
300 : {
301 : "autovacuum_freeze_table_age",
302 : "Age at which VACUUM should perform a full table sweep to freeze row versions",
303 : RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
304 : ShareUpdateExclusiveLock
305 : }, -1, 0, 2000000000
306 : },
307 : {
308 : {
309 : "autovacuum_multixact_freeze_table_age",
310 : "Age of multixact at which VACUUM should perform a full table sweep to freeze row versions",
311 : RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
312 : ShareUpdateExclusiveLock
313 : }, -1, 0, 2000000000
314 : },
315 : {
316 : {
317 : "log_autovacuum_min_duration",
318 : "Sets the minimum execution time above which autovacuum actions will be logged",
319 : RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
320 : ShareUpdateExclusiveLock
321 : },
322 : -1, -1, INT_MAX
323 : },
324 : {
325 : {
326 : "toast_tuple_target",
327 : "Sets the target tuple length at which external columns will be toasted",
328 : RELOPT_KIND_HEAP,
329 : ShareUpdateExclusiveLock
330 : },
331 : TOAST_TUPLE_TARGET, 128, TOAST_TUPLE_TARGET_MAIN
332 : },
333 : {
334 : {
335 : "pages_per_range",
336 : "Number of pages that each page range covers in a BRIN index",
337 : RELOPT_KIND_BRIN,
338 : AccessExclusiveLock
339 : }, 128, 1, 131072
340 : },
341 : {
342 : {
343 : "gin_pending_list_limit",
344 : "Maximum size of the pending list for this GIN index, in kilobytes.",
345 : RELOPT_KIND_GIN,
346 : AccessExclusiveLock
347 : },
348 : -1, 64, MAX_KILOBYTES
349 : },
350 : {
351 : {
352 : "effective_io_concurrency",
353 : "Number of simultaneous requests that can be handled efficiently by the disk subsystem.",
354 : RELOPT_KIND_TABLESPACE,
355 : ShareUpdateExclusiveLock
356 : },
357 : #ifdef USE_PREFETCH
358 : -1, 0, MAX_IO_CONCURRENCY
359 : #else
360 : 0, 0, 0
361 : #endif
362 : },
363 : {
364 : {
365 : "maintenance_io_concurrency",
366 : "Number of simultaneous requests that can be handled efficiently by the disk subsystem for maintenance work.",
367 : RELOPT_KIND_TABLESPACE,
368 : ShareUpdateExclusiveLock
369 : },
370 : #ifdef USE_PREFETCH
371 : -1, 0, MAX_IO_CONCURRENCY
372 : #else
373 : 0, 0, 0
374 : #endif
375 : },
376 : {
377 : {
378 : "parallel_workers",
379 : "Number of parallel processes that can be used per executor node for this relation.",
380 : RELOPT_KIND_HEAP,
381 : ShareUpdateExclusiveLock
382 : },
383 : -1, 0, 1024
384 : },
385 :
386 : /* list terminator */
387 : {{NULL}}
388 : };
389 :
390 : static relopt_real realRelOpts[] =
391 : {
392 : {
393 : {
394 : "autovacuum_vacuum_cost_delay",
395 : "Vacuum cost delay in milliseconds, for autovacuum",
396 : RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
397 : ShareUpdateExclusiveLock
398 : },
399 : -1, 0.0, 100.0
400 : },
401 : {
402 : {
403 : "autovacuum_vacuum_scale_factor",
404 : "Number of tuple updates or deletes prior to vacuum as a fraction of reltuples",
405 : RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
406 : ShareUpdateExclusiveLock
407 : },
408 : -1, 0.0, 100.0
409 : },
410 : {
411 : {
412 : "autovacuum_vacuum_insert_scale_factor",
413 : "Number of tuple inserts prior to vacuum as a fraction of reltuples",
414 : RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
415 : ShareUpdateExclusiveLock
416 : },
417 : -1, 0.0, 100.0
418 : },
419 : {
420 : {
421 : "autovacuum_analyze_scale_factor",
422 : "Number of tuple inserts, updates or deletes prior to analyze as a fraction of reltuples",
423 : RELOPT_KIND_HEAP,
424 : ShareUpdateExclusiveLock
425 : },
426 : -1, 0.0, 100.0
427 : },
428 : {
429 : {
430 : "seq_page_cost",
431 : "Sets the planner's estimate of the cost of a sequentially fetched disk page.",
432 : RELOPT_KIND_TABLESPACE,
433 : ShareUpdateExclusiveLock
434 : },
435 : -1, 0.0, DBL_MAX
436 : },
437 : {
438 : {
439 : "random_page_cost",
440 : "Sets the planner's estimate of the cost of a nonsequentially fetched disk page.",
441 : RELOPT_KIND_TABLESPACE,
442 : ShareUpdateExclusiveLock
443 : },
444 : -1, 0.0, DBL_MAX
445 : },
446 : {
447 : {
448 : "n_distinct",
449 : "Sets the planner's estimate of the number of distinct values appearing in a column (excluding child relations).",
450 : RELOPT_KIND_ATTRIBUTE,
451 : ShareUpdateExclusiveLock
452 : },
453 : 0, -1.0, DBL_MAX
454 : },
455 : {
456 : {
457 : "n_distinct_inherited",
458 : "Sets the planner's estimate of the number of distinct values appearing in a column (including child relations).",
459 : RELOPT_KIND_ATTRIBUTE,
460 : ShareUpdateExclusiveLock
461 : },
462 : 0, -1.0, DBL_MAX
463 : },
464 : {
465 : {
466 : "vacuum_cleanup_index_scale_factor",
467 : "Deprecated B-Tree parameter.",
468 : RELOPT_KIND_BTREE,
469 : ShareUpdateExclusiveLock
470 : },
471 : -1, 0.0, 1e10
472 : },
473 : /* list terminator */
474 : {{NULL}}
475 : };
476 :
477 : /* values from StdRdOptIndexCleanup */
478 : static relopt_enum_elt_def StdRdOptIndexCleanupValues[] =
479 : {
480 : {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO},
481 : {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON},
482 : {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF},
483 : {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON},
484 : {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF},
485 : {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON},
486 : {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF},
487 : {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON},
488 : {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF},
489 : {(const char *) NULL} /* list terminator */
490 : };
491 :
492 : /* values from GistOptBufferingMode */
493 : static relopt_enum_elt_def gistBufferingOptValues[] =
494 : {
495 : {"auto", GIST_OPTION_BUFFERING_AUTO},
496 : {"on", GIST_OPTION_BUFFERING_ON},
497 : {"off", GIST_OPTION_BUFFERING_OFF},
498 : {(const char *) NULL} /* list terminator */
499 : };
500 :
501 : /* values from ViewOptCheckOption */
502 : static relopt_enum_elt_def viewCheckOptValues[] =
503 : {
504 : /* no value for NOT_SET */
505 : {"local", VIEW_OPTION_CHECK_OPTION_LOCAL},
506 : {"cascaded", VIEW_OPTION_CHECK_OPTION_CASCADED},
507 : {(const char *) NULL} /* list terminator */
508 : };
509 :
510 : static relopt_enum enumRelOpts[] =
511 : {
512 : {
513 : {
514 : "vacuum_index_cleanup",
515 : "Controls index vacuuming and index cleanup",
516 : RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
517 : ShareUpdateExclusiveLock
518 : },
519 : StdRdOptIndexCleanupValues,
520 : STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO,
521 : gettext_noop("Valid values are \"on\", \"off\", and \"auto\".")
522 : },
523 : {
524 : {
525 : "buffering",
526 : "Enables buffering build for this GiST index",
527 : RELOPT_KIND_GIST,
528 : AccessExclusiveLock
529 : },
530 : gistBufferingOptValues,
531 : GIST_OPTION_BUFFERING_AUTO,
532 : gettext_noop("Valid values are \"on\", \"off\", and \"auto\".")
533 : },
534 : {
535 : {
536 : "check_option",
537 : "View has WITH CHECK OPTION defined (local or cascaded).",
538 : RELOPT_KIND_VIEW,
539 : AccessExclusiveLock
540 : },
541 : viewCheckOptValues,
542 : VIEW_OPTION_CHECK_OPTION_NOT_SET,
543 : gettext_noop("Valid values are \"local\" and \"cascaded\".")
544 : },
545 : /* list terminator */
546 : {{NULL}}
547 : };
548 :
549 : static relopt_string stringRelOpts[] =
550 : {
551 : /* list terminator */
552 : {{NULL}}
553 : };
554 :
555 : static relopt_gen **relOpts = NULL;
556 : static bits32 last_assigned_kind = RELOPT_KIND_LAST_DEFAULT;
557 :
558 : static int num_custom_options = 0;
559 : static relopt_gen **custom_options = NULL;
560 : static bool need_initialization = true;
561 :
562 : static void initialize_reloptions(void);
563 : static void parse_one_reloption(relopt_value *option, char *text_str,
564 : int text_len, bool validate);
565 :
566 : /*
567 : * Get the length of a string reloption (either default or the user-defined
568 : * value). This is used for allocation purposes when building a set of
569 : * relation options.
570 : */
571 : #define GET_STRING_RELOPTION_LEN(option) \
572 : ((option).isset ? strlen((option).values.string_val) : \
573 : ((relopt_string *) (option).gen)->default_len)
574 :
575 : /*
576 : * initialize_reloptions
577 : * initialization routine, must be called before parsing
578 : *
579 : * Initialize the relOpts array and fill each variable's type and name length.
580 : */
581 : static void
582 CBC 3149 : initialize_reloptions(void)
583 : {
584 : int i;
585 : int j;
586 :
587 3149 : j = 0;
588 28341 : for (i = 0; boolRelOpts[i].gen.name; i++)
589 : {
590 25192 : Assert(DoLockModesConflict(boolRelOpts[i].gen.lockmode,
591 : boolRelOpts[i].gen.lockmode));
592 25192 : j++;
593 : }
594 72427 : for (i = 0; intRelOpts[i].gen.name; i++)
595 : {
596 69278 : Assert(DoLockModesConflict(intRelOpts[i].gen.lockmode,
597 : intRelOpts[i].gen.lockmode));
598 69278 : j++;
599 : }
600 31490 : for (i = 0; realRelOpts[i].gen.name; i++)
601 : {
602 28341 : Assert(DoLockModesConflict(realRelOpts[i].gen.lockmode,
603 : realRelOpts[i].gen.lockmode));
604 28341 : j++;
605 : }
606 12596 : for (i = 0; enumRelOpts[i].gen.name; i++)
607 : {
608 9447 : Assert(DoLockModesConflict(enumRelOpts[i].gen.lockmode,
609 : enumRelOpts[i].gen.lockmode));
610 9447 : j++;
611 : }
612 3149 : for (i = 0; stringRelOpts[i].gen.name; i++)
613 : {
614 UBC 0 : Assert(DoLockModesConflict(stringRelOpts[i].gen.lockmode,
615 : stringRelOpts[i].gen.lockmode));
616 0 : j++;
617 : }
618 CBC 3149 : j += num_custom_options;
619 :
620 3149 : if (relOpts)
621 UBC 0 : pfree(relOpts);
622 CBC 6298 : relOpts = MemoryContextAlloc(TopMemoryContext,
623 3149 : (j + 1) * sizeof(relopt_gen *));
624 :
625 3149 : j = 0;
626 28341 : for (i = 0; boolRelOpts[i].gen.name; i++)
627 : {
628 25192 : relOpts[j] = &boolRelOpts[i].gen;
629 25192 : relOpts[j]->type = RELOPT_TYPE_BOOL;
630 25192 : relOpts[j]->namelen = strlen(relOpts[j]->name);
631 25192 : j++;
632 : }
633 :
634 72427 : for (i = 0; intRelOpts[i].gen.name; i++)
635 : {
636 69278 : relOpts[j] = &intRelOpts[i].gen;
637 69278 : relOpts[j]->type = RELOPT_TYPE_INT;
638 69278 : relOpts[j]->namelen = strlen(relOpts[j]->name);
639 69278 : j++;
640 : }
641 :
642 31490 : for (i = 0; realRelOpts[i].gen.name; i++)
643 : {
644 28341 : relOpts[j] = &realRelOpts[i].gen;
645 28341 : relOpts[j]->type = RELOPT_TYPE_REAL;
646 28341 : relOpts[j]->namelen = strlen(relOpts[j]->name);
647 28341 : j++;
648 : }
649 :
650 12596 : for (i = 0; enumRelOpts[i].gen.name; i++)
651 : {
652 9447 : relOpts[j] = &enumRelOpts[i].gen;
653 9447 : relOpts[j]->type = RELOPT_TYPE_ENUM;
654 9447 : relOpts[j]->namelen = strlen(relOpts[j]->name);
655 9447 : j++;
656 : }
657 :
658 3149 : for (i = 0; stringRelOpts[i].gen.name; i++)
659 : {
660 UBC 0 : relOpts[j] = &stringRelOpts[i].gen;
661 0 : relOpts[j]->type = RELOPT_TYPE_STRING;
662 0 : relOpts[j]->namelen = strlen(relOpts[j]->name);
663 0 : j++;
664 : }
665 :
666 CBC 6257 : for (i = 0; i < num_custom_options; i++)
667 : {
668 3108 : relOpts[j] = custom_options[i];
669 3108 : j++;
670 : }
671 :
672 : /* add a list terminator */
673 3149 : relOpts[j] = NULL;
674 :
675 : /* flag the work is complete */
676 3149 : need_initialization = false;
677 3149 : }
678 :
679 : /*
680 : * add_reloption_kind
681 : * Create a new relopt_kind value, to be used in custom reloptions by
682 : * user-defined AMs.
683 : */
684 : relopt_kind
685 96 : add_reloption_kind(void)
686 : {
687 : /* don't hand out the last bit so that the enum's behavior is portable */
688 96 : if (last_assigned_kind >= RELOPT_KIND_MAX)
689 UBC 0 : ereport(ERROR,
690 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
691 : errmsg("user-defined relation parameter types limit exceeded")));
692 CBC 96 : last_assigned_kind <<= 1;
693 96 : return (relopt_kind) last_assigned_kind;
694 : }
695 :
696 : /*
697 : * add_reloption
698 : * Add an already-created custom reloption to the list, and recompute the
699 : * main parser table.
700 : */
701 : static void
702 3141 : add_reloption(relopt_gen *newoption)
703 : {
704 : static int max_custom_options = 0;
705 :
706 3141 : if (num_custom_options >= max_custom_options)
707 : {
708 : MemoryContext oldcxt;
709 :
710 381 : oldcxt = MemoryContextSwitchTo(TopMemoryContext);
711 :
712 381 : if (max_custom_options == 0)
713 : {
714 96 : max_custom_options = 8;
715 96 : custom_options = palloc(max_custom_options * sizeof(relopt_gen *));
716 : }
717 : else
718 : {
719 285 : max_custom_options *= 2;
720 285 : custom_options = repalloc(custom_options,
721 : max_custom_options * sizeof(relopt_gen *));
722 : }
723 381 : MemoryContextSwitchTo(oldcxt);
724 : }
725 3141 : custom_options[num_custom_options++] = newoption;
726 :
727 3141 : need_initialization = true;
728 3141 : }
729 :
730 : /*
731 : * init_local_reloptions
732 : * Initialize local reloptions that will parsed into bytea structure of
733 : * 'relopt_struct_size'.
734 : */
735 : void
736 GNC 1666 : init_local_reloptions(local_relopts *relopts, Size relopt_struct_size)
737 : {
738 1666 : relopts->options = NIL;
739 1666 : relopts->validators = NIL;
740 1666 : relopts->relopt_struct_size = relopt_struct_size;
741 CBC 1666 : }
742 :
743 : /*
744 : * register_reloptions_validator
745 : * Register custom validation callback that will be called at the end of
746 : * build_local_reloptions().
747 : */
748 : void
749 UNC 0 : register_reloptions_validator(local_relopts *relopts, relopts_validator validator)
750 : {
751 0 : relopts->validators = lappend(relopts->validators, validator);
752 UBC 0 : }
753 :
754 : /*
755 : * add_local_reloption
756 : * Add an already-created custom reloption to the local list.
757 : */
758 : static void
759 CBC 1081 : add_local_reloption(local_relopts *relopts, relopt_gen *newoption, int offset)
760 : {
761 1081 : local_relopt *opt = palloc(sizeof(*opt));
762 :
763 1081 : Assert(offset < relopts->relopt_struct_size);
764 :
765 1081 : opt->option = newoption;
766 1081 : opt->offset = offset;
767 :
768 1081 : relopts->options = lappend(relopts->options, opt);
769 1081 : }
770 :
771 : /*
772 : * allocate_reloption
773 : * Allocate a new reloption and initialize the type-agnostic fields
774 : * (for types other than string)
775 : */
776 : static relopt_gen *
777 4222 : allocate_reloption(bits32 kinds, int type, const char *name, const char *desc,
778 : LOCKMODE lockmode)
779 : {
780 : MemoryContext oldcxt;
781 : size_t size;
782 : relopt_gen *newoption;
783 :
784 4222 : if (kinds != RELOPT_KIND_LOCAL)
785 3141 : oldcxt = MemoryContextSwitchTo(TopMemoryContext);
786 : else
787 1081 : oldcxt = NULL;
788 :
789 4222 : switch (type)
790 : {
791 1 : case RELOPT_TYPE_BOOL:
792 1 : size = sizeof(relopt_bool);
793 1 : break;
794 3721 : case RELOPT_TYPE_INT:
795 3721 : size = sizeof(relopt_int);
796 3721 : break;
797 497 : case RELOPT_TYPE_REAL:
798 497 : size = sizeof(relopt_real);
799 497 : break;
800 1 : case RELOPT_TYPE_ENUM:
801 1 : size = sizeof(relopt_enum);
802 1 : break;
803 2 : case RELOPT_TYPE_STRING:
804 2 : size = sizeof(relopt_string);
805 2 : break;
806 UBC 0 : default:
807 0 : elog(ERROR, "unsupported reloption type %d", type);
808 : return NULL; /* keep compiler quiet */
809 : }
810 :
811 CBC 4222 : newoption = palloc(size);
812 :
813 4222 : newoption->name = pstrdup(name);
814 4222 : if (desc)
815 4221 : newoption->desc = pstrdup(desc);
816 : else
817 1 : newoption->desc = NULL;
818 4222 : newoption->kinds = kinds;
819 4222 : newoption->namelen = strlen(name);
820 4222 : newoption->type = type;
821 4222 : newoption->lockmode = lockmode;
822 :
823 4222 : if (oldcxt != NULL)
824 3141 : MemoryContextSwitchTo(oldcxt);
825 :
826 4222 : return newoption;
827 : }
828 :
829 : /*
830 : * init_bool_reloption
831 : * Allocate and initialize a new boolean reloption
832 : */
833 : static relopt_bool *
834 1 : init_bool_reloption(bits32 kinds, const char *name, const char *desc,
835 : bool default_val, LOCKMODE lockmode)
836 : {
837 : relopt_bool *newoption;
838 :
839 1 : newoption = (relopt_bool *) allocate_reloption(kinds, RELOPT_TYPE_BOOL,
840 : name, desc, lockmode);
841 1 : newoption->default_val = default_val;
842 :
843 1 : return newoption;
844 : }
845 :
846 : /*
847 : * add_bool_reloption
848 : * Add a new boolean reloption
849 : */
850 : void
851 1 : add_bool_reloption(bits32 kinds, const char *name, const char *desc,
852 : bool default_val, LOCKMODE lockmode)
853 : {
854 1 : relopt_bool *newoption = init_bool_reloption(kinds, name, desc,
855 : default_val, lockmode);
856 :
857 1 : add_reloption((relopt_gen *) newoption);
858 1 : }
859 :
860 : /*
861 : * add_local_bool_reloption
862 : * Add a new boolean local reloption
863 : *
864 : * 'offset' is offset of bool-typed field.
865 : */
866 : void
867 UBC 0 : add_local_bool_reloption(local_relopts *relopts, const char *name,
868 : const char *desc, bool default_val, int offset)
869 : {
870 0 : relopt_bool *newoption = init_bool_reloption(RELOPT_KIND_LOCAL,
871 : name, desc,
872 : default_val, 0);
873 :
874 0 : add_local_reloption(relopts, (relopt_gen *) newoption, offset);
875 0 : }
876 :
877 :
878 : /*
879 : * init_real_reloption
880 : * Allocate and initialize a new integer reloption
881 : */
882 : static relopt_int *
883 CBC 3721 : init_int_reloption(bits32 kinds, const char *name, const char *desc,
884 : int default_val, int min_val, int max_val,
885 : LOCKMODE lockmode)
886 : {
887 : relopt_int *newoption;
888 :
889 3721 : newoption = (relopt_int *) allocate_reloption(kinds, RELOPT_TYPE_INT,
890 : name, desc, lockmode);
891 3721 : newoption->default_val = default_val;
892 3721 : newoption->min = min_val;
893 3721 : newoption->max = max_val;
894 :
895 3721 : return newoption;
896 : }
897 :
898 : /*
899 : * add_int_reloption
900 : * Add a new integer reloption
901 : */
902 : void
903 3136 : add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val,
904 : int min_val, int max_val, LOCKMODE lockmode)
905 : {
906 3136 : relopt_int *newoption = init_int_reloption(kinds, name, desc,
907 : default_val, min_val,
908 : max_val, lockmode);
909 :
910 3136 : add_reloption((relopt_gen *) newoption);
911 3136 : }
912 :
913 : /*
914 : * add_local_int_reloption
915 : * Add a new local integer reloption
916 : *
917 : * 'offset' is offset of int-typed field.
918 : */
919 : void
920 585 : add_local_int_reloption(local_relopts *relopts, const char *name,
921 : const char *desc, int default_val, int min_val,
922 : int max_val, int offset)
923 : {
924 585 : relopt_int *newoption = init_int_reloption(RELOPT_KIND_LOCAL,
925 : name, desc, default_val,
926 : min_val, max_val, 0);
927 :
928 585 : add_local_reloption(relopts, (relopt_gen *) newoption, offset);
929 585 : }
930 :
931 : /*
932 : * init_real_reloption
933 : * Allocate and initialize a new real reloption
934 : */
935 : static relopt_real *
936 497 : init_real_reloption(bits32 kinds, const char *name, const char *desc,
937 : double default_val, double min_val, double max_val,
938 : LOCKMODE lockmode)
939 : {
940 : relopt_real *newoption;
941 :
942 497 : newoption = (relopt_real *) allocate_reloption(kinds, RELOPT_TYPE_REAL,
943 : name, desc, lockmode);
944 497 : newoption->default_val = default_val;
945 497 : newoption->min = min_val;
946 497 : newoption->max = max_val;
947 :
948 497 : return newoption;
949 : }
950 :
951 : /*
952 : * add_real_reloption
953 : * Add a new float reloption
954 : */
955 : void
956 1 : add_real_reloption(bits32 kinds, const char *name, const char *desc,
957 : double default_val, double min_val, double max_val,
958 : LOCKMODE lockmode)
959 : {
960 1 : relopt_real *newoption = init_real_reloption(kinds, name, desc,
961 : default_val, min_val,
962 : max_val, lockmode);
963 :
964 1 : add_reloption((relopt_gen *) newoption);
965 1 : }
966 :
967 : /*
968 : * add_local_real_reloption
969 : * Add a new local float reloption
970 : *
971 : * 'offset' is offset of double-typed field.
972 : */
973 : void
974 496 : add_local_real_reloption(local_relopts *relopts, const char *name,
975 : const char *desc, double default_val,
976 : double min_val, double max_val, int offset)
977 : {
978 496 : relopt_real *newoption = init_real_reloption(RELOPT_KIND_LOCAL,
979 : name, desc,
980 : default_val, min_val,
981 : max_val, 0);
982 :
983 496 : add_local_reloption(relopts, (relopt_gen *) newoption, offset);
984 496 : }
985 :
986 : /*
987 : * init_enum_reloption
988 : * Allocate and initialize a new enum reloption
989 : */
990 : static relopt_enum *
991 1 : init_enum_reloption(bits32 kinds, const char *name, const char *desc,
992 : relopt_enum_elt_def *members, int default_val,
993 : const char *detailmsg, LOCKMODE lockmode)
994 : {
995 : relopt_enum *newoption;
996 :
997 1 : newoption = (relopt_enum *) allocate_reloption(kinds, RELOPT_TYPE_ENUM,
998 : name, desc, lockmode);
999 1 : newoption->members = members;
1000 1 : newoption->default_val = default_val;
1001 1 : newoption->detailmsg = detailmsg;
1002 :
1003 1 : return newoption;
1004 : }
1005 :
1006 :
1007 : /*
1008 : * add_enum_reloption
1009 : * Add a new enum reloption
1010 : *
1011 : * The members array must have a terminating NULL entry.
1012 : *
1013 : * The detailmsg is shown when unsupported values are passed, and has this
1014 : * form: "Valid values are \"foo\", \"bar\", and \"bar\"."
1015 : *
1016 : * The members array and detailmsg are not copied -- caller must ensure that
1017 : * they are valid throughout the life of the process.
1018 : */
1019 : void
1020 1 : add_enum_reloption(bits32 kinds, const char *name, const char *desc,
1021 : relopt_enum_elt_def *members, int default_val,
1022 : const char *detailmsg, LOCKMODE lockmode)
1023 : {
1024 1 : relopt_enum *newoption = init_enum_reloption(kinds, name, desc,
1025 : members, default_val,
1026 : detailmsg, lockmode);
1027 :
1028 1 : add_reloption((relopt_gen *) newoption);
1029 1 : }
1030 :
1031 : /*
1032 : * add_local_enum_reloption
1033 : * Add a new local enum reloption
1034 : *
1035 : * 'offset' is offset of int-typed field.
1036 : */
1037 : void
1038 UBC 0 : add_local_enum_reloption(local_relopts *relopts, const char *name,
1039 : const char *desc, relopt_enum_elt_def *members,
1040 : int default_val, const char *detailmsg, int offset)
1041 : {
1042 0 : relopt_enum *newoption = init_enum_reloption(RELOPT_KIND_LOCAL,
1043 : name, desc,
1044 : members, default_val,
1045 : detailmsg, 0);
1046 :
1047 0 : add_local_reloption(relopts, (relopt_gen *) newoption, offset);
1048 0 : }
1049 :
1050 : /*
1051 : * init_string_reloption
1052 : * Allocate and initialize a new string reloption
1053 : */
1054 : static relopt_string *
1055 CBC 2 : init_string_reloption(bits32 kinds, const char *name, const char *desc,
1056 : const char *default_val,
1057 : validate_string_relopt validator,
1058 : fill_string_relopt filler,
1059 : LOCKMODE lockmode)
1060 : {
1061 : relopt_string *newoption;
1062 :
1063 : /* make sure the validator/default combination is sane */
1064 2 : if (validator)
1065 2 : (validator) (default_val);
1066 :
1067 2 : newoption = (relopt_string *) allocate_reloption(kinds, RELOPT_TYPE_STRING,
1068 : name, desc, lockmode);
1069 2 : newoption->validate_cb = validator;
1070 2 : newoption->fill_cb = filler;
1071 2 : if (default_val)
1072 : {
1073 1 : if (kinds == RELOPT_KIND_LOCAL)
1074 UBC 0 : newoption->default_val = strdup(default_val);
1075 : else
1076 CBC 1 : newoption->default_val = MemoryContextStrdup(TopMemoryContext, default_val);
1077 1 : newoption->default_len = strlen(default_val);
1078 1 : newoption->default_isnull = false;
1079 : }
1080 : else
1081 : {
1082 1 : newoption->default_val = "";
1083 1 : newoption->default_len = 0;
1084 1 : newoption->default_isnull = true;
1085 : }
1086 :
1087 2 : return newoption;
1088 : }
1089 :
1090 : /*
1091 : * add_string_reloption
1092 : * Add a new string reloption
1093 : *
1094 : * "validator" is an optional function pointer that can be used to test the
1095 : * validity of the values. It must elog(ERROR) when the argument string is
1096 : * not acceptable for the variable. Note that the default value must pass
1097 : * the validation.
1098 : */
1099 : void
1100 2 : add_string_reloption(bits32 kinds, const char *name, const char *desc,
1101 : const char *default_val, validate_string_relopt validator,
1102 : LOCKMODE lockmode)
1103 : {
1104 2 : relopt_string *newoption = init_string_reloption(kinds, name, desc,
1105 : default_val,
1106 : validator, NULL,
1107 : lockmode);
1108 :
1109 2 : add_reloption((relopt_gen *) newoption);
1110 2 : }
1111 :
1112 : /*
1113 : * add_local_string_reloption
1114 : * Add a new local string reloption
1115 : *
1116 : * 'offset' is offset of int-typed field that will store offset of string value
1117 : * in the resulting bytea structure.
1118 : */
1119 : void
1120 UBC 0 : add_local_string_reloption(local_relopts *relopts, const char *name,
1121 : const char *desc, const char *default_val,
1122 : validate_string_relopt validator,
1123 : fill_string_relopt filler, int offset)
1124 : {
1125 0 : relopt_string *newoption = init_string_reloption(RELOPT_KIND_LOCAL,
1126 : name, desc,
1127 : default_val,
1128 : validator, filler,
1129 : 0);
1130 :
1131 0 : add_local_reloption(relopts, (relopt_gen *) newoption, offset);
1132 0 : }
1133 :
1134 : /*
1135 : * Transform a relation options list (list of DefElem) into the text array
1136 : * format that is kept in pg_class.reloptions, including only those options
1137 : * that are in the passed namespace. The output values do not include the
1138 : * namespace.
1139 : *
1140 : * This is used for three cases: CREATE TABLE/INDEX, ALTER TABLE SET, and
1141 : * ALTER TABLE RESET. In the ALTER cases, oldOptions is the existing
1142 : * reloptions value (possibly NULL), and we replace or remove entries
1143 : * as needed.
1144 : *
1145 : * If acceptOidsOff is true, then we allow oids = false, but throw error when
1146 : * on. This is solely needed for backwards compatibility.
1147 : *
1148 : * Note that this is not responsible for determining whether the options
1149 : * are valid, but it does check that namespaces for all the options given are
1150 : * listed in validnsps. The NULL namespace is always valid and need not be
1151 : * explicitly listed. Passing a NULL pointer means that only the NULL
1152 : * namespace is valid.
1153 : *
1154 : * Both oldOptions and the result are text arrays (or NULL for "default"),
1155 : * but we declare them as Datums to avoid including array.h in reloptions.h.
1156 : */
1157 : Datum
1158 CBC 126256 : transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
1159 : char *validnsps[], bool acceptOidsOff, bool isReset)
1160 : {
1161 : Datum result;
1162 : ArrayBuildState *astate;
1163 : ListCell *cell;
1164 :
1165 : /* no change if empty list */
1166 126256 : if (defList == NIL)
1167 123877 : return oldOptions;
1168 :
1169 : /* We build new array using accumArrayResult */
1170 2379 : astate = NULL;
1171 :
1172 : /* Copy any oldOptions that aren't to be replaced */
1173 2379 : if (PointerIsValid(DatumGetPointer(oldOptions)))
1174 : {
1175 165 : ArrayType *array = DatumGetArrayTypeP(oldOptions);
1176 : Datum *oldoptions;
1177 : int noldoptions;
1178 : int i;
1179 :
1180 GNC 165 : deconstruct_array_builtin(array, TEXTOID, &oldoptions, NULL, &noldoptions);
1181 ECB :
1182 GIC 419 : for (i = 0; i < noldoptions; i++)
1183 ECB : {
1184 CBC 254 : char *text_str = VARDATA(oldoptions[i]);
1185 GIC 254 : int text_len = VARSIZE(oldoptions[i]) - VARHDRSZ;
1186 :
1187 ECB : /* Search for a match in defList */
1188 GIC 377 : foreach(cell, defList)
1189 ECB : {
1190 GIC 278 : DefElem *def = (DefElem *) lfirst(cell);
1191 : int kw_len;
1192 :
1193 ECB : /* ignore if not in the same namespace */
1194 GIC 278 : if (namspace == NULL)
1195 ECB : {
1196 GBC 254 : if (def->defnamespace != NULL)
1197 UIC 0 : continue;
1198 ECB : }
1199 CBC 24 : else if (def->defnamespace == NULL)
1200 15 : continue;
1201 GBC 9 : else if (strcmp(def->defnamespace, namspace) != 0)
1202 UIC 0 : continue;
1203 ECB :
1204 CBC 263 : kw_len = strlen(def->defname);
1205 263 : if (text_len > kw_len && text_str[kw_len] == '=' &&
1206 166 : strncmp(text_str, def->defname, kw_len) == 0)
1207 GIC 155 : break;
1208 ECB : }
1209 GIC 254 : if (!cell)
1210 : {
1211 ECB : /* No match, so keep old option */
1212 GIC 99 : astate = accumArrayResult(astate, oldoptions[i],
1213 : false, TEXTOID,
1214 : CurrentMemoryContext);
1215 : }
1216 : }
1217 : }
1218 :
1219 : /*
1220 : * If CREATE/SET, add new options to array; if RESET, just check that the
1221 : * user didn't say RESET (option=val). (Must do this because the grammar
1222 : * doesn't enforce it.)
1223 ECB : */
1224 GIC 4913 : foreach(cell, defList)
1225 ECB : {
1226 GIC 2552 : DefElem *def = (DefElem *) lfirst(cell);
1227 ECB :
1228 GIC 2552 : if (isReset)
1229 ECB : {
1230 CBC 119 : if (def->arg != NULL)
1231 GIC 6 : ereport(ERROR,
1232 : (errcode(ERRCODE_SYNTAX_ERROR),
1233 : errmsg("RESET must not include values for parameters")));
1234 : }
1235 : else
1236 : {
1237 : text *t;
1238 : const char *value;
1239 : Size len;
1240 :
1241 : /*
1242 : * Error out if the namespace is not valid. A NULL namespace is
1243 : * always valid.
1244 ECB : */
1245 GIC 2433 : if (def->defnamespace != NULL)
1246 ECB : {
1247 GIC 56 : bool valid = false;
1248 : int i;
1249 ECB :
1250 GIC 56 : if (validnsps)
1251 ECB : {
1252 GIC 56 : for (i = 0; validnsps[i]; i++)
1253 ECB : {
1254 GIC 53 : if (strcmp(def->defnamespace, validnsps[i]) == 0)
1255 ECB : {
1256 CBC 50 : valid = true;
1257 GIC 50 : break;
1258 : }
1259 : }
1260 : }
1261 ECB :
1262 CBC 56 : if (!valid)
1263 GIC 6 : ereport(ERROR,
1264 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1265 : errmsg("unrecognized parameter namespace \"%s\"",
1266 : def->defnamespace)));
1267 : }
1268 :
1269 ECB : /* ignore if not in the same namespace */
1270 GIC 2427 : if (namspace == NULL)
1271 ECB : {
1272 CBC 2034 : if (def->defnamespace != NULL)
1273 GIC 25 : continue;
1274 ECB : }
1275 CBC 393 : else if (def->defnamespace == NULL)
1276 368 : continue;
1277 GBC 25 : else if (strcmp(def->defnamespace, namspace) != 0)
1278 UIC 0 : continue;
1279 :
1280 : /*
1281 : * Flatten the DefElem into a text string like "name=arg". If we
1282 : * have just "name", assume "name=true" is meant. Note: the
1283 : * namespace is not output.
1284 ECB : */
1285 CBC 2034 : if (def->arg != NULL)
1286 GIC 1071 : value = defGetString(def);
1287 ECB : else
1288 GIC 963 : value = "true";
1289 :
1290 : /*
1291 : * This is not a great place for this test, but there's no other
1292 : * convenient place to filter the option out. As WITH (oids =
1293 : * false) will be removed someday, this seems like an acceptable
1294 : * amount of ugly.
1295 ECB : */
1296 CBC 2034 : if (acceptOidsOff && def->defnamespace == NULL &&
1297 GIC 1390 : strcmp(def->defname, "oids") == 0)
1298 ECB : {
1299 CBC 9 : if (defGetBoolean(def))
1300 GIC 6 : ereport(ERROR,
1301 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1302 : errmsg("tables declared WITH OIDS are not supported")));
1303 ECB : /* skip over option, reloptions machinery doesn't know it */
1304 GIC 3 : continue;
1305 : }
1306 ECB :
1307 GIC 2025 : len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
1308 ECB : /* +1 leaves room for sprintf's trailing null */
1309 CBC 2025 : t = (text *) palloc(len + 1);
1310 2025 : SET_VARSIZE(t, len);
1311 GIC 2025 : sprintf(VARDATA(t), "%s=%s", def->defname, value);
1312 ECB :
1313 GIC 2025 : astate = accumArrayResult(astate, PointerGetDatum(t),
1314 : false, TEXTOID,
1315 : CurrentMemoryContext);
1316 : }
1317 : }
1318 ECB :
1319 CBC 2361 : if (astate)
1320 GIC 1951 : result = makeArrayResult(astate, CurrentMemoryContext);
1321 ECB : else
1322 GIC 410 : result = (Datum) 0;
1323 ECB :
1324 GIC 2361 : return result;
1325 : }
1326 :
1327 :
1328 : /*
1329 : * Convert the text-array format of reloptions into a List of DefElem.
1330 : * This is the inverse of transformRelOptions().
1331 : */
1332 ECB : List *
1333 GIC 12586 : untransformRelOptions(Datum options)
1334 ECB : {
1335 GIC 12586 : List *result = NIL;
1336 : ArrayType *array;
1337 : Datum *optiondatums;
1338 : int noptions;
1339 : int i;
1340 :
1341 ECB : /* Nothing to do if no options */
1342 CBC 12586 : if (!PointerIsValid(DatumGetPointer(options)))
1343 GIC 1521 : return result;
1344 ECB :
1345 GIC 11065 : array = DatumGetArrayTypeP(options);
1346 ECB :
1347 GNC 11065 : deconstruct_array_builtin(array, TEXTOID, &optiondatums, NULL, &noptions);
1348 :
1349 GIC 32818 : for (i = 0; i < noptions; i++)
1350 : {
1351 ECB : char *s;
1352 : char *p;
1353 CBC 21753 : Node *val = NULL;
1354 ECB :
1355 CBC 21753 : s = TextDatumGetCString(optiondatums[i]);
1356 GIC 21753 : p = strchr(s, '=');
1357 CBC 21753 : if (p)
1358 ECB : {
1359 GIC 21753 : *p++ = '\0';
1360 GNC 21753 : val = (Node *) makeString(p);
1361 : }
1362 21753 : result = lappend(result, makeDefElem(s, val, -1));
1363 ECB : }
1364 :
1365 GIC 11065 : return result;
1366 : }
1367 :
1368 : /*
1369 : * Extract and parse reloptions from a pg_class tuple.
1370 : *
1371 : * This is a low-level routine, expected to be used by relcache code and
1372 : * callers that do not have a table's relcache entry (e.g. autovacuum). For
1373 : * other uses, consider grabbing the rd_options pointer from the relcache entry
1374 : * instead.
1375 : *
1376 : * tupdesc is pg_class' tuple descriptor. amoptions is a pointer to the index
1377 : * AM's options parser function in the case of a tuple corresponding to an
1378 : * index, or NULL otherwise.
1379 ECB : */
1380 : bytea *
1381 GIC 794692 : extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
1382 : amoptions_function amoptions)
1383 : {
1384 : bytea *options;
1385 : bool isnull;
1386 : Datum datum;
1387 ECB : Form_pg_class classForm;
1388 :
1389 GIC 794692 : datum = fastgetattr(tuple,
1390 : Anum_pg_class_reloptions,
1391 ECB : tupdesc,
1392 : &isnull);
1393 GIC 794692 : if (isnull)
1394 CBC 786983 : return NULL;
1395 :
1396 GIC 7709 : classForm = (Form_pg_class) GETSTRUCT(tuple);
1397 ECB :
1398 : /* Parse into appropriate format; don't error out here */
1399 CBC 7709 : switch (classForm->relkind)
1400 : {
1401 GIC 4404 : case RELKIND_RELATION:
1402 ECB : case RELKIND_TOASTVALUE:
1403 : case RELKIND_MATVIEW:
1404 GBC 4404 : options = heap_reloptions(classForm->relkind, datum, false);
1405 4404 : break;
1406 UBC 0 : case RELKIND_PARTITIONED_TABLE:
1407 LBC 0 : options = partitioned_table_reloptions(datum, false);
1408 0 : break;
1409 CBC 2535 : case RELKIND_VIEW:
1410 2535 : options = view_reloptions(datum, false);
1411 GIC 2535 : break;
1412 CBC 770 : case RELKIND_INDEX:
1413 ECB : case RELKIND_PARTITIONED_INDEX:
1414 GBC 770 : options = index_reloptions(amoptions, datum, false);
1415 770 : break;
1416 UBC 0 : case RELKIND_FOREIGN_TABLE:
1417 0 : options = NULL;
1418 0 : break;
1419 UIC 0 : default:
1420 0 : Assert(false); /* can't get here */
1421 : options = NULL; /* keep compiler quiet */
1422 : break;
1423 ECB : }
1424 :
1425 GIC 7709 : return options;
1426 : }
1427 ECB :
1428 : static void
1429 GIC 9804 : parseRelOptionsInternal(Datum options, bool validate,
1430 ECB : relopt_value *reloptions, int numoptions)
1431 : {
1432 GIC 9804 : ArrayType *array = DatumGetArrayTypeP(options);
1433 : Datum *optiondatums;
1434 : int noptions;
1435 ECB : int i;
1436 :
1437 GNC 9804 : deconstruct_array_builtin(array, TEXTOID, &optiondatums, NULL, &noptions);
1438 ECB :
1439 CBC 20360 : for (i = 0; i < noptions; i++)
1440 : {
1441 GIC 10716 : char *text_str = VARDATA(optiondatums[i]);
1442 10716 : int text_len = VARSIZE(optiondatums[i]) - VARHDRSZ;
1443 ECB : int j;
1444 :
1445 : /* Search for a match in reloptions */
1446 GIC 41259 : for (j = 0; j < numoptions; j++)
1447 ECB : {
1448 CBC 41220 : int kw_len = reloptions[j].gen->namelen;
1449 :
1450 41220 : if (text_len > kw_len && text_str[kw_len] == '=' &&
1451 GIC 11151 : strncmp(text_str, reloptions[j].gen->name, kw_len) == 0)
1452 ECB : {
1453 GIC 10677 : parse_one_reloption(&reloptions[j], text_str, text_len,
1454 : validate);
1455 10550 : break;
1456 ECB : }
1457 : }
1458 :
1459 GIC 10589 : if (j >= numoptions && validate)
1460 : {
1461 ECB : char *s;
1462 : char *p;
1463 :
1464 CBC 33 : s = TextDatumGetCString(optiondatums[i]);
1465 33 : p = strchr(s, '=');
1466 GIC 33 : if (p)
1467 33 : *p = '\0';
1468 33 : ereport(ERROR,
1469 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1470 : errmsg("unrecognized parameter \"%s\"", s)));
1471 : }
1472 ECB : }
1473 :
1474 : /* It's worth avoiding memory leaks in this function */
1475 CBC 9644 : pfree(optiondatums);
1476 ECB :
1477 GIC 9644 : if (((void *) array) != DatumGetPointer(options))
1478 7845 : pfree(array);
1479 9644 : }
1480 :
1481 : /*
1482 : * Interpret reloptions that are given in text-array format.
1483 : *
1484 : * options is a reloption text array as constructed by transformRelOptions.
1485 : * kind specifies the family of options to be processed.
1486 : *
1487 : * The return value is a relopt_value * array on which the options actually
1488 : * set in the options array are marked with isset=true. The length of this
1489 : * array is returned in *numrelopts. Options not set are also present in the
1490 : * array; this is so that the caller can easily locate the default values.
1491 : *
1492 : * If there are no options of the given kind, numrelopts is set to 0 and NULL
1493 : * is returned (unless options are illegally supplied despite none being
1494 : * defined, in which case an error occurs).
1495 : *
1496 : * Note: values of type int, bool and real are allocated as part of the
1497 : * returned array. Values of type string are allocated separately and must
1498 ECB : * be freed by the caller.
1499 : */
1500 : static relopt_value *
1501 CBC 85256 : parseRelOptions(Datum options, bool validate, relopt_kind kind,
1502 ECB : int *numrelopts)
1503 : {
1504 GIC 85256 : relopt_value *reloptions = NULL;
1505 85256 : int numoptions = 0;
1506 ECB : int i;
1507 : int j;
1508 :
1509 GIC 85256 : if (need_initialization)
1510 3145 : initialize_reloptions();
1511 ECB :
1512 : /* Build a list of expected options, based on kind */
1513 :
1514 GIC 3670394 : for (i = 0; relOpts[i]; i++)
1515 CBC 3585138 : if (relOpts[i]->kinds & kind)
1516 GIC 867741 : numoptions++;
1517 ECB :
1518 GIC 85256 : if (numoptions > 0)
1519 ECB : {
1520 GIC 85256 : reloptions = palloc(numoptions * sizeof(relopt_value));
1521 ECB :
1522 GIC 3670394 : for (i = 0, j = 0; relOpts[i]; i++)
1523 ECB : {
1524 CBC 3585138 : if (relOpts[i]->kinds & kind)
1525 ECB : {
1526 GIC 867741 : reloptions[j].gen = relOpts[i];
1527 867741 : reloptions[j].isset = false;
1528 867741 : j++;
1529 : }
1530 : }
1531 ECB : }
1532 :
1533 : /* Done if no options */
1534 CBC 85256 : if (PointerIsValid(DatumGetPointer(options)))
1535 9594 : parseRelOptionsInternal(options, validate, reloptions, numoptions);
1536 :
1537 GIC 85138 : *numrelopts = numoptions;
1538 85138 : return reloptions;
1539 : }
1540 ECB :
1541 : /* Parse local unregistered options. */
1542 : static relopt_value *
1543 CBC 833 : parseLocalRelOptions(local_relopts *relopts, Datum options, bool validate)
1544 : {
1545 833 : int nopts = list_length(relopts->options);
1546 GIC 833 : relopt_value *values = palloc(sizeof(*values) * nopts);
1547 ECB : ListCell *lc;
1548 GIC 833 : int i = 0;
1549 ECB :
1550 GIC 1914 : foreach(lc, relopts->options)
1551 ECB : {
1552 CBC 1081 : local_relopt *opt = lfirst(lc);
1553 :
1554 1081 : values[i].gen = opt->option;
1555 GIC 1081 : values[i].isset = false;
1556 :
1557 CBC 1081 : i++;
1558 ECB : }
1559 :
1560 CBC 833 : if (options != (Datum) 0)
1561 GIC 210 : parseRelOptionsInternal(options, validate, values, nopts);
1562 :
1563 791 : return values;
1564 : }
1565 :
1566 : /*
1567 : * Subroutine for parseRelOptions, to parse and validate a single option's
1568 ECB : * value
1569 : */
1570 : static void
1571 GIC 10677 : parse_one_reloption(relopt_value *option, char *text_str, int text_len,
1572 : bool validate)
1573 : {
1574 ECB : char *value;
1575 : int value_len;
1576 : bool parsed;
1577 CBC 10677 : bool nofree = false;
1578 :
1579 GIC 10677 : if (option->isset && validate)
1580 6 : ereport(ERROR,
1581 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1582 ECB : errmsg("parameter \"%s\" specified more than once",
1583 : option->gen->name)));
1584 :
1585 CBC 10671 : value_len = text_len - option->gen->namelen - 1;
1586 GIC 10671 : value = (char *) palloc(value_len + 1);
1587 CBC 10671 : memcpy(value, text_str + option->gen->namelen + 1, value_len);
1588 GIC 10671 : value[value_len] = '\0';
1589 ECB :
1590 GIC 10671 : switch (option->gen->type)
1591 ECB : {
1592 CBC 6435 : case RELOPT_TYPE_BOOL:
1593 ECB : {
1594 GIC 6435 : parsed = parse_bool(value, &option->values.bool_val);
1595 6435 : if (validate && !parsed)
1596 18 : ereport(ERROR,
1597 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1598 ECB : errmsg("invalid value for boolean option \"%s\": %s",
1599 : option->gen->name, value)));
1600 : }
1601 CBC 6417 : break;
1602 GIC 3404 : case RELOPT_TYPE_INT:
1603 ECB : {
1604 CBC 3404 : relopt_int *optint = (relopt_int *) option->gen;
1605 ECB :
1606 GIC 3404 : parsed = parse_int(value, &option->values.int_val, 0, NULL);
1607 3404 : if (validate && !parsed)
1608 11 : ereport(ERROR,
1609 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1610 : errmsg("invalid value for integer option \"%s\": %s",
1611 : option->gen->name, value)));
1612 GIC 3393 : if (validate && (option->values.int_val < optint->min ||
1613 354 : option->values.int_val > optint->max))
1614 59 : ereport(ERROR,
1615 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1616 : errmsg("value %s out of bounds for option \"%s\"",
1617 : value, option->gen->name),
1618 ECB : errdetail("Valid values are between \"%d\" and \"%d\".",
1619 : optint->min, optint->max)));
1620 : }
1621 CBC 3334 : break;
1622 GIC 222 : case RELOPT_TYPE_REAL:
1623 ECB : {
1624 CBC 222 : relopt_real *optreal = (relopt_real *) option->gen;
1625 ECB :
1626 GIC 222 : parsed = parse_real(value, &option->values.real_val, 0, NULL);
1627 222 : if (validate && !parsed)
1628 8 : ereport(ERROR,
1629 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1630 : errmsg("invalid value for floating point option \"%s\": %s",
1631 : option->gen->name, value)));
1632 GIC 214 : if (validate && (option->values.real_val < optreal->min ||
1633 80 : option->values.real_val > optreal->max))
1634 15 : ereport(ERROR,
1635 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1636 : errmsg("value %s out of bounds for option \"%s\"",
1637 : value, option->gen->name),
1638 ECB : errdetail("Valid values are between \"%f\" and \"%f\".",
1639 : optreal->min, optreal->max)));
1640 : }
1641 CBC 199 : break;
1642 GIC 528 : case RELOPT_TYPE_ENUM:
1643 : {
1644 CBC 528 : relopt_enum *optenum = (relopt_enum *) option->gen;
1645 ECB : relopt_enum_elt_def *elt;
1646 :
1647 CBC 528 : parsed = false;
1648 GIC 1116 : for (elt = optenum->members; elt->string_val; elt++)
1649 ECB : {
1650 CBC 1106 : if (pg_strcasecmp(value, elt->string_val) == 0)
1651 ECB : {
1652 GIC 518 : option->values.enum_val = elt->symbol_val;
1653 518 : parsed = true;
1654 CBC 518 : break;
1655 ECB : }
1656 : }
1657 GIC 528 : if (validate && !parsed)
1658 10 : ereport(ERROR,
1659 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1660 : errmsg("invalid value for enum option \"%s\": %s",
1661 : option->gen->name, value),
1662 : optenum->detailmsg ?
1663 : errdetail_internal("%s", _(optenum->detailmsg)) : 0));
1664 :
1665 : /*
1666 ECB : * If value is not among the allowed string values, but we are
1667 EUB : * not asked to validate, just use the default numeric value.
1668 : */
1669 CBC 518 : if (!parsed)
1670 LBC 0 : option->values.enum_val = optenum->default_val;
1671 : }
1672 CBC 518 : break;
1673 GIC 82 : case RELOPT_TYPE_STRING:
1674 ECB : {
1675 CBC 82 : relopt_string *optstring = (relopt_string *) option->gen;
1676 ECB :
1677 CBC 82 : option->values.string_val = value;
1678 82 : nofree = true;
1679 GIC 82 : if (validate && optstring->validate_cb)
1680 CBC 28 : (optstring->validate_cb) (value);
1681 GBC 82 : parsed = true;
1682 EUB : }
1683 GIC 82 : break;
1684 UIC 0 : default:
1685 0 : elog(ERROR, "unsupported reloption type %d", option->gen->type);
1686 : parsed = true; /* quiet compiler */
1687 ECB : break;
1688 : }
1689 :
1690 CBC 10550 : if (parsed)
1691 10550 : option->isset = true;
1692 GIC 10550 : if (!nofree)
1693 10468 : pfree(value);
1694 10550 : }
1695 :
1696 : /*
1697 : * Given the result from parseRelOptions, allocate a struct that's of the
1698 : * specified base size plus any extra space that's needed for string variables.
1699 : *
1700 : * "base" should be sizeof(struct) of the reloptions struct (StdRdOptions or
1701 ECB : * equivalent).
1702 : */
1703 : static void *
1704 GIC 85929 : allocateReloptStruct(Size base, relopt_value *options, int numoptions)
1705 : {
1706 CBC 85929 : Size size = base;
1707 : int i;
1708 ECB :
1709 GIC 953329 : for (i = 0; i < numoptions; i++)
1710 ECB : {
1711 GIC 867400 : relopt_value *optval = &options[i];
1712 ECB :
1713 GIC 867400 : if (optval->gen->type == RELOPT_TYPE_STRING)
1714 ECB : {
1715 GIC 116 : relopt_string *optstr = (relopt_string *) optval->gen;
1716 EUB :
1717 GBC 116 : if (optstr->fill_cb)
1718 : {
1719 UBC 0 : const char *val = optval->isset ? optval->values.string_val :
1720 UIC 0 : optstr->default_isnull ? NULL : optstr->default_val;
1721 :
1722 LBC 0 : size += optstr->fill_cb(val, NULL);
1723 : }
1724 : else
1725 GIC 116 : size += GET_STRING_RELOPTION_LEN(*optval) + 1;
1726 ECB : }
1727 : }
1728 :
1729 GIC 85929 : return palloc0(size);
1730 : }
1731 :
1732 : /*
1733 : * Given the result of parseRelOptions and a parsing table, fill in the
1734 : * struct (previously allocated with allocateReloptStruct) with the parsed
1735 : * values.
1736 : *
1737 : * rdopts is the pointer to the allocated struct to be filled.
1738 : * basesize is the sizeof(struct) that was passed to allocateReloptStruct.
1739 : * options, of length numoptions, is parseRelOptions' output.
1740 : * elems, of length numelems, is the table describing the allowed options.
1741 ECB : * When validate is true, it is expected that all options appear in elems.
1742 : */
1743 : static void
1744 GIC 85929 : fillRelOptions(void *rdopts, Size basesize,
1745 : relopt_value *options, int numoptions,
1746 : bool validate,
1747 ECB : const relopt_parse_elt *elems, int numelems)
1748 : {
1749 : int i;
1750 GIC 85929 : int offset = basesize;
1751 :
1752 CBC 953329 : for (i = 0; i < numoptions; i++)
1753 : {
1754 ECB : int j;
1755 GIC 867400 : bool found = false;
1756 ECB :
1757 GIC 8496924 : for (j = 0; j < numelems; j++)
1758 : {
1759 CBC 8496924 : if (strcmp(options[i].gen->name, elems[j].optname) == 0)
1760 : {
1761 : relopt_string *optstring;
1762 867400 : char *itempos = ((char *) rdopts) + elems[j].offset;
1763 : char *string_val;
1764 ECB :
1765 CBC 867400 : switch (options[i].gen->type)
1766 ECB : {
1767 CBC 188989 : case RELOPT_TYPE_BOOL:
1768 377978 : *(bool *) itempos = options[i].isset ?
1769 188989 : options[i].values.bool_val :
1770 182573 : ((relopt_bool *) options[i].gen)->default_val;
1771 188989 : break;
1772 460666 : case RELOPT_TYPE_INT:
1773 921332 : *(int *) itempos = options[i].isset ?
1774 460666 : options[i].values.int_val :
1775 457345 : ((relopt_int *) options[i].gen)->default_val;
1776 460666 : break;
1777 133384 : case RELOPT_TYPE_REAL:
1778 266768 : *(double *) itempos = options[i].isset ?
1779 133384 : options[i].values.real_val :
1780 133192 : ((relopt_real *) options[i].gen)->default_val;
1781 133384 : break;
1782 84245 : case RELOPT_TYPE_ENUM:
1783 168490 : *(int *) itempos = options[i].isset ?
1784 84245 : options[i].values.enum_val :
1785 83727 : ((relopt_enum *) options[i].gen)->default_val;
1786 84245 : break;
1787 116 : case RELOPT_TYPE_STRING:
1788 116 : optstring = (relopt_string *) options[i].gen;
1789 116 : if (options[i].isset)
1790 GIC 80 : string_val = options[i].values.string_val;
1791 CBC 36 : else if (!optstring->default_isnull)
1792 GIC 15 : string_val = optstring->default_val;
1793 ECB : else
1794 GIC 21 : string_val = NULL;
1795 :
1796 GBC 116 : if (optstring->fill_cb)
1797 : {
1798 : Size size =
1799 UBC 0 : optstring->fill_cb(string_val,
1800 : (char *) rdopts + offset);
1801 EUB :
1802 UBC 0 : if (size)
1803 : {
1804 UIC 0 : *(int *) itempos = offset;
1805 UBC 0 : offset += size;
1806 : }
1807 ECB : else
1808 LBC 0 : *(int *) itempos = 0;
1809 : }
1810 GIC 116 : else if (string_val == NULL)
1811 CBC 21 : *(int *) itempos = 0;
1812 ECB : else
1813 : {
1814 GIC 95 : strcpy((char *) rdopts + offset, string_val);
1815 CBC 95 : *(int *) itempos = offset;
1816 GBC 95 : offset += strlen(string_val) + 1;
1817 EUB : }
1818 GIC 116 : break;
1819 UIC 0 : default:
1820 0 : elog(ERROR, "unsupported reloption type %d",
1821 ECB : options[i].gen->type);
1822 : break;
1823 : }
1824 GIC 867400 : found = true;
1825 CBC 867400 : break;
1826 EUB : }
1827 : }
1828 GIC 867400 : if (validate && !found)
1829 LBC 0 : elog(ERROR, "reloption \"%s\" not found in parse table",
1830 ECB : options[i].gen->name);
1831 : }
1832 GIC 85929 : SET_VARSIZE(rdopts, offset);
1833 85929 : }
1834 :
1835 :
1836 : /*
1837 ECB : * Option parser for anything that uses StdRdOptions.
1838 : */
1839 : bytea *
1840 GIC 37565 : default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
1841 : {
1842 : static const relopt_parse_elt tab[] = {
1843 : {"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
1844 : {"autovacuum_enabled", RELOPT_TYPE_BOOL,
1845 : offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, enabled)},
1846 : {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,
1847 : offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)},
1848 : {"autovacuum_vacuum_insert_threshold", RELOPT_TYPE_INT,
1849 : offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_threshold)},
1850 : {"autovacuum_analyze_threshold", RELOPT_TYPE_INT,
1851 : offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)},
1852 : {"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,
1853 : offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)},
1854 : {"autovacuum_freeze_min_age", RELOPT_TYPE_INT,
1855 : offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_min_age)},
1856 : {"autovacuum_freeze_max_age", RELOPT_TYPE_INT,
1857 : offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_max_age)},
1858 : {"autovacuum_freeze_table_age", RELOPT_TYPE_INT,
1859 : offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_table_age)},
1860 : {"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT,
1861 : offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_min_age)},
1862 : {"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT,
1863 : offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_max_age)},
1864 : {"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT,
1865 : offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_table_age)},
1866 : {"log_autovacuum_min_duration", RELOPT_TYPE_INT,
1867 : offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, log_min_duration)},
1868 : {"toast_tuple_target", RELOPT_TYPE_INT,
1869 : offsetof(StdRdOptions, toast_tuple_target)},
1870 : {"autovacuum_vacuum_cost_delay", RELOPT_TYPE_REAL,
1871 : offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)},
1872 : {"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
1873 : offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_scale_factor)},
1874 : {"autovacuum_vacuum_insert_scale_factor", RELOPT_TYPE_REAL,
1875 : offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_scale_factor)},
1876 : {"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
1877 : offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_scale_factor)},
1878 : {"user_catalog_table", RELOPT_TYPE_BOOL,
1879 : offsetof(StdRdOptions, user_catalog_table)},
1880 : {"parallel_workers", RELOPT_TYPE_INT,
1881 : offsetof(StdRdOptions, parallel_workers)},
1882 : {"vacuum_index_cleanup", RELOPT_TYPE_ENUM,
1883 : offsetof(StdRdOptions, vacuum_index_cleanup)},
1884 : {"vacuum_truncate", RELOPT_TYPE_BOOL,
1885 ECB : offsetof(StdRdOptions, vacuum_truncate)}
1886 : };
1887 :
1888 GIC 37565 : return (bytea *) build_reloptions(reloptions, validate, kind,
1889 : sizeof(StdRdOptions),
1890 : tab, lengthof(tab));
1891 : }
1892 :
1893 : /*
1894 : * build_reloptions
1895 : *
1896 : * Parses "reloptions" provided by the caller, returning them in a
1897 : * structure containing the parsed options. The parsing is done with
1898 : * the help of a parsing table describing the allowed options, defined
1899 : * by "relopt_elems" of length "num_relopt_elems".
1900 : *
1901 : * "validate" must be true if reloptions value is freshly built by
1902 : * transformRelOptions(), as opposed to being read from the catalog, in which
1903 : * case the values contained in it must already be valid.
1904 : *
1905 : * NULL is returned if the passed-in options did not match any of the options
1906 : * in the parsing table, unless validate is true in which case an error would
1907 ECB : * be reported.
1908 : */
1909 : void *
1910 GIC 85256 : build_reloptions(Datum reloptions, bool validate,
1911 : relopt_kind kind,
1912 : Size relopt_struct_size,
1913 : const relopt_parse_elt *relopt_elems,
1914 : int num_relopt_elems)
1915 : {
1916 : int numoptions;
1917 : relopt_value *options;
1918 ECB : void *rdopts;
1919 :
1920 : /* parse options specific to given relation option kind */
1921 GIC 85256 : options = parseRelOptions(reloptions, validate, kind, &numoptions);
1922 CBC 85138 : Assert(numoptions <= num_relopt_elems);
1923 :
1924 EUB : /* if none set, we're done */
1925 GBC 85138 : if (numoptions == 0)
1926 : {
1927 UIC 0 : Assert(options == NULL);
1928 0 : return NULL;
1929 ECB : }
1930 :
1931 : /* allocate and fill the structure */
1932 GIC 85138 : rdopts = allocateReloptStruct(relopt_struct_size, options, numoptions);
1933 CBC 85138 : fillRelOptions(rdopts, relopt_struct_size, options, numoptions,
1934 : validate, relopt_elems, num_relopt_elems);
1935 ECB :
1936 GIC 85138 : pfree(options);
1937 :
1938 85138 : return rdopts;
1939 : }
1940 :
1941 : /*
1942 : * Parse local options, allocate a bytea struct that's of the specified
1943 : * 'base_size' plus any extra space that's needed for string variables,
1944 ECB : * fill its option's fields located at the given offsets and return it.
1945 : */
1946 : void *
1947 CBC 833 : build_local_reloptions(local_relopts *relopts, Datum options, bool validate)
1948 : {
1949 GIC 833 : int noptions = list_length(relopts->options);
1950 CBC 833 : relopt_parse_elt *elems = palloc(sizeof(*elems) * noptions);
1951 : relopt_value *vals;
1952 : void *opts;
1953 833 : int i = 0;
1954 : ListCell *lc;
1955 ECB :
1956 GIC 1914 : foreach(lc, relopts->options)
1957 ECB : {
1958 CBC 1081 : local_relopt *opt = lfirst(lc);
1959 ECB :
1960 GIC 1081 : elems[i].optname = opt->option->name;
1961 CBC 1081 : elems[i].opttype = opt->option->type;
1962 GIC 1081 : elems[i].offset = opt->offset;
1963 :
1964 CBC 1081 : i++;
1965 ECB : }
1966 :
1967 GIC 833 : vals = parseLocalRelOptions(relopts, options, validate);
1968 791 : opts = allocateReloptStruct(relopts->relopt_struct_size, vals, noptions);
1969 CBC 791 : fillRelOptions(opts, relopts->relopt_struct_size, vals, noptions, validate,
1970 EUB : elems, noptions);
1971 :
1972 CBC 791 : foreach(lc, relopts->validators)
1973 LBC 0 : ((relopts_validator) lfirst(lc)) (opts, vals, noptions);
1974 :
1975 CBC 791 : if (elems)
1976 GIC 791 : pfree(elems);
1977 :
1978 791 : return opts;
1979 : }
1980 :
1981 : /*
1982 ECB : * Option parser for partitioned tables
1983 : */
1984 : bytea *
1985 CBC 2172 : partitioned_table_reloptions(Datum reloptions, bool validate)
1986 : {
1987 GNC 2172 : if (validate && reloptions)
1988 6 : ereport(ERROR,
1989 : errcode(ERRCODE_WRONG_OBJECT_TYPE),
1990 : errmsg("cannot specify storage parameters for a partitioned table"),
1991 : errhint("Specify storage parameters for its leaf partitions, instead."));
1992 2166 : return NULL;
1993 : }
1994 :
1995 ECB : /*
1996 : * Option parser for views
1997 : */
1998 : bytea *
1999 GIC 46623 : view_reloptions(Datum reloptions, bool validate)
2000 : {
2001 : static const relopt_parse_elt tab[] = {
2002 : {"security_barrier", RELOPT_TYPE_BOOL,
2003 : offsetof(ViewOptions, security_barrier)},
2004 : {"security_invoker", RELOPT_TYPE_BOOL,
2005 : offsetof(ViewOptions, security_invoker)},
2006 ECB : {"check_option", RELOPT_TYPE_ENUM,
2007 : offsetof(ViewOptions, check_option)}
2008 : };
2009 :
2010 GIC 46623 : return (bytea *) build_reloptions(reloptions, validate,
2011 : RELOPT_KIND_VIEW,
2012 : sizeof(ViewOptions),
2013 : tab, lengthof(tab));
2014 : }
2015 :
2016 ECB : /*
2017 : * Parse options for heaps, views and toast tables.
2018 : */
2019 : bytea *
2020 CBC 38833 : heap_reloptions(char relkind, Datum reloptions, bool validate)
2021 : {
2022 ECB : StdRdOptions *rdopts;
2023 :
2024 CBC 38833 : switch (relkind)
2025 ECB : {
2026 GIC 17447 : case RELKIND_TOASTVALUE:
2027 : rdopts = (StdRdOptions *)
2028 CBC 17447 : default_reloptions(reloptions, validate, RELOPT_KIND_TOAST);
2029 17444 : if (rdopts != NULL)
2030 ECB : {
2031 : /* adjust default-only parameters for TOAST relations */
2032 CBC 17444 : rdopts->fillfactor = 100;
2033 17444 : rdopts->autovacuum.analyze_threshold = -1;
2034 GIC 17444 : rdopts->autovacuum.analyze_scale_factor = -1;
2035 ECB : }
2036 CBC 17444 : return (bytea *) rdopts;
2037 GIC 20118 : case RELKIND_RELATION:
2038 ECB : case RELKIND_MATVIEW:
2039 GIC 20118 : return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
2040 1268 : default:
2041 : /* other relkinds are not supported */
2042 1268 : return NULL;
2043 : }
2044 : }
2045 :
2046 :
2047 : /*
2048 : * Parse options for indexes.
2049 : *
2050 : * amoptions index AM's option parser function
2051 ECB : * reloptions options as text[] datum
2052 : * validate error flag
2053 : */
2054 : bytea *
2055 GIC 46188 : index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate)
2056 ECB : {
2057 CBC 46188 : Assert(amoptions != NULL);
2058 :
2059 ECB : /* Assume function is strict */
2060 GIC 46188 : if (!PointerIsValid(DatumGetPointer(reloptions)))
2061 45191 : return NULL;
2062 :
2063 997 : return amoptions(reloptions, validate);
2064 : }
2065 :
2066 ECB : /*
2067 : * Option parser for attribute reloptions
2068 : */
2069 : bytea *
2070 GIC 19 : attribute_reloptions(Datum reloptions, bool validate)
2071 : {
2072 : static const relopt_parse_elt tab[] = {
2073 ECB : {"n_distinct", RELOPT_TYPE_REAL, offsetof(AttributeOpts, n_distinct)},
2074 : {"n_distinct_inherited", RELOPT_TYPE_REAL, offsetof(AttributeOpts, n_distinct_inherited)}
2075 : };
2076 :
2077 GIC 19 : return (bytea *) build_reloptions(reloptions, validate,
2078 : RELOPT_KIND_ATTRIBUTE,
2079 : sizeof(AttributeOpts),
2080 : tab, lengthof(tab));
2081 : }
2082 :
2083 ECB : /*
2084 : * Option parser for tablespace reloptions
2085 : */
2086 : bytea *
2087 GIC 52 : tablespace_reloptions(Datum reloptions, bool validate)
2088 : {
2089 : static const relopt_parse_elt tab[] = {
2090 : {"random_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, random_page_cost)},
2091 : {"seq_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, seq_page_cost)},
2092 ECB : {"effective_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, effective_io_concurrency)},
2093 : {"maintenance_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, maintenance_io_concurrency)}
2094 : };
2095 :
2096 GIC 52 : return (bytea *) build_reloptions(reloptions, validate,
2097 : RELOPT_KIND_TABLESPACE,
2098 : sizeof(TableSpaceOpts),
2099 : tab, lengthof(tab));
2100 : }
2101 :
2102 : /*
2103 : * Determine the required LOCKMODE from an option list.
2104 : *
2105 ECB : * Called from AlterTableGetLockLevel(), see that function
2106 : * for a longer explanation of how this works.
2107 : */
2108 : LOCKMODE
2109 GIC 367 : AlterTableGetRelOptionsLockLevel(List *defList)
2110 ECB : {
2111 GBC 367 : LOCKMODE lockmode = NoLock;
2112 : ListCell *cell;
2113 ECB :
2114 CBC 367 : if (defList == NIL)
2115 UIC 0 : return AccessExclusiveLock;
2116 ECB :
2117 GIC 367 : if (need_initialization)
2118 CBC 4 : initialize_reloptions();
2119 :
2120 GIC 752 : foreach(cell, defList)
2121 ECB : {
2122 GIC 385 : DefElem *def = (DefElem *) lfirst(cell);
2123 ECB : int i;
2124 :
2125 CBC 16798 : for (i = 0; relOpts[i]; i++)
2126 : {
2127 16413 : if (strncmp(relOpts[i]->name,
2128 16413 : def->defname,
2129 GIC 16413 : relOpts[i]->namelen + 1) == 0)
2130 : {
2131 549 : if (lockmode < relOpts[i]->lockmode)
2132 367 : lockmode = relOpts[i]->lockmode;
2133 ECB : }
2134 : }
2135 : }
2136 :
2137 GIC 367 : return lockmode;
2138 : }
|