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