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