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