LCOV - differential code coverage report
Current view: top level - src/backend/access/common - reloptions.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 90.1 % 553 498 2 7 14 32 13 177 12 296 8 186 2 9
Current Date: 2023-04-08 15:15:32 Functions: 90.2 % 41 37 1 3 18 2 17 18 1 1
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a