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