LCOV - code coverage report
Current view: top level - src/backend/bootstrap - bootstrap.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 293 356 82.3 %
Date: 2017-09-29 13:40:31 Functions: 18 18 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * bootstrap.c
       4             :  *    routines to support running postgres in 'bootstrap' mode
       5             :  *  bootstrap mode is used to create the initial template database
       6             :  *
       7             :  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
       8             :  * Portions Copyright (c) 1994, Regents of the University of California
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/bootstrap/bootstrap.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #include "postgres.h"
      16             : 
      17             : #include <unistd.h>
      18             : #include <signal.h>
      19             : 
      20             : #include "access/htup_details.h"
      21             : #include "access/xact.h"
      22             : #include "bootstrap/bootstrap.h"
      23             : #include "catalog/index.h"
      24             : #include "catalog/pg_collation.h"
      25             : #include "catalog/pg_type.h"
      26             : #include "libpq/pqsignal.h"
      27             : #include "miscadmin.h"
      28             : #include "nodes/makefuncs.h"
      29             : #include "pg_getopt.h"
      30             : #include "pgstat.h"
      31             : #include "postmaster/bgwriter.h"
      32             : #include "postmaster/startup.h"
      33             : #include "postmaster/walwriter.h"
      34             : #include "replication/walreceiver.h"
      35             : #include "storage/bufmgr.h"
      36             : #include "storage/bufpage.h"
      37             : #include "storage/condition_variable.h"
      38             : #include "storage/ipc.h"
      39             : #include "storage/proc.h"
      40             : #include "tcop/tcopprot.h"
      41             : #include "utils/builtins.h"
      42             : #include "utils/fmgroids.h"
      43             : #include "utils/memutils.h"
      44             : #include "utils/ps_status.h"
      45             : #include "utils/rel.h"
      46             : #include "utils/relmapper.h"
      47             : #include "utils/tqual.h"
      48             : 
      49             : uint32      bootstrap_data_checksum_version = 0;    /* No checksum */
      50             : 
      51             : 
      52             : #define ALLOC(t, c) \
      53             :     ((t *) MemoryContextAllocZero(TopMemoryContext, (unsigned)(c) * sizeof(t)))
      54             : 
      55             : static void CheckerModeMain(void);
      56             : static void BootstrapModeMain(void);
      57             : static void bootstrap_signals(void);
      58             : static void ShutdownAuxiliaryProcess(int code, Datum arg);
      59             : static Form_pg_attribute AllocateAttribute(void);
      60             : static Oid  gettype(char *type);
      61             : static void cleanup(void);
      62             : 
      63             : /* ----------------
      64             :  *      global variables
      65             :  * ----------------
      66             :  */
      67             : 
      68             : AuxProcType MyAuxProcType = NotAnAuxProcess;    /* declared in miscadmin.h */
      69             : 
      70             : Relation    boot_reldesc;       /* current relation descriptor */
      71             : 
      72             : Form_pg_attribute attrtypes[MAXATTR];   /* points to attribute info */
      73             : int         numattr;            /* number of attributes for cur. rel */
      74             : 
      75             : 
      76             : /*
      77             :  * Basic information associated with each type.  This is used before
      78             :  * pg_type is filled, so it has to cover the datatypes used as column types
      79             :  * in the core "bootstrapped" catalogs.
      80             :  *
      81             :  *      XXX several of these input/output functions do catalog scans
      82             :  *          (e.g., F_REGPROCIN scans pg_proc).  this obviously creates some
      83             :  *          order dependencies in the catalog creation process.
      84             :  */
      85             : struct typinfo
      86             : {
      87             :     char        name[NAMEDATALEN];
      88             :     Oid         oid;
      89             :     Oid         elem;
      90             :     int16       len;
      91             :     bool        byval;
      92             :     char        align;
      93             :     char        storage;
      94             :     Oid         collation;
      95             :     Oid         inproc;
      96             :     Oid         outproc;
      97             : };
      98             : 
      99             : static const struct typinfo TypInfo[] = {
     100             :     {"bool", BOOLOID, 0, 1, true, 'c', 'p', InvalidOid,
     101             :     F_BOOLIN, F_BOOLOUT},
     102             :     {"bytea", BYTEAOID, 0, -1, false, 'i', 'x', InvalidOid,
     103             :     F_BYTEAIN, F_BYTEAOUT},
     104             :     {"char", CHAROID, 0, 1, true, 'c', 'p', InvalidOid,
     105             :     F_CHARIN, F_CHAROUT},
     106             :     {"int2", INT2OID, 0, 2, true, 's', 'p', InvalidOid,
     107             :     F_INT2IN, F_INT2OUT},
     108             :     {"int4", INT4OID, 0, 4, true, 'i', 'p', InvalidOid,
     109             :     F_INT4IN, F_INT4OUT},
     110             :     {"float4", FLOAT4OID, 0, 4, FLOAT4PASSBYVAL, 'i', 'p', InvalidOid,
     111             :     F_FLOAT4IN, F_FLOAT4OUT},
     112             :     {"name", NAMEOID, CHAROID, NAMEDATALEN, false, 'c', 'p', InvalidOid,
     113             :     F_NAMEIN, F_NAMEOUT},
     114             :     {"regclass", REGCLASSOID, 0, 4, true, 'i', 'p', InvalidOid,
     115             :     F_REGCLASSIN, F_REGCLASSOUT},
     116             :     {"regproc", REGPROCOID, 0, 4, true, 'i', 'p', InvalidOid,
     117             :     F_REGPROCIN, F_REGPROCOUT},
     118             :     {"regtype", REGTYPEOID, 0, 4, true, 'i', 'p', InvalidOid,
     119             :     F_REGTYPEIN, F_REGTYPEOUT},
     120             :     {"regrole", REGROLEOID, 0, 4, true, 'i', 'p', InvalidOid,
     121             :     F_REGROLEIN, F_REGROLEOUT},
     122             :     {"regnamespace", REGNAMESPACEOID, 0, 4, true, 'i', 'p', InvalidOid,
     123             :     F_REGNAMESPACEIN, F_REGNAMESPACEOUT},
     124             :     {"text", TEXTOID, 0, -1, false, 'i', 'x', DEFAULT_COLLATION_OID,
     125             :     F_TEXTIN, F_TEXTOUT},
     126             :     {"oid", OIDOID, 0, 4, true, 'i', 'p', InvalidOid,
     127             :     F_OIDIN, F_OIDOUT},
     128             :     {"tid", TIDOID, 0, 6, false, 's', 'p', InvalidOid,
     129             :     F_TIDIN, F_TIDOUT},
     130             :     {"xid", XIDOID, 0, 4, true, 'i', 'p', InvalidOid,
     131             :     F_XIDIN, F_XIDOUT},
     132             :     {"cid", CIDOID, 0, 4, true, 'i', 'p', InvalidOid,
     133             :     F_CIDIN, F_CIDOUT},
     134             :     {"pg_node_tree", PGNODETREEOID, 0, -1, false, 'i', 'x', DEFAULT_COLLATION_OID,
     135             :     F_PG_NODE_TREE_IN, F_PG_NODE_TREE_OUT},
     136             :     {"int2vector", INT2VECTOROID, INT2OID, -1, false, 'i', 'p', InvalidOid,
     137             :     F_INT2VECTORIN, F_INT2VECTOROUT},
     138             :     {"oidvector", OIDVECTOROID, OIDOID, -1, false, 'i', 'p', InvalidOid,
     139             :     F_OIDVECTORIN, F_OIDVECTOROUT},
     140             :     {"_int4", INT4ARRAYOID, INT4OID, -1, false, 'i', 'x', InvalidOid,
     141             :     F_ARRAY_IN, F_ARRAY_OUT},
     142             :     {"_text", 1009, TEXTOID, -1, false, 'i', 'x', DEFAULT_COLLATION_OID,
     143             :     F_ARRAY_IN, F_ARRAY_OUT},
     144             :     {"_oid", 1028, OIDOID, -1, false, 'i', 'x', InvalidOid,
     145             :     F_ARRAY_IN, F_ARRAY_OUT},
     146             :     {"_char", 1002, CHAROID, -1, false, 'i', 'x', InvalidOid,
     147             :     F_ARRAY_IN, F_ARRAY_OUT},
     148             :     {"_aclitem", 1034, ACLITEMOID, -1, false, 'i', 'x', InvalidOid,
     149             :     F_ARRAY_IN, F_ARRAY_OUT}
     150             : };
     151             : 
     152             : static const int n_types = sizeof(TypInfo) / sizeof(struct typinfo);
     153             : 
     154             : struct typmap
     155             : {                               /* a hack */
     156             :     Oid         am_oid;
     157             :     FormData_pg_type am_typ;
     158             : };
     159             : 
     160             : static struct typmap **Typ = NULL;
     161             : static struct typmap *Ap = NULL;
     162             : 
     163             : static Datum values[MAXATTR];   /* current row's attribute values */
     164             : static bool Nulls[MAXATTR];
     165             : 
     166             : static MemoryContext nogc = NULL;   /* special no-gc mem context */
     167             : 
     168             : /*
     169             :  *  At bootstrap time, we first declare all the indices to be built, and
     170             :  *  then build them.  The IndexList structure stores enough information
     171             :  *  to allow us to build the indices after they've been declared.
     172             :  */
     173             : 
     174             : typedef struct _IndexList
     175             : {
     176             :     Oid         il_heap;
     177             :     Oid         il_ind;
     178             :     IndexInfo  *il_info;
     179             :     struct _IndexList *il_next;
     180             : } IndexList;
     181             : 
     182             : static IndexList *ILHead = NULL;
     183             : 
     184             : 
     185             : /*
     186             :  *   AuxiliaryProcessMain
     187             :  *
     188             :  *   The main entry point for auxiliary processes, such as the bgwriter,
     189             :  *   walwriter, walreceiver, bootstrapper and the shared memory checker code.
     190             :  *
     191             :  *   This code is here just because of historical reasons.
     192             :  */
     193             : void
     194           7 : AuxiliaryProcessMain(int argc, char *argv[])
     195             : {
     196           7 :     char       *progname = argv[0];
     197             :     int         flag;
     198           7 :     char       *userDoption = NULL;
     199             : 
     200             :     /*
     201             :      * Initialize process environment (already done if under postmaster, but
     202             :      * not if standalone).
     203             :      */
     204           7 :     if (!IsUnderPostmaster)
     205           3 :         InitStandaloneProcess(argv[0]);
     206             : 
     207             :     /*
     208             :      * process command arguments
     209             :      */
     210             : 
     211             :     /* Set defaults, to be overridden by explicit options below */
     212           7 :     if (!IsUnderPostmaster)
     213           3 :         InitializeGUCOptions();
     214             : 
     215             :     /* Ignore the initial --boot argument, if present */
     216           7 :     if (argc > 1 && strcmp(argv[1], "--boot") == 0)
     217             :     {
     218           3 :         argv++;
     219           3 :         argc--;
     220             :     }
     221             : 
     222             :     /* If no -x argument, we are a CheckerProcess */
     223           7 :     MyAuxProcType = CheckerProcess;
     224             : 
     225          30 :     while ((flag = getopt(argc, argv, "B:c:d:D:Fkr:x:-:")) != -1)
     226             :     {
     227          16 :         switch (flag)
     228             :         {
     229             :             case 'B':
     230           0 :                 SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV);
     231           0 :                 break;
     232             :             case 'D':
     233           0 :                 userDoption = pstrdup(optarg);
     234           0 :                 break;
     235             :             case 'd':
     236             :                 {
     237             :                     /* Turn on debugging for the bootstrap process. */
     238             :                     char       *debugstr;
     239             : 
     240           0 :                     debugstr = psprintf("debug%s", optarg);
     241           0 :                     SetConfigOption("log_min_messages", debugstr,
     242             :                                     PGC_POSTMASTER, PGC_S_ARGV);
     243           0 :                     SetConfigOption("client_min_messages", debugstr,
     244             :                                     PGC_POSTMASTER, PGC_S_ARGV);
     245           0 :                     pfree(debugstr);
     246             :                 }
     247           0 :                 break;
     248             :             case 'F':
     249           3 :                 SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV);
     250           3 :                 break;
     251             :             case 'k':
     252           0 :                 bootstrap_data_checksum_version = PG_DATA_CHECKSUM_VERSION;
     253           0 :                 break;
     254             :             case 'r':
     255           0 :                 strlcpy(OutputFileName, optarg, MAXPGPATH);
     256           0 :                 break;
     257             :             case 'x':
     258           7 :                 MyAuxProcType = atoi(optarg);
     259           7 :                 break;
     260             :             case 'c':
     261             :             case '-':
     262             :                 {
     263             :                     char       *name,
     264             :                                *value;
     265             : 
     266           6 :                     ParseLongOption(optarg, &name, &value);
     267           6 :                     if (!value)
     268             :                     {
     269           0 :                         if (flag == '-')
     270           0 :                             ereport(ERROR,
     271             :                                     (errcode(ERRCODE_SYNTAX_ERROR),
     272             :                                      errmsg("--%s requires a value",
     273             :                                             optarg)));
     274             :                         else
     275           0 :                             ereport(ERROR,
     276             :                                     (errcode(ERRCODE_SYNTAX_ERROR),
     277             :                                      errmsg("-c %s requires a value",
     278             :                                             optarg)));
     279             :                     }
     280             : 
     281           6 :                     SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV);
     282           6 :                     free(name);
     283           6 :                     if (value)
     284           6 :                         free(value);
     285           6 :                     break;
     286             :                 }
     287             :             default:
     288           0 :                 write_stderr("Try \"%s --help\" for more information.\n",
     289             :                              progname);
     290           0 :                 proc_exit(1);
     291             :                 break;
     292             :         }
     293             :     }
     294             : 
     295           7 :     if (argc != optind)
     296             :     {
     297           0 :         write_stderr("%s: invalid command-line arguments\n", progname);
     298           0 :         proc_exit(1);
     299             :     }
     300             : 
     301             :     /*
     302             :      * Identify myself via ps
     303             :      */
     304           7 :     if (IsUnderPostmaster)
     305             :     {
     306             :         const char *statmsg;
     307             : 
     308           4 :         switch (MyAuxProcType)
     309             :         {
     310             :             case StartupProcess:
     311           1 :                 statmsg = "startup process";
     312           1 :                 break;
     313             :             case BgWriterProcess:
     314           1 :                 statmsg = "writer process";
     315           1 :                 break;
     316             :             case CheckpointerProcess:
     317           1 :                 statmsg = "checkpointer process";
     318           1 :                 break;
     319             :             case WalWriterProcess:
     320           1 :                 statmsg = "wal writer process";
     321           1 :                 break;
     322             :             case WalReceiverProcess:
     323           0 :                 statmsg = "wal receiver process";
     324           0 :                 break;
     325             :             default:
     326           0 :                 statmsg = "??? process";
     327           0 :                 break;
     328             :         }
     329           4 :         init_ps_display(statmsg, "", "", "");
     330             :     }
     331             : 
     332             :     /* Acquire configuration parameters, unless inherited from postmaster */
     333           7 :     if (!IsUnderPostmaster)
     334             :     {
     335           3 :         if (!SelectConfigFiles(userDoption, progname))
     336           0 :             proc_exit(1);
     337             :     }
     338             : 
     339             :     /* Validate we have been given a reasonable-looking DataDir */
     340           7 :     Assert(DataDir);
     341           7 :     ValidatePgVersion(DataDir);
     342             : 
     343             :     /* Change into DataDir (if under postmaster, should be done already) */
     344           7 :     if (!IsUnderPostmaster)
     345           3 :         ChangeToDataDir();
     346             : 
     347             :     /* If standalone, create lockfile for data directory */
     348           7 :     if (!IsUnderPostmaster)
     349           3 :         CreateDataDirLockFile(false);
     350             : 
     351           7 :     SetProcessingMode(BootstrapProcessing);
     352           7 :     IgnoreSystemIndexes = true;
     353             : 
     354             :     /* Initialize MaxBackends (if under postmaster, was done already) */
     355           7 :     if (!IsUnderPostmaster)
     356           3 :         InitializeMaxBackends();
     357             : 
     358           7 :     BaseInit();
     359             : 
     360             :     /*
     361             :      * When we are an auxiliary process, we aren't going to do the full
     362             :      * InitPostgres pushups, but there are a couple of things that need to get
     363             :      * lit up even in an auxiliary process.
     364             :      */
     365           7 :     if (IsUnderPostmaster)
     366             :     {
     367             :         /*
     368             :          * Create a PGPROC so we can use LWLocks.  In the EXEC_BACKEND case,
     369             :          * this was already done by SubPostmasterMain().
     370             :          */
     371             : #ifndef EXEC_BACKEND
     372           4 :         InitAuxiliaryProcess();
     373             : #endif
     374             : 
     375             :         /*
     376             :          * Assign the ProcSignalSlot for an auxiliary process.  Since it
     377             :          * doesn't have a BackendId, the slot is statically allocated based on
     378             :          * the auxiliary process type (MyAuxProcType).  Backends use slots
     379             :          * indexed in the range from 1 to MaxBackends (inclusive), so we use
     380             :          * MaxBackends + AuxProcType + 1 as the index of the slot for an
     381             :          * auxiliary process.
     382             :          *
     383             :          * This will need rethinking if we ever want more than one of a
     384             :          * particular auxiliary process type.
     385             :          */
     386           4 :         ProcSignalInit(MaxBackends + MyAuxProcType + 1);
     387             : 
     388             :         /* finish setting up bufmgr.c */
     389           4 :         InitBufferPoolBackend();
     390             : 
     391             :         /* Initialize backend status information */
     392           4 :         pgstat_initialize();
     393           4 :         pgstat_bestart();
     394             : 
     395             :         /* register a before-shutdown callback for LWLock cleanup */
     396           4 :         before_shmem_exit(ShutdownAuxiliaryProcess, 0);
     397             :     }
     398             : 
     399             :     /*
     400             :      * XLOG operations
     401             :      */
     402           7 :     SetProcessingMode(NormalProcessing);
     403             : 
     404           7 :     switch (MyAuxProcType)
     405             :     {
     406             :         case CheckerProcess:
     407             :             /* don't set signals, they're useless here */
     408           2 :             CheckerModeMain();
     409           0 :             proc_exit(1);       /* should never return */
     410             : 
     411             :         case BootstrapProcess:
     412             : 
     413             :             /*
     414             :              * There was a brief instant during which mode was Normal; this is
     415             :              * okay.  We need to be in bootstrap mode during BootStrapXLOG for
     416             :              * the sake of multixact initialization.
     417             :              */
     418           1 :             SetProcessingMode(BootstrapProcessing);
     419           1 :             bootstrap_signals();
     420           1 :             BootStrapXLOG();
     421           1 :             BootstrapModeMain();
     422           0 :             proc_exit(1);       /* should never return */
     423             : 
     424             :         case StartupProcess:
     425             :             /* don't set signals, startup process has its own agenda */
     426           1 :             StartupProcessMain();
     427             :             proc_exit(1);       /* should never return */
     428             : 
     429             :         case BgWriterProcess:
     430             :             /* don't set signals, bgwriter has its own agenda */
     431           1 :             BackgroundWriterMain();
     432             :             proc_exit(1);       /* should never return */
     433             : 
     434             :         case CheckpointerProcess:
     435             :             /* don't set signals, checkpointer has its own agenda */
     436           1 :             CheckpointerMain();
     437             :             proc_exit(1);       /* should never return */
     438             : 
     439             :         case WalWriterProcess:
     440             :             /* don't set signals, walwriter has its own agenda */
     441           1 :             InitXLOGAccess();
     442           1 :             WalWriterMain();
     443             :             proc_exit(1);       /* should never return */
     444             : 
     445             :         case WalReceiverProcess:
     446             :             /* don't set signals, walreceiver has its own agenda */
     447           0 :             WalReceiverMain();
     448             :             proc_exit(1);       /* should never return */
     449             : 
     450             :         default:
     451           0 :             elog(PANIC, "unrecognized process type: %d", (int) MyAuxProcType);
     452             :             proc_exit(1);
     453             :     }
     454             : }
     455             : 
     456             : /*
     457             :  * In shared memory checker mode, all we really want to do is create shared
     458             :  * memory and semaphores (just to prove we can do it with the current GUC
     459             :  * settings).  Since, in fact, that was already done by BaseInit(),
     460             :  * we have nothing more to do here.
     461             :  */
     462             : static void
     463           2 : CheckerModeMain(void)
     464             : {
     465           2 :     proc_exit(0);
     466             : }
     467             : 
     468             : /*
     469             :  *   The main entry point for running the backend in bootstrap mode
     470             :  *
     471             :  *   The bootstrap mode is used to initialize the template database.
     472             :  *   The bootstrap backend doesn't speak SQL, but instead expects
     473             :  *   commands in a special bootstrap language.
     474             :  */
     475             : static void
     476           1 : BootstrapModeMain(void)
     477             : {
     478             :     int         i;
     479             : 
     480           1 :     Assert(!IsUnderPostmaster);
     481           1 :     Assert(IsBootstrapProcessingMode());
     482             : 
     483             :     /*
     484             :      * Do backend-like initialization for bootstrap mode
     485             :      */
     486           1 :     InitProcess();
     487             : 
     488           1 :     InitPostgres(NULL, InvalidOid, NULL, InvalidOid, NULL);
     489             : 
     490             :     /* Initialize stuff for bootstrap-file processing */
     491          41 :     for (i = 0; i < MAXATTR; i++)
     492             :     {
     493          40 :         attrtypes[i] = NULL;
     494          40 :         Nulls[i] = false;
     495             :     }
     496             : 
     497             :     /*
     498             :      * Process bootstrap input.
     499             :      */
     500           1 :     StartTransactionCommand();
     501           1 :     boot_yyparse();
     502           1 :     CommitTransactionCommand();
     503             : 
     504             :     /*
     505             :      * We should now know about all mapped relations, so it's okay to write
     506             :      * out the initial relation mapping files.
     507             :      */
     508           1 :     RelationMapFinishBootstrap();
     509             : 
     510             :     /* Clean up and exit */
     511           1 :     cleanup();
     512           1 :     proc_exit(0);
     513             : }
     514             : 
     515             : 
     516             : /* ----------------------------------------------------------------
     517             :  *                      misc functions
     518             :  * ----------------------------------------------------------------
     519             :  */
     520             : 
     521             : /*
     522             :  * Set up signal handling for a bootstrap process
     523             :  */
     524             : static void
     525           1 : bootstrap_signals(void)
     526             : {
     527           1 :     Assert(!IsUnderPostmaster);
     528             : 
     529             :     /* Set up appropriately for interactive use */
     530           1 :     pqsignal(SIGHUP, die);
     531           1 :     pqsignal(SIGINT, die);
     532           1 :     pqsignal(SIGTERM, die);
     533           1 :     pqsignal(SIGQUIT, die);
     534           1 : }
     535             : 
     536             : /*
     537             :  * Begin shutdown of an auxiliary process.  This is approximately the equivalent
     538             :  * of ShutdownPostgres() in postinit.c.  We can't run transactions in an
     539             :  * auxiliary process, so most of the work of AbortTransaction() is not needed,
     540             :  * but we do need to make sure we've released any LWLocks we are holding.
     541             :  * (This is only critical during an error exit.)
     542             :  */
     543             : static void
     544           4 : ShutdownAuxiliaryProcess(int code, Datum arg)
     545             : {
     546           4 :     LWLockReleaseAll();
     547           4 :     ConditionVariableCancelSleep();
     548           4 :     pgstat_report_wait_end();
     549           4 : }
     550             : 
     551             : /* ----------------------------------------------------------------
     552             :  *              MANUAL BACKEND INTERACTIVE INTERFACE COMMANDS
     553             :  * ----------------------------------------------------------------
     554             :  */
     555             : 
     556             : /* ----------------
     557             :  *      boot_openrel
     558             :  * ----------------
     559             :  */
     560             : void
     561          58 : boot_openrel(char *relname)
     562             : {
     563             :     int         i;
     564             :     struct typmap **app;
     565             :     Relation    rel;
     566             :     HeapScanDesc scan;
     567             :     HeapTuple   tup;
     568             : 
     569          58 :     if (strlen(relname) >= NAMEDATALEN)
     570           0 :         relname[NAMEDATALEN - 1] = '\0';
     571             : 
     572          58 :     if (Typ == NULL)
     573             :     {
     574             :         /* We can now load the pg_type data */
     575           1 :         rel = heap_open(TypeRelationId, NoLock);
     576           1 :         scan = heap_beginscan_catalog(rel, 0, NULL);
     577           1 :         i = 0;
     578         170 :         while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
     579         168 :             ++i;
     580           1 :         heap_endscan(scan);
     581           1 :         app = Typ = ALLOC(struct typmap *, i + 1);
     582         170 :         while (i-- > 0)
     583         168 :             *app++ = ALLOC(struct typmap, 1);
     584           1 :         *app = NULL;
     585           1 :         scan = heap_beginscan_catalog(rel, 0, NULL);
     586           1 :         app = Typ;
     587         170 :         while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
     588             :         {
     589         168 :             (*app)->am_oid = HeapTupleGetOid(tup);
     590         336 :             memcpy((char *) &(*app)->am_typ,
     591         336 :                    (char *) GETSTRUCT(tup),
     592             :                    sizeof((*app)->am_typ));
     593         168 :             app++;
     594             :         }
     595           1 :         heap_endscan(scan);
     596           1 :         heap_close(rel, NoLock);
     597             :     }
     598             : 
     599          58 :     if (boot_reldesc != NULL)
     600           0 :         closerel(NULL);
     601             : 
     602          58 :     elog(DEBUG4, "open relation %s, attrsize %d",
     603             :          relname, (int) ATTRIBUTE_FIXED_PART_SIZE);
     604             : 
     605          58 :     boot_reldesc = heap_openrv(makeRangeVar(NULL, relname, -1), NoLock);
     606          58 :     numattr = boot_reldesc->rd_rel->relnatts;
     607         459 :     for (i = 0; i < numattr; i++)
     608             :     {
     609         401 :         if (attrtypes[i] == NULL)
     610           0 :             attrtypes[i] = AllocateAttribute();
     611         401 :         memmove((char *) attrtypes[i],
     612         401 :                 (char *) TupleDescAttr(boot_reldesc->rd_att, i),
     613             :                 ATTRIBUTE_FIXED_PART_SIZE);
     614             : 
     615             :         {
     616         401 :             Form_pg_attribute at = attrtypes[i];
     617             : 
     618         401 :             elog(DEBUG4, "create attribute %d name %s len %d num %d type %u",
     619             :                  i, NameStr(at->attname), at->attlen, at->attnum,
     620             :                  at->atttypid);
     621             :         }
     622             :     }
     623          58 : }
     624             : 
     625             : /* ----------------
     626             :  *      closerel
     627             :  * ----------------
     628             :  */
     629             : void
     630          62 : closerel(char *name)
     631             : {
     632          62 :     if (name)
     633             :     {
     634          62 :         if (boot_reldesc)
     635             :         {
     636          62 :             if (strcmp(RelationGetRelationName(boot_reldesc), name) != 0)
     637           0 :                 elog(ERROR, "close of %s when %s was expected",
     638             :                      name, RelationGetRelationName(boot_reldesc));
     639             :         }
     640             :         else
     641           0 :             elog(ERROR, "close of %s before any relation was opened",
     642             :                  name);
     643             :     }
     644             : 
     645          62 :     if (boot_reldesc == NULL)
     646           0 :         elog(ERROR, "no open relation to close");
     647             :     else
     648             :     {
     649          62 :         elog(DEBUG4, "close relation %s",
     650             :              RelationGetRelationName(boot_reldesc));
     651          62 :         heap_close(boot_reldesc, NoLock);
     652          62 :         boot_reldesc = NULL;
     653             :     }
     654          62 : }
     655             : 
     656             : 
     657             : 
     658             : /* ----------------
     659             :  * DEFINEATTR()
     660             :  *
     661             :  * define a <field,type> pair
     662             :  * if there are n fields in a relation to be created, this routine
     663             :  * will be called n times
     664             :  * ----------------
     665             :  */
     666             : void
     667         515 : DefineAttr(char *name, char *type, int attnum, int nullness)
     668             : {
     669             :     Oid         typeoid;
     670             : 
     671         515 :     if (boot_reldesc != NULL)
     672             :     {
     673           0 :         elog(WARNING, "no open relations allowed with CREATE command");
     674           0 :         closerel(NULL);
     675             :     }
     676             : 
     677         515 :     if (attrtypes[attnum] == NULL)
     678          33 :         attrtypes[attnum] = AllocateAttribute();
     679         515 :     MemSet(attrtypes[attnum], 0, ATTRIBUTE_FIXED_PART_SIZE);
     680             : 
     681         515 :     namestrcpy(&attrtypes[attnum]->attname, name);
     682         515 :     elog(DEBUG4, "column %s %s", NameStr(attrtypes[attnum]->attname), type);
     683         515 :     attrtypes[attnum]->attnum = attnum + 1; /* fillatt */
     684             : 
     685         515 :     typeoid = gettype(type);
     686             : 
     687         515 :     if (Typ != NULL)
     688             :     {
     689         397 :         attrtypes[attnum]->atttypid = Ap->am_oid;
     690         397 :         attrtypes[attnum]->attlen = Ap->am_typ.typlen;
     691         397 :         attrtypes[attnum]->attbyval = Ap->am_typ.typbyval;
     692         397 :         attrtypes[attnum]->attstorage = Ap->am_typ.typstorage;
     693         397 :         attrtypes[attnum]->attalign = Ap->am_typ.typalign;
     694         397 :         attrtypes[attnum]->attcollation = Ap->am_typ.typcollation;
     695             :         /* if an array type, assume 1-dimensional attribute */
     696         397 :         if (Ap->am_typ.typelem != InvalidOid && Ap->am_typ.typlen < 0)
     697          42 :             attrtypes[attnum]->attndims = 1;
     698             :         else
     699         355 :             attrtypes[attnum]->attndims = 0;
     700             :     }
     701             :     else
     702             :     {
     703         118 :         attrtypes[attnum]->atttypid = TypInfo[typeoid].oid;
     704         118 :         attrtypes[attnum]->attlen = TypInfo[typeoid].len;
     705         118 :         attrtypes[attnum]->attbyval = TypInfo[typeoid].byval;
     706         118 :         attrtypes[attnum]->attstorage = TypInfo[typeoid].storage;
     707         118 :         attrtypes[attnum]->attalign = TypInfo[typeoid].align;
     708         118 :         attrtypes[attnum]->attcollation = TypInfo[typeoid].collation;
     709             :         /* if an array type, assume 1-dimensional attribute */
     710         135 :         if (TypInfo[typeoid].elem != InvalidOid &&
     711          17 :             attrtypes[attnum]->attlen < 0)
     712          13 :             attrtypes[attnum]->attndims = 1;
     713             :         else
     714         105 :             attrtypes[attnum]->attndims = 0;
     715             :     }
     716             : 
     717         515 :     attrtypes[attnum]->attstattarget = -1;
     718         515 :     attrtypes[attnum]->attcacheoff = -1;
     719         515 :     attrtypes[attnum]->atttypmod = -1;
     720         515 :     attrtypes[attnum]->attislocal = true;
     721             : 
     722         515 :     if (nullness == BOOTCOL_NULL_FORCE_NOT_NULL)
     723             :     {
     724          18 :         attrtypes[attnum]->attnotnull = true;
     725             :     }
     726         497 :     else if (nullness == BOOTCOL_NULL_FORCE_NULL)
     727             :     {
     728           0 :         attrtypes[attnum]->attnotnull = false;
     729             :     }
     730             :     else
     731             :     {
     732         497 :         Assert(nullness == BOOTCOL_NULL_AUTO);
     733             : 
     734             :         /*
     735             :          * Mark as "not null" if type is fixed-width and prior columns are
     736             :          * too.  This corresponds to case where column can be accessed
     737             :          * directly via C struct declaration.
     738             :          *
     739             :          * oidvector and int2vector are also treated as not-nullable, even
     740             :          * though they are no longer fixed-width.
     741             :          */
     742             : #define MARKNOTNULL(att) \
     743             :         ((att)->attlen > 0 || \
     744             :          (att)->atttypid == OIDVECTOROID || \
     745             :          (att)->atttypid == INT2VECTOROID)
     746             : 
     747         497 :         if (MARKNOTNULL(attrtypes[attnum]))
     748             :         {
     749             :             int         i;
     750             : 
     751             :             /* check earlier attributes */
     752        2828 :             for (i = 0; i < attnum; i++)
     753             :             {
     754        2409 :                 if (!attrtypes[i]->attnotnull)
     755           3 :                     break;
     756             :             }
     757         422 :             if (i == attnum)
     758         419 :                 attrtypes[attnum]->attnotnull = true;
     759             :         }
     760             :     }
     761         515 : }
     762             : 
     763             : 
     764             : /* ----------------
     765             :  *      InsertOneTuple
     766             :  *
     767             :  * If objectid is not zero, it is a specific OID to assign to the tuple.
     768             :  * Otherwise, an OID will be assigned (if necessary) by heap_insert.
     769             :  * ----------------
     770             :  */
     771             : void
     772        5738 : InsertOneTuple(Oid objectid)
     773             : {
     774             :     HeapTuple   tuple;
     775             :     TupleDesc   tupDesc;
     776             :     int         i;
     777             : 
     778        5738 :     elog(DEBUG4, "inserting row oid %u, %d columns", objectid, numattr);
     779             : 
     780        5738 :     tupDesc = CreateTupleDesc(numattr,
     781        5738 :                               RelationGetForm(boot_reldesc)->relhasoids,
     782             :                               attrtypes);
     783        5738 :     tuple = heap_form_tuple(tupDesc, values, Nulls);
     784        5738 :     if (objectid != (Oid) 0)
     785        3928 :         HeapTupleSetOid(tuple, objectid);
     786        5738 :     pfree(tupDesc);             /* just free's tupDesc, not the attrtypes */
     787             : 
     788        5738 :     simple_heap_insert(boot_reldesc, tuple);
     789        5738 :     heap_freetuple(tuple);
     790        5738 :     elog(DEBUG4, "row inserted");
     791             : 
     792             :     /*
     793             :      * Reset null markers for next tuple
     794             :      */
     795      120262 :     for (i = 0; i < numattr; i++)
     796      114524 :         Nulls[i] = false;
     797        5738 : }
     798             : 
     799             : /* ----------------
     800             :  *      InsertOneValue
     801             :  * ----------------
     802             :  */
     803             : void
     804       91074 : InsertOneValue(char *value, int i)
     805             : {
     806             :     Oid         typoid;
     807             :     int16       typlen;
     808             :     bool        typbyval;
     809             :     char        typalign;
     810             :     char        typdelim;
     811             :     Oid         typioparam;
     812             :     Oid         typinput;
     813             :     Oid         typoutput;
     814             : 
     815       91074 :     AssertArg(i >= 0 && i < MAXATTR);
     816             : 
     817       91074 :     elog(DEBUG4, "inserting column %d value \"%s\"", i, value);
     818             : 
     819       91074 :     typoid = TupleDescAttr(boot_reldesc->rd_att, i)->atttypid;
     820             : 
     821       91074 :     boot_get_type_io_data(typoid,
     822             :                           &typlen, &typbyval, &typalign,
     823             :                           &typdelim, &typioparam,
     824             :                           &typinput, &typoutput);
     825             : 
     826       91074 :     values[i] = OidInputFunctionCall(typinput, value, typioparam, -1);
     827             : 
     828             :     /*
     829             :      * We use ereport not elog here so that parameters aren't evaluated unless
     830             :      * the message is going to be printed, which generally it isn't
     831             :      */
     832       91074 :     ereport(DEBUG4,
     833             :             (errmsg_internal("inserted -> %s",
     834             :                              OidOutputFunctionCall(typoutput, values[i]))));
     835       91074 : }
     836             : 
     837             : /* ----------------
     838             :  *      InsertOneNull
     839             :  * ----------------
     840             :  */
     841             : void
     842       23450 : InsertOneNull(int i)
     843             : {
     844       23450 :     elog(DEBUG4, "inserting column %d NULL", i);
     845       23450 :     Assert(i >= 0 && i < MAXATTR);
     846       23450 :     if (TupleDescAttr(boot_reldesc->rd_att, i)->attnotnull)
     847           0 :         elog(ERROR,
     848             :              "NULL value specified for not-null column \"%s\" of relation \"%s\"",
     849             :              NameStr(TupleDescAttr(boot_reldesc->rd_att, i)->attname),
     850             :              RelationGetRelationName(boot_reldesc));
     851       23450 :     values[i] = PointerGetDatum(NULL);
     852       23450 :     Nulls[i] = true;
     853       23450 : }
     854             : 
     855             : /* ----------------
     856             :  *      cleanup
     857             :  * ----------------
     858             :  */
     859             : static void
     860           1 : cleanup(void)
     861             : {
     862           1 :     if (boot_reldesc != NULL)
     863           0 :         closerel(NULL);
     864           1 : }
     865             : 
     866             : /* ----------------
     867             :  *      gettype
     868             :  *
     869             :  * NB: this is really ugly; it will return an integer index into TypInfo[],
     870             :  * and not an OID at all, until the first reference to a type not known in
     871             :  * TypInfo[].  At that point it will read and cache pg_type in the Typ array,
     872             :  * and subsequently return a real OID (and set the global pointer Ap to
     873             :  * point at the found row in Typ).  So caller must check whether Typ is
     874             :  * still NULL to determine what the return value is!
     875             :  * ----------------
     876             :  */
     877             : static Oid
     878         515 : gettype(char *type)
     879             : {
     880             :     int         i;
     881             :     Relation    rel;
     882             :     HeapScanDesc scan;
     883             :     HeapTuple   tup;
     884             :     struct typmap **app;
     885             : 
     886         515 :     if (Typ != NULL)
     887             :     {
     888        6148 :         for (app = Typ; *app != NULL; app++)
     889             :         {
     890        6148 :             if (strncmp(NameStr((*app)->am_typ.typname), type, NAMEDATALEN) == 0)
     891             :             {
     892         397 :                 Ap = *app;
     893         397 :                 return (*app)->am_oid;
     894             :             }
     895             :         }
     896             :     }
     897             :     else
     898             :     {
     899        1052 :         for (i = 0; i < n_types; i++)
     900             :         {
     901        1052 :             if (strncmp(type, TypInfo[i].name, NAMEDATALEN) == 0)
     902         118 :                 return i;
     903             :         }
     904           0 :         elog(DEBUG4, "external type: %s", type);
     905           0 :         rel = heap_open(TypeRelationId, NoLock);
     906           0 :         scan = heap_beginscan_catalog(rel, 0, NULL);
     907           0 :         i = 0;
     908           0 :         while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
     909           0 :             ++i;
     910           0 :         heap_endscan(scan);
     911           0 :         app = Typ = ALLOC(struct typmap *, i + 1);
     912           0 :         while (i-- > 0)
     913           0 :             *app++ = ALLOC(struct typmap, 1);
     914           0 :         *app = NULL;
     915           0 :         scan = heap_beginscan_catalog(rel, 0, NULL);
     916           0 :         app = Typ;
     917           0 :         while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
     918             :         {
     919           0 :             (*app)->am_oid = HeapTupleGetOid(tup);
     920           0 :             memmove((char *) &(*app++)->am_typ,
     921           0 :                     (char *) GETSTRUCT(tup),
     922             :                     sizeof((*app)->am_typ));
     923             :         }
     924           0 :         heap_endscan(scan);
     925           0 :         heap_close(rel, NoLock);
     926           0 :         return gettype(type);
     927             :     }
     928           0 :     elog(ERROR, "unrecognized type \"%s\"", type);
     929             :     /* not reached, here to make compiler happy */
     930             :     return 0;
     931             : }
     932             : 
     933             : /* ----------------
     934             :  *      boot_get_type_io_data
     935             :  *
     936             :  * Obtain type I/O information at bootstrap time.  This intentionally has
     937             :  * almost the same API as lsyscache.c's get_type_io_data, except that
     938             :  * we only support obtaining the typinput and typoutput routines, not
     939             :  * the binary I/O routines.  It is exported so that array_in and array_out
     940             :  * can be made to work during early bootstrap.
     941             :  * ----------------
     942             :  */
     943             : void
     944       91349 : boot_get_type_io_data(Oid typid,
     945             :                       int16 *typlen,
     946             :                       bool *typbyval,
     947             :                       char *typalign,
     948             :                       char *typdelim,
     949             :                       Oid *typioparam,
     950             :                       Oid *typinput,
     951             :                       Oid *typoutput)
     952             : {
     953       91349 :     if (Typ != NULL)
     954             :     {
     955             :         /* We have the boot-time contents of pg_type, so use it */
     956             :         struct typmap **app;
     957             :         struct typmap *ap;
     958             : 
     959       24397 :         app = Typ;
     960      232383 :         while (*app && (*app)->am_oid != typid)
     961      183589 :             ++app;
     962       24397 :         ap = *app;
     963       24397 :         if (ap == NULL)
     964           0 :             elog(ERROR, "type OID %u not found in Typ list", typid);
     965             : 
     966       24397 :         *typlen = ap->am_typ.typlen;
     967       24397 :         *typbyval = ap->am_typ.typbyval;
     968       24397 :         *typalign = ap->am_typ.typalign;
     969       24397 :         *typdelim = ap->am_typ.typdelim;
     970             : 
     971             :         /* XXX this logic must match getTypeIOParam() */
     972       24397 :         if (OidIsValid(ap->am_typ.typelem))
     973        1082 :             *typioparam = ap->am_typ.typelem;
     974             :         else
     975       23315 :             *typioparam = typid;
     976             : 
     977       24397 :         *typinput = ap->am_typ.typinput;
     978       24397 :         *typoutput = ap->am_typ.typoutput;
     979             :     }
     980             :     else
     981             :     {
     982             :         /* We don't have pg_type yet, so use the hard-wired TypInfo array */
     983             :         int         typeindex;
     984             : 
     985      481894 :         for (typeindex = 0; typeindex < n_types; typeindex++)
     986             :         {
     987      481894 :             if (TypInfo[typeindex].oid == typid)
     988       66952 :                 break;
     989             :         }
     990       66952 :         if (typeindex >= n_types)
     991           0 :             elog(ERROR, "type OID %u not found in TypInfo", typid);
     992             : 
     993       66952 :         *typlen = TypInfo[typeindex].len;
     994       66952 :         *typbyval = TypInfo[typeindex].byval;
     995       66952 :         *typalign = TypInfo[typeindex].align;
     996             :         /* We assume typdelim is ',' for all boot-time types */
     997       66952 :         *typdelim = ',';
     998             : 
     999             :         /* XXX this logic must match getTypeIOParam() */
    1000       66952 :         if (OidIsValid(TypInfo[typeindex].elem))
    1001        6215 :             *typioparam = TypInfo[typeindex].elem;
    1002             :         else
    1003       60737 :             *typioparam = typid;
    1004             : 
    1005       66952 :         *typinput = TypInfo[typeindex].inproc;
    1006       66952 :         *typoutput = TypInfo[typeindex].outproc;
    1007             :     }
    1008       91349 : }
    1009             : 
    1010             : /* ----------------
    1011             :  *      AllocateAttribute
    1012             :  *
    1013             :  * Note: bootstrap never sets any per-column ACLs, so we only need
    1014             :  * ATTRIBUTE_FIXED_PART_SIZE space per attribute.
    1015             :  * ----------------
    1016             :  */
    1017             : static Form_pg_attribute
    1018          33 : AllocateAttribute(void)
    1019             : {
    1020          33 :     return (Form_pg_attribute)
    1021          33 :         MemoryContextAllocZero(TopMemoryContext, ATTRIBUTE_FIXED_PART_SIZE);
    1022             : }
    1023             : 
    1024             : /*
    1025             :  *      MapArrayTypeName
    1026             :  *
    1027             :  * Given a type name, produce the corresponding array type name by prepending
    1028             :  * '_' and truncating as needed to fit in NAMEDATALEN-1 bytes.  This is only
    1029             :  * used in bootstrap mode, so we can get away with assuming that the input is
    1030             :  * ASCII and we don't need multibyte-aware truncation.
    1031             :  *
    1032             :  * The given string normally ends with '[]' or '[digits]'; we discard that.
    1033             :  *
    1034             :  * The result is a palloc'd string.
    1035             :  */
    1036             : char *
    1037          45 : MapArrayTypeName(const char *s)
    1038             : {
    1039             :     int         i,
    1040             :                 j;
    1041             :     char        newStr[NAMEDATALEN];
    1042             : 
    1043          45 :     newStr[0] = '_';
    1044          45 :     j = 1;
    1045         269 :     for (i = 0; i < NAMEDATALEN - 2 && s[i] != '['; i++, j++)
    1046         224 :         newStr[j] = s[i];
    1047             : 
    1048          45 :     newStr[j] = '\0';
    1049             : 
    1050          45 :     return pstrdup(newStr);
    1051             : }
    1052             : 
    1053             : 
    1054             : /*
    1055             :  *  index_register() -- record an index that has been set up for building
    1056             :  *                      later.
    1057             :  *
    1058             :  *      At bootstrap time, we define a bunch of indexes on system catalogs.
    1059             :  *      We postpone actually building the indexes until just before we're
    1060             :  *      finished with initialization, however.  This is because the indexes
    1061             :  *      themselves have catalog entries, and those have to be included in the
    1062             :  *      indexes on those catalogs.  Doing it in two phases is the simplest
    1063             :  *      way of making sure the indexes have the right contents at the end.
    1064             :  */
    1065             : void
    1066         127 : index_register(Oid heap,
    1067             :                Oid ind,
    1068             :                IndexInfo *indexInfo)
    1069             : {
    1070             :     IndexList  *newind;
    1071             :     MemoryContext oldcxt;
    1072             : 
    1073             :     /*
    1074             :      * XXX mao 10/31/92 -- don't gc index reldescs, associated info at
    1075             :      * bootstrap time.  we'll declare the indexes now, but want to create them
    1076             :      * later.
    1077             :      */
    1078             : 
    1079         127 :     if (nogc == NULL)
    1080           1 :         nogc = AllocSetContextCreate(NULL,
    1081             :                                      "BootstrapNoGC",
    1082             :                                      ALLOCSET_DEFAULT_SIZES);
    1083             : 
    1084         127 :     oldcxt = MemoryContextSwitchTo(nogc);
    1085             : 
    1086         127 :     newind = (IndexList *) palloc(sizeof(IndexList));
    1087         127 :     newind->il_heap = heap;
    1088         127 :     newind->il_ind = ind;
    1089         127 :     newind->il_info = (IndexInfo *) palloc(sizeof(IndexInfo));
    1090             : 
    1091         127 :     memcpy(newind->il_info, indexInfo, sizeof(IndexInfo));
    1092             :     /* expressions will likely be null, but may as well copy it */
    1093         254 :     newind->il_info->ii_Expressions =
    1094         127 :         copyObject(indexInfo->ii_Expressions);
    1095         127 :     newind->il_info->ii_ExpressionsState = NIL;
    1096             :     /* predicate will likely be null, but may as well copy it */
    1097         254 :     newind->il_info->ii_Predicate =
    1098         127 :         copyObject(indexInfo->ii_Predicate);
    1099         127 :     newind->il_info->ii_PredicateState = NULL;
    1100             :     /* no exclusion constraints at bootstrap time, so no need to copy */
    1101         127 :     Assert(indexInfo->ii_ExclusionOps == NULL);
    1102         127 :     Assert(indexInfo->ii_ExclusionProcs == NULL);
    1103         127 :     Assert(indexInfo->ii_ExclusionStrats == NULL);
    1104             : 
    1105         127 :     newind->il_next = ILHead;
    1106         127 :     ILHead = newind;
    1107             : 
    1108         127 :     MemoryContextSwitchTo(oldcxt);
    1109         127 : }
    1110             : 
    1111             : 
    1112             : /*
    1113             :  * build_indices -- fill in all the indexes registered earlier
    1114             :  */
    1115             : void
    1116           1 : build_indices(void)
    1117             : {
    1118         128 :     for (; ILHead != NULL; ILHead = ILHead->il_next)
    1119             :     {
    1120             :         Relation    heap;
    1121             :         Relation    ind;
    1122             : 
    1123             :         /* need not bother with locks during bootstrap */
    1124         127 :         heap = heap_open(ILHead->il_heap, NoLock);
    1125         127 :         ind = index_open(ILHead->il_ind, NoLock);
    1126             : 
    1127         127 :         index_build(heap, ind, ILHead->il_info, false, false);
    1128             : 
    1129         127 :         index_close(ind, NoLock);
    1130         127 :         heap_close(heap, NoLock);
    1131             :     }
    1132           1 : }

Generated by: LCOV version 1.11