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-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 114 : CheckerModeMain(void)
220 : {
221 114 : proc_exit(0);
222 : }
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 196 : BootstrapModeMain(int argc, char *argv[], bool check_only)
238 : {
239 : int i;
240 196 : char *progname = argv[0];
241 : pg_getopt_ctx optctx;
242 : int flag;
243 196 : char *userDoption = NULL;
244 196 : uint32 bootstrap_data_checksum_version = PG_DATA_CHECKSUM_OFF;
245 : yyscan_t scanner;
246 :
247 : Assert(!IsUnderPostmaster);
248 :
249 196 : InitStandaloneProcess(argv[0]);
250 :
251 : /* Set defaults, to be overridden by explicit options below */
252 196 : InitializeGUCOptions();
253 :
254 : /* an initial --boot or --check should be present */
255 : Assert(argc > 1
256 : && (strcmp(argv[1], "--boot") == 0
257 : || strcmp(argv[1], "--check") == 0));
258 196 : argv++;
259 196 : argc--;
260 :
261 196 : pg_getopt_start(&optctx, argc, argv, "B:c:d:D:Fkr:X:-:");
262 1258 : while ((flag = pg_getopt_next(&optctx)) != -1)
263 : {
264 1086 : switch (flag)
265 : {
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 : (errcode(ERRCODE_SYNTAX_ERROR),
280 : errmsg("--%s must be first argument", optctx.optarg)));
281 :
282 : pg_fallthrough;
283 : case 'c':
284 : {
285 : char *name,
286 : *value;
287 :
288 786 : ParseLongOption(optctx.optarg, &name, &value);
289 786 : if (!value)
290 : {
291 0 : if (flag == '-')
292 0 : ereport(ERROR,
293 : (errcode(ERRCODE_SYNTAX_ERROR),
294 : errmsg("--%s requires a value",
295 : optctx.optarg)));
296 : else
297 0 : ereport(ERROR,
298 : (errcode(ERRCODE_SYNTAX_ERROR),
299 : errmsg("-c %s requires a value",
300 : optctx.optarg)));
301 : }
302 :
303 786 : SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV);
304 762 : pfree(name);
305 762 : pfree(value);
306 762 : break;
307 : }
308 0 : case 'D':
309 0 : userDoption = pstrdup(optctx.optarg);
310 0 : break;
311 0 : case 'd':
312 : {
313 : /* Turn on debugging for the bootstrap process. */
314 : char *debugstr;
315 :
316 0 : debugstr = psprintf("debug%s", optctx.optarg);
317 0 : SetConfigOption("log_min_messages", debugstr,
318 : PGC_POSTMASTER, PGC_S_ARGV);
319 0 : SetConfigOption("client_min_messages", debugstr,
320 : PGC_POSTMASTER, PGC_S_ARGV);
321 0 : pfree(debugstr);
322 : }
323 0 : break;
324 196 : case 'F':
325 196 : SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV);
326 196 : break;
327 46 : case 'k':
328 46 : bootstrap_data_checksum_version = PG_DATA_CHECKSUM_VERSION;
329 46 : break;
330 0 : case 'r':
331 0 : strlcpy(OutputFileName, optctx.optarg, MAXPGPATH);
332 0 : break;
333 58 : case 'X':
334 58 : SetConfigOption("wal_segment_size", optctx.optarg, PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
335 58 : break;
336 0 : default:
337 0 : write_stderr("Try \"%s --help\" for more information.\n",
338 : progname);
339 0 : proc_exit(1);
340 : break;
341 : }
342 : }
343 :
344 172 : if (argc != optctx.optind)
345 : {
346 0 : write_stderr("%s: invalid command-line arguments\n", progname);
347 0 : proc_exit(1);
348 : }
349 :
350 : /* Acquire configuration parameters */
351 172 : 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 171 : checkDataDir();
359 171 : ChangeToDataDir();
360 :
361 171 : CreateDataDirLockFile(false);
362 :
363 171 : SetProcessingMode(BootstrapProcessing);
364 171 : IgnoreSystemIndexes = true;
365 :
366 171 : RegisterBuiltinShmemCallbacks();
367 :
368 171 : 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 171 : InitPostmasterChildSlots();
376 :
377 171 : InitializeFastPathLocks();
378 :
379 171 : ShmemCallRequestCallbacks();
380 171 : 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 171 : 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 171 : if (check_only)
394 : {
395 114 : SetProcessingMode(NormalProcessing);
396 114 : CheckerModeMain();
397 0 : abort();
398 : }
399 :
400 : /*
401 : * Do backend-like initialization for bootstrap mode
402 : */
403 57 : InitProcess();
404 :
405 57 : BaseInit();
406 :
407 57 : bootstrap_signals();
408 57 : 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 57 : if (pg_link_canary_is_frontend())
415 0 : elog(ERROR, "backend is incorrectly linked to frontend functions");
416 :
417 57 : InitPostgres(NULL, InvalidOid, NULL, InvalidOid, 0, NULL);
418 :
419 : /* Initialize stuff for bootstrap-file processing */
420 2337 : for (i = 0; i < MAXATTR; i++)
421 : {
422 2280 : attrtypes[i] = NULL;
423 2280 : Nulls[i] = false;
424 : }
425 :
426 57 : if (boot_yylex_init(&scanner) != 0)
427 0 : elog(ERROR, "yylex_init() failed: %m");
428 :
429 : /*
430 : * Process bootstrap input.
431 : */
432 57 : StartTransactionCommand();
433 57 : boot_yyparse(scanner);
434 57 : 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 57 : RelationMapFinishBootstrap();
441 :
442 : /* Clean up and exit */
443 57 : cleanup();
444 57 : proc_exit(0);
445 : }
446 :
447 :
448 : /* ----------------------------------------------------------------
449 : * misc functions
450 : * ----------------------------------------------------------------
451 : */
452 :
453 : /*
454 : * Set up signal handling for a bootstrap process
455 : */
456 : static void
457 57 : bootstrap_signals(void)
458 : {
459 : 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 57 : pqsignal(SIGHUP, SIG_DFL);
467 57 : pqsignal(SIGINT, SIG_DFL);
468 57 : pqsignal(SIGTERM, SIG_DFL);
469 57 : pqsignal(SIGQUIT, SIG_DFL);
470 57 : }
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 3705 : boot_openrel(char *relname)
485 : {
486 : int i;
487 :
488 3705 : if (strlen(relname) >= NAMEDATALEN)
489 0 : 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 3705 : if (Typ == NIL)
496 0 : populate_typ_list();
497 :
498 3705 : if (boot_reldesc != NULL)
499 0 : closerel(NULL);
500 :
501 3705 : elog(DEBUG4, "open relation %s, attrsize %d",
502 : relname, (int) ATTRIBUTE_FIXED_PART_SIZE);
503 :
504 3705 : boot_reldesc = table_openrv(makeRangeVar(NULL, relname, -1), NoLock);
505 3705 : numattr = RelationGetNumberOfAttributes(boot_reldesc);
506 33516 : for (i = 0; i < numattr; i++)
507 : {
508 29811 : if (attrtypes[i] == NULL)
509 0 : attrtypes[i] = AllocateAttribute();
510 29811 : memmove(attrtypes[i],
511 29811 : TupleDescAttr(boot_reldesc->rd_att, i),
512 : ATTRIBUTE_FIXED_PART_SIZE);
513 :
514 : {
515 29811 : Form_pg_attribute at = attrtypes[i];
516 :
517 29811 : 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 3705 : }
523 :
524 : /* ----------------
525 : * closerel
526 : * ----------------
527 : */
528 : void
529 3933 : closerel(char *relname)
530 : {
531 3933 : if (relname)
532 : {
533 3933 : if (boot_reldesc)
534 : {
535 3933 : if (strcmp(RelationGetRelationName(boot_reldesc), relname) != 0)
536 0 : elog(ERROR, "close of %s when %s was expected",
537 : relname, RelationGetRelationName(boot_reldesc));
538 : }
539 : else
540 0 : elog(ERROR, "close of %s before any relation was opened",
541 : relname);
542 : }
543 :
544 3933 : if (boot_reldesc == NULL)
545 0 : elog(ERROR, "no open relation to close");
546 : else
547 : {
548 3933 : elog(DEBUG4, "close relation %s",
549 : RelationGetRelationName(boot_reldesc));
550 3933 : table_close(boot_reldesc, NoLock);
551 3933 : boot_reldesc = NULL;
552 : }
553 3933 : }
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 36708 : DefineAttr(char *name, char *type, int attnum, int nullness)
567 : {
568 : Oid typeoid;
569 :
570 36708 : if (boot_reldesc != NULL)
571 : {
572 0 : elog(WARNING, "no open relations allowed with CREATE command");
573 0 : closerel(NULL);
574 : }
575 :
576 36708 : if (attrtypes[attnum] == NULL)
577 1938 : attrtypes[attnum] = AllocateAttribute();
578 36708 : MemSet(attrtypes[attnum], 0, ATTRIBUTE_FIXED_PART_SIZE);
579 :
580 36708 : namestrcpy(&attrtypes[attnum]->attname, name);
581 36708 : elog(DEBUG4, "column %s %s", NameStr(attrtypes[attnum]->attname), type);
582 36708 : attrtypes[attnum]->attnum = attnum + 1;
583 :
584 36708 : typeoid = gettype(type);
585 :
586 36708 : if (Typ != NIL)
587 : {
588 31806 : attrtypes[attnum]->atttypid = Ap->am_oid;
589 31806 : attrtypes[attnum]->attlen = Ap->am_typ.typlen;
590 31806 : attrtypes[attnum]->attbyval = Ap->am_typ.typbyval;
591 31806 : attrtypes[attnum]->attalign = Ap->am_typ.typalign;
592 31806 : attrtypes[attnum]->attstorage = Ap->am_typ.typstorage;
593 31806 : attrtypes[attnum]->attcompression = InvalidCompressionMethod;
594 31806 : attrtypes[attnum]->attcollation = Ap->am_typ.typcollation;
595 : /* if an array type, assume 1-dimensional attribute */
596 31806 : if (Ap->am_typ.typelem != InvalidOid && Ap->am_typ.typlen < 0)
597 3078 : attrtypes[attnum]->attndims = 1;
598 : else
599 28728 : attrtypes[attnum]->attndims = 0;
600 : }
601 : else
602 : {
603 4902 : attrtypes[attnum]->atttypid = TypInfo[typeoid].oid;
604 4902 : attrtypes[attnum]->attlen = TypInfo[typeoid].len;
605 4902 : attrtypes[attnum]->attbyval = TypInfo[typeoid].byval;
606 4902 : attrtypes[attnum]->attalign = TypInfo[typeoid].align;
607 4902 : attrtypes[attnum]->attstorage = TypInfo[typeoid].storage;
608 4902 : attrtypes[attnum]->attcompression = InvalidCompressionMethod;
609 4902 : attrtypes[attnum]->attcollation = TypInfo[typeoid].collation;
610 : /* if an array type, assume 1-dimensional attribute */
611 4902 : if (TypInfo[typeoid].elem != InvalidOid &&
612 798 : attrtypes[attnum]->attlen < 0)
613 627 : attrtypes[attnum]->attndims = 1;
614 : else
615 4275 : attrtypes[attnum]->attndims = 0;
616 : }
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 36708 : if (OidIsValid(attrtypes[attnum]->attcollation))
625 5928 : attrtypes[attnum]->attcollation = C_COLLATION_OID;
626 :
627 36708 : attrtypes[attnum]->atttypmod = -1;
628 36708 : attrtypes[attnum]->attislocal = true;
629 :
630 36708 : if (nullness == BOOTCOL_NULL_FORCE_NOT_NULL)
631 : {
632 2052 : attrtypes[attnum]->attnotnull = true;
633 : }
634 34656 : else if (nullness == BOOTCOL_NULL_FORCE_NULL)
635 : {
636 228 : attrtypes[attnum]->attnotnull = false;
637 : }
638 : else
639 : {
640 : 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 34428 : if (attrtypes[attnum]->attlen > 0)
648 : {
649 : int i;
650 :
651 : /* check earlier attributes */
652 205029 : for (i = 0; i < attnum; i++)
653 : {
654 175845 : if (attrtypes[i]->attlen <= 0 ||
655 175674 : !attrtypes[i]->attnotnull)
656 : break;
657 : }
658 29355 : if (i == attnum)
659 29184 : attrtypes[attnum]->attnotnull = true;
660 : }
661 : }
662 36708 : }
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 623979 : InsertOneTuple(void)
674 : {
675 : HeapTuple tuple;
676 : TupleDesc tupDesc;
677 : int i;
678 :
679 623979 : elog(DEBUG4, "inserting row with %d columns", numattr);
680 :
681 623979 : tupDesc = CreateTupleDesc(numattr, attrtypes);
682 623979 : tuple = heap_form_tuple(tupDesc, values, Nulls);
683 623979 : pfree(tupDesc); /* just free's tupDesc, not the attrtypes */
684 :
685 623979 : simple_heap_insert(boot_reldesc, tuple);
686 623979 : heap_freetuple(tuple);
687 623979 : elog(DEBUG4, "row inserted");
688 :
689 : /*
690 : * Reset null markers for next tuple
691 : */
692 9887733 : for (i = 0; i < numattr; i++)
693 9263754 : Nulls[i] = false;
694 623979 : }
695 :
696 : /* ----------------
697 : * InsertOneValue
698 : * ----------------
699 : */
700 : void
701 7438680 : 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 7438680 : elog(DEBUG4, "inserting column %d value \"%s\"", i, value);
717 :
718 7438680 : attr = TupleDescAttr(RelationGetDescr(boot_reldesc), i);
719 7438680 : typoid = attr->atttypid;
720 :
721 7438680 : 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 7438680 : if (typoid == PG_NODE_TREEOID)
733 : {
734 : /* pg_proc.proargdefaults */
735 2394 : if (RelationGetRelid(boot_reldesc) == ProcedureRelationId &&
736 : i == Anum_pg_proc_proargdefaults - 1)
737 2394 : InsertOneProargdefaultsValue(value);
738 : else /* maybe other cases later */
739 0 : 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 7436286 : 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 7438680 : ereport(DEBUG4,
754 : (errmsg_internal("inserted -> %s",
755 : OidOutputFunctionCall(typoutput, values[i]))));
756 7438680 : }
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 2394 : InsertOneProargdefaultsValue(char *value)
769 : {
770 : int pronargs;
771 : oidvector *proargtypes;
772 : Datum arrayval;
773 : Datum *array_datums;
774 : bool *array_nulls;
775 : int array_count;
776 : List *proargdefaults;
777 : char *nodestring;
778 :
779 : /* The pg_proc columns we need to use must have been filled already */
780 : StaticAssertDecl(Anum_pg_proc_pronargs < Anum_pg_proc_proargdefaults,
781 : "pronargs must come before proargdefaults");
782 : StaticAssertDecl(Anum_pg_proc_pronargdefaults < Anum_pg_proc_proargdefaults,
783 : "pronargdefaults must come before proargdefaults");
784 : StaticAssertDecl(Anum_pg_proc_proargtypes < Anum_pg_proc_proargdefaults,
785 : "proargtypes must come before proargdefaults");
786 2394 : if (Nulls[Anum_pg_proc_pronargs - 1])
787 0 : elog(ERROR, "pronargs must not be null");
788 2394 : if (Nulls[Anum_pg_proc_proargtypes - 1])
789 0 : elog(ERROR, "proargtypes must not be null");
790 2394 : pronargs = DatumGetInt16(values[Anum_pg_proc_pronargs - 1]);
791 2394 : proargtypes = DatumGetPointer(values[Anum_pg_proc_proargtypes - 1]);
792 : Assert(pronargs == proargtypes->dim1);
793 :
794 : /* Parse the input string as an array value, then deconstruct to Datums */
795 2394 : arrayval = OidFunctionCall3(F_ARRAY_IN,
796 : CStringGetDatum(value),
797 : ObjectIdGetDatum(CSTRINGOID),
798 : Int32GetDatum(-1));
799 2394 : deconstruct_array_builtin(DatumGetArrayTypeP(arrayval), CSTRINGOID,
800 : &array_datums, &array_nulls, &array_count);
801 :
802 : /* The values should correspond to the last N argtypes */
803 2394 : if (array_count > pronargs)
804 0 : elog(ERROR, "too many proargdefaults entries");
805 :
806 : /* Build the List of Const nodes */
807 2394 : proargdefaults = NIL;
808 6099 : for (int i = 0; i < array_count; i++)
809 : {
810 3705 : Oid argtype = proargtypes->values[pronargs - array_count + i];
811 : int16 typlen;
812 : bool typbyval;
813 : char typalign;
814 : char typdelim;
815 : Oid typioparam;
816 : Oid typinput;
817 : Oid typoutput;
818 : Oid typcollation;
819 : Datum defval;
820 : bool defnull;
821 : Const *defConst;
822 :
823 3705 : boot_get_type_io_data(argtype,
824 : &typlen, &typbyval, &typalign,
825 : &typdelim, &typioparam,
826 : &typinput, &typoutput,
827 : &typcollation);
828 :
829 3705 : defnull = array_nulls[i];
830 3705 : if (defnull)
831 342 : defval = (Datum) 0;
832 : else
833 3363 : defval = OidInputFunctionCall(typinput,
834 3363 : DatumGetCString(array_datums[i]),
835 : typioparam, -1);
836 :
837 3705 : defConst = makeConst(argtype,
838 : -1, /* never any typmod */
839 : typcollation,
840 : typlen,
841 : defval,
842 : defnull,
843 : typbyval);
844 3705 : proargdefaults = lappend(proargdefaults, defConst);
845 : }
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 2394 : nodestring = nodeToString(proargdefaults);
852 2394 : values[Anum_pg_proc_proargdefaults - 1] = CStringGetTextDatum(nodestring);
853 2394 : 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 2394 : values[Anum_pg_proc_pronargdefaults - 1] = Int16GetDatum(array_count);
860 2394 : Nulls[Anum_pg_proc_pronargdefaults - 1] = false;
861 2394 : }
862 :
863 : /* ----------------
864 : * InsertOneNull
865 : * ----------------
866 : */
867 : void
868 1825074 : InsertOneNull(int i)
869 : {
870 1825074 : elog(DEBUG4, "inserting column %d NULL", i);
871 : Assert(i >= 0 && i < MAXATTR);
872 1825074 : if (TupleDescAttr(boot_reldesc->rd_att, i)->attnotnull)
873 0 : elog(ERROR,
874 : "NULL value specified for not-null column \"%s\" of relation \"%s\"",
875 : NameStr(TupleDescAttr(boot_reldesc->rd_att, i)->attname),
876 : RelationGetRelationName(boot_reldesc));
877 1825074 : values[i] = PointerGetDatum(NULL);
878 1825074 : Nulls[i] = true;
879 1825074 : }
880 :
881 : /* ----------------
882 : * cleanup
883 : * ----------------
884 : */
885 : static void
886 57 : cleanup(void)
887 : {
888 57 : if (boot_reldesc != NULL)
889 0 : closerel(NULL);
890 57 : }
891 :
892 : /* ----------------
893 : * populate_typ_list
894 : *
895 : * Load the Typ list by reading pg_type.
896 : * ----------------
897 : */
898 : static void
899 114 : populate_typ_list(void)
900 : {
901 : Relation rel;
902 : TableScanDesc scan;
903 : HeapTuple tup;
904 : MemoryContext old;
905 :
906 : Assert(Typ == NIL);
907 :
908 114 : rel = table_open(TypeRelationId, NoLock);
909 114 : scan = table_beginscan_catalog(rel, 0, NULL);
910 114 : old = MemoryContextSwitchTo(TopMemoryContext);
911 24396 : while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
912 : {
913 24282 : Form_pg_type typForm = (Form_pg_type) GETSTRUCT(tup);
914 : struct typmap *newtyp;
915 :
916 24282 : newtyp = palloc_object(struct typmap);
917 24282 : Typ = lappend(Typ, newtyp);
918 :
919 24282 : newtyp->am_oid = typForm->oid;
920 24282 : memcpy(&newtyp->am_typ, typForm, sizeof(newtyp->am_typ));
921 : }
922 114 : MemoryContextSwitchTo(old);
923 114 : table_endscan(scan);
924 114 : table_close(rel, NoLock);
925 114 : }
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 36765 : gettype(char *type)
940 : {
941 36765 : if (Typ != NIL)
942 : {
943 : ListCell *lc;
944 :
945 621699 : foreach(lc, Typ)
946 : {
947 621642 : struct typmap *app = lfirst(lc);
948 :
949 621642 : if (strncmp(NameStr(app->am_typ.typname), type, NAMEDATALEN) == 0)
950 : {
951 31749 : Ap = app;
952 31749 : return app->am_oid;
953 : }
954 : }
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 57 : list_free_deep(Typ);
962 57 : Typ = NIL;
963 57 : 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 12939 : foreach(lc, Typ)
970 : {
971 12939 : struct typmap *app = lfirst(lc);
972 :
973 12939 : if (strncmp(NameStr(app->am_typ.typname), type, NAMEDATALEN) == 0)
974 : {
975 57 : Ap = app;
976 57 : return app->am_oid;
977 : }
978 : }
979 : }
980 : else
981 : {
982 : int i;
983 :
984 47481 : for (i = 0; i < n_types; i++)
985 : {
986 47424 : if (strncmp(type, TypInfo[i].name, NAMEDATALEN) == 0)
987 4902 : return i;
988 : }
989 : /* Not in TypInfo, so we'd better be able to read pg_type now */
990 57 : elog(DEBUG4, "external type: %s", type);
991 57 : populate_typ_list();
992 57 : return gettype(type);
993 : }
994 0 : elog(ERROR, "unrecognized type \"%s\"", type);
995 : /* not reached, here to make compiler happy */
996 : return 0;
997 : }
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 7479492 : 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 : {
1021 7479492 : if (Typ != NIL)
1022 : {
1023 : /* We have the boot-time contents of pg_type, so use it */
1024 2940525 : struct typmap *ap = NULL;
1025 : ListCell *lc;
1026 :
1027 26073087 : foreach(lc, Typ)
1028 : {
1029 26073087 : ap = lfirst(lc);
1030 26073087 : if (ap->am_oid == typid)
1031 2940525 : break;
1032 : }
1033 :
1034 2940525 : if (!ap || ap->am_oid != typid)
1035 0 : elog(ERROR, "type OID %u not found in Typ list", typid);
1036 :
1037 2940525 : *typlen = ap->am_typ.typlen;
1038 2940525 : *typbyval = ap->am_typ.typbyval;
1039 2940525 : *typalign = ap->am_typ.typalign;
1040 2940525 : *typdelim = ap->am_typ.typdelim;
1041 :
1042 : /* XXX this logic must match getTypeIOParam() */
1043 2940525 : if (OidIsValid(ap->am_typ.typelem))
1044 82992 : *typioparam = ap->am_typ.typelem;
1045 : else
1046 2857533 : *typioparam = typid;
1047 :
1048 2940525 : *typinput = ap->am_typ.typinput;
1049 2940525 : *typoutput = ap->am_typ.typoutput;
1050 :
1051 2940525 : *typcollation = ap->am_typ.typcollation;
1052 : }
1053 : else
1054 : {
1055 : /* We don't have pg_type yet, so use the hard-wired TypInfo array */
1056 : int typeindex;
1057 :
1058 38213826 : for (typeindex = 0; typeindex < n_types; typeindex++)
1059 : {
1060 38213826 : if (TypInfo[typeindex].oid == typid)
1061 4538967 : break;
1062 : }
1063 4538967 : if (typeindex >= n_types)
1064 0 : elog(ERROR, "type OID %u not found in TypInfo", typid);
1065 :
1066 4538967 : *typlen = TypInfo[typeindex].len;
1067 4538967 : *typbyval = TypInfo[typeindex].byval;
1068 4538967 : *typalign = TypInfo[typeindex].align;
1069 : /* We assume typdelim is ',' for all boot-time types */
1070 4538967 : *typdelim = ',';
1071 :
1072 : /* XXX this logic must match getTypeIOParam() */
1073 4538967 : if (OidIsValid(TypInfo[typeindex].elem))
1074 439356 : *typioparam = TypInfo[typeindex].elem;
1075 : else
1076 4099611 : *typioparam = typid;
1077 :
1078 4538967 : *typinput = TypInfo[typeindex].inproc;
1079 4538967 : *typoutput = TypInfo[typeindex].outproc;
1080 :
1081 4538967 : *typcollation = TypInfo[typeindex].collation;
1082 : }
1083 7479492 : }
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 4845 : boot_get_role_oid(const char *rolname)
1095 : {
1096 9063 : for (int i = 0; i < lengthof(RolInfo); i++)
1097 : {
1098 9063 : if (strcmp(RolInfo[i].rolname, rolname) == 0)
1099 4845 : return RolInfo[i].oid;
1100 : }
1101 0 : return InvalidOid;
1102 : }
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 1938 : AllocateAttribute(void)
1113 : {
1114 1938 : return (Form_pg_attribute)
1115 1938 : MemoryContextAllocZero(TopMemoryContext, ATTRIBUTE_FIXED_PART_SIZE);
1116 : }
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 9804 : index_register(Oid heap,
1131 : Oid ind,
1132 : const IndexInfo *indexInfo)
1133 : {
1134 : IndexList *newind;
1135 : 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 9804 : if (nogc == NULL)
1144 57 : nogc = AllocSetContextCreate(NULL,
1145 : "BootstrapNoGC",
1146 : ALLOCSET_DEFAULT_SIZES);
1147 :
1148 9804 : oldcxt = MemoryContextSwitchTo(nogc);
1149 :
1150 9804 : newind = palloc_object(IndexList);
1151 9804 : newind->il_heap = heap;
1152 9804 : newind->il_ind = ind;
1153 9804 : newind->il_info = palloc_object(IndexInfo);
1154 :
1155 9804 : memcpy(newind->il_info, indexInfo, sizeof(IndexInfo));
1156 : /* expressions will likely be null, but may as well copy it */
1157 19608 : newind->il_info->ii_Expressions =
1158 9804 : copyObject(indexInfo->ii_Expressions);
1159 9804 : newind->il_info->ii_ExpressionsState = NIL;
1160 : /* predicate will likely be null, but may as well copy it */
1161 19608 : newind->il_info->ii_Predicate =
1162 9804 : copyObject(indexInfo->ii_Predicate);
1163 9804 : newind->il_info->ii_PredicateState = NULL;
1164 : /* no exclusion constraints at bootstrap time, so no need to copy */
1165 : Assert(indexInfo->ii_ExclusionOps == NULL);
1166 : Assert(indexInfo->ii_ExclusionProcs == NULL);
1167 : Assert(indexInfo->ii_ExclusionStrats == NULL);
1168 :
1169 9804 : newind->il_next = ILHead;
1170 9804 : ILHead = newind;
1171 :
1172 9804 : MemoryContextSwitchTo(oldcxt);
1173 9804 : }
1174 :
1175 :
1176 : /*
1177 : * build_indices -- fill in all the indexes registered earlier
1178 : */
1179 : void
1180 57 : build_indices(void)
1181 : {
1182 9861 : for (; ILHead != NULL; ILHead = ILHead->il_next)
1183 : {
1184 : Relation heap;
1185 : Relation ind;
1186 :
1187 : /* need not bother with locks during bootstrap */
1188 9804 : heap = table_open(ILHead->il_heap, NoLock);
1189 9804 : ind = index_open(ILHead->il_ind, NoLock);
1190 :
1191 9804 : index_build(heap, ind, ILHead->il_info, false, false, false);
1192 :
1193 9804 : index_close(ind, NoLock);
1194 9804 : table_close(heap, NoLock);
1195 : }
1196 57 : }
|