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