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