LCOV - code coverage report
Current view: top level - src/backend/access/common - reloptions.c (source / functions) Hit Total Coverage
Test: PostgreSQL 11devel Lines: 345 395 87.3 %
Date: 2017-11-22 12:18:04 Functions: 19 22 86.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 220 274 80.3 %

           Branch data     Line data    Source code
       1                 :            : /*-------------------------------------------------------------------------
       2                 :            :  *
       3                 :            :  * reloptions.c
       4                 :            :  *    Core support for relation options (pg_class.reloptions)
       5                 :            :  *
       6                 :            :  * Portions Copyright (c) 1996-2017, 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/htup_details.h"
      23                 :            : #include "access/nbtree.h"
      24                 :            : #include "access/reloptions.h"
      25                 :            : #include "access/spgist.h"
      26                 :            : #include "access/tuptoaster.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                 :            :  * Note that we don't handle "oids" in relOpts because it is handled by
      56                 :            :  * interpretOidsOption().
      57                 :            :  *
      58                 :            :  * The default choice for any new option should be AccessExclusiveLock.
      59                 :            :  * In some cases the lock level can be reduced from there, but the lock
      60                 :            :  * level chosen should always conflict with itself to ensure that multiple
      61                 :            :  * changes aren't lost when we attempt concurrent changes.
      62                 :            :  * The choice of lock level depends completely upon how that parameter
      63                 :            :  * is used within the server, not upon how and when you'd like to change it.
      64                 :            :  * Safety first. Existing choices are documented here, and elsewhere in
      65                 :            :  * backend code where the parameters are used.
      66                 :            :  *
      67                 :            :  * In general, anything that affects the results obtained from a SELECT must be
      68                 :            :  * protected by AccessExclusiveLock.
      69                 :            :  *
      70                 :            :  * Autovacuum related parameters can be set at ShareUpdateExclusiveLock
      71                 :            :  * since they are only used by the AV procs and don't change anything
      72                 :            :  * currently executing.
      73                 :            :  *
      74                 :            :  * Fillfactor can be set because it applies only to subsequent changes made to
      75                 :            :  * data blocks, as documented in heapio.c
      76                 :            :  *
      77                 :            :  * n_distinct options can be set at ShareUpdateExclusiveLock because they
      78                 :            :  * are only used during ANALYZE, which uses a ShareUpdateExclusiveLock,
      79                 :            :  * so the ANALYZE will not be affected by in-flight changes. Changing those
      80                 :            :  * values has no affect until the next ANALYZE, so no need for stronger lock.
      81                 :            :  *
      82                 :            :  * Planner-related parameters can be set with ShareUpdateExclusiveLock because
      83                 :            :  * they only affect planning and not the correctness of the execution. Plans
      84                 :            :  * cannot be changed in mid-flight, so changes here could not easily result in
      85                 :            :  * new improved plans in any case. So we allow existing queries to continue
      86                 :            :  * and existing plans to survive, a small price to pay for allowing better
      87                 :            :  * plans to be introduced concurrently without interfering with users.
      88                 :            :  *
      89                 :            :  * Setting parallel_workers is safe, since it acts the same as
      90                 :            :  * max_parallel_workers_per_gather which is a USERSET parameter that doesn't
      91                 :            :  * affect existing plans or queries.
      92                 :            :  */
      93                 :            : 
      94                 :            : static relopt_bool boolRelOpts[] =
      95                 :            : {
      96                 :            :     {
      97                 :            :         {
      98                 :            :             "autosummarize",
      99                 :            :             "Enables automatic summarization on this BRIN index",
     100                 :            :             RELOPT_KIND_BRIN,
     101                 :            :             AccessExclusiveLock
     102                 :            :         },
     103                 :            :         false
     104                 :            :     },
     105                 :            :     {
     106                 :            :         {
     107                 :            :             "autovacuum_enabled",
     108                 :            :             "Enables autovacuum in this relation",
     109                 :            :             RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
     110                 :            :             ShareUpdateExclusiveLock
     111                 :            :         },
     112                 :            :         true
     113                 :            :     },
     114                 :            :     {
     115                 :            :         {
     116                 :            :             "user_catalog_table",
     117                 :            :             "Declare a table as an additional catalog table, e.g. for the purpose of logical replication",
     118                 :            :             RELOPT_KIND_HEAP,
     119                 :            :             AccessExclusiveLock
     120                 :            :         },
     121                 :            :         false
     122                 :            :     },
     123                 :            :     {
     124                 :            :         {
     125                 :            :             "fastupdate",
     126                 :            :             "Enables \"fast update\" feature for this GIN index",
     127                 :            :             RELOPT_KIND_GIN,
     128                 :            :             AccessExclusiveLock
     129                 :            :         },
     130                 :            :         true
     131                 :            :     },
     132                 :            :     {
     133                 :            :         {
     134                 :            :             "security_barrier",
     135                 :            :             "View acts as a row security barrier",
     136                 :            :             RELOPT_KIND_VIEW,
     137                 :            :             AccessExclusiveLock
     138                 :            :         },
     139                 :            :         false
     140                 :            :     },
     141                 :            :     /* list terminator */
     142                 :            :     {{NULL}}
     143                 :            : };
     144                 :            : 
     145                 :            : static relopt_int intRelOpts[] =
     146                 :            : {
     147                 :            :     {
     148                 :            :         {
     149                 :            :             "fillfactor",
     150                 :            :             "Packs table pages only to this percentage",
     151                 :            :             RELOPT_KIND_HEAP,
     152                 :            :             ShareUpdateExclusiveLock    /* since it applies only to later
     153                 :            :                                          * inserts */
     154                 :            :         },
     155                 :            :         HEAP_DEFAULT_FILLFACTOR, HEAP_MIN_FILLFACTOR, 100
     156                 :            :     },
     157                 :            :     {
     158                 :            :         {
     159                 :            :             "fillfactor",
     160                 :            :             "Packs btree index pages only to this percentage",
     161                 :            :             RELOPT_KIND_BTREE,
     162                 :            :             ShareUpdateExclusiveLock    /* since it applies only to later
     163                 :            :                                          * inserts */
     164                 :            :         },
     165                 :            :         BTREE_DEFAULT_FILLFACTOR, BTREE_MIN_FILLFACTOR, 100
     166                 :            :     },
     167                 :            :     {
     168                 :            :         {
     169                 :            :             "fillfactor",
     170                 :            :             "Packs hash index pages only to this percentage",
     171                 :            :             RELOPT_KIND_HASH,
     172                 :            :             ShareUpdateExclusiveLock    /* since it applies only to later
     173                 :            :                                          * inserts */
     174                 :            :         },
     175                 :            :         HASH_DEFAULT_FILLFACTOR, HASH_MIN_FILLFACTOR, 100
     176                 :            :     },
     177                 :            :     {
     178                 :            :         {
     179                 :            :             "fillfactor",
     180                 :            :             "Packs gist index pages only to this percentage",
     181                 :            :             RELOPT_KIND_GIST,
     182                 :            :             ShareUpdateExclusiveLock    /* since it applies only to later
     183                 :            :                                          * inserts */
     184                 :            :         },
     185                 :            :         GIST_DEFAULT_FILLFACTOR, GIST_MIN_FILLFACTOR, 100
     186                 :            :     },
     187                 :            :     {
     188                 :            :         {
     189                 :            :             "fillfactor",
     190                 :            :             "Packs spgist index pages only to this percentage",
     191                 :            :             RELOPT_KIND_SPGIST,
     192                 :            :             ShareUpdateExclusiveLock    /* since it applies only to later
     193                 :            :                                          * inserts */
     194                 :            :         },
     195                 :            :         SPGIST_DEFAULT_FILLFACTOR, SPGIST_MIN_FILLFACTOR, 100
     196                 :            :     },
     197                 :            :     {
     198                 :            :         {
     199                 :            :             "autovacuum_vacuum_threshold",
     200                 :            :             "Minimum number of tuple updates or deletes prior to vacuum",
     201                 :            :             RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
     202                 :            :             ShareUpdateExclusiveLock
     203                 :            :         },
     204                 :            :         -1, 0, INT_MAX
     205                 :            :     },
     206                 :            :     {
     207                 :            :         {
     208                 :            :             "autovacuum_analyze_threshold",
     209                 :            :             "Minimum number of tuple inserts, updates or deletes prior to analyze",
     210                 :            :             RELOPT_KIND_HEAP,
     211                 :            :             ShareUpdateExclusiveLock
     212                 :            :         },
     213                 :            :         -1, 0, INT_MAX
     214                 :            :     },
     215                 :            :     {
     216                 :            :         {
     217                 :            :             "autovacuum_vacuum_cost_delay",
     218                 :            :             "Vacuum cost delay in milliseconds, for autovacuum",
     219                 :            :             RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
     220                 :            :             ShareUpdateExclusiveLock
     221                 :            :         },
     222                 :            :         -1, 0, 100
     223                 :            :     },
     224                 :            :     {
     225                 :            :         {
     226                 :            :             "autovacuum_vacuum_cost_limit",
     227                 :            :             "Vacuum cost amount available before napping, for autovacuum",
     228                 :            :             RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
     229                 :            :             ShareUpdateExclusiveLock
     230                 :            :         },
     231                 :            :         -1, 1, 10000
     232                 :            :     },
     233                 :            :     {
     234                 :            :         {
     235                 :            :             "autovacuum_freeze_min_age",
     236                 :            :             "Minimum age at which VACUUM should freeze a table row, for autovacuum",
     237                 :            :             RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
     238                 :            :             ShareUpdateExclusiveLock
     239                 :            :         },
     240                 :            :         -1, 0, 1000000000
     241                 :            :     },
     242                 :            :     {
     243                 :            :         {
     244                 :            :             "autovacuum_multixact_freeze_min_age",
     245                 :            :             "Minimum multixact age at which VACUUM should freeze a row multixact's, for autovacuum",
     246                 :            :             RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
     247                 :            :             ShareUpdateExclusiveLock
     248                 :            :         },
     249                 :            :         -1, 0, 1000000000
     250                 :            :     },
     251                 :            :     {
     252                 :            :         {
     253                 :            :             "autovacuum_freeze_max_age",
     254                 :            :             "Age at which to autovacuum a table to prevent transaction ID wraparound",
     255                 :            :             RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
     256                 :            :             ShareUpdateExclusiveLock
     257                 :            :         },
     258                 :            :         -1, 100000, 2000000000
     259                 :            :     },
     260                 :            :     {
     261                 :            :         {
     262                 :            :             "autovacuum_multixact_freeze_max_age",
     263                 :            :             "Multixact age at which to autovacuum a table to prevent multixact wraparound",
     264                 :            :             RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
     265                 :            :             ShareUpdateExclusiveLock
     266                 :            :         },
     267                 :            :         -1, 10000, 2000000000
     268                 :            :     },
     269                 :            :     {
     270                 :            :         {
     271                 :            :             "autovacuum_freeze_table_age",
     272                 :            :             "Age at which VACUUM should perform a full table sweep to freeze row versions",
     273                 :            :             RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
     274                 :            :             ShareUpdateExclusiveLock
     275                 :            :         }, -1, 0, 2000000000
     276                 :            :     },
     277                 :            :     {
     278                 :            :         {
     279                 :            :             "autovacuum_multixact_freeze_table_age",
     280                 :            :             "Age of multixact at which VACUUM should perform a full table sweep to freeze row versions",
     281                 :            :             RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
     282                 :            :             ShareUpdateExclusiveLock
     283                 :            :         }, -1, 0, 2000000000
     284                 :            :     },
     285                 :            :     {
     286                 :            :         {
     287                 :            :             "log_autovacuum_min_duration",
     288                 :            :             "Sets the minimum execution time above which autovacuum actions will be logged",
     289                 :            :             RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
     290                 :            :             ShareUpdateExclusiveLock
     291                 :            :         },
     292                 :            :         -1, -1, INT_MAX
     293                 :            :     },
     294                 :            :     {
     295                 :            :         {
     296                 :            :             "toast_tuple_target",
     297                 :            :             "Sets the target tuple length at which external columns will be toasted",
     298                 :            :             RELOPT_KIND_HEAP,
     299                 :            :             ShareUpdateExclusiveLock
     300                 :            :         },
     301                 :            :         TOAST_TUPLE_TARGET, 128, TOAST_TUPLE_TARGET_MAIN
     302                 :            :     },
     303                 :            :     {
     304                 :            :         {
     305                 :            :             "pages_per_range",
     306                 :            :             "Number of pages that each page range covers in a BRIN index",
     307                 :            :             RELOPT_KIND_BRIN,
     308                 :            :             AccessExclusiveLock
     309                 :            :         }, 128, 1, 131072
     310                 :            :     },
     311                 :            :     {
     312                 :            :         {
     313                 :            :             "gin_pending_list_limit",
     314                 :            :             "Maximum size of the pending list for this GIN index, in kilobytes.",
     315                 :            :             RELOPT_KIND_GIN,
     316                 :            :             AccessExclusiveLock
     317                 :            :         },
     318                 :            :         -1, 64, MAX_KILOBYTES
     319                 :            :     },
     320                 :            :     {
     321                 :            :         {
     322                 :            :             "effective_io_concurrency",
     323                 :            :             "Number of simultaneous requests that can be handled efficiently by the disk subsystem.",
     324                 :            :             RELOPT_KIND_TABLESPACE,
     325                 :            :             ShareUpdateExclusiveLock
     326                 :            :         },
     327                 :            : #ifdef USE_PREFETCH
     328                 :            :         -1, 0, MAX_IO_CONCURRENCY
     329                 :            : #else
     330                 :            :         0, 0, 0
     331                 :            : #endif
     332                 :            :     },
     333                 :            :     {
     334                 :            :         {
     335                 :            :             "parallel_workers",
     336                 :            :             "Number of parallel processes that can be used per executor node for this relation.",
     337                 :            :             RELOPT_KIND_HEAP,
     338                 :            :             ShareUpdateExclusiveLock
     339                 :            :         },
     340                 :            :         -1, 0, 1024
     341                 :            :     },
     342                 :            : 
     343                 :            :     /* list terminator */
     344                 :            :     {{NULL}}
     345                 :            : };
     346                 :            : 
     347                 :            : static relopt_real realRelOpts[] =
     348                 :            : {
     349                 :            :     {
     350                 :            :         {
     351                 :            :             "autovacuum_vacuum_scale_factor",
     352                 :            :             "Number of tuple updates or deletes prior to vacuum as a fraction of reltuples",
     353                 :            :             RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
     354                 :            :             ShareUpdateExclusiveLock
     355                 :            :         },
     356                 :            :         -1, 0.0, 100.0
     357                 :            :     },
     358                 :            :     {
     359                 :            :         {
     360                 :            :             "autovacuum_analyze_scale_factor",
     361                 :            :             "Number of tuple inserts, updates or deletes prior to analyze as a fraction of reltuples",
     362                 :            :             RELOPT_KIND_HEAP,
     363                 :            :             ShareUpdateExclusiveLock
     364                 :            :         },
     365                 :            :         -1, 0.0, 100.0
     366                 :            :     },
     367                 :            :     {
     368                 :            :         {
     369                 :            :             "seq_page_cost",
     370                 :            :             "Sets the planner's estimate of the cost of a sequentially fetched disk page.",
     371                 :            :             RELOPT_KIND_TABLESPACE,
     372                 :            :             ShareUpdateExclusiveLock
     373                 :            :         },
     374                 :            :         -1, 0.0, DBL_MAX
     375                 :            :     },
     376                 :            :     {
     377                 :            :         {
     378                 :            :             "random_page_cost",
     379                 :            :             "Sets the planner's estimate of the cost of a nonsequentially fetched disk page.",
     380                 :            :             RELOPT_KIND_TABLESPACE,
     381                 :            :             ShareUpdateExclusiveLock
     382                 :            :         },
     383                 :            :         -1, 0.0, DBL_MAX
     384                 :            :     },
     385                 :            :     {
     386                 :            :         {
     387                 :            :             "n_distinct",
     388                 :            :             "Sets the planner's estimate of the number of distinct values appearing in a column (excluding child relations).",
     389                 :            :             RELOPT_KIND_ATTRIBUTE,
     390                 :            :             ShareUpdateExclusiveLock
     391                 :            :         },
     392                 :            :         0, -1.0, DBL_MAX
     393                 :            :     },
     394                 :            :     {
     395                 :            :         {
     396                 :            :             "n_distinct_inherited",
     397                 :            :             "Sets the planner's estimate of the number of distinct values appearing in a column (including child relations).",
     398                 :            :             RELOPT_KIND_ATTRIBUTE,
     399                 :            :             ShareUpdateExclusiveLock
     400                 :            :         },
     401                 :            :         0, -1.0, DBL_MAX
     402                 :            :     },
     403                 :            :     /* list terminator */
     404                 :            :     {{NULL}}
     405                 :            : };
     406                 :            : 
     407                 :            : static relopt_string stringRelOpts[] =
     408                 :            : {
     409                 :            :     {
     410                 :            :         {
     411                 :            :             "buffering",
     412                 :            :             "Enables buffering build for this GiST index",
     413                 :            :             RELOPT_KIND_GIST,
     414                 :            :             AccessExclusiveLock
     415                 :            :         },
     416                 :            :         4,
     417                 :            :         false,
     418                 :            :         gistValidateBufferingOption,
     419                 :            :         "auto"
     420                 :            :     },
     421                 :            :     {
     422                 :            :         {
     423                 :            :             "check_option",
     424                 :            :             "View has WITH CHECK OPTION defined (local or cascaded).",
     425                 :            :             RELOPT_KIND_VIEW,
     426                 :            :             AccessExclusiveLock
     427                 :            :         },
     428                 :            :         0,
     429                 :            :         true,
     430                 :            :         validateWithCheckOption,
     431                 :            :         NULL
     432                 :            :     },
     433                 :            :     /* list terminator */
     434                 :            :     {{NULL}}
     435                 :            : };
     436                 :            : 
     437                 :            : static relopt_gen **relOpts = NULL;
     438                 :            : static bits32 last_assigned_kind = RELOPT_KIND_LAST_DEFAULT;
     439                 :            : 
     440                 :            : static int  num_custom_options = 0;
     441                 :            : static relopt_gen **custom_options = NULL;
     442                 :            : static bool need_initialization = true;
     443                 :            : 
     444                 :            : static void initialize_reloptions(void);
     445                 :            : static void parse_one_reloption(relopt_value *option, char *text_str,
     446                 :            :                     int text_len, bool validate);
     447                 :            : 
     448                 :            : /*
     449                 :            :  * initialize_reloptions
     450                 :            :  *      initialization routine, must be called before parsing
     451                 :            :  *
     452                 :            :  * Initialize the relOpts array and fill each variable's type and name length.
     453                 :            :  */
     454                 :            : static void
     455                 :       2452 : initialize_reloptions(void)
     456                 :            : {
     457                 :            :     int         i;
     458                 :            :     int         j;
     459                 :            : 
     460                 :       2452 :     j = 0;
     461         [ +  + ]:      14712 :     for (i = 0; boolRelOpts[i].gen.name; i++)
     462                 :            :     {
     463                 :            :         Assert(DoLockModesConflict(boolRelOpts[i].gen.lockmode,
     464                 :            :                                    boolRelOpts[i].gen.lockmode));
     465                 :      12260 :         j++;
     466                 :            :     }
     467         [ +  + ]:      53944 :     for (i = 0; intRelOpts[i].gen.name; i++)
     468                 :            :     {
     469                 :            :         Assert(DoLockModesConflict(intRelOpts[i].gen.lockmode,
     470                 :            :                                    intRelOpts[i].gen.lockmode));
     471                 :      51492 :         j++;
     472                 :            :     }
     473         [ +  + ]:      17164 :     for (i = 0; realRelOpts[i].gen.name; i++)
     474                 :            :     {
     475                 :            :         Assert(DoLockModesConflict(realRelOpts[i].gen.lockmode,
     476                 :            :                                    realRelOpts[i].gen.lockmode));
     477                 :      14712 :         j++;
     478                 :            :     }
     479         [ +  + ]:       7356 :     for (i = 0; stringRelOpts[i].gen.name; i++)
     480                 :            :     {
     481                 :            :         Assert(DoLockModesConflict(stringRelOpts[i].gen.lockmode,
     482                 :            :                                    stringRelOpts[i].gen.lockmode));
     483                 :       4904 :         j++;
     484                 :            :     }
     485                 :       2452 :     j += num_custom_options;
     486                 :            : 
     487         [ -  + ]:       2452 :     if (relOpts)
     488                 :          0 :         pfree(relOpts);
     489                 :       2452 :     relOpts = MemoryContextAlloc(TopMemoryContext,
     490                 :       2452 :                                  (j + 1) * sizeof(relopt_gen *));
     491                 :            : 
     492                 :       2452 :     j = 0;
     493         [ +  + ]:      14712 :     for (i = 0; boolRelOpts[i].gen.name; i++)
     494                 :            :     {
     495                 :      12260 :         relOpts[j] = &boolRelOpts[i].gen;
     496                 :      12260 :         relOpts[j]->type = RELOPT_TYPE_BOOL;
     497                 :      12260 :         relOpts[j]->namelen = strlen(relOpts[j]->name);
     498                 :      12260 :         j++;
     499                 :            :     }
     500                 :            : 
     501         [ +  + ]:      53944 :     for (i = 0; intRelOpts[i].gen.name; i++)
     502                 :            :     {
     503                 :      51492 :         relOpts[j] = &intRelOpts[i].gen;
     504                 :      51492 :         relOpts[j]->type = RELOPT_TYPE_INT;
     505                 :      51492 :         relOpts[j]->namelen = strlen(relOpts[j]->name);
     506                 :      51492 :         j++;
     507                 :            :     }
     508                 :            : 
     509         [ +  + ]:      17164 :     for (i = 0; realRelOpts[i].gen.name; i++)
     510                 :            :     {
     511                 :      14712 :         relOpts[j] = &realRelOpts[i].gen;
     512                 :      14712 :         relOpts[j]->type = RELOPT_TYPE_REAL;
     513                 :      14712 :         relOpts[j]->namelen = strlen(relOpts[j]->name);
     514                 :      14712 :         j++;
     515                 :            :     }
     516                 :            : 
     517         [ +  + ]:       7356 :     for (i = 0; stringRelOpts[i].gen.name; i++)
     518                 :            :     {
     519                 :       4904 :         relOpts[j] = &stringRelOpts[i].gen;
     520                 :       4904 :         relOpts[j]->type = RELOPT_TYPE_STRING;
     521                 :       4904 :         relOpts[j]->namelen = strlen(relOpts[j]->name);
     522                 :       4904 :         j++;
     523                 :            :     }
     524                 :            : 
     525         [ +  + ]:       2518 :     for (i = 0; i < num_custom_options; i++)
     526                 :            :     {
     527                 :         66 :         relOpts[j] = custom_options[i];
     528                 :         66 :         j++;
     529                 :            :     }
     530                 :            : 
     531                 :            :     /* add a list terminator */
     532                 :       2452 :     relOpts[j] = NULL;
     533                 :            : 
     534                 :            :     /* flag the work is complete */
     535                 :       2452 :     need_initialization = false;
     536                 :       2452 : }
     537                 :            : 
     538                 :            : /*
     539                 :            :  * add_reloption_kind
     540                 :            :  *      Create a new relopt_kind value, to be used in custom reloptions by
     541                 :            :  *      user-defined AMs.
     542                 :            :  */
     543                 :            : relopt_kind
     544                 :          2 : add_reloption_kind(void)
     545                 :            : {
     546                 :            :     /* don't hand out the last bit so that the enum's behavior is portable */
     547         [ -  + ]:          2 :     if (last_assigned_kind >= RELOPT_KIND_MAX)
     548         [ #  # ]:          0 :         ereport(ERROR,
     549                 :            :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     550                 :            :                  errmsg("user-defined relation parameter types limit exceeded")));
     551                 :          2 :     last_assigned_kind <<= 1;
     552                 :          2 :     return (relopt_kind) last_assigned_kind;
     553                 :            : }
     554                 :            : 
     555                 :            : /*
     556                 :            :  * add_reloption
     557                 :            :  *      Add an already-created custom reloption to the list, and recompute the
     558                 :            :  *      main parser table.
     559                 :            :  */
     560                 :            : static void
     561                 :         66 : add_reloption(relopt_gen *newoption)
     562                 :            : {
     563                 :            :     static int  max_custom_options = 0;
     564                 :            : 
     565         [ +  + ]:         66 :     if (num_custom_options >= max_custom_options)
     566                 :            :     {
     567                 :            :         MemoryContext oldcxt;
     568                 :            : 
     569                 :          8 :         oldcxt = MemoryContextSwitchTo(TopMemoryContext);
     570                 :            : 
     571         [ +  + ]:          8 :         if (max_custom_options == 0)
     572                 :            :         {
     573                 :          2 :             max_custom_options = 8;
     574                 :          2 :             custom_options = palloc(max_custom_options * sizeof(relopt_gen *));
     575                 :            :         }
     576                 :            :         else
     577                 :            :         {
     578                 :          6 :             max_custom_options *= 2;
     579                 :          6 :             custom_options = repalloc(custom_options,
     580                 :            :                                       max_custom_options * sizeof(relopt_gen *));
     581                 :            :         }
     582                 :          8 :         MemoryContextSwitchTo(oldcxt);
     583                 :            :     }
     584                 :         66 :     custom_options[num_custom_options++] = newoption;
     585                 :            : 
     586                 :         66 :     need_initialization = true;
     587                 :         66 : }
     588                 :            : 
     589                 :            : /*
     590                 :            :  * allocate_reloption
     591                 :            :  *      Allocate a new reloption and initialize the type-agnostic fields
     592                 :            :  *      (for types other than string)
     593                 :            :  */
     594                 :            : static relopt_gen *
     595                 :         66 : allocate_reloption(bits32 kinds, int type, const char *name, const char *desc)
     596                 :            : {
     597                 :            :     MemoryContext oldcxt;
     598                 :            :     size_t      size;
     599                 :            :     relopt_gen *newoption;
     600                 :            : 
     601                 :         66 :     oldcxt = MemoryContextSwitchTo(TopMemoryContext);
     602                 :            : 
     603   [ -  +  -  -  :         66 :     switch (type)
                      - ]
     604                 :            :     {
     605                 :            :         case RELOPT_TYPE_BOOL:
     606                 :          0 :             size = sizeof(relopt_bool);
     607                 :          0 :             break;
     608                 :            :         case RELOPT_TYPE_INT:
     609                 :         66 :             size = sizeof(relopt_int);
     610                 :         66 :             break;
     611                 :            :         case RELOPT_TYPE_REAL:
     612                 :          0 :             size = sizeof(relopt_real);
     613                 :          0 :             break;
     614                 :            :         case RELOPT_TYPE_STRING:
     615                 :          0 :             size = sizeof(relopt_string);
     616                 :          0 :             break;
     617                 :            :         default:
     618                 :          0 :             elog(ERROR, "unsupported reloption type %d", type);
     619                 :            :             return NULL;        /* keep compiler quiet */
     620                 :            :     }
     621                 :            : 
     622                 :         66 :     newoption = palloc(size);
     623                 :            : 
     624                 :         66 :     newoption->name = pstrdup(name);
     625         [ +  - ]:         66 :     if (desc)
     626                 :         66 :         newoption->desc = pstrdup(desc);
     627                 :            :     else
     628                 :          0 :         newoption->desc = NULL;
     629                 :         66 :     newoption->kinds = kinds;
     630                 :         66 :     newoption->namelen = strlen(name);
     631                 :         66 :     newoption->type = type;
     632                 :            : 
     633                 :         66 :     MemoryContextSwitchTo(oldcxt);
     634                 :            : 
     635                 :         66 :     return newoption;
     636                 :            : }
     637                 :            : 
     638                 :            : /*
     639                 :            :  * add_bool_reloption
     640                 :            :  *      Add a new boolean reloption
     641                 :            :  */
     642                 :            : void
     643                 :          0 : add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val)
     644                 :            : {
     645                 :            :     relopt_bool *newoption;
     646                 :            : 
     647                 :          0 :     newoption = (relopt_bool *) allocate_reloption(kinds, RELOPT_TYPE_BOOL,
     648                 :            :                                                    name, desc);
     649                 :          0 :     newoption->default_val = default_val;
     650                 :            : 
     651                 :          0 :     add_reloption((relopt_gen *) newoption);
     652                 :          0 : }
     653                 :            : 
     654                 :            : /*
     655                 :            :  * add_int_reloption
     656                 :            :  *      Add a new integer reloption
     657                 :            :  */
     658                 :            : void
     659                 :         66 : add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val,
     660                 :            :                   int min_val, int max_val)
     661                 :            : {
     662                 :            :     relopt_int *newoption;
     663                 :            : 
     664                 :         66 :     newoption = (relopt_int *) allocate_reloption(kinds, RELOPT_TYPE_INT,
     665                 :            :                                                   name, desc);
     666                 :         66 :     newoption->default_val = default_val;
     667                 :         66 :     newoption->min = min_val;
     668                 :         66 :     newoption->max = max_val;
     669                 :            : 
     670                 :         66 :     add_reloption((relopt_gen *) newoption);
     671                 :         66 : }
     672                 :            : 
     673                 :            : /*
     674                 :            :  * add_real_reloption
     675                 :            :  *      Add a new float reloption
     676                 :            :  */
     677                 :            : void
     678                 :          0 : add_real_reloption(bits32 kinds, const char *name, const char *desc, double default_val,
     679                 :            :                    double min_val, double max_val)
     680                 :            : {
     681                 :            :     relopt_real *newoption;
     682                 :            : 
     683                 :          0 :     newoption = (relopt_real *) allocate_reloption(kinds, RELOPT_TYPE_REAL,
     684                 :            :                                                    name, desc);
     685                 :          0 :     newoption->default_val = default_val;
     686                 :          0 :     newoption->min = min_val;
     687                 :          0 :     newoption->max = max_val;
     688                 :            : 
     689                 :          0 :     add_reloption((relopt_gen *) newoption);
     690                 :          0 : }
     691                 :            : 
     692                 :            : /*
     693                 :            :  * add_string_reloption
     694                 :            :  *      Add a new string reloption
     695                 :            :  *
     696                 :            :  * "validator" is an optional function pointer that can be used to test the
     697                 :            :  * validity of the values.  It must elog(ERROR) when the argument string is
     698                 :            :  * not acceptable for the variable.  Note that the default value must pass
     699                 :            :  * the validation.
     700                 :            :  */
     701                 :            : void
     702                 :          0 : add_string_reloption(bits32 kinds, const char *name, const char *desc, const char *default_val,
     703                 :            :                      validate_string_relopt validator)
     704                 :            : {
     705                 :            :     relopt_string *newoption;
     706                 :            : 
     707                 :            :     /* make sure the validator/default combination is sane */
     708         [ #  # ]:          0 :     if (validator)
     709                 :          0 :         (validator) (default_val);
     710                 :            : 
     711                 :          0 :     newoption = (relopt_string *) allocate_reloption(kinds, RELOPT_TYPE_STRING,
     712                 :            :                                                      name, desc);
     713                 :          0 :     newoption->validate_cb = validator;
     714         [ #  # ]:          0 :     if (default_val)
     715                 :            :     {
     716                 :          0 :         newoption->default_val = MemoryContextStrdup(TopMemoryContext,
     717                 :            :                                                      default_val);
     718                 :          0 :         newoption->default_len = strlen(default_val);
     719                 :          0 :         newoption->default_isnull = false;
     720                 :            :     }
     721                 :            :     else
     722                 :            :     {
     723                 :          0 :         newoption->default_val = "";
     724                 :          0 :         newoption->default_len = 0;
     725                 :          0 :         newoption->default_isnull = true;
     726                 :            :     }
     727                 :            : 
     728                 :          0 :     add_reloption((relopt_gen *) newoption);
     729                 :          0 : }
     730                 :            : 
     731                 :            : /*
     732                 :            :  * Transform a relation options list (list of DefElem) into the text array
     733                 :            :  * format that is kept in pg_class.reloptions, including only those options
     734                 :            :  * that are in the passed namespace.  The output values do not include the
     735                 :            :  * namespace.
     736                 :            :  *
     737                 :            :  * This is used for three cases: CREATE TABLE/INDEX, ALTER TABLE SET, and
     738                 :            :  * ALTER TABLE RESET.  In the ALTER cases, oldOptions is the existing
     739                 :            :  * reloptions value (possibly NULL), and we replace or remove entries
     740                 :            :  * as needed.
     741                 :            :  *
     742                 :            :  * If ignoreOids is true, then we should ignore any occurrence of "oids"
     743                 :            :  * in the list (it will be or has been handled by interpretOidsOption()).
     744                 :            :  *
     745                 :            :  * Note that this is not responsible for determining whether the options
     746                 :            :  * are valid, but it does check that namespaces for all the options given are
     747                 :            :  * listed in validnsps.  The NULL namespace is always valid and need not be
     748                 :            :  * explicitly listed.  Passing a NULL pointer means that only the NULL
     749                 :            :  * namespace is valid.
     750                 :            :  *
     751                 :            :  * Both oldOptions and the result are text arrays (or NULL for "default"),
     752                 :            :  * but we declare them as Datums to avoid including array.h in reloptions.h.
     753                 :            :  */
     754                 :            : Datum
     755                 :      98400 : transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
     756                 :            :                     char *validnsps[], bool ignoreOids, bool isReset)
     757                 :            : {
     758                 :            :     Datum       result;
     759                 :            :     ArrayBuildState *astate;
     760                 :            :     ListCell   *cell;
     761                 :            : 
     762                 :            :     /* no change if empty list */
     763         [ +  + ]:      98400 :     if (defList == NIL)
     764                 :      92280 :         return oldOptions;
     765                 :            : 
     766                 :            :     /* We build new array using accumArrayResult */
     767                 :       6120 :     astate = NULL;
     768                 :            : 
     769                 :            :     /* Copy any oldOptions that aren't to be replaced */
     770         [ +  + ]:       6120 :     if (PointerIsValid(DatumGetPointer(oldOptions)))
     771                 :            :     {
     772                 :        100 :         ArrayType  *array = DatumGetArrayTypeP(oldOptions);
     773                 :            :         Datum      *oldoptions;
     774                 :            :         int         noldoptions;
     775                 :            :         int         i;
     776                 :            : 
     777                 :        100 :         deconstruct_array(array, TEXTOID, -1, false, 'i',
     778                 :            :                           &oldoptions, NULL, &noldoptions);
     779                 :            : 
     780         [ +  + ]:        248 :         for (i = 0; i < noldoptions; i++)
     781                 :            :         {
     782                 :        148 :             char       *text_str = VARDATA(oldoptions[i]);
     783                 :        148 :             int         text_len = VARSIZE(oldoptions[i]) - VARHDRSZ;
     784                 :            : 
     785                 :            :             /* Search for a match in defList */
     786         [ +  + ]:        224 :             foreach(cell, defList)
     787                 :            :             {
     788                 :        176 :                 DefElem    *def = (DefElem *) lfirst(cell);
     789                 :            :                 int         kw_len;
     790                 :            : 
     791                 :            :                 /* ignore if not in the same namespace */
     792         [ +  + ]:        176 :                 if (namspace == NULL)
     793                 :            :                 {
     794         [ -  + ]:        156 :                     if (def->defnamespace != NULL)
     795                 :          0 :                         continue;
     796                 :            :                 }
     797         [ +  + ]:         20 :                 else if (def->defnamespace == NULL)
     798                 :         12 :                     continue;
     799         [ -  + ]:          8 :                 else if (pg_strcasecmp(def->defnamespace, namspace) != 0)
     800                 :          0 :                     continue;
     801                 :            : 
     802                 :        164 :                 kw_len = strlen(def->defname);
     803         [ +  + ]:        264 :                 if (text_len > kw_len && text_str[kw_len] == '=' &&
           [ +  +  +  - ]
     804                 :        100 :                     pg_strncasecmp(text_str, def->defname, kw_len) == 0)
     805                 :        100 :                     break;
     806                 :            :             }
     807         [ +  + ]:        148 :             if (!cell)
     808                 :            :             {
     809                 :            :                 /* No match, so keep old option */
     810                 :         48 :                 astate = accumArrayResult(astate, oldoptions[i],
     811                 :            :                                           false, TEXTOID,
     812                 :            :                                           CurrentMemoryContext);
     813                 :            :             }
     814                 :            :         }
     815                 :            :     }
     816                 :            : 
     817                 :            :     /*
     818                 :            :      * If CREATE/SET, add new options to array; if RESET, just check that the
     819                 :            :      * user didn't say RESET (option=val).  (Must do this because the grammar
     820                 :            :      * doesn't enforce it.)
     821                 :            :      */
     822         [ +  + ]:      12370 :     foreach(cell, defList)
     823                 :            :     {
     824                 :       6266 :         DefElem    *def = (DefElem *) lfirst(cell);
     825                 :            : 
     826         [ +  + ]:       6266 :         if (isReset)
     827                 :            :         {
     828         [ +  + ]:         80 :             if (def->arg != NULL)
     829         [ +  - ]:          8 :                 ereport(ERROR,
     830                 :            :                         (errcode(ERRCODE_SYNTAX_ERROR),
     831                 :            :                          errmsg("RESET must not include values for parameters")));
     832                 :            :         }
     833                 :            :         else
     834                 :            :         {
     835                 :            :             text       *t;
     836                 :            :             const char *value;
     837                 :            :             Size        len;
     838                 :            : 
     839                 :            :             /*
     840                 :            :              * Error out if the namespace is not valid.  A NULL namespace is
     841                 :            :              * always valid.
     842                 :            :              */
     843         [ +  + ]:       6186 :             if (def->defnamespace != NULL)
     844                 :            :             {
     845                 :         52 :                 bool        valid = false;
     846                 :            :                 int         i;
     847                 :            : 
     848         [ +  + ]:         52 :                 if (validnsps)
     849                 :            :                 {
     850         [ +  + ]:         52 :                     for (i = 0; validnsps[i]; i++)
     851                 :            :                     {
     852         [ +  + ]:         48 :                         if (pg_strcasecmp(def->defnamespace,
     853                 :         48 :                                           validnsps[i]) == 0)
     854                 :            :                         {
     855                 :         44 :                             valid = true;
     856                 :         44 :                             break;
     857                 :            :                         }
     858                 :            :                     }
     859                 :            :                 }
     860                 :            : 
     861         [ +  + ]:         52 :                 if (!valid)
     862         [ +  - ]:          8 :                     ereport(ERROR,
     863                 :            :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     864                 :            :                              errmsg("unrecognized parameter namespace \"%s\"",
     865                 :            :                                     def->defnamespace)));
     866                 :            :             }
     867                 :            : 
     868 [ +  + ][ +  + ]:       6178 :             if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0)
     869                 :       5108 :                 continue;
     870                 :            : 
     871                 :            :             /* ignore if not in the same namespace */
     872         [ +  + ]:       1070 :             if (namspace == NULL)
     873                 :            :             {
     874         [ +  + ]:        930 :                 if (def->defnamespace != NULL)
     875                 :         22 :                     continue;
     876                 :            :             }
     877         [ +  + ]:        140 :             else if (def->defnamespace == NULL)
     878                 :        118 :                 continue;
     879         [ -  + ]:         22 :             else if (pg_strcasecmp(def->defnamespace, namspace) != 0)
     880                 :          0 :                 continue;
     881                 :            : 
     882                 :            :             /*
     883                 :            :              * Flatten the DefElem into a text string like "name=arg". If we
     884                 :            :              * have just "name", assume "name=true" is meant.  Note: the
     885                 :            :              * namespace is not output.
     886                 :            :              */
     887         [ +  + ]:        930 :             if (def->arg != NULL)
     888                 :        620 :                 value = defGetString(def);
     889                 :            :             else
     890                 :        310 :                 value = "true";
     891                 :        930 :             len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
     892                 :            :             /* +1 leaves room for sprintf's trailing null */
     893                 :        930 :             t = (text *) palloc(len + 1);
     894                 :        930 :             SET_VARSIZE(t, len);
     895                 :        930 :             sprintf(VARDATA(t), "%s=%s", def->defname, value);
     896                 :            : 
     897                 :        930 :             astate = accumArrayResult(astate, PointerGetDatum(t),
     898                 :            :                                       false, TEXTOID,
     899                 :            :                                       CurrentMemoryContext);
     900                 :            :         }
     901                 :            :     }
     902                 :            : 
     903         [ +  + ]:       6104 :     if (astate)
     904                 :        868 :         result = makeArrayResult(astate, CurrentMemoryContext);
     905                 :            :     else
     906                 :       5236 :         result = (Datum) 0;
     907                 :            : 
     908                 :       6104 :     return result;
     909                 :            : }
     910                 :            : 
     911                 :            : 
     912                 :            : /*
     913                 :            :  * Convert the text-array format of reloptions into a List of DefElem.
     914                 :            :  * This is the inverse of transformRelOptions().
     915                 :            :  */
     916                 :            : List *
     917                 :      13992 : untransformRelOptions(Datum options)
     918                 :            : {
     919                 :      13992 :     List       *result = NIL;
     920                 :            :     ArrayType  *array;
     921                 :            :     Datum      *optiondatums;
     922                 :            :     int         noptions;
     923                 :            :     int         i;
     924                 :            : 
     925                 :            :     /* Nothing to do if no options */
     926         [ +  + ]:      13992 :     if (!PointerIsValid(DatumGetPointer(options)))
     927                 :        818 :         return result;
     928                 :            : 
     929                 :      13174 :     array = DatumGetArrayTypeP(options);
     930                 :            : 
     931                 :      13174 :     deconstruct_array(array, TEXTOID, -1, false, 'i',
     932                 :            :                       &optiondatums, NULL, &noptions);
     933                 :            : 
     934         [ +  + ]:      38778 :     for (i = 0; i < noptions; i++)
     935                 :            :     {
     936                 :            :         char       *s;
     937                 :            :         char       *p;
     938                 :      25604 :         Node       *val = NULL;
     939                 :            : 
     940                 :      25604 :         s = TextDatumGetCString(optiondatums[i]);
     941                 :      25604 :         p = strchr(s, '=');
     942         [ +  - ]:      25604 :         if (p)
     943                 :            :         {
     944                 :      25604 :             *p++ = '\0';
     945                 :      25604 :             val = (Node *) makeString(pstrdup(p));
     946                 :            :         }
     947                 :      25604 :         result = lappend(result, makeDefElem(pstrdup(s), val, -1));
     948                 :            :     }
     949                 :            : 
     950                 :      13992 :     return result;
     951                 :            : }
     952                 :            : 
     953                 :            : /*
     954                 :            :  * Extract and parse reloptions from a pg_class tuple.
     955                 :            :  *
     956                 :            :  * This is a low-level routine, expected to be used by relcache code and
     957                 :            :  * callers that do not have a table's relcache entry (e.g. autovacuum).  For
     958                 :            :  * other uses, consider grabbing the rd_options pointer from the relcache entry
     959                 :            :  * instead.
     960                 :            :  *
     961                 :            :  * tupdesc is pg_class' tuple descriptor.  amoptions is a pointer to the index
     962                 :            :  * AM's options parser function in the case of a tuple corresponding to an
     963                 :            :  * index, or NULL otherwise.
     964                 :            :  */
     965                 :            : bytea *
     966                 :     490264 : extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
     967                 :            :                   amoptions_function amoptions)
     968                 :            : {
     969                 :            :     bytea      *options;
     970                 :            :     bool        isnull;
     971                 :            :     Datum       datum;
     972                 :            :     Form_pg_class classForm;
     973                 :            : 
     974 [ -  + ][ #  # ]:     490264 :     datum = fastgetattr(tuple,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ +  + ]
     975                 :            :                         Anum_pg_class_reloptions,
     976                 :            :                         tupdesc,
     977                 :            :                         &isnull);
     978         [ +  + ]:     490264 :     if (isnull)
     979                 :     486752 :         return NULL;
     980                 :            : 
     981                 :       3512 :     classForm = (Form_pg_class) GETSTRUCT(tuple);
     982                 :            : 
     983                 :            :     /* Parse into appropriate format; don't error out here */
     984   [ +  +  +  -  :       3512 :     switch (classForm->relkind)
                      - ]
     985                 :            :     {
     986                 :            :         case RELKIND_RELATION:
     987                 :            :         case RELKIND_TOASTVALUE:
     988                 :            :         case RELKIND_MATVIEW:
     989                 :            :         case RELKIND_PARTITIONED_TABLE:
     990                 :       2162 :             options = heap_reloptions(classForm->relkind, datum, false);
     991                 :       2162 :             break;
     992                 :            :         case RELKIND_VIEW:
     993                 :        826 :             options = view_reloptions(datum, false);
     994                 :        826 :             break;
     995                 :            :         case RELKIND_INDEX:
     996                 :        524 :             options = index_reloptions(amoptions, datum, false);
     997                 :        524 :             break;
     998                 :            :         case RELKIND_FOREIGN_TABLE:
     999                 :          0 :             options = NULL;
    1000                 :          0 :             break;
    1001                 :            :         default:
    1002                 :            :             Assert(false);      /* can't get here */
    1003                 :          0 :             options = NULL;     /* keep compiler quiet */
    1004                 :          0 :             break;
    1005                 :            :     }
    1006                 :            : 
    1007                 :     490264 :     return options;
    1008                 :            : }
    1009                 :            : 
    1010                 :            : /*
    1011                 :            :  * Interpret reloptions that are given in text-array format.
    1012                 :            :  *
    1013                 :            :  * options is a reloption text array as constructed by transformRelOptions.
    1014                 :            :  * kind specifies the family of options to be processed.
    1015                 :            :  *
    1016                 :            :  * The return value is a relopt_value * array on which the options actually
    1017                 :            :  * set in the options array are marked with isset=true.  The length of this
    1018                 :            :  * array is returned in *numrelopts.  Options not set are also present in the
    1019                 :            :  * array; this is so that the caller can easily locate the default values.
    1020                 :            :  *
    1021                 :            :  * If there are no options of the given kind, numrelopts is set to 0 and NULL
    1022                 :            :  * is returned (unless options are illegally supplied despite none being
    1023                 :            :  * defined, in which case an error occurs).
    1024                 :            :  *
    1025                 :            :  * Note: values of type int, bool and real are allocated as part of the
    1026                 :            :  * returned array.  Values of type string are allocated separately and must
    1027                 :            :  * be freed by the caller.
    1028                 :            :  */
    1029                 :            : relopt_value *
    1030                 :      65200 : parseRelOptions(Datum options, bool validate, relopt_kind kind,
    1031                 :            :                 int *numrelopts)
    1032                 :            : {
    1033                 :      65200 :     relopt_value *reloptions = NULL;
    1034                 :      65200 :     int         numoptions = 0;
    1035                 :            :     int         i;
    1036                 :            :     int         j;
    1037                 :            : 
    1038         [ +  + ]:      65200 :     if (need_initialization)
    1039                 :       2448 :         initialize_reloptions();
    1040                 :            : 
    1041                 :            :     /* Build a list of expected options, based on kind */
    1042                 :            : 
    1043         [ +  + ]:    2283452 :     for (i = 0; relOpts[i]; i++)
    1044         [ +  + ]:    2218252 :         if (relOpts[i]->kinds & kind)
    1045                 :     531648 :             numoptions++;
    1046                 :            : 
    1047         [ +  + ]:      65200 :     if (numoptions > 0)
    1048                 :            :     {
    1049                 :      64584 :         reloptions = palloc(numoptions * sizeof(relopt_value));
    1050                 :            : 
    1051         [ +  + ]:    2261892 :         for (i = 0, j = 0; relOpts[i]; i++)
    1052                 :            :         {
    1053         [ +  + ]:    2197308 :             if (relOpts[i]->kinds & kind)
    1054                 :            :             {
    1055                 :     531648 :                 reloptions[j].gen = relOpts[i];
    1056                 :     531648 :                 reloptions[j].isset = false;
    1057                 :     531648 :                 j++;
    1058                 :            :             }
    1059                 :            :         }
    1060                 :            :     }
    1061                 :            : 
    1062                 :            :     /* Done if no options */
    1063         [ +  + ]:      65200 :     if (PointerIsValid(DatumGetPointer(options)))
    1064                 :            :     {
    1065                 :       4388 :         ArrayType  *array = DatumGetArrayTypeP(options);
    1066                 :            :         Datum      *optiondatums;
    1067                 :            :         int         noptions;
    1068                 :            : 
    1069                 :       4388 :         deconstruct_array(array, TEXTOID, -1, false, 'i',
    1070                 :            :                           &optiondatums, NULL, &noptions);
    1071                 :            : 
    1072         [ +  + ]:       9262 :         for (i = 0; i < noptions; i++)
    1073                 :            :         {
    1074                 :       5010 :             char       *text_str = VARDATA(optiondatums[i]);
    1075                 :       5010 :             int         text_len = VARSIZE(optiondatums[i]) - VARHDRSZ;
    1076                 :            :             int         j;
    1077                 :            : 
    1078                 :            :             /* Search for a match in reloptions */
    1079         [ +  + ]:      19148 :             for (j = 0; j < numoptions; j++)
    1080                 :            :             {
    1081                 :      19116 :                 int         kw_len = reloptions[j].gen->namelen;
    1082                 :            : 
    1083         [ +  + ]:      24220 :                 if (text_len > kw_len && text_str[kw_len] == '=' &&
           [ +  +  +  + ]
    1084                 :       5104 :                     pg_strncasecmp(text_str, reloptions[j].gen->name,
    1085                 :            :                                    kw_len) == 0)
    1086                 :            :                 {
    1087                 :       4978 :                     parse_one_reloption(&reloptions[j], text_str, text_len,
    1088                 :            :                                         validate);
    1089                 :       4874 :                     break;
    1090                 :            :                 }
    1091                 :            :             }
    1092                 :            : 
    1093 [ +  + ][ +  - ]:       4906 :             if (j >= numoptions && validate)
    1094                 :            :             {
    1095                 :            :                 char       *s;
    1096                 :            :                 char       *p;
    1097                 :            : 
    1098                 :         32 :                 s = TextDatumGetCString(optiondatums[i]);
    1099                 :         32 :                 p = strchr(s, '=');
    1100         [ +  - ]:         32 :                 if (p)
    1101                 :         32 :                     *p = '\0';
    1102         [ +  - ]:         32 :                 ereport(ERROR,
    1103                 :            :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1104                 :            :                          errmsg("unrecognized parameter \"%s\"", s)));
    1105                 :            :             }
    1106                 :            :         }
    1107                 :            : 
    1108                 :            :         /* It's worth avoiding memory leaks in this function */
    1109                 :       4252 :         pfree(optiondatums);
    1110         [ +  + ]:       4252 :         if (((void *) array) != DatumGetPointer(options))
    1111                 :       4252 :             pfree(array);
    1112                 :            :     }
    1113                 :            : 
    1114                 :      65064 :     *numrelopts = numoptions;
    1115                 :      65064 :     return reloptions;
    1116                 :            : }
    1117                 :            : 
    1118                 :            : /*
    1119                 :            :  * Subroutine for parseRelOptions, to parse and validate a single option's
    1120                 :            :  * value
    1121                 :            :  */
    1122                 :            : static void
    1123                 :       4978 : parse_one_reloption(relopt_value *option, char *text_str, int text_len,
    1124                 :            :                     bool validate)
    1125                 :            : {
    1126                 :            :     char       *value;
    1127                 :            :     int         value_len;
    1128                 :            :     bool        parsed;
    1129                 :       4978 :     bool        nofree = false;
    1130                 :            : 
    1131 [ +  + ][ +  - ]:       4978 :     if (option->isset && validate)
    1132         [ +  - ]:          4 :         ereport(ERROR,
    1133                 :            :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1134                 :            :                  errmsg("parameter \"%s\" specified more than once",
    1135                 :            :                         option->gen->name)));
    1136                 :            : 
    1137                 :       4974 :     value_len = text_len - option->gen->namelen - 1;
    1138                 :       4974 :     value = (char *) palloc(value_len + 1);
    1139                 :       4974 :     memcpy(value, text_str + option->gen->namelen + 1, value_len);
    1140                 :       4974 :     value[value_len] = '\0';
    1141                 :            : 
    1142   [ +  +  +  +  :       4974 :     switch (option->gen->type)
                      - ]
    1143                 :            :     {
    1144                 :            :         case RELOPT_TYPE_BOOL:
    1145                 :            :             {
    1146                 :       1580 :                 parsed = parse_bool(value, &option->values.bool_val);
    1147 [ +  + ][ +  + ]:       1580 :                 if (validate && !parsed)
    1148         [ +  - ]:         16 :                     ereport(ERROR,
    1149                 :            :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1150                 :            :                              errmsg("invalid value for boolean option \"%s\": %s",
    1151                 :            :                                     option->gen->name, value)));
    1152                 :            :             }
    1153                 :       1564 :             break;
    1154                 :            :         case RELOPT_TYPE_INT:
    1155                 :            :             {
    1156                 :       2840 :                 relopt_int *optint = (relopt_int *) option->gen;
    1157                 :            : 
    1158                 :       2840 :                 parsed = parse_int(value, &option->values.int_val, 0, NULL);
    1159 [ +  + ][ +  + ]:       2840 :                 if (validate && !parsed)
    1160         [ +  - ]:         16 :                     ereport(ERROR,
    1161                 :            :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1162                 :            :                              errmsg("invalid value for integer option \"%s\": %s",
    1163                 :            :                                     option->gen->name, value)));
    1164 [ +  + ][ +  + ]:       2824 :                 if (validate && (option->values.int_val < optint->min ||
                 [ +  + ]
    1165                 :        248 :                                  option->values.int_val > optint->max))
    1166         [ +  - ]:         44 :                     ereport(ERROR,
    1167                 :            :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1168                 :            :                              errmsg("value %s out of bounds for option \"%s\"",
    1169                 :            :                                     value, option->gen->name),
    1170                 :            :                              errdetail("Valid values are between \"%d\" and \"%d\".",
    1171                 :            :                                        optint->min, optint->max)));
    1172                 :            :             }
    1173                 :       2780 :             break;
    1174                 :            :         case RELOPT_TYPE_REAL:
    1175                 :            :             {
    1176                 :        122 :                 relopt_real *optreal = (relopt_real *) option->gen;
    1177                 :            : 
    1178                 :        122 :                 parsed = parse_real(value, &option->values.real_val);
    1179 [ +  + ][ +  + ]:        122 :                 if (validate && !parsed)
    1180         [ +  - ]:          8 :                     ereport(ERROR,
    1181                 :            :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1182                 :            :                              errmsg("invalid value for floating point option \"%s\": %s",
    1183                 :            :                                     option->gen->name, value)));
    1184 [ +  + ][ +  + ]:        114 :                 if (validate && (option->values.real_val < optreal->min ||
                 [ +  + ]
    1185                 :         70 :                                  option->values.real_val > optreal->max))
    1186         [ +  - ]:          8 :                     ereport(ERROR,
    1187                 :            :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1188                 :            :                              errmsg("value %s out of bounds for option \"%s\"",
    1189                 :            :                                     value, option->gen->name),
    1190                 :            :                              errdetail("Valid values are between \"%f\" and \"%f\".",
    1191                 :            :                                        optreal->min, optreal->max)));
    1192                 :            :             }
    1193                 :        106 :             break;
    1194                 :            :         case RELOPT_TYPE_STRING:
    1195                 :            :             {
    1196                 :        432 :                 relopt_string *optstring = (relopt_string *) option->gen;
    1197                 :            : 
    1198                 :        432 :                 option->values.string_val = value;
    1199                 :        432 :                 nofree = true;
    1200 [ +  + ][ +  - ]:        432 :                 if (validate && optstring->validate_cb)
    1201                 :        104 :                     (optstring->validate_cb) (value);
    1202                 :        424 :                 parsed = true;
    1203                 :            :             }
    1204                 :        424 :             break;
    1205                 :            :         default:
    1206                 :          0 :             elog(ERROR, "unsupported reloption type %d", option->gen->type);
    1207                 :            :             parsed = true;      /* quiet compiler */
    1208                 :            :             break;
    1209                 :            :     }
    1210                 :            : 
    1211         [ +  - ]:       4874 :     if (parsed)
    1212                 :       4874 :         option->isset = true;
    1213         [ +  + ]:       4874 :     if (!nofree)
    1214                 :       4450 :         pfree(value);
    1215                 :       4874 : }
    1216                 :            : 
    1217                 :            : /*
    1218                 :            :  * Given the result from parseRelOptions, allocate a struct that's of the
    1219                 :            :  * specified base size plus any extra space that's needed for string variables.
    1220                 :            :  *
    1221                 :            :  * "base" should be sizeof(struct) of the reloptions struct (StdRdOptions or
    1222                 :            :  * equivalent).
    1223                 :            :  */
    1224                 :            : void *
    1225                 :      64448 : allocateReloptStruct(Size base, relopt_value *options, int numoptions)
    1226                 :            : {
    1227                 :      64448 :     Size        size = base;
    1228                 :            :     int         i;
    1229                 :            : 
    1230         [ +  + ]:     594720 :     for (i = 0; i < numoptions; i++)
    1231         [ +  + ]:     530272 :         if (options[i].gen->type == RELOPT_TYPE_STRING)
    1232         [ +  + ]:      33444 :             size += GET_STRING_RELOPTION_LEN(options[i]) + 1;
    1233                 :            : 
    1234                 :      64448 :     return palloc0(size);
    1235                 :            : }
    1236                 :            : 
    1237                 :            : /*
    1238                 :            :  * Given the result of parseRelOptions and a parsing table, fill in the
    1239                 :            :  * struct (previously allocated with allocateReloptStruct) with the parsed
    1240                 :            :  * values.
    1241                 :            :  *
    1242                 :            :  * rdopts is the pointer to the allocated struct to be filled.
    1243                 :            :  * basesize is the sizeof(struct) that was passed to allocateReloptStruct.
    1244                 :            :  * options, of length numoptions, is parseRelOptions' output.
    1245                 :            :  * elems, of length numelems, is the table describing the allowed options.
    1246                 :            :  * When validate is true, it is expected that all options appear in elems.
    1247                 :            :  */
    1248                 :            : void
    1249                 :      64448 : fillRelOptions(void *rdopts, Size basesize,
    1250                 :            :                relopt_value *options, int numoptions,
    1251                 :            :                bool validate,
    1252                 :            :                const relopt_parse_elt *elems, int numelems)
    1253                 :            : {
    1254                 :            :     int         i;
    1255                 :      64448 :     int         offset = basesize;
    1256                 :            : 
    1257         [ +  + ]:     594720 :     for (i = 0; i < numoptions; i++)
    1258                 :            :     {
    1259                 :            :         int         j;
    1260                 :     530272 :         bool        found = false;
    1261                 :            : 
    1262         [ +  - ]:    4317070 :         for (j = 0; j < numelems; j++)
    1263                 :            :         {
    1264         [ +  + ]:    4317070 :             if (pg_strcasecmp(options[i].gen->name, elems[j].optname) == 0)
    1265                 :            :             {
    1266                 :            :                 relopt_string *optstring;
    1267                 :     530272 :                 char       *itempos = ((char *) rdopts) + elems[j].offset;
    1268                 :            :                 char       *string_val;
    1269                 :            : 
    1270   [ +  +  +  +  :     530272 :                 switch (options[i].gen->type)
                      - ]
    1271                 :            :                 {
    1272                 :            :                     case RELOPT_TYPE_BOOL:
    1273         [ +  + ]:      80148 :                         *(bool *) itempos = options[i].isset ?
    1274                 :       1564 :                             options[i].values.bool_val :
    1275                 :      78584 :                             ((relopt_bool *) options[i].gen)->default_val;
    1276                 :      80148 :                         break;
    1277                 :            :                     case RELOPT_TYPE_INT:
    1278                 :     740128 :                         *(int *) itempos = options[i].isset ?
    1279         [ +  + ]:     370064 :                             options[i].values.int_val :
    1280                 :     367288 :                             ((relopt_int *) options[i].gen)->default_val;
    1281                 :     370064 :                         break;
    1282                 :            :                     case RELOPT_TYPE_REAL:
    1283                 :      93232 :                         *(double *) itempos = options[i].isset ?
    1284         [ +  + ]:      46616 :                             options[i].values.real_val :
    1285                 :      46518 :                             ((relopt_real *) options[i].gen)->default_val;
    1286                 :      46616 :                         break;
    1287                 :            :                     case RELOPT_TYPE_STRING:
    1288                 :      33444 :                         optstring = (relopt_string *) options[i].gen;
    1289         [ +  + ]:      33444 :                         if (options[i].isset)
    1290                 :        424 :                             string_val = options[i].values.string_val;
    1291         [ +  + ]:      33020 :                         else if (!optstring->default_isnull)
    1292                 :         38 :                             string_val = optstring->default_val;
    1293                 :            :                         else
    1294                 :      32982 :                             string_val = NULL;
    1295                 :            : 
    1296         [ +  + ]:      33444 :                         if (string_val == NULL)
    1297                 :      32982 :                             *(int *) itempos = 0;
    1298                 :            :                         else
    1299                 :            :                         {
    1300                 :        462 :                             strcpy((char *) rdopts + offset, string_val);
    1301                 :        462 :                             *(int *) itempos = offset;
    1302                 :        462 :                             offset += strlen(string_val) + 1;
    1303                 :            :                         }
    1304                 :      33444 :                         break;
    1305                 :            :                     default:
    1306                 :          0 :                         elog(ERROR, "unsupported reloption type %d",
    1307                 :            :                              options[i].gen->type);
    1308                 :            :                         break;
    1309                 :            :                 }
    1310                 :     530272 :                 found = true;
    1311                 :     530272 :                 break;
    1312                 :            :             }
    1313                 :            :         }
    1314 [ +  + ][ -  + ]:     530272 :         if (validate && !found)
    1315                 :          0 :             elog(ERROR, "reloption \"%s\" not found in parse table",
    1316                 :            :                  options[i].gen->name);
    1317                 :            :     }
    1318                 :      64448 :     SET_VARSIZE(rdopts, offset);
    1319                 :      64448 : }
    1320                 :            : 
    1321                 :            : 
    1322                 :            : /*
    1323                 :            :  * Option parser for anything that uses StdRdOptions.
    1324                 :            :  */
    1325                 :            : bytea *
    1326                 :      31338 : default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
    1327                 :            : {
    1328                 :            :     relopt_value *options;
    1329                 :            :     StdRdOptions *rdopts;
    1330                 :            :     int         numoptions;
    1331                 :            :     static const relopt_parse_elt tab[] = {
    1332                 :            :         {"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
    1333                 :            :         {"autovacuum_enabled", RELOPT_TYPE_BOOL,
    1334                 :            :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, enabled)},
    1335                 :            :         {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,
    1336                 :            :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)},
    1337                 :            :         {"autovacuum_analyze_threshold", RELOPT_TYPE_INT,
    1338                 :            :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)},
    1339                 :            :         {"autovacuum_vacuum_cost_delay", RELOPT_TYPE_INT,
    1340                 :            :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)},
    1341                 :            :         {"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,
    1342                 :            :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)},
    1343                 :            :         {"autovacuum_freeze_min_age", RELOPT_TYPE_INT,
    1344                 :            :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_min_age)},
    1345                 :            :         {"autovacuum_freeze_max_age", RELOPT_TYPE_INT,
    1346                 :            :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_max_age)},
    1347                 :            :         {"autovacuum_freeze_table_age", RELOPT_TYPE_INT,
    1348                 :            :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_table_age)},
    1349                 :            :         {"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT,
    1350                 :            :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_min_age)},
    1351                 :            :         {"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT,
    1352                 :            :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_max_age)},
    1353                 :            :         {"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT,
    1354                 :            :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_table_age)},
    1355                 :            :         {"log_autovacuum_min_duration", RELOPT_TYPE_INT,
    1356                 :            :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, log_min_duration)},
    1357                 :            :         {"toast_tuple_target", RELOPT_TYPE_INT,
    1358                 :            :         offsetof(StdRdOptions, toast_tuple_target)},
    1359                 :            :         {"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
    1360                 :            :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_scale_factor)},
    1361                 :            :         {"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
    1362                 :            :         offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_scale_factor)},
    1363                 :            :         {"user_catalog_table", RELOPT_TYPE_BOOL,
    1364                 :            :         offsetof(StdRdOptions, user_catalog_table)},
    1365                 :            :         {"parallel_workers", RELOPT_TYPE_INT,
    1366                 :            :         offsetof(StdRdOptions, parallel_workers)}
    1367                 :            :     };
    1368                 :            : 
    1369                 :      31338 :     options = parseRelOptions(reloptions, validate, kind, &numoptions);
    1370                 :            : 
    1371                 :            :     /* if none set, we're done */
    1372         [ +  + ]:      31246 :     if (numoptions == 0)
    1373                 :        616 :         return NULL;
    1374                 :            : 
    1375                 :      30630 :     rdopts = allocateReloptStruct(sizeof(StdRdOptions), options, numoptions);
    1376                 :            : 
    1377                 :      30630 :     fillRelOptions((void *) rdopts, sizeof(StdRdOptions), options, numoptions,
    1378                 :            :                    validate, tab, lengthof(tab));
    1379                 :            : 
    1380                 :      30630 :     pfree(options);
    1381                 :            : 
    1382                 :      31246 :     return (bytea *) rdopts;
    1383                 :            : }
    1384                 :            : 
    1385                 :            : /*
    1386                 :            :  * Option parser for views
    1387                 :            :  */
    1388                 :            : bytea *
    1389                 :      33378 : view_reloptions(Datum reloptions, bool validate)
    1390                 :            : {
    1391                 :            :     relopt_value *options;
    1392                 :            :     ViewOptions *vopts;
    1393                 :            :     int         numoptions;
    1394                 :            :     static const relopt_parse_elt tab[] = {
    1395                 :            :         {"security_barrier", RELOPT_TYPE_BOOL,
    1396                 :            :         offsetof(ViewOptions, security_barrier)},
    1397                 :            :         {"check_option", RELOPT_TYPE_STRING,
    1398                 :            :         offsetof(ViewOptions, check_option_offset)}
    1399                 :            :     };
    1400                 :            : 
    1401                 :      33378 :     options = parseRelOptions(reloptions, validate, RELOPT_KIND_VIEW, &numoptions);
    1402                 :            : 
    1403                 :            :     /* if none set, we're done */
    1404         [ -  + ]:      33358 :     if (numoptions == 0)
    1405                 :          0 :         return NULL;
    1406                 :            : 
    1407                 :      33358 :     vopts = allocateReloptStruct(sizeof(ViewOptions), options, numoptions);
    1408                 :            : 
    1409                 :      33358 :     fillRelOptions((void *) vopts, sizeof(ViewOptions), options, numoptions,
    1410                 :            :                    validate, tab, lengthof(tab));
    1411                 :            : 
    1412                 :      33358 :     pfree(options);
    1413                 :            : 
    1414                 :      33358 :     return (bytea *) vopts;
    1415                 :            : }
    1416                 :            : 
    1417                 :            : /*
    1418                 :            :  * Parse options for heaps, views and toast tables.
    1419                 :            :  */
    1420                 :            : bytea *
    1421                 :      32372 : heap_reloptions(char relkind, Datum reloptions, bool validate)
    1422                 :            : {
    1423                 :            :     StdRdOptions *rdopts;
    1424                 :            : 
    1425   [ +  +  +  + ]:      32372 :     switch (relkind)
    1426                 :            :     {
    1427                 :            :         case RELKIND_TOASTVALUE:
    1428                 :      14284 :             rdopts = (StdRdOptions *)
    1429                 :      14284 :                 default_reloptions(reloptions, validate, RELOPT_KIND_TOAST);
    1430         [ +  - ]:      14280 :             if (rdopts != NULL)
    1431                 :            :             {
    1432                 :            :                 /* adjust default-only parameters for TOAST relations */
    1433                 :      14280 :                 rdopts->fillfactor = 100;
    1434                 :      14280 :                 rdopts->autovacuum.analyze_threshold = -1;
    1435                 :      14280 :                 rdopts->autovacuum.analyze_scale_factor = -1;
    1436                 :            :             }
    1437                 :      14280 :             return (bytea *) rdopts;
    1438                 :            :         case RELKIND_RELATION:
    1439                 :            :         case RELKIND_MATVIEW:
    1440                 :      16172 :             return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
    1441                 :            :         case RELKIND_PARTITIONED_TABLE:
    1442                 :        616 :             return default_reloptions(reloptions, validate,
    1443                 :            :                                       RELOPT_KIND_PARTITIONED);
    1444                 :            :         default:
    1445                 :            :             /* other relkinds are not supported */
    1446                 :       1300 :             return NULL;
    1447                 :            :     }
    1448                 :            : }
    1449                 :            : 
    1450                 :            : 
    1451                 :            : /*
    1452                 :            :  * Parse options for indexes.
    1453                 :            :  *
    1454                 :            :  *  amoptions   index AM's option parser function
    1455                 :            :  *  reloptions  options as text[] datum
    1456                 :            :  *  validate    error flag
    1457                 :            :  */
    1458                 :            : bytea *
    1459                 :      36090 : index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate)
    1460                 :            : {
    1461                 :            :     Assert(amoptions != NULL);
    1462                 :            : 
    1463                 :            :     /* Assume function is strict */
    1464         [ +  + ]:      36090 :     if (!PointerIsValid(DatumGetPointer(reloptions)))
    1465                 :      35404 :         return NULL;
    1466                 :            : 
    1467                 :        686 :     return amoptions(reloptions, validate);
    1468                 :            : }
    1469                 :            : 
    1470                 :            : /*
    1471                 :            :  * Option parser for attribute reloptions
    1472                 :            :  */
    1473                 :            : bytea *
    1474                 :         26 : attribute_reloptions(Datum reloptions, bool validate)
    1475                 :            : {
    1476                 :            :     relopt_value *options;
    1477                 :            :     AttributeOpts *aopts;
    1478                 :            :     int         numoptions;
    1479                 :            :     static const relopt_parse_elt tab[] = {
    1480                 :            :         {"n_distinct", RELOPT_TYPE_REAL, offsetof(AttributeOpts, n_distinct)},
    1481                 :            :         {"n_distinct_inherited", RELOPT_TYPE_REAL, offsetof(AttributeOpts, n_distinct_inherited)}
    1482                 :            :     };
    1483                 :            : 
    1484                 :         26 :     options = parseRelOptions(reloptions, validate, RELOPT_KIND_ATTRIBUTE,
    1485                 :            :                               &numoptions);
    1486                 :            : 
    1487                 :            :     /* if none set, we're done */
    1488         [ -  + ]:         26 :     if (numoptions == 0)
    1489                 :          0 :         return NULL;
    1490                 :            : 
    1491                 :         26 :     aopts = allocateReloptStruct(sizeof(AttributeOpts), options, numoptions);
    1492                 :            : 
    1493                 :         26 :     fillRelOptions((void *) aopts, sizeof(AttributeOpts), options, numoptions,
    1494                 :            :                    validate, tab, lengthof(tab));
    1495                 :            : 
    1496                 :         26 :     pfree(options);
    1497                 :            : 
    1498                 :         26 :     return (bytea *) aopts;
    1499                 :            : }
    1500                 :            : 
    1501                 :            : /*
    1502                 :            :  * Option parser for tablespace reloptions
    1503                 :            :  */
    1504                 :            : bytea *
    1505                 :         38 : tablespace_reloptions(Datum reloptions, bool validate)
    1506                 :            : {
    1507                 :            :     relopt_value *options;
    1508                 :            :     TableSpaceOpts *tsopts;
    1509                 :            :     int         numoptions;
    1510                 :            :     static const relopt_parse_elt tab[] = {
    1511                 :            :         {"random_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, random_page_cost)},
    1512                 :            :         {"seq_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, seq_page_cost)},
    1513                 :            :         {"effective_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, effective_io_concurrency)}
    1514                 :            :     };
    1515                 :            : 
    1516                 :         38 :     options = parseRelOptions(reloptions, validate, RELOPT_KIND_TABLESPACE,
    1517                 :            :                               &numoptions);
    1518                 :            : 
    1519                 :            :     /* if none set, we're done */
    1520         [ -  + ]:         30 :     if (numoptions == 0)
    1521                 :          0 :         return NULL;
    1522                 :            : 
    1523                 :         30 :     tsopts = allocateReloptStruct(sizeof(TableSpaceOpts), options, numoptions);
    1524                 :            : 
    1525                 :         30 :     fillRelOptions((void *) tsopts, sizeof(TableSpaceOpts), options, numoptions,
    1526                 :            :                    validate, tab, lengthof(tab));
    1527                 :            : 
    1528                 :         30 :     pfree(options);
    1529                 :            : 
    1530                 :         30 :     return (bytea *) tsopts;
    1531                 :            : }
    1532                 :            : 
    1533                 :            : /*
    1534                 :            :  * Determine the required LOCKMODE from an option list.
    1535                 :            :  *
    1536                 :            :  * Called from AlterTableGetLockLevel(), see that function
    1537                 :            :  * for a longer explanation of how this works.
    1538                 :            :  */
    1539                 :            : LOCKMODE
    1540                 :        168 : AlterTableGetRelOptionsLockLevel(List *defList)
    1541                 :            : {
    1542                 :        168 :     LOCKMODE    lockmode = NoLock;
    1543                 :            :     ListCell   *cell;
    1544                 :            : 
    1545         [ -  + ]:        168 :     if (defList == NIL)
    1546                 :          0 :         return AccessExclusiveLock;
    1547                 :            : 
    1548         [ +  + ]:        168 :     if (need_initialization)
    1549                 :          4 :         initialize_reloptions();
    1550                 :            : 
    1551         [ +  + ]:        352 :     foreach(cell, defList)
    1552                 :            :     {
    1553                 :        184 :         DefElem    *def = (DefElem *) lfirst(cell);
    1554                 :            :         int         i;
    1555                 :            : 
    1556         [ +  + ]:       6440 :         for (i = 0; relOpts[i]; i++)
    1557                 :            :         {
    1558         [ +  + ]:       6256 :             if (pg_strncasecmp(relOpts[i]->name,
    1559                 :       6256 :                                def->defname,
    1560                 :       6256 :                                relOpts[i]->namelen + 1) == 0)
    1561                 :            :             {
    1562         [ +  + ]:        376 :                 if (lockmode < relOpts[i]->lockmode)
    1563                 :        168 :                     lockmode = relOpts[i]->lockmode;
    1564                 :            :             }
    1565                 :            :         }
    1566                 :            :     }
    1567                 :            : 
    1568                 :        168 :     return lockmode;
    1569                 :            : }

Generated by: LCOV version 1.13