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