Coverage Report

Created: 2025-08-12 06:43

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