Coverage Report

Created: 2026-08-13 07:12

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