LCOV - code coverage report
Current view: top level - src/backend/access/common - reloptions.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 487 544 89.5 %
Date: 2020-06-01 00:06:26 Functions: 36 41 87.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * reloptions.c
       4             :  *    Core support for relation options (pg_class.reloptions)
       5             :  *
       6             :  * Portions Copyright (c) 1996-2020, 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             :             "vacuum_index_cleanup",
     146             :             "Enables index vacuuming and index cleanup",
     147             :             RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
     148             :             ShareUpdateExclusiveLock
     149             :         },
     150             :         true
     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             :             "Number of tuple inserts prior to index cleanup as a fraction of reltuples.",
     468             :             RELOPT_KIND_BTREE,
     469             :             ShareUpdateExclusiveLock
     470             :         },
     471             :         -1, 0.0, 1e10
     472             :     },
     473             :     /* list terminator */
     474             :     {{NULL}}
     475             : };
     476             : 
     477             : /* values from GistOptBufferingMode */
     478             : relopt_enum_elt_def gistBufferingOptValues[] =
     479             : {
     480             :     {"auto", GIST_OPTION_BUFFERING_AUTO},
     481             :     {"on", GIST_OPTION_BUFFERING_ON},
     482             :     {"off", GIST_OPTION_BUFFERING_OFF},
     483             :     {(const char *) NULL}       /* list terminator */
     484             : };
     485             : 
     486             : /* values from ViewOptCheckOption */
     487             : relopt_enum_elt_def viewCheckOptValues[] =
     488             : {
     489             :     /* no value for NOT_SET */
     490             :     {"local", VIEW_OPTION_CHECK_OPTION_LOCAL},
     491             :     {"cascaded", VIEW_OPTION_CHECK_OPTION_CASCADED},
     492             :     {(const char *) NULL}       /* list terminator */
     493             : };
     494             : 
     495             : static relopt_enum enumRelOpts[] =
     496             : {
     497             :     {
     498             :         {
     499             :             "buffering",
     500             :             "Enables buffering build for this GiST index",
     501             :             RELOPT_KIND_GIST,
     502             :             AccessExclusiveLock
     503             :         },
     504             :         gistBufferingOptValues,
     505             :         GIST_OPTION_BUFFERING_AUTO,
     506             :         gettext_noop("Valid values are \"on\", \"off\", and \"auto\".")
     507             :     },
     508             :     {
     509             :         {
     510             :             "check_option",
     511             :             "View has WITH CHECK OPTION defined (local or cascaded).",
     512             :             RELOPT_KIND_VIEW,
     513             :             AccessExclusiveLock
     514             :         },
     515             :         viewCheckOptValues,
     516             :         VIEW_OPTION_CHECK_OPTION_NOT_SET,
     517             :         gettext_noop("Valid values are \"local\" and \"cascaded\".")
     518             :     },
     519             :     /* list terminator */
     520             :     {{NULL}}
     521             : };
     522             : 
     523             : static relopt_string stringRelOpts[] =
     524             : {
     525             :     /* list terminator */
     526             :     {{NULL}}
     527             : };
     528             : 
     529             : static relopt_gen **relOpts = NULL;
     530             : static bits32 last_assigned_kind = RELOPT_KIND_LAST_DEFAULT;
     531             : 
     532             : static int  num_custom_options = 0;
     533             : static relopt_gen **custom_options = NULL;
     534             : static bool need_initialization = true;
     535             : 
     536             : static void initialize_reloptions(void);
     537             : static void parse_one_reloption(relopt_value *option, char *text_str,
     538             :                                 int text_len, bool validate);
     539             : 
     540             : /*
     541             :  * Get the length of a string reloption (either default or the user-defined
     542             :  * value).  This is used for allocation purposes when building a set of
     543             :  * relation options.
     544             :  */
     545             : #define GET_STRING_RELOPTION_LEN(option) \
     546             :     ((option).isset ? strlen((option).values.string_val) : \
     547             :      ((relopt_string *) (option).gen)->default_len)
     548             : 
     549             : /*
     550             :  * initialize_reloptions
     551             :  *      initialization routine, must be called before parsing
     552             :  *
     553             :  * Initialize the relOpts array and fill each variable's type and name length.
     554             :  */
     555             : static void
     556        3782 : initialize_reloptions(void)
     557             : {
     558             :     int         i;
     559             :     int         j;
     560             : 
     561        3782 :     j = 0;
     562       34038 :     for (i = 0; boolRelOpts[i].gen.name; i++)
     563             :     {
     564             :         Assert(DoLockModesConflict(boolRelOpts[i].gen.lockmode,
     565             :                                    boolRelOpts[i].gen.lockmode));
     566       30256 :         j++;
     567             :     }
     568       86986 :     for (i = 0; intRelOpts[i].gen.name; i++)
     569             :     {
     570             :         Assert(DoLockModesConflict(intRelOpts[i].gen.lockmode,
     571             :                                    intRelOpts[i].gen.lockmode));
     572       83204 :         j++;
     573             :     }
     574       37820 :     for (i = 0; realRelOpts[i].gen.name; i++)
     575             :     {
     576             :         Assert(DoLockModesConflict(realRelOpts[i].gen.lockmode,
     577             :                                    realRelOpts[i].gen.lockmode));
     578       34038 :         j++;
     579             :     }
     580       11346 :     for (i = 0; enumRelOpts[i].gen.name; i++)
     581             :     {
     582             :         Assert(DoLockModesConflict(enumRelOpts[i].gen.lockmode,
     583             :                                    enumRelOpts[i].gen.lockmode));
     584        7564 :         j++;
     585             :     }
     586        3782 :     for (i = 0; stringRelOpts[i].gen.name; i++)
     587             :     {
     588             :         Assert(DoLockModesConflict(stringRelOpts[i].gen.lockmode,
     589             :                                    stringRelOpts[i].gen.lockmode));
     590           0 :         j++;
     591             :     }
     592        3782 :     j += num_custom_options;
     593             : 
     594        3782 :     if (relOpts)
     595           0 :         pfree(relOpts);
     596        7564 :     relOpts = MemoryContextAlloc(TopMemoryContext,
     597        3782 :                                  (j + 1) * sizeof(relopt_gen *));
     598             : 
     599        3782 :     j = 0;
     600       34038 :     for (i = 0; boolRelOpts[i].gen.name; i++)
     601             :     {
     602       30256 :         relOpts[j] = &boolRelOpts[i].gen;
     603       30256 :         relOpts[j]->type = RELOPT_TYPE_BOOL;
     604       30256 :         relOpts[j]->namelen = strlen(relOpts[j]->name);
     605       30256 :         j++;
     606             :     }
     607             : 
     608       86986 :     for (i = 0; intRelOpts[i].gen.name; i++)
     609             :     {
     610       83204 :         relOpts[j] = &intRelOpts[i].gen;
     611       83204 :         relOpts[j]->type = RELOPT_TYPE_INT;
     612       83204 :         relOpts[j]->namelen = strlen(relOpts[j]->name);
     613       83204 :         j++;
     614             :     }
     615             : 
     616       37820 :     for (i = 0; realRelOpts[i].gen.name; i++)
     617             :     {
     618       34038 :         relOpts[j] = &realRelOpts[i].gen;
     619       34038 :         relOpts[j]->type = RELOPT_TYPE_REAL;
     620       34038 :         relOpts[j]->namelen = strlen(relOpts[j]->name);
     621       34038 :         j++;
     622             :     }
     623             : 
     624       11346 :     for (i = 0; enumRelOpts[i].gen.name; i++)
     625             :     {
     626        7564 :         relOpts[j] = &enumRelOpts[i].gen;
     627        7564 :         relOpts[j]->type = RELOPT_TYPE_ENUM;
     628        7564 :         relOpts[j]->namelen = strlen(relOpts[j]->name);
     629        7564 :         j++;
     630             :     }
     631             : 
     632        3782 :     for (i = 0; stringRelOpts[i].gen.name; i++)
     633             :     {
     634           0 :         relOpts[j] = &stringRelOpts[i].gen;
     635           0 :         relOpts[j]->type = RELOPT_TYPE_STRING;
     636           0 :         relOpts[j]->namelen = strlen(relOpts[j]->name);
     637           0 :         j++;
     638             :     }
     639             : 
     640        3860 :     for (i = 0; i < num_custom_options; i++)
     641             :     {
     642          78 :         relOpts[j] = custom_options[i];
     643          78 :         j++;
     644             :     }
     645             : 
     646             :     /* add a list terminator */
     647        3782 :     relOpts[j] = NULL;
     648             : 
     649             :     /* flag the work is complete */
     650        3782 :     need_initialization = false;
     651        3782 : }
     652             : 
     653             : /*
     654             :  * add_reloption_kind
     655             :  *      Create a new relopt_kind value, to be used in custom reloptions by
     656             :  *      user-defined AMs.
     657             :  */
     658             : relopt_kind
     659           4 : add_reloption_kind(void)
     660             : {
     661             :     /* don't hand out the last bit so that the enum's behavior is portable */
     662           4 :     if (last_assigned_kind >= RELOPT_KIND_MAX)
     663           0 :         ereport(ERROR,
     664             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     665             :                  errmsg("user-defined relation parameter types limit exceeded")));
     666           4 :     last_assigned_kind <<= 1;
     667           4 :     return (relopt_kind) last_assigned_kind;
     668             : }
     669             : 
     670             : /*
     671             :  * add_reloption
     672             :  *      Add an already-created custom reloption to the list, and recompute the
     673             :  *      main parser table.
     674             :  */
     675             : static void
     676          78 : add_reloption(relopt_gen *newoption)
     677             : {
     678             :     static int  max_custom_options = 0;
     679             : 
     680          78 :     if (num_custom_options >= max_custom_options)
     681             :     {
     682             :         MemoryContext oldcxt;
     683             : 
     684          10 :         oldcxt = MemoryContextSwitchTo(TopMemoryContext);
     685             : 
     686          10 :         if (max_custom_options == 0)
     687             :         {
     688           4 :             max_custom_options = 8;
     689           4 :             custom_options = palloc(max_custom_options * sizeof(relopt_gen *));
     690             :         }
     691             :         else
     692             :         {
     693           6 :             max_custom_options *= 2;
     694           6 :             custom_options = repalloc(custom_options,
     695             :                                       max_custom_options * sizeof(relopt_gen *));
     696             :         }
     697          10 :         MemoryContextSwitchTo(oldcxt);
     698             :     }
     699          78 :     custom_options[num_custom_options++] = newoption;
     700             : 
     701          78 :     need_initialization = true;
     702          78 : }
     703             : 
     704             : /*
     705             :  * init_local_reloptions
     706             :  *      Initialize local reloptions that will parsed into bytea structure of
     707             :  *      'relopt_struct_size'.
     708             :  */
     709             : void
     710         392 : init_local_reloptions(local_relopts *opts, Size relopt_struct_size)
     711             : {
     712         392 :     opts->options = NIL;
     713         392 :     opts->validators = NIL;
     714         392 :     opts->relopt_struct_size = relopt_struct_size;
     715         392 : }
     716             : 
     717             : /*
     718             :  * register_reloptions_validator
     719             :  *      Register custom validation callback that will be called at the end of
     720             :  *      build_local_reloptions().
     721             :  */
     722             : void
     723           0 : register_reloptions_validator(local_relopts *opts, relopts_validator validator)
     724             : {
     725           0 :     opts->validators = lappend(opts->validators, validator);
     726           0 : }
     727             : 
     728             : /*
     729             :  * add_local_reloption
     730             :  *      Add an already-created custom reloption to the local list.
     731             :  */
     732             : static void
     733         196 : add_local_reloption(local_relopts *relopts, relopt_gen *newoption, int offset)
     734             : {
     735         196 :     local_relopt *opt = palloc(sizeof(*opt));
     736             : 
     737             :     Assert(offset < relopts->relopt_struct_size);
     738             : 
     739         196 :     opt->option = newoption;
     740         196 :     opt->offset = offset;
     741             : 
     742         196 :     relopts->options = lappend(relopts->options, opt);
     743         196 : }
     744             : 
     745             : /*
     746             :  * allocate_reloption
     747             :  *      Allocate a new reloption and initialize the type-agnostic fields
     748             :  *      (for types other than string)
     749             :  */
     750             : static relopt_gen *
     751         274 : allocate_reloption(bits32 kinds, int type, const char *name, const char *desc,
     752             :                    LOCKMODE lockmode)
     753             : {
     754             :     MemoryContext oldcxt;
     755             :     size_t      size;
     756             :     relopt_gen *newoption;
     757             : 
     758         274 :     if (kinds != RELOPT_KIND_LOCAL)
     759          78 :         oldcxt = MemoryContextSwitchTo(TopMemoryContext);
     760             :     else
     761         196 :         oldcxt = NULL;
     762             : 
     763         274 :     switch (type)
     764             :     {
     765           2 :         case RELOPT_TYPE_BOOL:
     766           2 :             size = sizeof(relopt_bool);
     767           2 :             break;
     768         264 :         case RELOPT_TYPE_INT:
     769         264 :             size = sizeof(relopt_int);
     770         264 :             break;
     771           2 :         case RELOPT_TYPE_REAL:
     772           2 :             size = sizeof(relopt_real);
     773           2 :             break;
     774           2 :         case RELOPT_TYPE_ENUM:
     775           2 :             size = sizeof(relopt_enum);
     776           2 :             break;
     777           4 :         case RELOPT_TYPE_STRING:
     778           4 :             size = sizeof(relopt_string);
     779           4 :             break;
     780           0 :         default:
     781           0 :             elog(ERROR, "unsupported reloption type %d", type);
     782             :             return NULL;        /* keep compiler quiet */
     783             :     }
     784             : 
     785         274 :     newoption = palloc(size);
     786             : 
     787         274 :     newoption->name = pstrdup(name);
     788         274 :     if (desc)
     789         272 :         newoption->desc = pstrdup(desc);
     790             :     else
     791           2 :         newoption->desc = NULL;
     792         274 :     newoption->kinds = kinds;
     793         274 :     newoption->namelen = strlen(name);
     794         274 :     newoption->type = type;
     795         274 :     newoption->lockmode = lockmode;
     796             : 
     797         274 :     if (oldcxt != NULL)
     798          78 :         MemoryContextSwitchTo(oldcxt);
     799             : 
     800         274 :     return newoption;
     801             : }
     802             : 
     803             : /*
     804             :  * init_bool_reloption
     805             :  *      Allocate and initialize a new boolean reloption
     806             :  */
     807             : static relopt_bool *
     808           2 : init_bool_reloption(bits32 kinds, const char *name, const char *desc,
     809             :                     bool default_val, LOCKMODE lockmode)
     810             : {
     811             :     relopt_bool *newoption;
     812             : 
     813           2 :     newoption = (relopt_bool *) allocate_reloption(kinds, RELOPT_TYPE_BOOL,
     814             :                                                    name, desc, lockmode);
     815           2 :     newoption->default_val = default_val;
     816             : 
     817           2 :     return newoption;
     818             : }
     819             : 
     820             : /*
     821             :  * add_bool_reloption
     822             :  *      Add a new boolean reloption
     823             :  */
     824             : void
     825           2 : add_bool_reloption(bits32 kinds, const char *name, const char *desc,
     826             :                    bool default_val, LOCKMODE lockmode)
     827             : {
     828           2 :     relopt_bool *newoption = init_bool_reloption(kinds, name, desc,
     829             :                                                  default_val, lockmode);
     830             : 
     831           2 :     add_reloption((relopt_gen *) newoption);
     832           2 : }
     833             : 
     834             : /*
     835             :  * add_local_bool_reloption
     836             :  *      Add a new boolean local reloption
     837             :  *
     838             :  * 'offset' is offset of bool-typed field.
     839             :  */
     840             : void
     841           0 : add_local_bool_reloption(local_relopts *relopts, const char *name,
     842             :                          const char *desc, bool default_val, int offset)
     843             : {
     844           0 :     relopt_bool *newoption = init_bool_reloption(RELOPT_KIND_LOCAL,
     845             :                                                  name, desc,
     846             :                                                  default_val, 0);
     847             : 
     848           0 :     add_local_reloption(relopts, (relopt_gen *) newoption, offset);
     849           0 : }
     850             : 
     851             : 
     852             : /*
     853             :  * init_real_reloption
     854             :  *      Allocate and initialize a new integer reloption
     855             :  */
     856             : static relopt_int *
     857         264 : init_int_reloption(bits32 kinds, const char *name, const char *desc,
     858             :                    int default_val, int min_val, int max_val,
     859             :                    LOCKMODE lockmode)
     860             : {
     861             :     relopt_int *newoption;
     862             : 
     863         264 :     newoption = (relopt_int *) allocate_reloption(kinds, RELOPT_TYPE_INT,
     864             :                                                   name, desc, lockmode);
     865         264 :     newoption->default_val = default_val;
     866         264 :     newoption->min = min_val;
     867         264 :     newoption->max = max_val;
     868             : 
     869         264 :     return newoption;
     870             : }
     871             : 
     872             : /*
     873             :  * add_int_reloption
     874             :  *      Add a new integer reloption
     875             :  */
     876             : void
     877          68 : add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val,
     878             :                   int min_val, int max_val, LOCKMODE lockmode)
     879             : {
     880          68 :     relopt_int *newoption = init_int_reloption(kinds, name, desc,
     881             :                                                default_val, min_val,
     882             :                                                max_val, lockmode);
     883             : 
     884          68 :     add_reloption((relopt_gen *) newoption);
     885          68 : }
     886             : 
     887             : /*
     888             :  * add_local_int_reloption
     889             :  *      Add a new local integer reloption
     890             :  *
     891             :  * 'offset' is offset of int-typed field.
     892             :  */
     893             : void
     894         196 : add_local_int_reloption(local_relopts *relopts, const char *name,
     895             :                         const char *desc, int default_val, int min_val,
     896             :                         int max_val, int offset)
     897             : {
     898         196 :     relopt_int *newoption = init_int_reloption(RELOPT_KIND_LOCAL,
     899             :                                                name, desc, default_val,
     900             :                                                min_val, max_val, 0);
     901             : 
     902         196 :     add_local_reloption(relopts, (relopt_gen *) newoption, offset);
     903         196 : }
     904             : 
     905             : /*
     906             :  * init_real_reloption
     907             :  *      Allocate and initialize a new real reloption
     908             :  */
     909             : static relopt_real *
     910           2 : init_real_reloption(bits32 kinds, const char *name, const char *desc,
     911             :                     double default_val, double min_val, double max_val,
     912             :                     LOCKMODE lockmode)
     913             : {
     914             :     relopt_real *newoption;
     915             : 
     916           2 :     newoption = (relopt_real *) allocate_reloption(kinds, RELOPT_TYPE_REAL,
     917             :                                                    name, desc, lockmode);
     918           2 :     newoption->default_val = default_val;
     919           2 :     newoption->min = min_val;
     920           2 :     newoption->max = max_val;
     921             : 
     922           2 :     return newoption;
     923             : }
     924             : 
     925             : /*
     926             :  * add_real_reloption
     927             :  *      Add a new float reloption
     928             :  */
     929             : void
     930           2 : add_real_reloption(bits32 kinds, const char *name, const char *desc,
     931             :                    double default_val, double min_val, double max_val,
     932             :                    LOCKMODE lockmode)
     933             : {
     934           2 :     relopt_real *newoption = init_real_reloption(kinds, name, desc,
     935             :                                                  default_val, min_val,
     936             :                                                  max_val, lockmode);
     937             : 
     938           2 :     add_reloption((relopt_gen *) newoption);
     939           2 : }
     940             : 
     941             : /*
     942             :  * add_local_real_reloption
     943             :  *      Add a new local float reloption
     944             :  *
     945             :  * 'offset' is offset of double-typed field.
     946             :  */
     947             : void
     948           0 : add_local_real_reloption(local_relopts *relopts, const char *name,
     949             :                          const char *desc, double default_val,
     950             :                          double min_val, double max_val, int offset)
     951             : {
     952           0 :     relopt_real *newoption = init_real_reloption(RELOPT_KIND_LOCAL,
     953             :                                                  name, desc,
     954             :                                                  default_val, min_val,
     955             :                                                  max_val, 0);
     956             : 
     957           0 :     add_local_reloption(relopts, (relopt_gen *) newoption, offset);
     958           0 : }
     959             : 
     960             : /*
     961             :  * init_enum_reloption
     962             :  *      Allocate and initialize a new enum reloption
     963             :  */
     964             : static relopt_enum *
     965           2 : init_enum_reloption(bits32 kinds, const char *name, const char *desc,
     966             :                     relopt_enum_elt_def *members, int default_val,
     967             :                     const char *detailmsg, LOCKMODE lockmode)
     968             : {
     969             :     relopt_enum *newoption;
     970             : 
     971           2 :     newoption = (relopt_enum *) allocate_reloption(kinds, RELOPT_TYPE_ENUM,
     972             :                                                    name, desc, lockmode);
     973           2 :     newoption->members = members;
     974           2 :     newoption->default_val = default_val;
     975           2 :     newoption->detailmsg = detailmsg;
     976             : 
     977           2 :     return newoption;
     978             : }
     979             : 
     980             : 
     981             : /*
     982             :  * add_enum_reloption
     983             :  *      Add a new enum reloption
     984             :  *
     985             :  * The members array must have a terminating NULL entry.
     986             :  *
     987             :  * The detailmsg is shown when unsupported values are passed, and has this
     988             :  * form:   "Valid values are \"foo\", \"bar\", and \"bar\"."
     989             :  *
     990             :  * The members array and detailmsg are not copied -- caller must ensure that
     991             :  * they are valid throughout the life of the process.
     992             :  */
     993             : void
     994           2 : add_enum_reloption(bits32 kinds, const char *name, const char *desc,
     995             :                    relopt_enum_elt_def *members, int default_val,
     996             :                    const char *detailmsg, LOCKMODE lockmode)
     997             : {
     998           2 :     relopt_enum *newoption = init_enum_reloption(kinds, name, desc,
     999             :                                                  members, default_val,
    1000             :                                                  detailmsg, lockmode);
    1001             : 
    1002           2 :     add_reloption((relopt_gen *) newoption);
    1003           2 : }
    1004             : 
    1005             : /*
    1006             :  * add_local_enum_reloption
    1007             :  *      Add a new local enum reloption
    1008             :  *
    1009             :  * 'offset' is offset of int-typed field.
    1010             :  */
    1011             : void
    1012           0 : add_local_enum_reloption(local_relopts *relopts, const char *name,
    1013             :                          const char *desc, relopt_enum_elt_def *members,
    1014             :                          int default_val, const char *detailmsg, int offset)
    1015             : {
    1016           0 :     relopt_enum *newoption = init_enum_reloption(RELOPT_KIND_LOCAL,
    1017             :                                                  name, desc,
    1018             :                                                  members, default_val,
    1019             :                                                  detailmsg, 0);
    1020             : 
    1021           0 :     add_local_reloption(relopts, (relopt_gen *) newoption, offset);
    1022           0 : }
    1023             : 
    1024             : /*
    1025             :  * init_string_reloption
    1026             :  *      Allocate and initialize a new string reloption
    1027             :  */
    1028             : static relopt_string *
    1029           4 : init_string_reloption(bits32 kinds, const char *name, const char *desc,
    1030             :                       const char *default_val,
    1031             :                       validate_string_relopt validator,
    1032             :                       fill_string_relopt filler,
    1033             :                       LOCKMODE lockmode)
    1034             : {
    1035             :     relopt_string *newoption;
    1036             : 
    1037             :     /* make sure the validator/default combination is sane */
    1038           4 :     if (validator)
    1039           4 :         (validator) (default_val);
    1040             : 
    1041           4 :     newoption = (relopt_string *) allocate_reloption(kinds, RELOPT_TYPE_STRING,
    1042             :                                                      name, desc, lockmode);
    1043           4 :     newoption->validate_cb = validator;
    1044           4 :     newoption->fill_cb = filler;
    1045           4 :     if (default_val)
    1046             :     {
    1047           2 :         if (kinds == RELOPT_KIND_LOCAL)
    1048           0 :             newoption->default_val = strdup(default_val);
    1049             :         else
    1050           2 :             newoption->default_val = MemoryContextStrdup(TopMemoryContext, default_val);
    1051           2 :         newoption->default_len = strlen(default_val);
    1052           2 :         newoption->default_isnull = false;
    1053             :     }
    1054             :     else
    1055             :     {
    1056           2 :         newoption->default_val = "";
    1057           2 :         newoption->default_len = 0;
    1058           2 :         newoption->default_isnull = true;
    1059             :     }
    1060             : 
    1061           4 :     return newoption;
    1062             : }
    1063             : 
    1064             : /*
    1065             :  * add_string_reloption
    1066             :  *      Add a new string reloption
    1067             :  *
    1068             :  * "validator" is an optional function pointer that can be used to test the
    1069             :  * validity of the values.  It must elog(ERROR) when the argument string is
    1070             :  * not acceptable for the variable.  Note that the default value must pass
    1071             :  * the validation.
    1072             :  */
    1073             : void
    1074           4 : add_string_reloption(bits32 kinds, const char *name, const char *desc,
    1075             :                      const char *default_val, validate_string_relopt validator,
    1076             :                      LOCKMODE lockmode)
    1077             : {
    1078           4 :     relopt_string *newoption = init_string_reloption(kinds, name, desc,
    1079             :                                                      default_val,
    1080             :                                                      validator, NULL,
    1081             :                                                      lockmode);
    1082             : 
    1083           4 :     add_reloption((relopt_gen *) newoption);
    1084           4 : }
    1085             : 
    1086             : /*
    1087             :  * add_local_string_reloption
    1088             :  *      Add a new local string reloption
    1089             :  *
    1090             :  * 'offset' is offset of int-typed field that will store offset of string value
    1091             :  * in the resulting bytea structure.
    1092             :  */
    1093             : void
    1094           0 : add_local_string_reloption(local_relopts *relopts, const char *name,
    1095             :                            const char *desc, const char *default_val,
    1096             :                            validate_string_relopt validator,
    1097             :                            fill_string_relopt filler, int offset)
    1098             : {
    1099           0 :     relopt_string *newoption = init_string_reloption(RELOPT_KIND_LOCAL,
    1100             :                                                      name, desc,
    1101             :                                                      default_val,
    1102             :                                                      validator, filler,
    1103             :                                                      0);
    1104             : 
    1105           0 :     add_local_reloption(relopts, (relopt_gen *) newoption, offset);
    1106           0 : }
    1107             : 
    1108             : /*
    1109             :  * Transform a relation options list (list of DefElem) into the text array
    1110             :  * format that is kept in pg_class.reloptions, including only those options
    1111             :  * that are in the passed namespace.  The output values do not include the
    1112             :  * namespace.
    1113             :  *
    1114             :  * This is used for three cases: CREATE TABLE/INDEX, ALTER TABLE SET, and
    1115             :  * ALTER TABLE RESET.  In the ALTER cases, oldOptions is the existing
    1116             :  * reloptions value (possibly NULL), and we replace or remove entries
    1117             :  * as needed.
    1118             :  *
    1119             :  * If acceptOidsOff is true, then we allow oids = false, but throw error when
    1120             :  * on. This is solely needed for backwards compatibility.
    1121             :  *
    1122             :  * Note that this is not responsible for determining whether the options
    1123             :  * are valid, but it does check that namespaces for all the options given are
    1124             :  * listed in validnsps.  The NULL namespace is always valid and need not be
    1125             :  * explicitly listed.  Passing a NULL pointer means that only the NULL
    1126             :  * namespace is valid.
    1127             :  *
    1128             :  * Both oldOptions and the result are text arrays (or NULL for "default"),
    1129             :  * but we declare them as Datums to avoid including array.h in reloptions.h.
    1130             :  */
    1131             : Datum
    1132      143632 : transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
    1133             :                     char *validnsps[], bool acceptOidsOff, bool isReset)
    1134             : {
    1135             :     Datum       result;
    1136             :     ArrayBuildState *astate;
    1137             :     ListCell   *cell;
    1138             : 
    1139             :     /* no change if empty list */
    1140      143632 :     if (defList == NIL)
    1141      141334 :         return oldOptions;
    1142             : 
    1143             :     /* We build new array using accumArrayResult */
    1144        2298 :     astate = NULL;
    1145             : 
    1146             :     /* Copy any oldOptions that aren't to be replaced */
    1147        2298 :     if (PointerIsValid(DatumGetPointer(oldOptions)))
    1148             :     {
    1149         242 :         ArrayType  *array = DatumGetArrayTypeP(oldOptions);
    1150             :         Datum      *oldoptions;
    1151             :         int         noldoptions;
    1152             :         int         i;
    1153             : 
    1154         242 :         deconstruct_array(array, TEXTOID, -1, false, TYPALIGN_INT,
    1155             :                           &oldoptions, NULL, &noldoptions);
    1156             : 
    1157         636 :         for (i = 0; i < noldoptions; i++)
    1158             :         {
    1159         394 :             char       *text_str = VARDATA(oldoptions[i]);
    1160         394 :             int         text_len = VARSIZE(oldoptions[i]) - VARHDRSZ;
    1161             : 
    1162             :             /* Search for a match in defList */
    1163         592 :             foreach(cell, defList)
    1164             :             {
    1165         426 :                 DefElem    *def = (DefElem *) lfirst(cell);
    1166             :                 int         kw_len;
    1167             : 
    1168             :                 /* ignore if not in the same namespace */
    1169         426 :                 if (namspace == NULL)
    1170             :                 {
    1171         394 :                     if (def->defnamespace != NULL)
    1172           0 :                         continue;
    1173             :                 }
    1174          32 :                 else if (def->defnamespace == NULL)
    1175          20 :                     continue;
    1176          12 :                 else if (strcmp(def->defnamespace, namspace) != 0)
    1177           0 :                     continue;
    1178             : 
    1179         406 :                 kw_len = strlen(def->defname);
    1180         406 :                 if (text_len > kw_len && text_str[kw_len] == '=' &&
    1181         250 :                     strncmp(text_str, def->defname, kw_len) == 0)
    1182         228 :                     break;
    1183             :             }
    1184         394 :             if (!cell)
    1185             :             {
    1186             :                 /* No match, so keep old option */
    1187         166 :                 astate = accumArrayResult(astate, oldoptions[i],
    1188             :                                           false, TEXTOID,
    1189             :                                           CurrentMemoryContext);
    1190             :             }
    1191             :         }
    1192             :     }
    1193             : 
    1194             :     /*
    1195             :      * If CREATE/SET, add new options to array; if RESET, just check that the
    1196             :      * user didn't say RESET (option=val).  (Must do this because the grammar
    1197             :      * doesn't enforce it.)
    1198             :      */
    1199        4760 :     foreach(cell, defList)
    1200             :     {
    1201        2486 :         DefElem    *def = (DefElem *) lfirst(cell);
    1202             : 
    1203        2486 :         if (isReset)
    1204             :         {
    1205         166 :             if (def->arg != NULL)
    1206           8 :                 ereport(ERROR,
    1207             :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1208             :                          errmsg("RESET must not include values for parameters")));
    1209             :         }
    1210             :         else
    1211             :         {
    1212             :             text       *t;
    1213             :             const char *value;
    1214             :             Size        len;
    1215             : 
    1216             :             /*
    1217             :              * Error out if the namespace is not valid.  A NULL namespace is
    1218             :              * always valid.
    1219             :              */
    1220        2320 :             if (def->defnamespace != NULL)
    1221             :             {
    1222          76 :                 bool        valid = false;
    1223             :                 int         i;
    1224             : 
    1225          76 :                 if (validnsps)
    1226             :                 {
    1227          76 :                     for (i = 0; validnsps[i]; i++)
    1228             :                     {
    1229          72 :                         if (strcmp(def->defnamespace, validnsps[i]) == 0)
    1230             :                         {
    1231          68 :                             valid = true;
    1232          68 :                             break;
    1233             :                         }
    1234             :                     }
    1235             :                 }
    1236             : 
    1237          76 :                 if (!valid)
    1238           8 :                     ereport(ERROR,
    1239             :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1240             :                              errmsg("unrecognized parameter namespace \"%s\"",
    1241             :                                     def->defnamespace)));
    1242             :             }
    1243             : 
    1244             :             /* ignore if not in the same namespace */
    1245        2312 :             if (namspace == NULL)
    1246             :             {
    1247        1982 :                 if (def->defnamespace != NULL)
    1248          34 :                     continue;
    1249             :             }
    1250         330 :             else if (def->defnamespace == NULL)
    1251         296 :                 continue;
    1252          34 :             else if (strcmp(def->defnamespace, namspace) != 0)
    1253           0 :                 continue;
    1254             : 
    1255             :             /*
    1256             :              * Flatten the DefElem into a text string like "name=arg". If we
    1257             :              * have just "name", assume "name=true" is meant.  Note: the
    1258             :              * namespace is not output.
    1259             :              */
    1260        1982 :             if (def->arg != NULL)
    1261        1210 :                 value = defGetString(def);
    1262             :             else
    1263         772 :                 value = "true";
    1264             : 
    1265             :             /*
    1266             :              * This is not a great place for this test, but there's no other
    1267             :              * convenient place to filter the option out. As WITH (oids =
    1268             :              * false) will be removed someday, this seems like an acceptable
    1269             :              * amount of ugly.
    1270             :              */
    1271        1982 :             if (acceptOidsOff && def->defnamespace == NULL &&
    1272        1136 :                 strcmp(def->defname, "oids") == 0)
    1273             :             {
    1274          12 :                 if (defGetBoolean(def))
    1275           8 :                     ereport(ERROR,
    1276             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1277             :                              errmsg("tables declared WITH OIDS are not supported")));
    1278             :                 /* skip over option, reloptions machinery doesn't know it */
    1279           4 :                 continue;
    1280             :             }
    1281             : 
    1282        1970 :             len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
    1283             :             /* +1 leaves room for sprintf's trailing null */
    1284        1970 :             t = (text *) palloc(len + 1);
    1285        1970 :             SET_VARSIZE(t, len);
    1286        1970 :             sprintf(VARDATA(t), "%s=%s", def->defname, value);
    1287             : 
    1288        1970 :             astate = accumArrayResult(astate, PointerGetDatum(t),
    1289             :                                       false, TEXTOID,
    1290             :                                       CurrentMemoryContext);
    1291             :         }
    1292             :     }
    1293             : 
    1294        2274 :     if (astate)
    1295        1900 :         result = makeArrayResult(astate, CurrentMemoryContext);
    1296             :     else
    1297         374 :         result = (Datum) 0;
    1298             : 
    1299        2274 :     return result;
    1300             : }
    1301             : 
    1302             : 
    1303             : /*
    1304             :  * Convert the text-array format of reloptions into a List of DefElem.
    1305             :  * This is the inverse of transformRelOptions().
    1306             :  */
    1307             : List *
    1308       18850 : untransformRelOptions(Datum options)
    1309             : {
    1310       18850 :     List       *result = NIL;
    1311             :     ArrayType  *array;
    1312             :     Datum      *optiondatums;
    1313             :     int         noptions;
    1314             :     int         i;
    1315             : 
    1316             :     /* Nothing to do if no options */
    1317       18850 :     if (!PointerIsValid(DatumGetPointer(options)))
    1318        1666 :         return result;
    1319             : 
    1320       17184 :     array = DatumGetArrayTypeP(options);
    1321             : 
    1322       17184 :     deconstruct_array(array, TEXTOID, -1, false, TYPALIGN_INT,
    1323             :                       &optiondatums, NULL, &noptions);
    1324             : 
    1325       49898 :     for (i = 0; i < noptions; i++)
    1326             :     {
    1327             :         char       *s;
    1328             :         char       *p;
    1329       32714 :         Node       *val = NULL;
    1330             : 
    1331       32714 :         s = TextDatumGetCString(optiondatums[i]);
    1332       32714 :         p = strchr(s, '=');
    1333       32714 :         if (p)
    1334             :         {
    1335       32714 :             *p++ = '\0';
    1336       32714 :             val = (Node *) makeString(pstrdup(p));
    1337             :         }
    1338       32714 :         result = lappend(result, makeDefElem(pstrdup(s), val, -1));
    1339             :     }
    1340             : 
    1341       17184 :     return result;
    1342             : }
    1343             : 
    1344             : /*
    1345             :  * Extract and parse reloptions from a pg_class tuple.
    1346             :  *
    1347             :  * This is a low-level routine, expected to be used by relcache code and
    1348             :  * callers that do not have a table's relcache entry (e.g. autovacuum).  For
    1349             :  * other uses, consider grabbing the rd_options pointer from the relcache entry
    1350             :  * instead.
    1351             :  *
    1352             :  * tupdesc is pg_class' tuple descriptor.  amoptions is a pointer to the index
    1353             :  * AM's options parser function in the case of a tuple corresponding to an
    1354             :  * index, or NULL otherwise.
    1355             :  */
    1356             : bytea *
    1357      869614 : extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
    1358             :                   amoptions_function amoptions)
    1359             : {
    1360             :     bytea      *options;
    1361             :     bool        isnull;
    1362             :     Datum       datum;
    1363             :     Form_pg_class classForm;
    1364             : 
    1365      869614 :     datum = fastgetattr(tuple,
    1366             :                         Anum_pg_class_reloptions,
    1367             :                         tupdesc,
    1368             :                         &isnull);
    1369      869614 :     if (isnull)
    1370      861532 :         return NULL;
    1371             : 
    1372        8082 :     classForm = (Form_pg_class) GETSTRUCT(tuple);
    1373             : 
    1374             :     /* Parse into appropriate format; don't error out here */
    1375        8082 :     switch (classForm->relkind)
    1376             :     {
    1377        4860 :         case RELKIND_RELATION:
    1378             :         case RELKIND_TOASTVALUE:
    1379             :         case RELKIND_MATVIEW:
    1380        4860 :             options = heap_reloptions(classForm->relkind, datum, false);
    1381        4860 :             break;
    1382           0 :         case RELKIND_PARTITIONED_TABLE:
    1383           0 :             options = partitioned_table_reloptions(datum, false);
    1384           0 :             break;
    1385        2200 :         case RELKIND_VIEW:
    1386        2200 :             options = view_reloptions(datum, false);
    1387        2200 :             break;
    1388        1022 :         case RELKIND_INDEX:
    1389             :         case RELKIND_PARTITIONED_INDEX:
    1390        1022 :             options = index_reloptions(amoptions, datum, false);
    1391        1022 :             break;
    1392           0 :         case RELKIND_FOREIGN_TABLE:
    1393           0 :             options = NULL;
    1394           0 :             break;
    1395           0 :         default:
    1396             :             Assert(false);      /* can't get here */
    1397           0 :             options = NULL;     /* keep compiler quiet */
    1398           0 :             break;
    1399             :     }
    1400             : 
    1401        8082 :     return options;
    1402             : }
    1403             : 
    1404             : static void
    1405       10070 : parseRelOptionsInternal(Datum options, bool validate,
    1406             :                         relopt_value *reloptions, int numoptions)
    1407             : {
    1408       10070 :     ArrayType  *array = DatumGetArrayTypeP(options);
    1409             :     Datum      *optiondatums;
    1410             :     int         noptions;
    1411             :     int         i;
    1412             : 
    1413       10070 :     deconstruct_array(array, TEXTOID, -1, false, TYPALIGN_INT,
    1414             :                       &optiondatums, NULL, &noptions);
    1415             : 
    1416       21050 :     for (i = 0; i < noptions; i++)
    1417             :     {
    1418       11198 :         char       *text_str = VARDATA(optiondatums[i]);
    1419       11198 :         int         text_len = VARSIZE(optiondatums[i]) - VARHDRSZ;
    1420             :         int         j;
    1421             : 
    1422             :         /* Search for a match in reloptions */
    1423       52328 :         for (j = 0; j < numoptions; j++)
    1424             :         {
    1425       52276 :             int         kw_len = reloptions[j].gen->namelen;
    1426             : 
    1427       52276 :             if (text_len > kw_len && text_str[kw_len] == '=' &&
    1428       11640 :                 strncmp(text_str, reloptions[j].gen->name, kw_len) == 0)
    1429             :             {
    1430       11146 :                 parse_one_reloption(&reloptions[j], text_str, text_len,
    1431             :                                     validate);
    1432       10972 :                 break;
    1433             :             }
    1434             :         }
    1435             : 
    1436       11024 :         if (j >= numoptions && validate)
    1437             :         {
    1438             :             char       *s;
    1439             :             char       *p;
    1440             : 
    1441          44 :             s = TextDatumGetCString(optiondatums[i]);
    1442          44 :             p = strchr(s, '=');
    1443          44 :             if (p)
    1444          44 :                 *p = '\0';
    1445          44 :             ereport(ERROR,
    1446             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1447             :                      errmsg("unrecognized parameter \"%s\"", s)));
    1448             :         }
    1449             :     }
    1450             : 
    1451             :     /* It's worth avoiding memory leaks in this function */
    1452        9852 :     pfree(optiondatums);
    1453             : 
    1454        9852 :     if (((void *) array) != DatumGetPointer(options))
    1455        8140 :         pfree(array);
    1456        9852 : }
    1457             : 
    1458             : /*
    1459             :  * Interpret reloptions that are given in text-array format.
    1460             :  *
    1461             :  * options is a reloption text array as constructed by transformRelOptions.
    1462             :  * kind specifies the family of options to be processed.
    1463             :  *
    1464             :  * The return value is a relopt_value * array on which the options actually
    1465             :  * set in the options array are marked with isset=true.  The length of this
    1466             :  * array is returned in *numrelopts.  Options not set are also present in the
    1467             :  * array; this is so that the caller can easily locate the default values.
    1468             :  *
    1469             :  * If there are no options of the given kind, numrelopts is set to 0 and NULL
    1470             :  * is returned (unless options are illegally supplied despite none being
    1471             :  * defined, in which case an error occurs).
    1472             :  *
    1473             :  * Note: values of type int, bool and real are allocated as part of the
    1474             :  * returned array.  Values of type string are allocated separately and must
    1475             :  * be freed by the caller.
    1476             :  */
    1477             : static relopt_value *
    1478       99384 : parseRelOptions(Datum options, bool validate, relopt_kind kind,
    1479             :                 int *numrelopts)
    1480             : {
    1481       99384 :     relopt_value *reloptions = NULL;
    1482       99384 :     int         numoptions = 0;
    1483             :     int         i;
    1484             :     int         j;
    1485             : 
    1486       99384 :     if (need_initialization)
    1487        3776 :         initialize_reloptions();
    1488             : 
    1489             :     /* Build a list of expected options, based on kind */
    1490             : 
    1491     4176630 :     for (i = 0; relOpts[i]; i++)
    1492     4077246 :         if (relOpts[i]->kinds & kind)
    1493      985918 :             numoptions++;
    1494             : 
    1495       99384 :     if (numoptions > 0)
    1496             :     {
    1497       96968 :         reloptions = palloc(numoptions * sizeof(relopt_value));
    1498             : 
    1499     4075158 :         for (i = 0, j = 0; relOpts[i]; i++)
    1500             :         {
    1501     3978190 :             if (relOpts[i]->kinds & kind)
    1502             :             {
    1503      985918 :                 reloptions[j].gen = relOpts[i];
    1504      985918 :                 reloptions[j].isset = false;
    1505      985918 :                 j++;
    1506             :             }
    1507             :         }
    1508             :     }
    1509             : 
    1510             :     /* Done if no options */
    1511       99384 :     if (PointerIsValid(DatumGetPointer(options)))
    1512        9922 :         parseRelOptionsInternal(options, validate, reloptions, numoptions);
    1513             : 
    1514       99210 :     *numrelopts = numoptions;
    1515       99210 :     return reloptions;
    1516             : }
    1517             : 
    1518             : /* Parse local unregistered options. */
    1519             : static relopt_value *
    1520         196 : parseLocalRelOptions(local_relopts *relopts, Datum options, bool validate)
    1521             : {
    1522         196 :     int         nopts = list_length(relopts->options);
    1523         196 :     relopt_value *values = palloc(sizeof(*values) * nopts);
    1524             :     ListCell   *lc;
    1525         196 :     int         i = 0;
    1526             : 
    1527         392 :     foreach(lc, relopts->options)
    1528             :     {
    1529         196 :         local_relopt *opt = lfirst(lc);
    1530             : 
    1531         196 :         values[i].gen = opt->option;
    1532         196 :         values[i].isset = false;
    1533             : 
    1534         196 :         i++;
    1535             :     }
    1536             : 
    1537         196 :     if (options != (Datum) 0)
    1538         148 :         parseRelOptionsInternal(options, validate, values, nopts);
    1539             : 
    1540         152 :     return values;
    1541             : }
    1542             : 
    1543             : /*
    1544             :  * Subroutine for parseRelOptions, to parse and validate a single option's
    1545             :  * value
    1546             :  */
    1547             : static void
    1548       11146 : parse_one_reloption(relopt_value *option, char *text_str, int text_len,
    1549             :                     bool validate)
    1550             : {
    1551             :     char       *value;
    1552             :     int         value_len;
    1553             :     bool        parsed;
    1554       11146 :     bool        nofree = false;
    1555             : 
    1556       11146 :     if (option->isset && validate)
    1557           8 :         ereport(ERROR,
    1558             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1559             :                  errmsg("parameter \"%s\" specified more than once",
    1560             :                         option->gen->name)));
    1561             : 
    1562       11138 :     value_len = text_len - option->gen->namelen - 1;
    1563       11138 :     value = (char *) palloc(value_len + 1);
    1564       11138 :     memcpy(value, text_str + option->gen->namelen + 1, value_len);
    1565       11138 :     value[value_len] = '\0';
    1566             : 
    1567       11138 :     switch (option->gen->type)
    1568             :     {
    1569        5702 :         case RELOPT_TYPE_BOOL:
    1570             :             {
    1571        5702 :                 parsed = parse_bool(value, &option->values.bool_val);
    1572        5702 :                 if (validate && !parsed)
    1573          22 :                     ereport(ERROR,
    1574             :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1575             :                              errmsg("invalid value for boolean option \"%s\": %s",
    1576             :                                     option->gen->name, value)));
    1577             :             }
    1578        5680 :             break;
    1579        4280 :         case RELOPT_TYPE_INT:
    1580             :             {
    1581        4280 :                 relopt_int *optint = (relopt_int *) option->gen;
    1582             : 
    1583        4280 :                 parsed = parse_int(value, &option->values.int_val, 0, NULL);
    1584        4280 :                 if (validate && !parsed)
    1585          16 :                     ereport(ERROR,
    1586             :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1587             :                              errmsg("invalid value for integer option \"%s\": %s",
    1588             :                                     option->gen->name, value)));
    1589        4264 :                 if (validate && (option->values.int_val < optint->min ||
    1590         386 :                                  option->values.int_val > optint->max))
    1591          80 :                     ereport(ERROR,
    1592             :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1593             :                              errmsg("value %s out of bounds for option \"%s\"",
    1594             :                                     value, option->gen->name),
    1595             :                              errdetail("Valid values are between \"%d\" and \"%d\".",
    1596             :                                        optint->min, optint->max)));
    1597             :             }
    1598        4184 :             break;
    1599         386 :         case RELOPT_TYPE_REAL:
    1600             :             {
    1601         386 :                 relopt_real *optreal = (relopt_real *) option->gen;
    1602             : 
    1603         386 :                 parsed = parse_real(value, &option->values.real_val, 0, NULL);
    1604         386 :                 if (validate && !parsed)
    1605          20 :                     ereport(ERROR,
    1606             :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1607             :                              errmsg("invalid value for floating point option \"%s\": %s",
    1608             :                                     option->gen->name, value)));
    1609         366 :                 if (validate && (option->values.real_val < optreal->min ||
    1610         128 :                                  option->values.real_val > optreal->max))
    1611          12 :                     ereport(ERROR,
    1612             :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1613             :                              errmsg("value %s out of bounds for option \"%s\"",
    1614             :                                     value, option->gen->name),
    1615             :                              errdetail("Valid values are between \"%f\" and \"%f\".",
    1616             :                                        optreal->min, optreal->max)));
    1617             :             }
    1618         354 :             break;
    1619         606 :         case RELOPT_TYPE_ENUM:
    1620         590 :             {
    1621         606 :                 relopt_enum *optenum = (relopt_enum *) option->gen;
    1622             :                 relopt_enum_elt_def *elt;
    1623             : 
    1624         606 :                 parsed = false;
    1625        1060 :                 for (elt = optenum->members; elt->string_val; elt++)
    1626             :                 {
    1627        1044 :                     if (pg_strcasecmp(value, elt->string_val) == 0)
    1628             :                     {
    1629         590 :                         option->values.enum_val = elt->symbol_val;
    1630         590 :                         parsed = true;
    1631         590 :                         break;
    1632             :                     }
    1633             :                 }
    1634         606 :                 if (validate && !parsed)
    1635          16 :                     ereport(ERROR,
    1636             :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1637             :                              errmsg("invalid value for enum option \"%s\": %s",
    1638             :                                     option->gen->name, value),
    1639             :                              optenum->detailmsg ?
    1640             :                              errdetail_internal("%s", _(optenum->detailmsg)) : 0));
    1641             : 
    1642             :                 /*
    1643             :                  * If value is not among the allowed string values, but we are
    1644             :                  * not asked to validate, just use the default numeric value.
    1645             :                  */
    1646         590 :                 if (!parsed)
    1647           0 :                     option->values.enum_val = optenum->default_val;
    1648             :             }
    1649         590 :             break;
    1650         164 :         case RELOPT_TYPE_STRING:
    1651             :             {
    1652         164 :                 relopt_string *optstring = (relopt_string *) option->gen;
    1653             : 
    1654         164 :                 option->values.string_val = value;
    1655         164 :                 nofree = true;
    1656         164 :                 if (validate && optstring->validate_cb)
    1657          56 :                     (optstring->validate_cb) (value);
    1658         164 :                 parsed = true;
    1659             :             }
    1660         164 :             break;
    1661           0 :         default:
    1662           0 :             elog(ERROR, "unsupported reloption type %d", option->gen->type);
    1663             :             parsed = true;      /* quiet compiler */
    1664             :             break;
    1665             :     }
    1666             : 
    1667       10972 :     if (parsed)
    1668       10972 :         option->isset = true;
    1669       10972 :     if (!nofree)
    1670       10808 :         pfree(value);
    1671       10972 : }
    1672             : 
    1673             : /*
    1674             :  * Given the result from parseRelOptions, allocate a struct that's of the
    1675             :  * specified base size plus any extra space that's needed for string variables.
    1676             :  *
    1677             :  * "base" should be sizeof(struct) of the reloptions struct (StdRdOptions or
    1678             :  * equivalent).
    1679             :  */
    1680             : static void *
    1681       96946 : allocateReloptStruct(Size base, relopt_value *options, int numoptions)
    1682             : {
    1683       96946 :     Size        size = base;
    1684             :     int         i;
    1685             : 
    1686     1081096 :     for (i = 0; i < numoptions; i++)
    1687             :     {
    1688      984150 :         relopt_value *optval = &options[i];
    1689             : 
    1690      984150 :         if (optval->gen->type == RELOPT_TYPE_STRING)
    1691             :         {
    1692         232 :             relopt_string *optstr = (relopt_string *) optval->gen;
    1693             : 
    1694         232 :             if (optstr->fill_cb)
    1695             :             {
    1696           0 :                 const char *val = optval->isset ? optval->values.string_val :
    1697           0 :                 optstr->default_isnull ? NULL : optstr->default_val;
    1698             : 
    1699           0 :                 size += optstr->fill_cb(val, NULL);
    1700             :             }
    1701             :             else
    1702         232 :                 size += GET_STRING_RELOPTION_LEN(*optval) + 1;
    1703             :         }
    1704             :     }
    1705             : 
    1706       96946 :     return palloc0(size);
    1707             : }
    1708             : 
    1709             : /*
    1710             :  * Given the result of parseRelOptions and a parsing table, fill in the
    1711             :  * struct (previously allocated with allocateReloptStruct) with the parsed
    1712             :  * values.
    1713             :  *
    1714             :  * rdopts is the pointer to the allocated struct to be filled.
    1715             :  * basesize is the sizeof(struct) that was passed to allocateReloptStruct.
    1716             :  * options, of length numoptions, is parseRelOptions' output.
    1717             :  * elems, of length numelems, is the table describing the allowed options.
    1718             :  * When validate is true, it is expected that all options appear in elems.
    1719             :  */
    1720             : static void
    1721       96946 : fillRelOptions(void *rdopts, Size basesize,
    1722             :                relopt_value *options, int numoptions,
    1723             :                bool validate,
    1724             :                const relopt_parse_elt *elems, int numelems)
    1725             : {
    1726             :     int         i;
    1727       96946 :     int         offset = basesize;
    1728             : 
    1729     1081096 :     for (i = 0; i < numoptions; i++)
    1730             :     {
    1731             :         int         j;
    1732      984150 :         bool        found = false;
    1733             : 
    1734    10129018 :         for (j = 0; j < numelems; j++)
    1735             :         {
    1736    10129018 :             if (strcmp(options[i].gen->name, elems[j].optname) == 0)
    1737             :             {
    1738             :                 relopt_string *optstring;
    1739      984150 :                 char       *itempos = ((char *) rdopts) + elems[j].offset;
    1740             :                 char       *string_val;
    1741             : 
    1742      984150 :                 switch (options[i].gen->type)
    1743             :                 {
    1744      212602 :                     case RELOPT_TYPE_BOOL:
    1745      425204 :                         *(bool *) itempos = options[i].isset ?
    1746      212602 :                             options[i].values.bool_val :
    1747      206924 :                             ((relopt_bool *) options[i].gen)->default_val;
    1748      212602 :                         break;
    1749      559036 :                     case RELOPT_TYPE_INT:
    1750     1118072 :                         *(int *) itempos = options[i].isset ?
    1751      559036 :                             options[i].values.int_val :
    1752      554870 :                             ((relopt_int *) options[i].gen)->default_val;
    1753      559036 :                         break;
    1754      162496 :                     case RELOPT_TYPE_REAL:
    1755      324992 :                         *(double *) itempos = options[i].isset ?
    1756      162496 :                             options[i].values.real_val :
    1757      162152 :                             ((relopt_real *) options[i].gen)->default_val;
    1758      162496 :                         break;
    1759       49784 :                     case RELOPT_TYPE_ENUM:
    1760       99568 :                         *(int *) itempos = options[i].isset ?
    1761       49784 :                             options[i].values.enum_val :
    1762       49194 :                             ((relopt_enum *) options[i].gen)->default_val;
    1763       49784 :                         break;
    1764         232 :                     case RELOPT_TYPE_STRING:
    1765         232 :                         optstring = (relopt_string *) options[i].gen;
    1766         232 :                         if (options[i].isset)
    1767         160 :                             string_val = options[i].values.string_val;
    1768          72 :                         else if (!optstring->default_isnull)
    1769          30 :                             string_val = optstring->default_val;
    1770             :                         else
    1771          42 :                             string_val = NULL;
    1772             : 
    1773         232 :                         if (optstring->fill_cb)
    1774             :                         {
    1775             :                             Size        size =
    1776           0 :                             optstring->fill_cb(string_val,
    1777             :                                                (char *) rdopts + offset);
    1778             : 
    1779           0 :                             if (size)
    1780             :                             {
    1781           0 :                                 *(int *) itempos = offset;
    1782           0 :                                 offset += size;
    1783             :                             }
    1784             :                             else
    1785           0 :                                 *(int *) itempos = 0;
    1786             :                         }
    1787         232 :                         else if (string_val == NULL)
    1788          42 :                             *(int *) itempos = 0;
    1789             :                         else
    1790             :                         {
    1791         190 :                             strcpy((char *) rdopts + offset, string_val);
    1792         190 :                             *(int *) itempos = offset;
    1793         190 :                             offset += strlen(string_val) + 1;
    1794             :                         }
    1795         232 :                         break;
    1796           0 :                     default:
    1797           0 :                         elog(ERROR, "unsupported reloption type %d",
    1798             :                              options[i].gen->type);
    1799             :                         break;
    1800             :                 }
    1801      984150 :                 found = true;
    1802      984150 :                 break;
    1803             :             }
    1804             :         }
    1805      984150 :         if (validate && !found)
    1806           0 :             elog(ERROR, "reloption \"%s\" not found in parse table",
    1807             :                  options[i].gen->name);
    1808             :     }
    1809       96946 :     SET_VARSIZE(rdopts, offset);
    1810       96946 : }
    1811             : 
    1812             : 
    1813             : /*
    1814             :  * Option parser for anything that uses StdRdOptions.
    1815             :  */
    1816             : bytea *
    1817       45930 : default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
    1818             : {
    1819             :     static const relopt_parse_elt tab[] = {
    1820             :         {"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
    1821             :         {"autovacuum_enabled", RELOPT_TYPE_BOOL,
    1822             :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, enabled)},
    1823             :         {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,
    1824             :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)},
    1825             :         {"autovacuum_vacuum_insert_threshold", RELOPT_TYPE_INT,
    1826             :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_threshold)},
    1827             :         {"autovacuum_analyze_threshold", RELOPT_TYPE_INT,
    1828             :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)},
    1829             :         {"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,
    1830             :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)},
    1831             :         {"autovacuum_freeze_min_age", RELOPT_TYPE_INT,
    1832             :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_min_age)},
    1833             :         {"autovacuum_freeze_max_age", RELOPT_TYPE_INT,
    1834             :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_max_age)},
    1835             :         {"autovacuum_freeze_table_age", RELOPT_TYPE_INT,
    1836             :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_table_age)},
    1837             :         {"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT,
    1838             :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_min_age)},
    1839             :         {"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT,
    1840             :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_max_age)},
    1841             :         {"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT,
    1842             :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_table_age)},
    1843             :         {"log_autovacuum_min_duration", RELOPT_TYPE_INT,
    1844             :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, log_min_duration)},
    1845             :         {"toast_tuple_target", RELOPT_TYPE_INT,
    1846             :         offsetof(StdRdOptions, toast_tuple_target)},
    1847             :         {"autovacuum_vacuum_cost_delay", RELOPT_TYPE_REAL,
    1848             :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)},
    1849             :         {"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
    1850             :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_scale_factor)},
    1851             :         {"autovacuum_vacuum_insert_scale_factor", RELOPT_TYPE_REAL,
    1852             :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_scale_factor)},
    1853             :         {"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
    1854             :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_scale_factor)},
    1855             :         {"user_catalog_table", RELOPT_TYPE_BOOL,
    1856             :         offsetof(StdRdOptions, user_catalog_table)},
    1857             :         {"parallel_workers", RELOPT_TYPE_INT,
    1858             :         offsetof(StdRdOptions, parallel_workers)},
    1859             :         {"vacuum_index_cleanup", RELOPT_TYPE_BOOL,
    1860             :         offsetof(StdRdOptions, vacuum_index_cleanup)},
    1861             :         {"vacuum_truncate", RELOPT_TYPE_BOOL,
    1862             :         offsetof(StdRdOptions, vacuum_truncate)}
    1863             :     };
    1864             : 
    1865       45930 :     return (bytea *) build_reloptions(reloptions, validate, kind,
    1866             :                                       sizeof(StdRdOptions),
    1867             :                                       tab, lengthof(tab));
    1868             : }
    1869             : 
    1870             : /*
    1871             :  * build_reloptions
    1872             :  *
    1873             :  * Parses "reloptions" provided by the caller, returning them in a
    1874             :  * structure containing the parsed options.  The parsing is done with
    1875             :  * the help of a parsing table describing the allowed options, defined
    1876             :  * by "relopt_elems" of length "num_relopt_elems".
    1877             :  *
    1878             :  * "validate" must be true if reloptions value is freshly built by
    1879             :  * transformRelOptions(), as opposed to being read from the catalog, in which
    1880             :  * case the values contained in it must already be valid.
    1881             :  *
    1882             :  * NULL is returned if the passed-in options did not match any of the options
    1883             :  * in the parsing table, unless validate is true in which case an error would
    1884             :  * be reported.
    1885             :  */
    1886             : void *
    1887       99384 : build_reloptions(Datum reloptions, bool validate,
    1888             :                  relopt_kind kind,
    1889             :                  Size relopt_struct_size,
    1890             :                  const relopt_parse_elt *relopt_elems,
    1891             :                  int num_relopt_elems)
    1892             : {
    1893             :     int         numoptions;
    1894             :     relopt_value *options;
    1895             :     void       *rdopts;
    1896             : 
    1897             :     /* parse options specific to given relation option kind */
    1898       99384 :     options = parseRelOptions(reloptions, validate, kind, &numoptions);
    1899             :     Assert(numoptions <= num_relopt_elems);
    1900             : 
    1901             :     /* if none set, we're done */
    1902       99210 :     if (numoptions == 0)
    1903             :     {
    1904             :         Assert(options == NULL);
    1905        2416 :         return NULL;
    1906             :     }
    1907             : 
    1908             :     /* allocate and fill the structure */
    1909       96794 :     rdopts = allocateReloptStruct(relopt_struct_size, options, numoptions);
    1910       96794 :     fillRelOptions(rdopts, relopt_struct_size, options, numoptions,
    1911             :                    validate, relopt_elems, num_relopt_elems);
    1912             : 
    1913       96794 :     pfree(options);
    1914             : 
    1915       96794 :     return rdopts;
    1916             : }
    1917             : 
    1918             : /*
    1919             :  * Parse local options, allocate a bytea struct that's of the specified
    1920             :  * 'base_size' plus any extra space that's needed for string variables,
    1921             :  * fill its option's fields located at the given offsets and return it.
    1922             :  */
    1923             : void *
    1924         196 : build_local_reloptions(local_relopts *relopts, Datum options, bool validate)
    1925             : {
    1926         196 :     int         noptions = list_length(relopts->options);
    1927         196 :     relopt_parse_elt *elems = palloc(sizeof(*elems) * noptions);
    1928             :     relopt_value *vals;
    1929             :     void       *opts;
    1930         196 :     int         i = 0;
    1931             :     ListCell   *lc;
    1932             : 
    1933         392 :     foreach(lc, relopts->options)
    1934             :     {
    1935         196 :         local_relopt *opt = lfirst(lc);
    1936             : 
    1937         196 :         elems[i].optname = opt->option->name;
    1938         196 :         elems[i].opttype = opt->option->type;
    1939         196 :         elems[i].offset = opt->offset;
    1940             : 
    1941         196 :         i++;
    1942             :     }
    1943             : 
    1944         196 :     vals = parseLocalRelOptions(relopts, options, validate);
    1945         152 :     opts = allocateReloptStruct(relopts->relopt_struct_size, vals, noptions);
    1946         152 :     fillRelOptions(opts, relopts->relopt_struct_size, vals, noptions, validate,
    1947             :                    elems, noptions);
    1948             : 
    1949         152 :     foreach(lc, relopts->validators)
    1950           0 :         ((relopts_validator) lfirst(lc)) (opts, vals, noptions);
    1951             : 
    1952         152 :     if (elems)
    1953         152 :         pfree(elems);
    1954             : 
    1955         152 :     return opts;
    1956             : }
    1957             : 
    1958             : /*
    1959             :  * Option parser for partitioned tables
    1960             :  */
    1961             : bytea *
    1962        2416 : partitioned_table_reloptions(Datum reloptions, bool validate)
    1963             : {
    1964             :     /*
    1965             :      * There are no options for partitioned tables yet, but this is able to do
    1966             :      * some validation.
    1967             :      */
    1968        2416 :     return (bytea *) build_reloptions(reloptions, validate,
    1969             :                                       RELOPT_KIND_PARTITIONED,
    1970             :                                       0, NULL, 0);
    1971             : }
    1972             : 
    1973             : /*
    1974             :  * Option parser for views
    1975             :  */
    1976             : bytea *
    1977       49602 : view_reloptions(Datum reloptions, bool validate)
    1978             : {
    1979             :     static const relopt_parse_elt tab[] = {
    1980             :         {"security_barrier", RELOPT_TYPE_BOOL,
    1981             :         offsetof(ViewOptions, security_barrier)},
    1982             :         {"check_option", RELOPT_TYPE_ENUM,
    1983             :         offsetof(ViewOptions, check_option)}
    1984             :     };
    1985             : 
    1986       49602 :     return (bytea *) build_reloptions(reloptions, validate,
    1987             :                                       RELOPT_KIND_VIEW,
    1988             :                                       sizeof(ViewOptions),
    1989             :                                       tab, lengthof(tab));
    1990             : }
    1991             : 
    1992             : /*
    1993             :  * Parse options for heaps, views and toast tables.
    1994             :  */
    1995             : bytea *
    1996       47582 : heap_reloptions(char relkind, Datum reloptions, bool validate)
    1997             : {
    1998             :     StdRdOptions *rdopts;
    1999             : 
    2000       47582 :     switch (relkind)
    2001             :     {
    2002       21446 :         case RELKIND_TOASTVALUE:
    2003             :             rdopts = (StdRdOptions *)
    2004       21446 :                 default_reloptions(reloptions, validate, RELOPT_KIND_TOAST);
    2005       21442 :             if (rdopts != NULL)
    2006             :             {
    2007             :                 /* adjust default-only parameters for TOAST relations */
    2008       21442 :                 rdopts->fillfactor = 100;
    2009       21442 :                 rdopts->autovacuum.analyze_threshold = -1;
    2010       21442 :                 rdopts->autovacuum.analyze_scale_factor = -1;
    2011             :             }
    2012       21442 :             return (bytea *) rdopts;
    2013       24484 :         case RELKIND_RELATION:
    2014             :         case RELKIND_MATVIEW:
    2015       24484 :             return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
    2016        1652 :         default:
    2017             :             /* other relkinds are not supported */
    2018        1652 :             return NULL;
    2019             :     }
    2020             : }
    2021             : 
    2022             : 
    2023             : /*
    2024             :  * Parse options for indexes.
    2025             :  *
    2026             :  *  amoptions   index AM's option parser function
    2027             :  *  reloptions  options as text[] datum
    2028             :  *  validate    error flag
    2029             :  */
    2030             : bytea *
    2031       51952 : index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate)
    2032             : {
    2033             :     Assert(amoptions != NULL);
    2034             : 
    2035             :     /* Assume function is strict */
    2036       51952 :     if (!PointerIsValid(DatumGetPointer(reloptions)))
    2037       50594 :         return NULL;
    2038             : 
    2039        1358 :     return amoptions(reloptions, validate);
    2040             : }
    2041             : 
    2042             : /*
    2043             :  * Option parser for attribute reloptions
    2044             :  */
    2045             : bytea *
    2046          26 : attribute_reloptions(Datum reloptions, bool validate)
    2047             : {
    2048             :     static const relopt_parse_elt tab[] = {
    2049             :         {"n_distinct", RELOPT_TYPE_REAL, offsetof(AttributeOpts, n_distinct)},
    2050             :         {"n_distinct_inherited", RELOPT_TYPE_REAL, offsetof(AttributeOpts, n_distinct_inherited)}
    2051             :     };
    2052             : 
    2053          26 :     return (bytea *) build_reloptions(reloptions, validate,
    2054             :                                       RELOPT_KIND_ATTRIBUTE,
    2055             :                                       sizeof(AttributeOpts),
    2056             :                                       tab, lengthof(tab));
    2057             : }
    2058             : 
    2059             : /*
    2060             :  * Option parser for tablespace reloptions
    2061             :  */
    2062             : bytea *
    2063          52 : tablespace_reloptions(Datum reloptions, bool validate)
    2064             : {
    2065             :     static const relopt_parse_elt tab[] = {
    2066             :         {"random_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, random_page_cost)},
    2067             :         {"seq_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, seq_page_cost)},
    2068             :         {"effective_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, effective_io_concurrency)},
    2069             :         {"maintenance_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, maintenance_io_concurrency)}
    2070             :     };
    2071             : 
    2072          52 :     return (bytea *) build_reloptions(reloptions, validate,
    2073             :                                       RELOPT_KIND_TABLESPACE,
    2074             :                                       sizeof(TableSpaceOpts),
    2075             :                                       tab, lengthof(tab));
    2076             : }
    2077             : 
    2078             : /*
    2079             :  * Determine the required LOCKMODE from an option list.
    2080             :  *
    2081             :  * Called from AlterTableGetLockLevel(), see that function
    2082             :  * for a longer explanation of how this works.
    2083             :  */
    2084             : LOCKMODE
    2085         510 : AlterTableGetRelOptionsLockLevel(List *defList)
    2086             : {
    2087         510 :     LOCKMODE    lockmode = NoLock;
    2088             :     ListCell   *cell;
    2089             : 
    2090         510 :     if (defList == NIL)
    2091           0 :         return AccessExclusiveLock;
    2092             : 
    2093         510 :     if (need_initialization)
    2094           6 :         initialize_reloptions();
    2095             : 
    2096        1044 :     foreach(cell, defList)
    2097             :     {
    2098         534 :         DefElem    *def = (DefElem *) lfirst(cell);
    2099             :         int         i;
    2100             : 
    2101       22914 :         for (i = 0; relOpts[i]; i++)
    2102             :         {
    2103       44760 :             if (strncmp(relOpts[i]->name,
    2104       22380 :                         def->defname,
    2105       22380 :                         relOpts[i]->namelen + 1) == 0)
    2106             :             {
    2107         726 :                 if (lockmode < relOpts[i]->lockmode)
    2108         510 :                     lockmode = relOpts[i]->lockmode;
    2109             :             }
    2110             :         }
    2111             :     }
    2112             : 
    2113         510 :     return lockmode;
    2114             : }

Generated by: LCOV version 1.13