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