LCOV - differential code coverage report
Current view: top level - src/backend/bootstrap - bootstrap.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 86.6 % 307 266 3 6 24 8 14 134 11 107 10 142 9 11
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 16 16 13 2 1 14
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  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-2023, 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/genam.h"
      21                 : #include "access/heapam.h"
      22                 : #include "access/htup_details.h"
      23                 : #include "access/tableam.h"
      24                 : #include "access/toast_compression.h"
      25                 : #include "access/xact.h"
      26                 : #include "access/xlog_internal.h"
      27                 : #include "bootstrap/bootstrap.h"
      28                 : #include "catalog/index.h"
      29                 : #include "catalog/pg_collation.h"
      30                 : #include "catalog/pg_type.h"
      31                 : #include "common/link-canary.h"
      32                 : #include "libpq/pqsignal.h"
      33                 : #include "miscadmin.h"
      34                 : #include "nodes/makefuncs.h"
      35                 : #include "pg_getopt.h"
      36                 : #include "storage/bufmgr.h"
      37                 : #include "storage/bufpage.h"
      38                 : #include "storage/condition_variable.h"
      39                 : #include "storage/ipc.h"
      40                 : #include "storage/proc.h"
      41                 : #include "tcop/tcopprot.h"
      42                 : #include "utils/builtins.h"
      43                 : #include "utils/fmgroids.h"
      44                 : #include "utils/memutils.h"
      45                 : #include "utils/rel.h"
      46                 : #include "utils/relmapper.h"
      47                 : 
      48                 : uint32      bootstrap_data_checksum_version = 0;    /* No checksum */
      49                 : 
      50                 : 
      51                 : static void CheckerModeMain(void);
      52                 : static void bootstrap_signals(void);
      53                 : static Form_pg_attribute AllocateAttribute(void);
      54                 : static void populate_typ_list(void);
      55                 : static Oid  gettype(char *type);
      56                 : static void cleanup(void);
      57                 : 
      58                 : /* ----------------
      59                 :  *      global variables
      60                 :  * ----------------
      61                 :  */
      62                 : 
      63                 : Relation    boot_reldesc;       /* current relation descriptor */
      64                 : 
      65                 : Form_pg_attribute attrtypes[MAXATTR];   /* points to attribute info */
      66                 : int         numattr;            /* number of attributes for cur. rel */
      67                 : 
      68                 : 
      69                 : /*
      70                 :  * Basic information associated with each type.  This is used before
      71                 :  * pg_type is filled, so it has to cover the datatypes used as column types
      72                 :  * in the core "bootstrapped" catalogs.
      73                 :  *
      74                 :  *      XXX several of these input/output functions do catalog scans
      75                 :  *          (e.g., F_REGPROCIN scans pg_proc).  this obviously creates some
      76                 :  *          order dependencies in the catalog creation process.
      77                 :  */
      78                 : struct typinfo
      79                 : {
      80                 :     char        name[NAMEDATALEN];
      81                 :     Oid         oid;
      82                 :     Oid         elem;
      83                 :     int16       len;
      84                 :     bool        byval;
      85                 :     char        align;
      86                 :     char        storage;
      87                 :     Oid         collation;
      88                 :     Oid         inproc;
      89                 :     Oid         outproc;
      90                 : };
      91                 : 
      92                 : static const struct typinfo TypInfo[] = {
      93                 :     {"bool", BOOLOID, 0, 1, true, TYPALIGN_CHAR, TYPSTORAGE_PLAIN, InvalidOid,
      94                 :     F_BOOLIN, F_BOOLOUT},
      95                 :     {"bytea", BYTEAOID, 0, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, InvalidOid,
      96                 :     F_BYTEAIN, F_BYTEAOUT},
      97                 :     {"char", CHAROID, 0, 1, true, TYPALIGN_CHAR, TYPSTORAGE_PLAIN, InvalidOid,
      98                 :     F_CHARIN, F_CHAROUT},
      99                 :     {"int2", INT2OID, 0, 2, true, TYPALIGN_SHORT, TYPSTORAGE_PLAIN, InvalidOid,
     100                 :     F_INT2IN, F_INT2OUT},
     101                 :     {"int4", INT4OID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
     102                 :     F_INT4IN, F_INT4OUT},
     103                 :     {"float4", FLOAT4OID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
     104                 :     F_FLOAT4IN, F_FLOAT4OUT},
     105                 :     {"name", NAMEOID, CHAROID, NAMEDATALEN, false, TYPALIGN_CHAR, TYPSTORAGE_PLAIN, C_COLLATION_OID,
     106                 :     F_NAMEIN, F_NAMEOUT},
     107                 :     {"regclass", REGCLASSOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
     108                 :     F_REGCLASSIN, F_REGCLASSOUT},
     109                 :     {"regproc", REGPROCOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
     110                 :     F_REGPROCIN, F_REGPROCOUT},
     111                 :     {"regtype", REGTYPEOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
     112                 :     F_REGTYPEIN, F_REGTYPEOUT},
     113                 :     {"regrole", REGROLEOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
     114                 :     F_REGROLEIN, F_REGROLEOUT},
     115                 :     {"regnamespace", REGNAMESPACEOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
     116                 :     F_REGNAMESPACEIN, F_REGNAMESPACEOUT},
     117                 :     {"text", TEXTOID, 0, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, DEFAULT_COLLATION_OID,
     118                 :     F_TEXTIN, F_TEXTOUT},
     119                 :     {"oid", OIDOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
     120                 :     F_OIDIN, F_OIDOUT},
     121                 :     {"tid", TIDOID, 0, 6, false, TYPALIGN_SHORT, TYPSTORAGE_PLAIN, InvalidOid,
     122                 :     F_TIDIN, F_TIDOUT},
     123                 :     {"xid", XIDOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
     124                 :     F_XIDIN, F_XIDOUT},
     125                 :     {"cid", CIDOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
     126                 :     F_CIDIN, F_CIDOUT},
     127                 :     {"pg_node_tree", PG_NODE_TREEOID, 0, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, DEFAULT_COLLATION_OID,
     128                 :     F_PG_NODE_TREE_IN, F_PG_NODE_TREE_OUT},
     129                 :     {"int2vector", INT2VECTOROID, INT2OID, -1, false, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
     130                 :     F_INT2VECTORIN, F_INT2VECTOROUT},
     131                 :     {"oidvector", OIDVECTOROID, OIDOID, -1, false, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
     132                 :     F_OIDVECTORIN, F_OIDVECTOROUT},
     133                 :     {"_int4", INT4ARRAYOID, INT4OID, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, InvalidOid,
     134                 :     F_ARRAY_IN, F_ARRAY_OUT},
     135                 :     {"_text", 1009, TEXTOID, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, DEFAULT_COLLATION_OID,
     136                 :     F_ARRAY_IN, F_ARRAY_OUT},
     137                 :     {"_oid", 1028, OIDOID, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, InvalidOid,
     138                 :     F_ARRAY_IN, F_ARRAY_OUT},
     139                 :     {"_char", 1002, CHAROID, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, InvalidOid,
     140                 :     F_ARRAY_IN, F_ARRAY_OUT},
     141                 :     {"_aclitem", 1034, ACLITEMOID, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, InvalidOid,
     142                 :     F_ARRAY_IN, F_ARRAY_OUT}
     143                 : };
     144                 : 
     145                 : static const int n_types = sizeof(TypInfo) / sizeof(struct typinfo);
     146                 : 
     147                 : struct typmap
     148                 : {                               /* a hack */
     149                 :     Oid         am_oid;
     150                 :     FormData_pg_type am_typ;
     151                 : };
     152                 : 
     153                 : static List *Typ = NIL;         /* List of struct typmap* */
     154                 : static struct typmap *Ap = NULL;
     155                 : 
     156                 : static Datum values[MAXATTR];   /* current row's attribute values */
     157                 : static bool Nulls[MAXATTR];
     158                 : 
     159                 : static MemoryContext nogc = NULL;   /* special no-gc mem context */
     160                 : 
     161                 : /*
     162                 :  *  At bootstrap time, we first declare all the indices to be built, and
     163                 :  *  then build them.  The IndexList structure stores enough information
     164                 :  *  to allow us to build the indices after they've been declared.
     165                 :  */
     166                 : 
     167                 : typedef struct _IndexList
     168                 : {
     169                 :     Oid         il_heap;
     170                 :     Oid         il_ind;
     171                 :     IndexInfo  *il_info;
     172                 :     struct _IndexList *il_next;
     173                 : } IndexList;
     174                 : 
     175                 : static IndexList *ILHead = NULL;
     176                 : 
     177                 : 
     178                 : /*
     179                 :  * In shared memory checker mode, all we really want to do is create shared
     180                 :  * memory and semaphores (just to prove we can do it with the current GUC
     181                 :  * settings).  Since, in fact, that was already done by
     182                 :  * CreateSharedMemoryAndSemaphores(), we have nothing more to do here.
     183                 :  */
     184                 : static void
     185 CBC         610 : CheckerModeMain(void)
     186                 : {
     187             610 :     proc_exit(0);
     188                 : }
     189                 : 
     190                 : /*
     191                 :  *   The main entry point for running the backend in bootstrap mode
     192                 :  *
     193                 :  *   The bootstrap mode is used to initialize the template database.
     194                 :  *   The bootstrap backend doesn't speak SQL, but instead expects
     195                 :  *   commands in a special bootstrap language.
     196                 :  *
     197                 :  *   When check_only is true, startup is done only far enough to verify that
     198                 :  *   the current configuration, particularly the passed in options pertaining
     199                 :  *   to shared memory sizing, options work (or at least do not cause an error
     200                 :  *   up to shared memory creation).
     201                 :  */
     202                 : void
     203             940 : BootstrapModeMain(int argc, char *argv[], bool check_only)
     204                 : {
     205                 :     int         i;
     206             940 :     char       *progname = argv[0];
     207                 :     int         flag;
     208             940 :     char       *userDoption = NULL;
     209                 : 
     210             940 :     Assert(!IsUnderPostmaster);
     211                 : 
     212             940 :     InitStandaloneProcess(argv[0]);
     213                 : 
     214                 :     /* Set defaults, to be overridden by explicit options below */
     215             940 :     InitializeGUCOptions();
     216                 : 
     217                 :     /* an initial --boot or --check should be present */
     218             940 :     Assert(argc > 1
     219                 :            && (strcmp(argv[1], "--boot") == 0
     220                 :                || strcmp(argv[1], "--check") == 0));
     221             940 :     argv++;
     222             940 :     argc--;
     223                 : 
     224            5031 :     while ((flag = getopt(argc, argv, "B:c:d:D:Fkr:X:-:")) != -1)
     225                 :     {
     226            4115 :         switch (flag)
     227                 :         {
     228 UBC           0 :             case 'B':
     229               0 :                 SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV);
     230               0 :                 break;
     231 GNC        2868 :             case 'c':
     232                 :             case '-':
     233                 :                 {
     234                 :                     char       *name,
     235                 :                                *value;
     236                 : 
     237            2868 :                     ParseLongOption(optarg, &name, &value);
     238            2868 :                     if (!value)
     239                 :                     {
     240 UNC           0 :                         if (flag == '-')
     241               0 :                             ereport(ERROR,
     242                 :                                     (errcode(ERRCODE_SYNTAX_ERROR),
     243                 :                                      errmsg("--%s requires a value",
     244                 :                                             optarg)));
     245                 :                         else
     246               0 :                             ereport(ERROR,
     247                 :                                     (errcode(ERRCODE_SYNTAX_ERROR),
     248                 :                                      errmsg("-c %s requires a value",
     249                 :                                             optarg)));
     250                 :                     }
     251                 : 
     252 GNC        2868 :                     SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV);
     253            2844 :                     pfree(name);
     254            2844 :                     pfree(value);
     255            2844 :                     break;
     256                 :                 }
     257 LBC           0 :             case 'D':
     258 UIC           0 :                 userDoption = pstrdup(optarg);
     259               0 :                 break;
     260               0 :             case 'd':
     261                 :                 {
     262                 :                     /* Turn on debugging for the bootstrap process. */
     263 ECB             :                     char       *debugstr;
     264                 : 
     265 UIC           0 :                     debugstr = psprintf("debug%s", optarg);
     266 UBC           0 :                     SetConfigOption("log_min_messages", debugstr,
     267 EUB             :                                     PGC_POSTMASTER, PGC_S_ARGV);
     268 UIC           0 :                     SetConfigOption("client_min_messages", debugstr,
     269                 :                                     PGC_POSTMASTER, PGC_S_ARGV);
     270               0 :                     pfree(debugstr);
     271                 :                 }
     272 UBC           0 :                 break;
     273 GIC         940 :             case 'F':
     274             940 :                 SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV);
     275             940 :                 break;
     276               1 :             case 'k':
     277               1 :                 bootstrap_data_checksum_version = PG_DATA_CHECKSUM_VERSION;
     278 CBC           1 :                 break;
     279 LBC           0 :             case 'r':
     280               0 :                 strlcpy(OutputFileName, optarg, MAXPGPATH);
     281               0 :                 break;
     282 GIC         306 :             case 'X':
     283 EUB             :                 {
     284 GBC         306 :                     int         WalSegSz = strtoul(optarg, NULL, 0);
     285 EUB             : 
     286 GBC         306 :                     if (!IsValidWalSegSize(WalSegSz))
     287 UIC           0 :                         ereport(ERROR,
     288                 :                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     289                 :                                  errmsg("-X requires a power of two value between 1 MB and 1 GB")));
     290 GIC         306 :                     SetConfigOption("wal_segment_size", optarg, PGC_INTERNAL,
     291 EUB             :                                     PGC_S_DYNAMIC_DEFAULT);
     292                 :                 }
     293 GIC         306 :                 break;
     294 UBC           0 :             default:
     295 UIC           0 :                 write_stderr("Try \"%s --help\" for more information.\n",
     296 EUB             :                              progname);
     297 UIC           0 :                 proc_exit(1);
     298                 :                 break;
     299                 :         }
     300                 :     }
     301 ECB             : 
     302 GIC         916 :     if (argc != optind)
     303 EUB             :     {
     304 UBC           0 :         write_stderr("%s: invalid command-line arguments\n", progname);
     305 UIC           0 :         proc_exit(1);
     306                 :     }
     307                 : 
     308 ECB             :     /* Acquire configuration parameters */
     309 GBC         916 :     if (!SelectConfigFiles(userDoption, progname))
     310 UIC           0 :         proc_exit(1);
     311                 : 
     312                 :     /*
     313                 :      * Validate we have been given a reasonable-looking DataDir and change
     314                 :      * into it
     315 ECB             :      */
     316 CBC         915 :     checkDataDir();
     317 GIC         915 :     ChangeToDataDir();
     318 ECB             : 
     319 GIC         915 :     CreateDataDirLockFile(false);
     320 ECB             : 
     321 CBC         915 :     SetProcessingMode(BootstrapProcessing);
     322 GIC         915 :     IgnoreSystemIndexes = true;
     323 ECB             : 
     324 GIC         915 :     InitializeMaxBackends();
     325 ECB             : 
     326 GIC         915 :     CreateSharedMemoryAndSemaphores();
     327                 : 
     328                 :     /*
     329                 :      * XXX: It might make sense to move this into its own function at some
     330                 :      * point. Right now it seems like it'd cause more code duplication than
     331                 :      * it's worth.
     332 ECB             :      */
     333 GIC         915 :     if (check_only)
     334 ECB             :     {
     335 CBC         610 :         SetProcessingMode(NormalProcessing);
     336 GBC         610 :         CheckerModeMain();
     337 UIC           0 :         abort();
     338                 :     }
     339                 : 
     340                 :     /*
     341                 :      * Do backend-like initialization for bootstrap mode
     342 ECB             :      */
     343 GIC         305 :     InitProcess();
     344 ECB             : 
     345 GIC         305 :     BaseInit();
     346 ECB             : 
     347 CBC         305 :     bootstrap_signals();
     348 GIC         305 :     BootStrapXLOG();
     349                 : 
     350                 :     /*
     351                 :      * To ensure that src/common/link-canary.c is linked into the backend, we
     352                 :      * must call it from somewhere.  Here is as good as anywhere.
     353 ECB             :      */
     354 GBC         305 :     if (pg_link_canary_is_frontend())
     355 UIC           0 :         elog(ERROR, "backend is incorrectly linked to frontend functions");
     356 ECB             : 
     357 GIC         305 :     InitPostgres(NULL, InvalidOid, NULL, InvalidOid, false, false, NULL);
     358                 : 
     359 ECB             :     /* Initialize stuff for bootstrap-file processing */
     360 GIC       12505 :     for (i = 0; i < MAXATTR; i++)
     361 ECB             :     {
     362 CBC       12200 :         attrtypes[i] = NULL;
     363 GIC       12200 :         Nulls[i] = false;
     364                 :     }
     365                 : 
     366                 :     /*
     367                 :      * Process bootstrap input.
     368 ECB             :      */
     369 CBC         305 :     StartTransactionCommand();
     370             305 :     boot_yyparse();
     371 GIC         305 :     CommitTransactionCommand();
     372                 : 
     373                 :     /*
     374                 :      * We should now know about all mapped relations, so it's okay to write
     375                 :      * out the initial relation mapping files.
     376 ECB             :      */
     377 GIC         305 :     RelationMapFinishBootstrap();
     378                 : 
     379 ECB             :     /* Clean up and exit */
     380 CBC         305 :     cleanup();
     381 GIC         305 :     proc_exit(0);
     382                 : }
     383                 : 
     384                 : 
     385                 : /* ----------------------------------------------------------------
     386                 :  *                      misc functions
     387                 :  * ----------------------------------------------------------------
     388                 :  */
     389                 : 
     390                 : /*
     391                 :  * Set up signal handling for a bootstrap process
     392                 :  */
     393 ECB             : static void
     394 GIC         305 : bootstrap_signals(void)
     395 ECB             : {
     396 GIC         305 :     Assert(!IsUnderPostmaster);
     397                 : 
     398                 :     /*
     399                 :      * We don't actually need any non-default signal handling in bootstrap
     400                 :      * mode; "curl up and die" is a sufficient response for all these cases.
     401                 :      * Let's set that handling explicitly, as documentation if nothing else.
     402 ECB             :      */
     403 CBC         305 :     pqsignal(SIGHUP, SIG_DFL);
     404             305 :     pqsignal(SIGINT, SIG_DFL);
     405             305 :     pqsignal(SIGTERM, SIG_DFL);
     406             305 :     pqsignal(SIGQUIT, SIG_DFL);
     407 GIC         305 : }
     408                 : 
     409                 : /* ----------------------------------------------------------------
     410                 :  *              MANUAL BACKEND INTERACTIVE INTERFACE COMMANDS
     411                 :  * ----------------------------------------------------------------
     412                 :  */
     413                 : 
     414                 : /* ----------------
     415                 :  *      boot_openrel
     416                 :  *
     417                 :  * Execute BKI OPEN command.
     418                 :  * ----------------
     419                 :  */
     420 ECB             : void
     421 GIC       18300 : boot_openrel(char *relname)
     422                 : {
     423                 :     int         i;
     424 ECB             : 
     425 GBC       18300 :     if (strlen(relname) >= NAMEDATALEN)
     426 UIC           0 :         relname[NAMEDATALEN - 1] = '\0';
     427                 : 
     428                 :     /*
     429                 :      * pg_type must be filled before any OPEN command is executed, hence we
     430                 :      * can now populate Typ if we haven't yet.
     431 ECB             :      */
     432 GBC       18300 :     if (Typ == NIL)
     433 UIC           0 :         populate_typ_list();
     434 ECB             : 
     435 GBC       18300 :     if (boot_reldesc != NULL)
     436 UIC           0 :         closerel(NULL);
     437 ECB             : 
     438 GIC       18300 :     elog(DEBUG4, "open relation %s, attrsize %d",
     439                 :          relname, (int) ATTRIBUTE_FIXED_PART_SIZE);
     440 ECB             : 
     441 CBC       18300 :     boot_reldesc = table_openrv(makeRangeVar(NULL, relname, -1), NoLock);
     442           18300 :     numattr = RelationGetNumberOfAttributes(boot_reldesc);
     443 GIC      163480 :     for (i = 0; i < numattr; i++)
     444 ECB             :     {
     445 GBC      145180 :         if (attrtypes[i] == NULL)
     446 LBC           0 :             attrtypes[i] = AllocateAttribute();
     447 CBC      145180 :         memmove((char *) attrtypes[i],
     448 GIC      145180 :                 (char *) TupleDescAttr(boot_reldesc->rd_att, i),
     449                 :                 ATTRIBUTE_FIXED_PART_SIZE);
     450                 : 
     451 ECB             :         {
     452 GIC      145180 :             Form_pg_attribute at = attrtypes[i];
     453 ECB             : 
     454 GIC      145180 :             elog(DEBUG4, "create attribute %d name %s len %d num %d type %u",
     455                 :                  i, NameStr(at->attname), at->attlen, at->attnum,
     456                 :                  at->atttypid);
     457                 :         }
     458 ECB             :     }
     459 GIC       18300 : }
     460                 : 
     461                 : /* ----------------
     462                 :  *      closerel
     463                 :  * ----------------
     464                 :  */
     465 ECB             : void
     466 GNC       19520 : closerel(char *relname)
     467 ECB             : {
     468 GNC       19520 :     if (relname)
     469 ECB             :     {
     470 GIC       19520 :         if (boot_reldesc)
     471 ECB             :         {
     472 GNC       19520 :             if (strcmp(RelationGetRelationName(boot_reldesc), relname) != 0)
     473 UIC           0 :                 elog(ERROR, "close of %s when %s was expected",
     474                 :                      relname, RelationGetRelationName(boot_reldesc));
     475                 :         }
     476 EUB             :         else
     477 UIC           0 :             elog(ERROR, "close of %s before any relation was opened",
     478                 :                  relname);
     479                 :     }
     480 ECB             : 
     481 GBC       19520 :     if (boot_reldesc == NULL)
     482 UIC           0 :         elog(ERROR, "no open relation to close");
     483                 :     else
     484 ECB             :     {
     485 GIC       19520 :         elog(DEBUG4, "close relation %s",
     486 ECB             :              RelationGetRelationName(boot_reldesc));
     487 CBC       19520 :         table_close(boot_reldesc, NoLock);
     488 GIC       19520 :         boot_reldesc = NULL;
     489 ECB             :     }
     490 GIC       19520 : }
     491                 : 
     492                 : 
     493                 : 
     494                 : /* ----------------
     495                 :  * DEFINEATTR()
     496                 :  *
     497                 :  * define a <field,type> pair
     498                 :  * if there are n fields in a relation to be created, this routine
     499                 :  * will be called n times
     500                 :  * ----------------
     501                 :  */
     502 ECB             : void
     503 GIC      182085 : DefineAttr(char *name, char *type, int attnum, int nullness)
     504                 : {
     505                 :     Oid         typeoid;
     506 ECB             : 
     507 GIC      182085 :     if (boot_reldesc != NULL)
     508 EUB             :     {
     509 UBC           0 :         elog(WARNING, "no open relations allowed with CREATE command");
     510 UIC           0 :         closerel(NULL);
     511                 :     }
     512 ECB             : 
     513 CBC      182085 :     if (attrtypes[attnum] == NULL)
     514           10065 :         attrtypes[attnum] = AllocateAttribute();
     515 GIC      182085 :     MemSet(attrtypes[attnum], 0, ATTRIBUTE_FIXED_PART_SIZE);
     516 ECB             : 
     517 CBC      182085 :     namestrcpy(&attrtypes[attnum]->attname, name);
     518          182085 :     elog(DEBUG4, "column %s %s", NameStr(attrtypes[attnum]->attname), type);
     519 GIC      182085 :     attrtypes[attnum]->attnum = attnum + 1;
     520 ECB             : 
     521 GIC      182085 :     typeoid = gettype(type);
     522 ECB             : 
     523 GIC      182085 :     if (Typ != NIL)
     524 ECB             :     {
     525 CBC      155550 :         attrtypes[attnum]->atttypid = Ap->am_oid;
     526          155550 :         attrtypes[attnum]->attlen = Ap->am_typ.typlen;
     527          155550 :         attrtypes[attnum]->attbyval = Ap->am_typ.typbyval;
     528          155550 :         attrtypes[attnum]->attalign = Ap->am_typ.typalign;
     529          155550 :         attrtypes[attnum]->attstorage = Ap->am_typ.typstorage;
     530          155550 :         attrtypes[attnum]->attcompression = InvalidCompressionMethod;
     531 GIC      155550 :         attrtypes[attnum]->attcollation = Ap->am_typ.typcollation;
     532 ECB             :         /* if an array type, assume 1-dimensional attribute */
     533 CBC      155550 :         if (Ap->am_typ.typelem != InvalidOid && Ap->am_typ.typlen < 0)
     534 GIC       14640 :             attrtypes[attnum]->attndims = 1;
     535 ECB             :         else
     536 GIC      140910 :             attrtypes[attnum]->attndims = 0;
     537                 :     }
     538                 :     else
     539 ECB             :     {
     540 CBC       26535 :         attrtypes[attnum]->atttypid = TypInfo[typeoid].oid;
     541           26535 :         attrtypes[attnum]->attlen = TypInfo[typeoid].len;
     542           26535 :         attrtypes[attnum]->attbyval = TypInfo[typeoid].byval;
     543           26535 :         attrtypes[attnum]->attalign = TypInfo[typeoid].align;
     544           26535 :         attrtypes[attnum]->attstorage = TypInfo[typeoid].storage;
     545           26535 :         attrtypes[attnum]->attcompression = InvalidCompressionMethod;
     546 GIC       26535 :         attrtypes[attnum]->attcollation = TypInfo[typeoid].collation;
     547 ECB             :         /* if an array type, assume 1-dimensional attribute */
     548 CBC       26535 :         if (TypInfo[typeoid].elem != InvalidOid &&
     549            4270 :             attrtypes[attnum]->attlen < 0)
     550 GIC        3355 :             attrtypes[attnum]->attndims = 1;
     551 ECB             :         else
     552 GIC       23180 :             attrtypes[attnum]->attndims = 0;
     553                 :     }
     554                 : 
     555                 :     /*
     556                 :      * If a system catalog column is collation-aware, force it to use C
     557                 :      * collation, so that its behavior is independent of the database's
     558                 :      * collation.  This is essential to allow template0 to be cloned with a
     559                 :      * different database collation.
     560 ECB             :      */
     561 CBC      182085 :     if (OidIsValid(attrtypes[attnum]->attcollation))
     562 GIC       30195 :         attrtypes[attnum]->attcollation = C_COLLATION_OID;
     563 ECB             : 
     564 CBC      182085 :     attrtypes[attnum]->attstattarget = -1;
     565          182085 :     attrtypes[attnum]->attcacheoff = -1;
     566          182085 :     attrtypes[attnum]->atttypmod = -1;
     567 GIC      182085 :     attrtypes[attnum]->attislocal = true;
     568 ECB             : 
     569 GIC      182085 :     if (nullness == BOOTCOL_NULL_FORCE_NOT_NULL)
     570 ECB             :     {
     571 GIC       10370 :         attrtypes[attnum]->attnotnull = true;
     572 ECB             :     }
     573 GIC      171715 :     else if (nullness == BOOTCOL_NULL_FORCE_NULL)
     574 ECB             :     {
     575 GIC         610 :         attrtypes[attnum]->attnotnull = false;
     576                 :     }
     577                 :     else
     578 ECB             :     {
     579 GIC      171105 :         Assert(nullness == BOOTCOL_NULL_AUTO);
     580                 : 
     581                 :         /*
     582                 :          * Mark as "not null" if type is fixed-width and prior columns are
     583                 :          * likewise fixed-width and not-null.  This corresponds to case where
     584                 :          * column can be accessed directly via C struct declaration.
     585 ECB             :          */
     586 GIC      171105 :         if (attrtypes[attnum]->attlen > 0)
     587                 :         {
     588                 :             int         i;
     589                 : 
     590 ECB             :             /* check earlier attributes */
     591 GIC     1019005 :             for (i = 0; i < attnum; i++)
     592 ECB             :             {
     593 CBC      874130 :                 if (attrtypes[i]->attlen <= 0 ||
     594 GIC      873215 :                     !attrtypes[i]->attnotnull)
     595                 :                     break;
     596 ECB             :             }
     597 CBC      145790 :             if (i == attnum)
     598 GIC      144875 :                 attrtypes[attnum]->attnotnull = true;
     599                 :         }
     600 ECB             :     }
     601 GIC      182085 : }
     602                 : 
     603                 : 
     604                 : /* ----------------
     605                 :  *      InsertOneTuple
     606                 :  *
     607                 :  * If objectid is not zero, it is a specific OID to assign to the tuple.
     608                 :  * Otherwise, an OID will be assigned (if necessary) by heap_insert.
     609                 :  * ----------------
     610                 :  */
     611 ECB             : void
     612 GIC     3215615 : InsertOneTuple(void)
     613                 : {
     614                 :     HeapTuple   tuple;
     615                 :     TupleDesc   tupDesc;
     616                 :     int         i;
     617 ECB             : 
     618 GIC     3215615 :     elog(DEBUG4, "inserting row with %d columns", numattr);
     619 ECB             : 
     620 CBC     3215615 :     tupDesc = CreateTupleDesc(numattr, attrtypes);
     621         3215615 :     tuple = heap_form_tuple(tupDesc, values, Nulls);
     622 GIC     3215615 :     pfree(tupDesc);             /* just free's tupDesc, not the attrtypes */
     623 ECB             : 
     624 CBC     3215615 :     simple_heap_insert(boot_reldesc, tuple);
     625         3215615 :     heap_freetuple(tuple);
     626 GIC     3215615 :     elog(DEBUG4, "row inserted");
     627                 : 
     628                 :     /*
     629                 :      * Reset null markers for next tuple
     630 ECB             :      */
     631 CBC    50904500 :     for (i = 0; i < numattr; i++)
     632        47688885 :         Nulls[i] = false;
     633 GIC     3215615 : }
     634                 : 
     635                 : /* ----------------
     636                 :  *      InsertOneValue
     637                 :  * ----------------
     638                 :  */
     639 ECB             : void
     640 GIC    38343072 : InsertOneValue(char *value, int i)
     641                 : {
     642                 :     Oid         typoid;
     643                 :     int16       typlen;
     644                 :     bool        typbyval;
     645                 :     char        typalign;
     646                 :     char        typdelim;
     647                 :     Oid         typioparam;
     648                 :     Oid         typinput;
     649                 :     Oid         typoutput;
     650 ECB             : 
     651 GNC    38343072 :     Assert(i >= 0 && i < MAXATTR);
     652 ECB             : 
     653 GIC    38343072 :     elog(DEBUG4, "inserting column %d value \"%s\"", i, value);
     654 ECB             : 
     655 GIC    38343072 :     typoid = TupleDescAttr(boot_reldesc->rd_att, i)->atttypid;
     656 ECB             : 
     657 GIC    38343072 :     boot_get_type_io_data(typoid,
     658                 :                           &typlen, &typbyval, &typalign,
     659                 :                           &typdelim, &typioparam,
     660                 :                           &typinput, &typoutput);
     661 ECB             : 
     662 GIC    38343072 :     values[i] = OidInputFunctionCall(typinput, value, typioparam, -1);
     663                 : 
     664                 :     /*
     665                 :      * We use ereport not elog here so that parameters aren't evaluated unless
     666                 :      * the message is going to be printed, which generally it isn't
     667 ECB             :      */
     668 GIC    38343072 :     ereport(DEBUG4,
     669                 :             (errmsg_internal("inserted -> %s",
     670 ECB             :                              OidOutputFunctionCall(typoutput, values[i]))));
     671 GIC    38343072 : }
     672                 : 
     673                 : /* ----------------
     674                 :  *      InsertOneNull
     675                 :  * ----------------
     676                 :  */
     677 ECB             : void
     678 GIC     9345813 : InsertOneNull(int i)
     679 ECB             : {
     680 CBC     9345813 :     elog(DEBUG4, "inserting column %d NULL", i);
     681         9345813 :     Assert(i >= 0 && i < MAXATTR);
     682 GBC     9345813 :     if (TupleDescAttr(boot_reldesc->rd_att, i)->attnotnull)
     683 UIC           0 :         elog(ERROR,
     684                 :              "NULL value specified for not-null column \"%s\" of relation \"%s\"",
     685                 :              NameStr(TupleDescAttr(boot_reldesc->rd_att, i)->attname),
     686 ECB             :              RelationGetRelationName(boot_reldesc));
     687 CBC     9345813 :     values[i] = PointerGetDatum(NULL);
     688         9345813 :     Nulls[i] = true;
     689 GIC     9345813 : }
     690                 : 
     691                 : /* ----------------
     692                 :  *      cleanup
     693                 :  * ----------------
     694                 :  */
     695 ECB             : static void
     696 GIC         305 : cleanup(void)
     697 ECB             : {
     698 GBC         305 :     if (boot_reldesc != NULL)
     699 LBC           0 :         closerel(NULL);
     700 GIC         305 : }
     701                 : 
     702                 : /* ----------------
     703                 :  *      populate_typ_list
     704                 :  *
     705                 :  * Load the Typ list by reading pg_type.
     706                 :  * ----------------
     707                 :  */
     708 ECB             : static void
     709 GIC         610 : populate_typ_list(void)
     710                 : {
     711                 :     Relation    rel;
     712                 :     TableScanDesc scan;
     713                 :     HeapTuple   tup;
     714                 :     MemoryContext old;
     715 ECB             : 
     716 GIC         610 :     Assert(Typ == NIL);
     717 ECB             : 
     718 CBC         610 :     rel = table_open(TypeRelationId, NoLock);
     719             610 :     scan = table_beginscan_catalog(rel, 0, NULL);
     720             610 :     old = MemoryContextSwitchTo(TopMemoryContext);
     721 GIC      128100 :     while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
     722 ECB             :     {
     723 GIC      127490 :         Form_pg_type typForm = (Form_pg_type) GETSTRUCT(tup);
     724                 :         struct typmap *newtyp;
     725 ECB             : 
     726 CBC      127490 :         newtyp = (struct typmap *) palloc(sizeof(struct typmap));
     727 GIC      127490 :         Typ = lappend(Typ, newtyp);
     728 ECB             : 
     729 CBC      127490 :         newtyp->am_oid = typForm->oid;
     730 GIC      127490 :         memcpy(&newtyp->am_typ, typForm, sizeof(newtyp->am_typ));
     731 ECB             :     }
     732 CBC         610 :     MemoryContextSwitchTo(old);
     733             610 :     table_endscan(scan);
     734             610 :     table_close(rel, NoLock);
     735 GIC         610 : }
     736                 : 
     737                 : /* ----------------
     738                 :  *      gettype
     739                 :  *
     740                 :  * NB: this is really ugly; it will return an integer index into TypInfo[],
     741                 :  * and not an OID at all, until the first reference to a type not known in
     742                 :  * TypInfo[].  At that point it will read and cache pg_type in Typ,
     743                 :  * and subsequently return a real OID (and set the global pointer Ap to
     744                 :  * point at the found row in Typ).  So caller must check whether Typ is
     745                 :  * still NIL to determine what the return value is!
     746                 :  * ----------------
     747                 :  */
     748 ECB             : static Oid
     749 GIC      182390 : gettype(char *type)
     750 ECB             : {
     751 GIC      182390 :     if (Typ != NIL)
     752                 :     {
     753                 :         ListCell   *lc;
     754 ECB             : 
     755 GIC     2974360 :         foreach(lc, Typ)
     756 ECB             :         {
     757 GIC     2974055 :             struct typmap *app = lfirst(lc);
     758 ECB             : 
     759 GIC     2974055 :             if (strncmp(NameStr(app->am_typ.typname), type, NAMEDATALEN) == 0)
     760 ECB             :             {
     761 CBC      155245 :                 Ap = app;
     762 GIC      155245 :                 return app->am_oid;
     763                 :             }
     764                 :         }
     765                 : 
     766                 :         /*
     767                 :          * The type wasn't known; reload the pg_type contents and check again
     768                 :          * to handle composite types, added since last populating the list.
     769                 :          */
     770 ECB             : 
     771 CBC         305 :         list_free_deep(Typ);
     772             305 :         Typ = NIL;
     773 GIC         305 :         populate_typ_list();
     774                 : 
     775                 :         /*
     776                 :          * Calling gettype would result in infinite recursion for types
     777                 :          * missing in pg_type, so just repeat the lookup.
     778 ECB             :          */
     779 GIC       68015 :         foreach(lc, Typ)
     780 ECB             :         {
     781 GIC       68015 :             struct typmap *app = lfirst(lc);
     782 ECB             : 
     783 GIC       68015 :             if (strncmp(NameStr(app->am_typ.typname), type, NAMEDATALEN) == 0)
     784 ECB             :             {
     785 CBC         305 :                 Ap = app;
     786 GIC         305 :                 return app->am_oid;
     787                 :             }
     788                 :         }
     789                 :     }
     790                 :     else
     791                 :     {
     792                 :         int         i;
     793 ECB             : 
     794 GIC      252845 :         for (i = 0; i < n_types; i++)
     795 ECB             :         {
     796 CBC      252540 :             if (strncmp(type, TypInfo[i].name, NAMEDATALEN) == 0)
     797 GIC       26535 :                 return i;
     798                 :         }
     799 ECB             :         /* Not in TypInfo, so we'd better be able to read pg_type now */
     800 CBC         305 :         elog(DEBUG4, "external type: %s", type);
     801             305 :         populate_typ_list();
     802 GIC         305 :         return gettype(type);
     803 EUB             :     }
     804 UIC           0 :     elog(ERROR, "unrecognized type \"%s\"", type);
     805                 :     /* not reached, here to make compiler happy */
     806                 :     return 0;
     807                 : }
     808                 : 
     809                 : /* ----------------
     810                 :  *      boot_get_type_io_data
     811                 :  *
     812                 :  * Obtain type I/O information at bootstrap time.  This intentionally has
     813                 :  * almost the same API as lsyscache.c's get_type_io_data, except that
     814                 :  * we only support obtaining the typinput and typoutput routines, not
     815                 :  * the binary I/O routines.  It is exported so that array_in and array_out
     816                 :  * can be made to work during early bootstrap.
     817                 :  * ----------------
     818                 :  */
     819 ECB             : void
     820 GIC    38460802 : boot_get_type_io_data(Oid typid,
     821                 :                       int16 *typlen,
     822                 :                       bool *typbyval,
     823                 :                       char *typalign,
     824                 :                       char *typdelim,
     825                 :                       Oid *typioparam,
     826                 :                       Oid *typinput,
     827                 :                       Oid *typoutput)
     828 ECB             : {
     829 GIC    38460802 :     if (Typ != NIL)
     830                 :     {
     831 ECB             :         /* We have the boot-time contents of pg_type, so use it */
     832 GIC    15426592 :         struct typmap *ap = NULL;
     833                 :         ListCell   *lc;
     834 ECB             : 
     835 GIC   136466120 :         foreach(lc, Typ)
     836 ECB             :         {
     837 CBC   136466120 :             ap = lfirst(lc);
     838       136466120 :             if (ap->am_oid == typid)
     839 GIC    15426592 :                 break;
     840                 :         }
     841 ECB             : 
     842 GBC    15426592 :         if (!ap || ap->am_oid != typid)
     843 UIC           0 :             elog(ERROR, "type OID %u not found in Typ list", typid);
     844 ECB             : 
     845 CBC    15426592 :         *typlen = ap->am_typ.typlen;
     846        15426592 :         *typbyval = ap->am_typ.typbyval;
     847        15426592 :         *typalign = ap->am_typ.typalign;
     848 GIC    15426592 :         *typdelim = ap->am_typ.typdelim;
     849                 : 
     850 ECB             :         /* XXX this logic must match getTypeIOParam() */
     851 CBC    15426592 :         if (OidIsValid(ap->am_typ.typelem))
     852 GIC      440115 :             *typioparam = ap->am_typ.typelem;
     853 ECB             :         else
     854 GIC    14986477 :             *typioparam = typid;
     855 ECB             : 
     856 CBC    15426592 :         *typinput = ap->am_typ.typinput;
     857 GIC    15426592 :         *typoutput = ap->am_typ.typoutput;
     858                 :     }
     859                 :     else
     860                 :     {
     861                 :         /* We don't have pg_type yet, so use the hard-wired TypInfo array */
     862                 :         int         typeindex;
     863 ECB             : 
     864 GIC   183928420 :         for (typeindex = 0; typeindex < n_types; typeindex++)
     865 ECB             :         {
     866 CBC   183928420 :             if (TypInfo[typeindex].oid == typid)
     867 GIC    23034210 :                 break;
     868 ECB             :         }
     869 GBC    23034210 :         if (typeindex >= n_types)
     870 UIC           0 :             elog(ERROR, "type OID %u not found in TypInfo", typid);
     871 ECB             : 
     872 CBC    23034210 :         *typlen = TypInfo[typeindex].len;
     873        23034210 :         *typbyval = TypInfo[typeindex].byval;
     874 GIC    23034210 :         *typalign = TypInfo[typeindex].align;
     875 ECB             :         /* We assume typdelim is ',' for all boot-time types */
     876 GIC    23034210 :         *typdelim = ',';
     877                 : 
     878 ECB             :         /* XXX this logic must match getTypeIOParam() */
     879 CBC    23034210 :         if (OidIsValid(TypInfo[typeindex].elem))
     880 GIC     2182885 :             *typioparam = TypInfo[typeindex].elem;
     881 ECB             :         else
     882 GIC    20851325 :             *typioparam = typid;
     883 ECB             : 
     884 CBC    23034210 :         *typinput = TypInfo[typeindex].inproc;
     885 GIC    23034210 :         *typoutput = TypInfo[typeindex].outproc;
     886 ECB             :     }
     887 GIC    38460802 : }
     888                 : 
     889                 : /* ----------------
     890                 :  *      AllocateAttribute
     891                 :  *
     892                 :  * Note: bootstrap never sets any per-column ACLs, so we only need
     893                 :  * ATTRIBUTE_FIXED_PART_SIZE space per attribute.
     894                 :  * ----------------
     895                 :  */
     896 ECB             : static Form_pg_attribute
     897 GIC       10065 : AllocateAttribute(void)
     898 ECB             : {
     899 CBC       10065 :     return (Form_pg_attribute)
     900 GIC       10065 :         MemoryContextAllocZero(TopMemoryContext, ATTRIBUTE_FIXED_PART_SIZE);
     901                 : }
     902                 : 
     903                 : /*
     904                 :  *  index_register() -- record an index that has been set up for building
     905                 :  *                      later.
     906                 :  *
     907                 :  *      At bootstrap time, we define a bunch of indexes on system catalogs.
     908                 :  *      We postpone actually building the indexes until just before we're
     909                 :  *      finished with initialization, however.  This is because the indexes
     910                 :  *      themselves have catalog entries, and those have to be included in the
     911                 :  *      indexes on those catalogs.  Doing it in two phases is the simplest
     912                 :  *      way of making sure the indexes have the right contents at the end.
     913                 :  */
     914 ECB             : void
     915 GIC       48800 : index_register(Oid heap,
     916                 :                Oid ind,
     917                 :                IndexInfo *indexInfo)
     918                 : {
     919                 :     IndexList  *newind;
     920                 :     MemoryContext oldcxt;
     921                 : 
     922                 :     /*
     923                 :      * XXX mao 10/31/92 -- don't gc index reldescs, associated info at
     924                 :      * bootstrap time.  we'll declare the indexes now, but want to create them
     925                 :      * later.
     926                 :      */
     927 ECB             : 
     928 CBC       48800 :     if (nogc == NULL)
     929 GIC         305 :         nogc = AllocSetContextCreate(NULL,
     930                 :                                      "BootstrapNoGC",
     931                 :                                      ALLOCSET_DEFAULT_SIZES);
     932 ECB             : 
     933 GIC       48800 :     oldcxt = MemoryContextSwitchTo(nogc);
     934 ECB             : 
     935 CBC       48800 :     newind = (IndexList *) palloc(sizeof(IndexList));
     936           48800 :     newind->il_heap = heap;
     937           48800 :     newind->il_ind = ind;
     938 GIC       48800 :     newind->il_info = (IndexInfo *) palloc(sizeof(IndexInfo));
     939 ECB             : 
     940 GIC       48800 :     memcpy(newind->il_info, indexInfo, sizeof(IndexInfo));
     941 ECB             :     /* expressions will likely be null, but may as well copy it */
     942 CBC       97600 :     newind->il_info->ii_Expressions =
     943           48800 :         copyObject(indexInfo->ii_Expressions);
     944 GIC       48800 :     newind->il_info->ii_ExpressionsState = NIL;
     945 ECB             :     /* predicate will likely be null, but may as well copy it */
     946 CBC       97600 :     newind->il_info->ii_Predicate =
     947           48800 :         copyObject(indexInfo->ii_Predicate);
     948 GIC       48800 :     newind->il_info->ii_PredicateState = NULL;
     949 ECB             :     /* no exclusion constraints at bootstrap time, so no need to copy */
     950 CBC       48800 :     Assert(indexInfo->ii_ExclusionOps == NULL);
     951           48800 :     Assert(indexInfo->ii_ExclusionProcs == NULL);
     952 GIC       48800 :     Assert(indexInfo->ii_ExclusionStrats == NULL);
     953 ECB             : 
     954 CBC       48800 :     newind->il_next = ILHead;
     955 GIC       48800 :     ILHead = newind;
     956 ECB             : 
     957 CBC       48800 :     MemoryContextSwitchTo(oldcxt);
     958 GIC       48800 : }
     959                 : 
     960                 : 
     961                 : /*
     962                 :  * build_indices -- fill in all the indexes registered earlier
     963                 :  */
     964 ECB             : void
     965 GIC         305 : build_indices(void)
     966 ECB             : {
     967 GIC       49105 :     for (; ILHead != NULL; ILHead = ILHead->il_next)
     968                 :     {
     969                 :         Relation    heap;
     970                 :         Relation    ind;
     971                 : 
     972 ECB             :         /* need not bother with locks during bootstrap */
     973 CBC       48800 :         heap = table_open(ILHead->il_heap, NoLock);
     974 GIC       48800 :         ind = index_open(ILHead->il_ind, NoLock);
     975 ECB             : 
     976 GIC       48800 :         index_build(heap, ind, ILHead->il_info, false, false);
     977 ECB             : 
     978 CBC       48800 :         index_close(ind, NoLock);
     979 GIC       48800 :         table_close(heap, NoLock);
     980 ECB             :     }
     981 GIC         305 : }
        

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