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